mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge branch '0.15.0'
This commit is contained in:
commit
f22c3b549e
@ -11,13 +11,11 @@ addons:
|
|||||||
- gcc-4.8
|
- gcc-4.8
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- node_js: "5"
|
- node_js: "7"
|
||||||
- node_js: "6"
|
|
||||||
node_js:
|
node_js:
|
||||||
|
- "7"
|
||||||
- "6"
|
- "6"
|
||||||
- "5"
|
|
||||||
- "4"
|
- "4"
|
||||||
- "0.12"
|
|
||||||
- "0.10"
|
- "0.10"
|
||||||
script:
|
script:
|
||||||
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
|
- istanbul cover ./node_modules/.bin/grunt --report lcovonly && istanbul report text && ( cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js || true ) && rm -rf coverage
|
||||||
|
19
Gruntfile.js
19
Gruntfile.js
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013, 2015 IBM Corp.
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -104,30 +104,35 @@ module.exports = function(grunt) {
|
|||||||
"editor/js/settings.js",
|
"editor/js/settings.js",
|
||||||
"editor/js/user.js",
|
"editor/js/user.js",
|
||||||
"editor/js/comms.js",
|
"editor/js/comms.js",
|
||||||
|
"editor/js/text/bidi.js",
|
||||||
|
"editor/js/text/format.js",
|
||||||
"editor/js/ui/state.js",
|
"editor/js/ui/state.js",
|
||||||
"editor/js/nodes.js",
|
"editor/js/nodes.js",
|
||||||
"editor/js/history.js",
|
"editor/js/history.js",
|
||||||
"editor/js/validators.js",
|
"editor/js/validators.js",
|
||||||
|
"editor/js/ui/common/editableList.js",
|
||||||
|
"editor/js/ui/common/menu.js",
|
||||||
|
"editor/js/ui/common/popover.js",
|
||||||
|
"editor/js/ui/common/searchBox.js",
|
||||||
|
"editor/js/ui/common/tabs.js",
|
||||||
|
"editor/js/ui/common/typedInput.js",
|
||||||
"editor/js/ui/deploy.js",
|
"editor/js/ui/deploy.js",
|
||||||
"editor/js/ui/menu.js",
|
|
||||||
"editor/js/ui/keyboard.js",
|
"editor/js/ui/keyboard.js",
|
||||||
"editor/js/ui/tabs.js",
|
|
||||||
"editor/js/ui/popover.js",
|
|
||||||
"editor/js/ui/workspaces.js",
|
"editor/js/ui/workspaces.js",
|
||||||
"editor/js/ui/view.js",
|
"editor/js/ui/view.js",
|
||||||
"editor/js/ui/sidebar.js",
|
"editor/js/ui/sidebar.js",
|
||||||
"editor/js/ui/palette.js",
|
"editor/js/ui/palette.js",
|
||||||
"editor/js/ui/tab-info.js",
|
"editor/js/ui/tab-info.js",
|
||||||
"editor/js/ui/tab-config.js",
|
"editor/js/ui/tab-config.js",
|
||||||
|
"editor/js/ui/palette-editor.js",
|
||||||
"editor/js/ui/editor.js",
|
"editor/js/ui/editor.js",
|
||||||
"editor/js/ui/tray.js",
|
"editor/js/ui/tray.js",
|
||||||
"editor/js/ui/clipboard.js",
|
"editor/js/ui/clipboard.js",
|
||||||
"editor/js/ui/library.js",
|
"editor/js/ui/library.js",
|
||||||
"editor/js/ui/notifications.js",
|
"editor/js/ui/notifications.js",
|
||||||
|
"editor/js/ui/search.js",
|
||||||
"editor/js/ui/subflow.js",
|
"editor/js/ui/subflow.js",
|
||||||
"editor/js/ui/touch/radialMenu.js",
|
"editor/js/ui/touch/radialMenu.js"
|
||||||
"editor/js/ui/typedInput.js",
|
|
||||||
"editor/js/ui/editableList.js"
|
|
||||||
],
|
],
|
||||||
dest: "public/red/red.js"
|
dest: "public/red/red.js"
|
||||||
},
|
},
|
||||||
|
BIN
editor/icons/cog.png
Normal file
BIN
editor/icons/cog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 493 B |
@ -176,6 +176,7 @@ RED.history = (function() {
|
|||||||
n.n.x = n.ox;
|
n.n.x = n.ox;
|
||||||
n.n.y = n.oy;
|
n.n.y = n.oy;
|
||||||
n.n.dirty = true;
|
n.n.dirty = true;
|
||||||
|
n.n.changed = n.changed;
|
||||||
}
|
}
|
||||||
// A move could have caused a link splice
|
// A move could have caused a link splice
|
||||||
if (ev.links) {
|
if (ev.links) {
|
||||||
@ -234,10 +235,6 @@ RED.history = (function() {
|
|||||||
n.outputs = ev.node.out.length;
|
n.outputs = ev.node.out.length;
|
||||||
RED.editor.updateNodeProperties(n);
|
RED.editor.updateNodeProperties(n);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ev.node.type === 'subflow') {
|
|
||||||
$("#menu-item-workspace-menu-"+ev.node.id.replace(".","-")).text(ev.node.name);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
RED.editor.updateNodeProperties(ev.node);
|
RED.editor.updateNodeProperties(ev.node);
|
||||||
RED.editor.validateNode(ev.node);
|
RED.editor.validateNode(ev.node);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013, 2015 IBM Corp.
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -56,11 +56,9 @@ var RED = (function() {
|
|||||||
success: function(data) {
|
success: function(data) {
|
||||||
$("body").append(data);
|
$("body").append(data);
|
||||||
$("body").i18n();
|
$("body").i18n();
|
||||||
|
$("#palette > .palette-spinner").hide();
|
||||||
|
$(".palette-scroll").removeClass("hide");
|
||||||
$(".palette-spinner").hide();
|
$("#palette-search").removeClass("hide");
|
||||||
$(".palette-scroll").show();
|
|
||||||
$("#palette-search").show();
|
|
||||||
loadFlows();
|
loadFlows();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -69,14 +67,19 @@ var RED = (function() {
|
|||||||
function loadFlows() {
|
function loadFlows() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
headers: {
|
headers: {
|
||||||
"Accept":"application/json"
|
"Accept":"application/json",
|
||||||
},
|
},
|
||||||
cache: false,
|
cache: false,
|
||||||
url: 'flows',
|
url: 'flows',
|
||||||
success: function(nodes) {
|
success: function(nodes) {
|
||||||
RED.nodes.import(nodes);
|
var currentHash = window.location.hash;
|
||||||
|
RED.nodes.version(nodes.rev);
|
||||||
|
RED.nodes.import(nodes.flows);
|
||||||
RED.nodes.dirty(false);
|
RED.nodes.dirty(false);
|
||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
|
if (/^#flow\/.+$/.test(currentHash)) {
|
||||||
|
RED.workspaces.show(currentHash.substring(6));
|
||||||
|
}
|
||||||
RED.comms.subscribe("status/#",function(topic,msg) {
|
RED.comms.subscribe("status/#",function(topic,msg) {
|
||||||
var parts = topic.split("/");
|
var parts = topic.split("/");
|
||||||
var node = RED.nodes.node(parts[1]);
|
var node = RED.nodes.node(parts[1]);
|
||||||
@ -169,45 +172,59 @@ var RED = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadEditor() {
|
function loadEditor() {
|
||||||
RED.menu.init({id:"btn-sidemenu",
|
|
||||||
options: [
|
var menuOptions = [];
|
||||||
{id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
menuOptions.push({id:"menu-item-view-menu",label:RED._("menu.label.view.view"),options:[
|
||||||
{id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:RED.view.toggleShowGrid},
|
{id:"menu-item-view-show-grid",label:RED._("menu.label.view.showGrid"),toggle:true,onselect:RED.view.toggleShowGrid},
|
||||||
{id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:RED.view.toggleSnapGrid},
|
{id:"menu-item-view-snap-grid",label:RED._("menu.label.view.snapGrid"),toggle:true,onselect:RED.view.toggleSnapGrid},
|
||||||
{id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true},
|
{id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true},
|
||||||
null,
|
null,
|
||||||
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true}
|
{id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[
|
||||||
|
{id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}},
|
||||||
|
{id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}},
|
||||||
|
{id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}},
|
||||||
|
{id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}}
|
||||||
]},
|
]},
|
||||||
null,
|
null,
|
||||||
{id:"menu-item-import",label:RED._("menu.label.import"),options:[
|
{id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true}
|
||||||
|
]});
|
||||||
|
menuOptions.push(null);
|
||||||
|
menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[
|
||||||
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import},
|
{id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:RED.clipboard.import},
|
||||||
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
|
{id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]}
|
||||||
]},
|
]});
|
||||||
{id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
|
menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),disabled:true,options:[
|
||||||
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:RED.clipboard.export},
|
{id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),disabled:true,onselect:RED.clipboard.export},
|
||||||
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export}
|
{id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:RED.library.export}
|
||||||
]},
|
]});
|
||||||
null,
|
menuOptions.push(null);
|
||||||
{id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:function() {}},
|
menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:RED.search.show});
|
||||||
{id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
|
menuOptions.push(null);
|
||||||
|
menuOptions.push({id:"menu-item-config-nodes",label:RED._("menu.label.displayConfig"),onselect:function() {}});
|
||||||
|
menuOptions.push({id:"menu-item-workspace",label:RED._("menu.label.flows"),options:[
|
||||||
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
|
{id:"menu-item-workspace-add",label:RED._("menu.label.add"),onselect:RED.workspaces.add},
|
||||||
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
|
{id:"menu-item-workspace-edit",label:RED._("menu.label.rename"),onselect:RED.workspaces.edit},
|
||||||
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove},
|
{id:"menu-item-workspace-delete",label:RED._("menu.label.delete"),onselect:RED.workspaces.remove}
|
||||||
null
|
]});
|
||||||
]},
|
menuOptions.push({id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
|
||||||
{id:"menu-item-subflow",label:RED._("menu.label.subflows"), options: [
|
|
||||||
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow},
|
{id:"menu-item-subflow-create",label:RED._("menu.label.createSubflow"),onselect:RED.subflow.createSubflow},
|
||||||
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow},
|
{id:"menu-item-subflow-convert",label:RED._("menu.label.selectionToSubflow"),disabled:true,onselect:RED.subflow.convertToSubflow},
|
||||||
]},
|
]});
|
||||||
null,
|
menuOptions.push(null);
|
||||||
{id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp},
|
if (RED.settings.theme('palette.editable') !== false) {
|
||||||
{id:"menu-item-help",
|
RED.palette.editor.init();
|
||||||
label: RED.settings.theme("menu.menu-item-help.label","Node-RED Website"),
|
menuOptions.push({id:"menu-item-edit-palette",label:RED._("menu.label.editPalette"),onselect:RED.palette.editor.show});
|
||||||
|
menuOptions.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:RED.keyboard.showHelp});
|
||||||
|
menuOptions.push({id:"menu-item-help",
|
||||||
|
label: RED.settings.theme("menu.menu-item-help.label","Node-RED website"),
|
||||||
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
|
||||||
},
|
|
||||||
{id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: showAbout }
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: showAbout });
|
||||||
|
|
||||||
|
RED.menu.init({id:"btn-sidemenu",options: menuOptions});
|
||||||
|
|
||||||
RED.user.init();
|
RED.user.init();
|
||||||
|
|
||||||
@ -217,6 +234,7 @@ var RED = (function() {
|
|||||||
RED.subflow.init();
|
RED.subflow.init();
|
||||||
RED.workspaces.init();
|
RED.workspaces.init();
|
||||||
RED.clipboard.init();
|
RED.clipboard.init();
|
||||||
|
RED.search.init();
|
||||||
RED.view.init();
|
RED.view.init();
|
||||||
RED.editor.init();
|
RED.editor.init();
|
||||||
|
|
||||||
|
@ -23,21 +23,42 @@ RED.nodes = (function() {
|
|||||||
var workspaces = {};
|
var workspaces = {};
|
||||||
var workspacesOrder =[];
|
var workspacesOrder =[];
|
||||||
var subflows = {};
|
var subflows = {};
|
||||||
|
var loadedFlowVersion = null;
|
||||||
|
var pending = {
|
||||||
|
deleted: {},
|
||||||
|
added: {}
|
||||||
|
};
|
||||||
|
|
||||||
var dirty = false;
|
var dirty = false;
|
||||||
|
|
||||||
function setDirty(d) {
|
function setDirty(d) {
|
||||||
dirty = d;
|
dirty = d;
|
||||||
|
if (!d) {
|
||||||
|
pending = {
|
||||||
|
deleted: {},
|
||||||
|
added: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
RED.events.emit("nodes:change",{dirty:dirty});
|
RED.events.emit("nodes:change",{dirty:dirty});
|
||||||
}
|
}
|
||||||
|
|
||||||
var registry = (function() {
|
var registry = (function() {
|
||||||
|
var moduleList = {};
|
||||||
var nodeList = [];
|
var nodeList = [];
|
||||||
var nodeSets = {};
|
var nodeSets = {};
|
||||||
var typeToId = {};
|
var typeToId = {};
|
||||||
var nodeDefinitions = {};
|
var nodeDefinitions = {};
|
||||||
|
|
||||||
var exports = {
|
var exports = {
|
||||||
|
getModule: function(module) {
|
||||||
|
return moduleList[module];
|
||||||
|
},
|
||||||
|
getNodeSetForType: function(nodeType) {
|
||||||
|
return exports.getNodeSet(typeToId[nodeType]);
|
||||||
|
},
|
||||||
|
getModuleList: function() {
|
||||||
|
return moduleList;
|
||||||
|
},
|
||||||
getNodeList: function() {
|
getNodeList: function() {
|
||||||
return nodeList;
|
return nodeList;
|
||||||
},
|
},
|
||||||
@ -55,27 +76,33 @@ RED.nodes = (function() {
|
|||||||
typeToId[ns.types[j]] = ns.id;
|
typeToId[ns.types[j]] = ns.id;
|
||||||
}
|
}
|
||||||
nodeList.push(ns);
|
nodeList.push(ns);
|
||||||
|
|
||||||
|
moduleList[ns.module] = moduleList[ns.module] || {
|
||||||
|
name:ns.module,
|
||||||
|
version:ns.version,
|
||||||
|
local:ns.local,
|
||||||
|
sets:{}
|
||||||
|
};
|
||||||
|
moduleList[ns.module].sets[ns.name] = ns;
|
||||||
|
RED.events.emit("registry:node-set-added",ns);
|
||||||
},
|
},
|
||||||
removeNodeSet: function(id) {
|
removeNodeSet: function(id) {
|
||||||
var ns = nodeSets[id];
|
var ns = nodeSets[id];
|
||||||
for (var j=0;j<ns.types.length;j++) {
|
for (var j=0;j<ns.types.length;j++) {
|
||||||
if (ns.added) {
|
|
||||||
// TODO: too tightly coupled into palette UI
|
|
||||||
RED.palette.remove(ns.types[j]);
|
|
||||||
var def = nodeDefinitions[ns.types[j]];
|
|
||||||
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
|
||||||
def.onpaletteremove.call(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete typeToId[ns.types[j]];
|
delete typeToId[ns.types[j]];
|
||||||
}
|
}
|
||||||
delete nodeSets[id];
|
delete nodeSets[id];
|
||||||
for (var i=0;i<nodeList.length;i++) {
|
for (var i=0;i<nodeList.length;i++) {
|
||||||
if (nodeList[i].id == id) {
|
if (nodeList[i].id === id) {
|
||||||
nodeList.splice(i,1);
|
nodeList.splice(i,1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete moduleList[ns.module].sets[ns.name];
|
||||||
|
if (Object.keys(moduleList[ns.module].sets).length === 0) {
|
||||||
|
delete moduleList[ns.module];
|
||||||
|
}
|
||||||
|
RED.events.emit("registry:node-set-removed",ns);
|
||||||
return ns;
|
return ns;
|
||||||
},
|
},
|
||||||
getNodeSet: function(id) {
|
getNodeSet: function(id) {
|
||||||
@ -84,32 +111,19 @@ RED.nodes = (function() {
|
|||||||
enableNodeSet: function(id) {
|
enableNodeSet: function(id) {
|
||||||
var ns = nodeSets[id];
|
var ns = nodeSets[id];
|
||||||
ns.enabled = true;
|
ns.enabled = true;
|
||||||
for (var j=0;j<ns.types.length;j++) {
|
RED.events.emit("registry:node-set-enabled",ns);
|
||||||
// TODO: too tightly coupled into palette UI
|
|
||||||
RED.palette.show(ns.types[j]);
|
|
||||||
var def = nodeDefinitions[ns.types[j]];
|
|
||||||
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
|
||||||
def.onpaletteadd.call(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
disableNodeSet: function(id) {
|
disableNodeSet: function(id) {
|
||||||
var ns = nodeSets[id];
|
var ns = nodeSets[id];
|
||||||
ns.enabled = false;
|
ns.enabled = false;
|
||||||
for (var j=0;j<ns.types.length;j++) {
|
RED.events.emit("registry:node-set-disabled",ns);
|
||||||
// TODO: too tightly coupled into palette UI
|
|
||||||
RED.palette.hide(ns.types[j]);
|
|
||||||
var def = nodeDefinitions[ns.types[j]];
|
|
||||||
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
|
||||||
def.onpaletteremove.call(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
registerNodeType: function(nt,def) {
|
registerNodeType: function(nt,def) {
|
||||||
nodeDefinitions[nt] = def;
|
nodeDefinitions[nt] = def;
|
||||||
if (def.category != "subflows") {
|
if (def.category != "subflows") {
|
||||||
def.set = nodeSets[typeToId[nt]];
|
def.set = nodeSets[typeToId[nt]];
|
||||||
nodeSets[typeToId[nt]].added = true;
|
nodeSets[typeToId[nt]].added = true;
|
||||||
|
nodeSets[typeToId[nt]].enabled = true;
|
||||||
|
|
||||||
var ns;
|
var ns;
|
||||||
if (def.set.module === "node-red") {
|
if (def.set.module === "node-red") {
|
||||||
@ -127,10 +141,7 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
// TODO: too tightly coupled into palette UI
|
// TODO: too tightly coupled into palette UI
|
||||||
}
|
}
|
||||||
RED.palette.add(nt,def);
|
RED.events.emit("registry:node-type-added",nt);
|
||||||
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
|
||||||
def.onpaletteadd.call(def);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
removeNodeType: function(nt) {
|
removeNodeType: function(nt) {
|
||||||
if (nt.substring(0,8) != "subflow:") {
|
if (nt.substring(0,8) != "subflow:") {
|
||||||
@ -138,7 +149,7 @@ RED.nodes = (function() {
|
|||||||
throw new Error("this api is subflow only. called with:",nt);
|
throw new Error("this api is subflow only. called with:",nt);
|
||||||
}
|
}
|
||||||
delete nodeDefinitions[nt];
|
delete nodeDefinitions[nt];
|
||||||
RED.palette.remove(nt);
|
RED.events.emit("registry:node-type-removed",nt);
|
||||||
},
|
},
|
||||||
getNodeType: function(nt) {
|
getNodeType: function(nt) {
|
||||||
return nodeDefinitions[nt];
|
return nodeDefinitions[nt];
|
||||||
@ -175,6 +186,8 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
nodes.push(n);
|
nodes.push(n);
|
||||||
}
|
}
|
||||||
|
delete pending.deleted[n.id];
|
||||||
|
pending.added[n.id] = true;
|
||||||
RED.events.emit('nodes:add',n);
|
RED.events.emit('nodes:add',n);
|
||||||
}
|
}
|
||||||
function addLink(l) {
|
function addLink(l) {
|
||||||
@ -240,6 +253,12 @@ RED.nodes = (function() {
|
|||||||
if (node && node._def.onremove) {
|
if (node && node._def.onremove) {
|
||||||
node._def.onremove.call(n);
|
node._def.onremove.call(n);
|
||||||
}
|
}
|
||||||
|
delete pending.added[id];
|
||||||
|
pending.deleted[id] = true;
|
||||||
|
removedNodes.forEach(function(node) {
|
||||||
|
delete pending.added[node.id];
|
||||||
|
pending.deleted[node.id] = true;
|
||||||
|
});
|
||||||
return {links:removedLinks,nodes:removedNodes};
|
return {links:removedLinks,nodes:removedNodes};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,6 +271,8 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
function addWorkspace(ws) {
|
function addWorkspace(ws) {
|
||||||
workspaces[ws.id] = ws;
|
workspaces[ws.id] = ws;
|
||||||
|
pending.added[ws.id] = true;
|
||||||
|
delete pending.deleted[ws.id];
|
||||||
ws._def = {
|
ws._def = {
|
||||||
defaults: {
|
defaults: {
|
||||||
label: {value:""}
|
label: {value:""}
|
||||||
@ -289,6 +310,8 @@ RED.nodes = (function() {
|
|||||||
var result = removeNode(removedNodes[n].id);
|
var result = removeNode(removedNodes[n].id);
|
||||||
removedLinks = removedLinks.concat(result.links);
|
removedLinks = removedLinks.concat(result.links);
|
||||||
}
|
}
|
||||||
|
pending.deleted[id] = true;
|
||||||
|
delete pending.added[id]
|
||||||
return {nodes:removedNodes,links:removedLinks};
|
return {nodes:removedNodes,links:removedLinks};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,8 +332,17 @@ RED.nodes = (function() {
|
|||||||
});
|
});
|
||||||
sf.name = subflowName;
|
sf.name = subflowName;
|
||||||
}
|
}
|
||||||
|
sf._def = {
|
||||||
|
defaults:{},
|
||||||
|
icon:"subflow.png",
|
||||||
|
category: "subflows",
|
||||||
|
color: "#da9",
|
||||||
|
inputs: sf.in.length,
|
||||||
|
outputs: sf.out.length
|
||||||
|
}
|
||||||
subflows[sf.id] = sf;
|
subflows[sf.id] = sf;
|
||||||
|
delete pending.deleted[sf.id];
|
||||||
|
pending.added[sf.id] = true;
|
||||||
RED.nodes.registerType("subflow:"+sf.id, {
|
RED.nodes.registerType("subflow:"+sf.id, {
|
||||||
defaults:{name:{value:""}},
|
defaults:{name:{value:""}},
|
||||||
info: sf.info,
|
info: sf.info,
|
||||||
@ -334,6 +366,8 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
function removeSubflow(sf) {
|
function removeSubflow(sf) {
|
||||||
delete subflows[sf.id];
|
delete subflows[sf.id];
|
||||||
|
delete pending.added[sf.id];
|
||||||
|
pending.deleted[sf.id] = true;
|
||||||
registry.removeNodeType("subflow:"+sf.id);
|
registry.removeNodeType("subflow:"+sf.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,11 +453,12 @@ RED.nodes = (function() {
|
|||||||
for (var cred in n._def.credentials) {
|
for (var cred in n._def.credentials) {
|
||||||
if (n._def.credentials.hasOwnProperty(cred)) {
|
if (n._def.credentials.hasOwnProperty(cred)) {
|
||||||
if (n._def.credentials[cred].type == 'password') {
|
if (n._def.credentials[cred].type == 'password') {
|
||||||
if (n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
if (!n.credentials._ ||
|
||||||
|
n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
|
||||||
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
(n.credentials["has_"+cred] && n.credentials[cred])) {
|
||||||
credentialSet[cred] = n.credentials[cred];
|
credentialSet[cred] = n.credentials[cred];
|
||||||
}
|
}
|
||||||
} else if (n.credentials[cred] != null && n.credentials[cred] != n.credentials._[cred]) {
|
} else if (n.credentials[cred] != null && (!n.credentials._ || n.credentials[cred] != n.credentials._[cred])) {
|
||||||
credentialSet[cred] = n.credentials[cred];
|
credentialSet[cred] = n.credentials[cred];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,7 +572,10 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: rename this (createCompleteNodeSet)
|
//TODO: rename this (createCompleteNodeSet)
|
||||||
function createCompleteNodeSet() {
|
function createCompleteNodeSet(exportCredentials) {
|
||||||
|
if (exportCredentials === undefined) {
|
||||||
|
exportCredentials = true;
|
||||||
|
}
|
||||||
var nns = [];
|
var nns = [];
|
||||||
var i;
|
var i;
|
||||||
for (i=0;i<workspacesOrder.length;i++) {
|
for (i=0;i<workspacesOrder.length;i++) {
|
||||||
@ -552,16 +590,55 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
for (i in configNodes) {
|
for (i in configNodes) {
|
||||||
if (configNodes.hasOwnProperty(i)) {
|
if (configNodes.hasOwnProperty(i)) {
|
||||||
nns.push(convertNode(configNodes[i], true));
|
nns.push(convertNode(configNodes[i], exportCredentials));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i=0;i<nodes.length;i++) {
|
for (i=0;i<nodes.length;i++) {
|
||||||
var node = nodes[i];
|
var node = nodes[i];
|
||||||
nns.push(convertNode(node, true));
|
nns.push(convertNode(node, exportCredentials));
|
||||||
}
|
}
|
||||||
return nns;
|
return nns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkForMatchingSubflow(subflow,subflowNodes) {
|
||||||
|
var i;
|
||||||
|
var match = null;
|
||||||
|
try {
|
||||||
|
RED.nodes.eachSubflow(function(sf) {
|
||||||
|
if (sf.name != subflow.name ||
|
||||||
|
sf.info != subflow.info ||
|
||||||
|
sf.in.length != subflow.in.length ||
|
||||||
|
sf.out.length != subflow.out.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var sfNodes = RED.nodes.filterNodes({z:sf.id});
|
||||||
|
if (sfNodes.length != subflowNodes.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var subflowNodeSet = [subflow].concat(subflowNodes);
|
||||||
|
var sfNodeSet = [sf].concat(sfNodes);
|
||||||
|
|
||||||
|
var exportableSubflowNodes = JSON.stringify(subflowNodeSet);
|
||||||
|
var exportableSFNodes = JSON.stringify(createExportableNodeSet(sfNodeSet));
|
||||||
|
var nodeMap = {};
|
||||||
|
for (i=0;i<sfNodes.length;i++) {
|
||||||
|
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflowNodes[i].id+"\"","g"),'"'+sfNodes[i].id+'"');
|
||||||
|
}
|
||||||
|
exportableSubflowNodes = exportableSubflowNodes.replace(new RegExp("\""+subflow.id+"\"","g"),'"'+sf.id+'"');
|
||||||
|
|
||||||
|
if (exportableSubflowNodes !== exportableSFNodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = sf;
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
function compareNodes(nodeA,nodeB,idMustMatch) {
|
function compareNodes(nodeA,nodeB,idMustMatch) {
|
||||||
if (idMustMatch && nodeA.id != nodeB.id) {
|
if (idMustMatch && nodeA.id != nodeB.id) {
|
||||||
return false;
|
return false;
|
||||||
@ -591,10 +668,11 @@ RED.nodes = (function() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function importNodes(newNodesObj,createNewIds) {
|
function importNodes(newNodesObj,createNewIds,createMissingWorkspace) {
|
||||||
var i;
|
var i;
|
||||||
var n;
|
var n;
|
||||||
var newNodes;
|
var newNodes;
|
||||||
|
var nodeZmap = {};
|
||||||
if (typeof newNodesObj === "string") {
|
if (typeof newNodesObj === "string") {
|
||||||
if (newNodesObj === "") {
|
if (newNodesObj === "") {
|
||||||
return;
|
return;
|
||||||
@ -625,6 +703,11 @@ RED.nodes = (function() {
|
|||||||
unknownTypes.indexOf(n.type)==-1) {
|
unknownTypes.indexOf(n.type)==-1) {
|
||||||
unknownTypes.push(n.type);
|
unknownTypes.push(n.type);
|
||||||
}
|
}
|
||||||
|
if (n.z) {
|
||||||
|
nodeZmap[n.z] = nodeZmap[n.z] || [];
|
||||||
|
nodeZmap[n.z].push(n);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (unknownTypes.length > 0) {
|
if (unknownTypes.length > 0) {
|
||||||
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
|
||||||
@ -659,12 +742,15 @@ RED.nodes = (function() {
|
|||||||
var workspace_map = {};
|
var workspace_map = {};
|
||||||
var new_subflows = [];
|
var new_subflows = [];
|
||||||
var subflow_map = {};
|
var subflow_map = {};
|
||||||
|
var subflow_blacklist = {};
|
||||||
var node_map = {};
|
var node_map = {};
|
||||||
var new_nodes = [];
|
var new_nodes = [];
|
||||||
var new_links = [];
|
var new_links = [];
|
||||||
var nid;
|
var nid;
|
||||||
var def;
|
var def;
|
||||||
var configNode;
|
var configNode;
|
||||||
|
var missingWorkspace = null;
|
||||||
|
var d;
|
||||||
|
|
||||||
// Find all tabs and subflow templates
|
// Find all tabs and subflow templates
|
||||||
for (i=0;i<newNodes.length;i++) {
|
for (i=0;i<newNodes.length;i++) {
|
||||||
@ -686,6 +772,10 @@ RED.nodes = (function() {
|
|||||||
RED.workspaces.add(n);
|
RED.workspaces.add(n);
|
||||||
new_workspaces.push(n);
|
new_workspaces.push(n);
|
||||||
} else if (n.type === "subflow") {
|
} else if (n.type === "subflow") {
|
||||||
|
var matchingSubflow = checkForMatchingSubflow(n,nodeZmap[n.id]);
|
||||||
|
if (matchingSubflow) {
|
||||||
|
subflow_blacklist[n.id] = matchingSubflow;
|
||||||
|
} else {
|
||||||
subflow_map[n.id] = n;
|
subflow_map[n.id] = n;
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
nid = getID();
|
nid = getID();
|
||||||
@ -710,6 +800,7 @@ RED.nodes = (function() {
|
|||||||
addSubflow(n,createNewIds);
|
addSubflow(n,createNewIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add a tab if there isn't one there already
|
// Add a tab if there isn't one there already
|
||||||
if (defaultWorkspace == null) {
|
if (defaultWorkspace == null) {
|
||||||
@ -728,15 +819,25 @@ RED.nodes = (function() {
|
|||||||
var existingConfigNode = null;
|
var existingConfigNode = null;
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
if (n.z) {
|
if (n.z) {
|
||||||
if (subflow_map[n.z]) {
|
if (subflow_blacklist[n.z]) {
|
||||||
|
continue;
|
||||||
|
} else if (subflow_map[n.z]) {
|
||||||
n.z = subflow_map[n.z].id;
|
n.z = subflow_map[n.z].id;
|
||||||
} else {
|
} else {
|
||||||
n.z = workspace_map[n.z];
|
n.z = workspace_map[n.z];
|
||||||
if (!workspaces[n.z]) {
|
if (!workspaces[n.z]) {
|
||||||
|
if (createMissingWorkspace) {
|
||||||
|
if (missingWorkspace === null) {
|
||||||
|
missingWorkspace = RED.workspaces.add(null,true);
|
||||||
|
new_workspaces.push(missingWorkspace);
|
||||||
|
}
|
||||||
|
n.z = missingWorkspace.id;
|
||||||
|
} else {
|
||||||
n.z = activeWorkspace;
|
n.z = activeWorkspace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
existingConfigNode = RED.nodes.node(n.id);
|
existingConfigNode = RED.nodes.node(n.id);
|
||||||
if (existingConfigNode) {
|
if (existingConfigNode) {
|
||||||
if (n.z && existingConfigNode.z !== n.z) {
|
if (n.z && existingConfigNode.z !== n.z) {
|
||||||
@ -757,10 +858,19 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!existingConfigNode) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode._def.exclusive || existingConfigNode.z !== n.z) {
|
if (!existingConfigNode) { //} || !compareNodes(existingConfigNode,n,true) || existingConfigNode._def.exclusive || existingConfigNode.z !== n.z) {
|
||||||
configNode = {id:n.id, z:n.z, type:n.type, users:[]};
|
configNode = {id:n.id, z:n.z, type:n.type, users:[], _config:{}};
|
||||||
for (var d in def.defaults) {
|
for (d in def.defaults) {
|
||||||
if (def.defaults.hasOwnProperty(d)) {
|
if (def.defaults.hasOwnProperty(d)) {
|
||||||
configNode[d] = n[d];
|
configNode[d] = n[d];
|
||||||
|
configNode._config[d] = JSON.stringify(n[d]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (def.hasOwnProperty('credentials') && n.hasOwnProperty('credentials')) {
|
||||||
|
configNode.credentials = {};
|
||||||
|
for (d in def.credentials) {
|
||||||
|
if (def.credentials.hasOwnProperty(d) && n.credentials.hasOwnProperty(d)) {
|
||||||
|
configNode.credentials[d] = n.credentials[d];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configNode.label = def.label;
|
configNode.label = def.label;
|
||||||
@ -782,28 +892,46 @@ RED.nodes = (function() {
|
|||||||
if (n.type !== "workspace" && n.type !== "tab" && n.type !== "subflow") {
|
if (n.type !== "workspace" && n.type !== "tab" && n.type !== "subflow") {
|
||||||
def = registry.getNodeType(n.type);
|
def = registry.getNodeType(n.type);
|
||||||
if (!def || def.category != "config") {
|
if (!def || def.category != "config") {
|
||||||
var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
|
var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false,_config:{}};
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
if (subflow_map[node.z]) {
|
if (subflow_blacklist[n.z]) {
|
||||||
|
continue;
|
||||||
|
} else if (subflow_map[node.z]) {
|
||||||
node.z = subflow_map[node.z].id;
|
node.z = subflow_map[node.z].id;
|
||||||
} else {
|
} else {
|
||||||
node.z = workspace_map[node.z];
|
node.z = workspace_map[node.z];
|
||||||
if (!workspaces[node.z]) {
|
if (!workspaces[node.z]) {
|
||||||
|
if (createMissingWorkspace) {
|
||||||
|
if (missingWorkspace === null) {
|
||||||
|
missingWorkspace = RED.workspaces.add(null,true);
|
||||||
|
new_workspaces.push(missingWorkspace);
|
||||||
|
}
|
||||||
|
node.z = missingWorkspace.id;
|
||||||
|
} else {
|
||||||
node.z = activeWorkspace;
|
node.z = activeWorkspace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
node.id = getID();
|
node.id = getID();
|
||||||
} else {
|
} else {
|
||||||
node.id = n.id;
|
node.id = n.id;
|
||||||
if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) {
|
if (node.z == null || (!workspaces[node.z] && !subflow_map[node.z])) {
|
||||||
|
if (createMissingWorkspace) {
|
||||||
|
if (missingWorkspace === null) {
|
||||||
|
missingWorkspace = RED.workspaces.add(null,true);
|
||||||
|
new_workspaces.push(missingWorkspace);
|
||||||
|
}
|
||||||
|
node.z = missingWorkspace.id;
|
||||||
|
} else {
|
||||||
node.z = activeWorkspace;
|
node.z = activeWorkspace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
node.type = n.type;
|
node.type = n.type;
|
||||||
node._def = def;
|
node._def = def;
|
||||||
if (n.type.substring(0,7) === "subflow") {
|
if (n.type.substring(0,7) === "subflow") {
|
||||||
var parentId = n.type.split(":")[1];
|
var parentId = n.type.split(":")[1];
|
||||||
var subflow = subflow_map[parentId]||getSubflow(parentId);
|
var subflow = subflow_blacklist[parentId]||subflow_map[parentId]||getSubflow(parentId);
|
||||||
if (createNewIds) {
|
if (createNewIds) {
|
||||||
parentId = subflow.id;
|
parentId = subflow.id;
|
||||||
node.type = "subflow:"+parentId;
|
node.type = "subflow:"+parentId;
|
||||||
@ -844,9 +972,20 @@ RED.nodes = (function() {
|
|||||||
if (node._def.category != "config") {
|
if (node._def.category != "config") {
|
||||||
node.inputs = n.inputs||node._def.inputs;
|
node.inputs = n.inputs||node._def.inputs;
|
||||||
node.outputs = n.outputs||node._def.outputs;
|
node.outputs = n.outputs||node._def.outputs;
|
||||||
for (var d2 in node._def.defaults) {
|
for (d in node._def.defaults) {
|
||||||
if (node._def.defaults.hasOwnProperty(d2)) {
|
if (node._def.defaults.hasOwnProperty(d)) {
|
||||||
node[d2] = n[d2];
|
node[d] = n[d];
|
||||||
|
node._config[d] = JSON.stringify(n[d]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node._config.x = node.x;
|
||||||
|
node._config.y = node.y;
|
||||||
|
if (node._def.hasOwnProperty('credentials') && n.hasOwnProperty('credentials')) {
|
||||||
|
node.credentials = {};
|
||||||
|
for (d in node._def.credentials) {
|
||||||
|
if (node._def.credentials.hasOwnProperty(d) && n.credentials.hasOwnProperty(d)) {
|
||||||
|
node.credentials[d] = n.credentials[d];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -943,7 +1082,7 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RED.workspaces.refresh();
|
RED.workspaces.refresh();
|
||||||
return [new_nodes,new_links,new_workspaces,new_subflows];
|
return [new_nodes,new_links,new_workspaces,new_subflows,missingWorkspace];
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: supports filter.z|type
|
// TODO: supports filter.z|type
|
||||||
@ -1011,6 +1150,14 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flowVersion(version) {
|
||||||
|
if (version !== undefined) {
|
||||||
|
loadedFlowVersion = version;
|
||||||
|
} else {
|
||||||
|
return loadedFlowVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
registry:registry,
|
registry:registry,
|
||||||
setNodeList: registry.setNodeList,
|
setNodeList: registry.setNodeList,
|
||||||
@ -1074,11 +1221,15 @@ RED.nodes = (function() {
|
|||||||
|
|
||||||
node: getNode,
|
node: getNode,
|
||||||
|
|
||||||
|
version: flowVersion,
|
||||||
|
|
||||||
filterNodes: filterNodes,
|
filterNodes: filterNodes,
|
||||||
filterLinks: filterLinks,
|
filterLinks: filterLinks,
|
||||||
|
|
||||||
import: importNodes,
|
import: importNodes,
|
||||||
|
|
||||||
|
pending: function() { return pending },
|
||||||
|
|
||||||
getAllFlowNodes: getAllFlowNodes,
|
getAllFlowNodes: getAllFlowNodes,
|
||||||
createExportableNodeSet: createExportableNodeSet,
|
createExportableNodeSet: createExportableNodeSet,
|
||||||
createCompleteNodeSet: createCompleteNodeSet,
|
createCompleteNodeSet: createCompleteNodeSet,
|
||||||
|
@ -84,6 +84,7 @@ RED.settings = (function () {
|
|||||||
if (auth_tokens) {
|
if (auth_tokens) {
|
||||||
jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token);
|
jqXHR.setRequestHeader("Authorization","Bearer "+auth_tokens.access_token);
|
||||||
}
|
}
|
||||||
|
jqXHR.setRequestHeader("Node-RED-API-Version","v2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
130
editor/js/text/bidi.js
Normal file
130
editor/js/text/bidi.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
RED.text = {};
|
||||||
|
RED.text.bidi = (function() {
|
||||||
|
var textDir = "";
|
||||||
|
var LRE = "\u202A",
|
||||||
|
RLE = "\u202B",
|
||||||
|
PDF = "\u202C";
|
||||||
|
|
||||||
|
function isRTLValue(stringValue) {
|
||||||
|
var length = stringValue.length;
|
||||||
|
for (var i=0;i<length;i++) {
|
||||||
|
if (isBidiChar(stringValue.charCodeAt(i))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(isLatinChar(stringValue.charCodeAt(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBidiChar(c) {
|
||||||
|
return (c >= 0x05d0 && c <= 0x05ff)||
|
||||||
|
(c >= 0x0600 && c <= 0x065f)||
|
||||||
|
(c >= 0x066a && c <= 0x06ef)||
|
||||||
|
(c >= 0x06fa && c <= 0x07ff)||
|
||||||
|
(c >= 0xfb1d && c <= 0xfdff)||
|
||||||
|
(c >= 0xfe70 && c <= 0xfefc);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLatinChar(c){
|
||||||
|
return (c > 64 && c < 91)||(c > 96 && c < 123)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the text direction of a given string.
|
||||||
|
* @param value - the string
|
||||||
|
*/
|
||||||
|
function resolveBaseTextDir(value) {
|
||||||
|
if (textDir == "auto") {
|
||||||
|
if (isRTLValue(value)) {
|
||||||
|
return "rtl";
|
||||||
|
} else {
|
||||||
|
return "ltr";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return textDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onInputChange() {
|
||||||
|
$(this).attr("dir", resolveBaseTextDir($(this).val()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds event listeners to the Input to ensure its text-direction attribute
|
||||||
|
* is properly set based on its content.
|
||||||
|
* @param input - the input field
|
||||||
|
*/
|
||||||
|
function prepareInput(input) {
|
||||||
|
input.on("keyup",onInputChange).on("paste",onInputChange).on("cut",onInputChange);
|
||||||
|
// Set the initial text direction
|
||||||
|
onInputChange.call(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces the text direction of a given string by adding
|
||||||
|
* UCC (Unicode Control Characters)
|
||||||
|
* @param value - the string
|
||||||
|
*/
|
||||||
|
function enforceTextDirectionWithUCC(value) {
|
||||||
|
if (value) {
|
||||||
|
var dir = resolveBaseTextDir(value);
|
||||||
|
if (dir == "ltr") {
|
||||||
|
return LRE + value + PDF;
|
||||||
|
}
|
||||||
|
else if (dir == "rtl") {
|
||||||
|
return RLE + value + PDF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces the text direction for all the spans with style bidiAware under
|
||||||
|
* workspace or sidebar div
|
||||||
|
*/
|
||||||
|
function enforceTextDirectionOnPage() {
|
||||||
|
$("#workspace").find('span.bidiAware').each(function() {
|
||||||
|
$(this).attr("dir", resolveBaseTextDir($(this).html()));
|
||||||
|
});
|
||||||
|
$("#sidebar").find('span.bidiAware').each(function() {
|
||||||
|
$(this).attr("dir", resolveBaseTextDir($(this).text()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text direction preference
|
||||||
|
* @param dir - the text direction preference
|
||||||
|
*/
|
||||||
|
function setTextDirection(dir) {
|
||||||
|
textDir = dir;
|
||||||
|
RED.nodes.eachNode(function(n) { n.dirty = true;});
|
||||||
|
RED.view.redraw();
|
||||||
|
RED.palette.refresh();
|
||||||
|
enforceTextDirectionOnPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setTextDirection: setTextDirection,
|
||||||
|
enforceTextDirectionWithUCC: enforceTextDirectionWithUCC,
|
||||||
|
resolveBaseTextDir: resolveBaseTextDir,
|
||||||
|
prepareInput: prepareInput
|
||||||
|
}
|
||||||
|
})();
|
1330
editor/js/text/format.js
Normal file
1330
editor/js/text/format.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -46,12 +46,24 @@ RED.clipboard = (function() {
|
|||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "clipboard-dialog-copy",
|
||||||
|
class: "primary",
|
||||||
|
text: RED._("clipboard.export.copy"),
|
||||||
|
click: function() {
|
||||||
|
$("#clipboard-export").select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.getSelection().removeAllRanges();
|
||||||
|
RED.notify(RED._("clipboard.nodesExported"));
|
||||||
|
$( this ).dialog( "close" );
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "clipboard-dialog-ok",
|
id: "clipboard-dialog-ok",
|
||||||
class: "primary",
|
class: "primary",
|
||||||
text: RED._("common.label.import"),
|
text: RED._("common.label.import"),
|
||||||
click: function() {
|
click: function() {
|
||||||
RED.view.importNodes($("#clipboard-import").val());
|
RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new');
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,18 +77,36 @@ RED.clipboard = (function() {
|
|||||||
|
|
||||||
dialogContainer = dialog.children(".dialog-form");
|
dialogContainer = dialog.children(".dialog-form");
|
||||||
|
|
||||||
exportNodesDialog = '<div class="form-row">'+
|
exportNodesDialog =
|
||||||
'<label for="node-input-export" style="display: block; width:100%;"><i class="fa fa-clipboard"></i> '+RED._("clipboard.nodes")+'</label>'+
|
'<div class="form-row">'+
|
||||||
'<textarea readonly style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
|
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.export.copy"></label>'+
|
||||||
|
'<span id="export-range-group" class="button-group">'+
|
||||||
|
'<a id="export-range-selected" class="editor-button toggle" href="#" data-i18n="clipboard.export.selected"></a>'+
|
||||||
|
'<a id="export-range-flow" class="editor-button toggle" href="#" data-i18n="clipboard.export.current"></a>'+
|
||||||
|
'<a id="export-range-full" class="editor-button toggle" href="#" data-i18n="clipboard.export.all"></a>'+
|
||||||
|
'</span>'+
|
||||||
'</div>'+
|
'</div>'+
|
||||||
'<div class="form-tips">'+
|
'<div class="form-row">'+
|
||||||
RED._("clipboard.selectNodes")+
|
'<textarea readonly style="resize: none; width: 100%; border-radius: 4px;font-family: monospace; font-size: 12px; background:#f3f3f3; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-export" rows="5"></textarea>'+
|
||||||
|
'</div>'+
|
||||||
|
'<div class="form-row" style="text-align: right;">'+
|
||||||
|
'<span id="export-format-group" class="button-group">'+
|
||||||
|
'<a id="export-format-mini" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.compact"></a>'+
|
||||||
|
'<a id="export-format-full" class="editor-button editor-button-small toggle" href="#" data-i18n="clipboard.export.formatted"></a>'+
|
||||||
|
'</span>'+
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
importNodesDialog = '<div class="form-row">'+
|
importNodesDialog = '<div class="form-row">'+
|
||||||
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
|
'<textarea style="resize: none; width: 100%; border-radius: 0px;font-family: monospace; font-size: 12px; background:#eee; padding-left: 0.5em; box-sizing:border-box;" id="clipboard-import" rows="5" placeholder="'+
|
||||||
RED._("clipboard.pasteNodes")+
|
RED._("clipboard.pasteNodes")+
|
||||||
'"></textarea>'+
|
'"></textarea>'+
|
||||||
|
'</div>'+
|
||||||
|
'<div class="form-row">'+
|
||||||
|
'<label style="width:auto;margin-right: 10px;" data-i18n="clipboard.import.import"></label>'+
|
||||||
|
'<span id="import-tab" class="button-group">'+
|
||||||
|
'<a id="import-tab-current" class="editor-button toggle selected" href="#" data-i18n="clipboard.export.current"></a>'+
|
||||||
|
'<a id="import-tab-new" class="editor-button toggle" href="#" data-i18n="clipboard.import.newFlow"></a>'+
|
||||||
|
'</span>'+
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,32 +130,108 @@ RED.clipboard = (function() {
|
|||||||
function importNodes() {
|
function importNodes() {
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(importNodesDialog));
|
dialogContainer.append($(importNodesDialog));
|
||||||
|
dialogContainer.i18n();
|
||||||
|
|
||||||
$("#clipboard-dialog-ok").show();
|
$("#clipboard-dialog-ok").show();
|
||||||
$("#clipboard-dialog-cancel").show();
|
$("#clipboard-dialog-cancel").show();
|
||||||
$("#clipboard-dialog-close").hide();
|
$("#clipboard-dialog-close").hide();
|
||||||
|
$("#clipboard-dialog-copy").hide();
|
||||||
$("#clipboard-dialog-ok").button("disable");
|
$("#clipboard-dialog-ok").button("disable");
|
||||||
$("#clipboard-import").keyup(validateImport);
|
$("#clipboard-import").keyup(validateImport);
|
||||||
$("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
|
$("#clipboard-import").on('paste',function() { setTimeout(validateImport,10)});
|
||||||
|
|
||||||
|
$("#import-tab > a").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(this).parent().children().removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
});
|
||||||
|
|
||||||
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
|
dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportNodes() {
|
function exportNodes() {
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(exportNodesDialog));
|
dialogContainer.append($(exportNodesDialog));
|
||||||
|
dialogContainer.i18n();
|
||||||
|
|
||||||
|
$("#export-format-group > a").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(this).parent().children().removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
|
||||||
|
var flow = $("#clipboard-export").val();
|
||||||
|
if (flow.length > 0) {
|
||||||
|
var nodes = JSON.parse(flow);
|
||||||
|
|
||||||
|
var format = $(this).attr('id');
|
||||||
|
if (format === 'export-format-full') {
|
||||||
|
flow = JSON.stringify(nodes,null,4);
|
||||||
|
} else {
|
||||||
|
flow = JSON.stringify(nodes);
|
||||||
|
}
|
||||||
|
$("#clipboard-export").val(flow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#export-range-group > a").click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(this).parent().children().removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
var type = $(this).attr('id');
|
||||||
|
var flow = "";
|
||||||
|
var nodes = null;
|
||||||
|
if (type === 'export-range-selected') {
|
||||||
|
var selection = RED.view.selection();
|
||||||
|
nodes = RED.nodes.createExportableNodeSet(selection.nodes);
|
||||||
|
} else if (type === 'export-range-flow') {
|
||||||
|
var activeWorkspace = RED.workspaces.active();
|
||||||
|
nodes = RED.nodes.filterNodes({z:activeWorkspace});
|
||||||
|
var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
|
||||||
|
nodes.unshift(parentNode);
|
||||||
|
nodes = RED.nodes.createExportableNodeSet(nodes);
|
||||||
|
} else if (type === 'export-range-full') {
|
||||||
|
nodes = RED.nodes.createCompleteNodeSet(false);
|
||||||
|
}
|
||||||
|
if (nodes !== null) {
|
||||||
|
if (RED.settings.flowFilePretty) {
|
||||||
|
flow = JSON.stringify(nodes,null,4);
|
||||||
|
} else {
|
||||||
|
flow = JSON.stringify(nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flow.length > 0) {
|
||||||
|
$("#export-copy").removeClass('disabled');
|
||||||
|
} else {
|
||||||
|
$("#export-copy").addClass('disabled');
|
||||||
|
}
|
||||||
|
$("#clipboard-export").val(flow);
|
||||||
|
})
|
||||||
|
|
||||||
$("#clipboard-dialog-ok").hide();
|
$("#clipboard-dialog-ok").hide();
|
||||||
$("#clipboard-dialog-cancel").hide();
|
$("#clipboard-dialog-cancel").hide();
|
||||||
$("#clipboard-dialog-close").show();
|
$("#clipboard-dialog-copy").hide();
|
||||||
|
$("#clipboard-dialog-close").hide();
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (selection.nodes) {
|
if (selection.nodes) {
|
||||||
var nns = RED.nodes.createExportableNodeSet(selection.nodes);
|
$("#export-range-selected").click();
|
||||||
if (RED.settings.flowFilePretty) {
|
|
||||||
nns = JSON.stringify(nns,null,4);
|
|
||||||
} else {
|
} else {
|
||||||
nns = JSON.stringify(nns);
|
$("#export-range-selected").addClass('disabled').removeClass('selected');
|
||||||
|
$("#export-range-flow").click();
|
||||||
|
}
|
||||||
|
if (RED.settings.flowFilePretty) {
|
||||||
|
$("#export-format-full").click();
|
||||||
|
} else {
|
||||||
|
$("#export-format-mini").click();
|
||||||
}
|
}
|
||||||
$("#clipboard-export")
|
$("#clipboard-export")
|
||||||
.val(nns)
|
|
||||||
.focus(function() {
|
.focus(function() {
|
||||||
var textarea = $(this);
|
var textarea = $(this);
|
||||||
textarea.select();
|
textarea.select();
|
||||||
@ -135,7 +241,18 @@ RED.clipboard = (function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
|
dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" );
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
$("#clipboard-export").focus();
|
||||||
|
if (!document.queryCommandEnabled("copy")) {
|
||||||
|
$("#clipboard-dialog-cancel").hide();
|
||||||
|
$("#clipboard-dialog-close").show();
|
||||||
|
} else {
|
||||||
|
$("#clipboard-dialog-cancel").show();
|
||||||
|
$("#clipboard-dialog-copy").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideDropTarget() {
|
function hideDropTarget() {
|
||||||
|
@ -66,11 +66,30 @@
|
|||||||
that.addItem({});
|
that.addItem({});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.element.css("position") === "absolute") {
|
||||||
|
["top","left","bottom","right"].forEach(function(s) {
|
||||||
|
var v = that.element.css(s);
|
||||||
|
if (s!=="auto" && s!=="") {
|
||||||
|
that.topContainer.css(s,v);
|
||||||
|
that.uiContainer.css(s,"0");
|
||||||
|
that.element.css(s,'auto');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.element.css("position","static");
|
||||||
|
this.topContainer.css("position","absolute");
|
||||||
|
this.uiContainer.css("position","absolute");
|
||||||
|
|
||||||
|
}
|
||||||
this.uiContainer.addClass("red-ui-editableList-container");
|
this.uiContainer.addClass("red-ui-editableList-container");
|
||||||
|
|
||||||
this.uiHeight = this.element.height();
|
this.uiHeight = this.element.height();
|
||||||
|
|
||||||
|
this.activeFilter = this.options.filter||null;
|
||||||
|
this.activeSort = this.options.sort||null;
|
||||||
|
this.scrollOnAdd = this.options.scrollOnAdd;
|
||||||
|
if (this.scrollOnAdd === undefined) {
|
||||||
|
this.scrollOnAdd = true;
|
||||||
|
}
|
||||||
var minHeight = this.element.css("minHeight");
|
var minHeight = this.element.css("minHeight");
|
||||||
if (minHeight !== '0px') {
|
if (minHeight !== '0px') {
|
||||||
this.uiContainer.css("minHeight",minHeight);
|
this.uiContainer.css("minHeight",minHeight);
|
||||||
@ -141,6 +160,42 @@
|
|||||||
},
|
},
|
||||||
_destroy: function() {
|
_destroy: function() {
|
||||||
},
|
},
|
||||||
|
_refreshFilter: function() {
|
||||||
|
var that = this;
|
||||||
|
var count = 0;
|
||||||
|
if (!this.activeFilter) {
|
||||||
|
this.element.children().show();
|
||||||
|
}
|
||||||
|
var items = this.items();
|
||||||
|
items.each(function (i,el) {
|
||||||
|
var data = el.data('data');
|
||||||
|
try {
|
||||||
|
if (that.activeFilter(data)) {
|
||||||
|
el.parent().show();
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
el.parent().hide();
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
el.parent().show();
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
_refreshSort: function() {
|
||||||
|
if (this.activeSort) {
|
||||||
|
var items = this.element.children();
|
||||||
|
var that = this;
|
||||||
|
items.sort(function(A,B) {
|
||||||
|
return that.activeSort($(A).find(".red-ui-editableList-item-content").data('data'),$(B).find(".red-ui-editableList-item-content").data('data'));
|
||||||
|
});
|
||||||
|
$.each(items,function(idx,li) {
|
||||||
|
that.element.append(li);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
width: function(desiredWidth) {
|
width: function(desiredWidth) {
|
||||||
this.uiWidth = desiredWidth;
|
this.uiWidth = desiredWidth;
|
||||||
this._resize();
|
this._resize();
|
||||||
@ -152,7 +207,23 @@
|
|||||||
addItem: function(data) {
|
addItem: function(data) {
|
||||||
var that = this;
|
var that = this;
|
||||||
data = data || {};
|
data = data || {};
|
||||||
var li = $('<li>').appendTo(this.element);
|
var li = $('<li>');
|
||||||
|
var added = false;
|
||||||
|
if (this.activeSort) {
|
||||||
|
var items = this.items();
|
||||||
|
var skip = false;
|
||||||
|
items.each(function(i,el) {
|
||||||
|
if (added) { return }
|
||||||
|
var itemData = el.data('data');
|
||||||
|
if (that.activeSort(data,itemData) < 0) {
|
||||||
|
li.insertBefore(el.closest("li"));
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!added) {
|
||||||
|
li.appendTo(this.element);
|
||||||
|
}
|
||||||
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
|
var row = $('<div/>').addClass("red-ui-editableList-item-content").appendTo(li);
|
||||||
row.data('data',data);
|
row.data('data',data);
|
||||||
if (this.options.sortable === true) {
|
if (this.options.sortable === true) {
|
||||||
@ -178,9 +249,20 @@
|
|||||||
var index = that.element.children().length-1;
|
var index = that.element.children().length-1;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
that.options.addItem(row,index,data);
|
that.options.addItem(row,index,data);
|
||||||
|
if (that.activeFilter) {
|
||||||
|
try {
|
||||||
|
if (!that.activeFilter(data)) {
|
||||||
|
li.hide();
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!that.activeSort && that.scrollOnAdd) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
that.uiContainer.scrollTop(that.element.height());
|
that.uiContainer.scrollTop(that.element.height());
|
||||||
},0);
|
},0);
|
||||||
|
}
|
||||||
},0);
|
},0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -198,6 +280,21 @@
|
|||||||
},
|
},
|
||||||
empty: function() {
|
empty: function() {
|
||||||
this.element.empty();
|
this.element.empty();
|
||||||
|
},
|
||||||
|
filter: function(filter) {
|
||||||
|
if (filter !== undefined) {
|
||||||
|
this.activeFilter = filter;
|
||||||
|
}
|
||||||
|
return this._refreshFilter();
|
||||||
|
},
|
||||||
|
sort: function(sort) {
|
||||||
|
if (sort !== undefined) {
|
||||||
|
this.activeSort = sort;
|
||||||
|
}
|
||||||
|
return this._refreshSort();
|
||||||
|
},
|
||||||
|
length: function() {
|
||||||
|
return this.element.children().length;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})(jQuery);
|
})(jQuery);
|
96
editor/js/ui/common/searchBox.js
Normal file
96
editor/js/ui/common/searchBox.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
$.widget( "nodered.searchBox", {
|
||||||
|
_create: function() {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
this.currentTimeout = null;
|
||||||
|
this.lastSent = "";
|
||||||
|
this.element.val("");
|
||||||
|
this.uiContainer = this.element.wrap("<div>").parent();
|
||||||
|
this.uiContainer.addClass("red-ui-searchBox-container");
|
||||||
|
|
||||||
|
$('<i class="fa fa-search"></i>').prependTo(this.uiContainer);
|
||||||
|
this.clearButton = $('<a href="#"><i class="fa fa-times"></i></a>').appendTo(this.uiContainer);
|
||||||
|
this.clearButton.on("click",function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
that.element.val("");
|
||||||
|
that._change("",true);
|
||||||
|
that.element.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resultCount = $('<span>',{class:"red-ui-searchBox-resultCount hide"}).appendTo(this.uiContainer);
|
||||||
|
|
||||||
|
this.element.val("");
|
||||||
|
this.element.on("keydown",function(evt) {
|
||||||
|
if (evt.keyCode === 27) {
|
||||||
|
that.element.val("");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.element.on("keyup",function(evt) {
|
||||||
|
that._change($(this).val());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.element.on("focus",function() {
|
||||||
|
$("body").one("mousedown",function() {
|
||||||
|
that.element.blur();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
_change: function(val,instant) {
|
||||||
|
var fireEvent = false;
|
||||||
|
if (val === "") {
|
||||||
|
this.clearButton.hide();
|
||||||
|
fireEvent = true;
|
||||||
|
} else {
|
||||||
|
this.clearButton.show();
|
||||||
|
fireEvent = (val.length >= (this.options.minimumLength||0));
|
||||||
|
}
|
||||||
|
var current = this.element.val();
|
||||||
|
fireEvent = fireEvent && current !== this.lastSent;
|
||||||
|
if (fireEvent) {
|
||||||
|
if (!instant && this.options.delay > 0) {
|
||||||
|
clearTimeout(this.currentTimeout);
|
||||||
|
var that = this;
|
||||||
|
this.currentTimeout = setTimeout(function() {
|
||||||
|
that.lastSent = that.element.val();
|
||||||
|
that._trigger("change");
|
||||||
|
},this.options.delay);
|
||||||
|
} else {
|
||||||
|
this._trigger("change");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: function(val) {
|
||||||
|
if (val === undefined) {
|
||||||
|
return this.element.val();
|
||||||
|
} else {
|
||||||
|
this.element.val(val);
|
||||||
|
this._change(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count: function(val) {
|
||||||
|
if (val === undefined || val === null || val === "") {
|
||||||
|
this.resultCount.text("").hide();
|
||||||
|
} else {
|
||||||
|
this.resultCount.text(val).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
@ -17,15 +17,58 @@
|
|||||||
|
|
||||||
|
|
||||||
RED.tabs = (function() {
|
RED.tabs = (function() {
|
||||||
|
|
||||||
|
|
||||||
function createTabs(options) {
|
function createTabs(options) {
|
||||||
var tabs = {};
|
var tabs = {};
|
||||||
var currentTabWidth;
|
var currentTabWidth;
|
||||||
var currentActiveTabWidth = 0;
|
var currentActiveTabWidth = 0;
|
||||||
|
|
||||||
var ul = $("#"+options.id);
|
var ul = $("#"+options.id);
|
||||||
ul.addClass("red-ui-tabs");
|
var wrapper = ul.wrap( "<div>" ).parent();
|
||||||
|
var scrollContainer = ul.wrap( "<div>" ).parent();
|
||||||
|
wrapper.addClass("red-ui-tabs");
|
||||||
|
if (options.addButton && typeof options.addButton === 'function') {
|
||||||
|
wrapper.addClass("red-ui-tabs-add");
|
||||||
|
var addButton = $('<div class="red-ui-tab-button"><a href="#"><i class="fa fa-plus"></i></a></div>').appendTo(wrapper);
|
||||||
|
addButton.find('a').click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
options.addButton();
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
var scrollLeft;
|
||||||
|
var scrollRight;
|
||||||
|
|
||||||
|
if (options.scrollable) {
|
||||||
|
wrapper.addClass("red-ui-tabs-scrollable");
|
||||||
|
scrollContainer.addClass("red-ui-tabs-scroll-container");
|
||||||
|
scrollContainer.scroll(updateScroll);
|
||||||
|
scrollLeft = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-left"><a href="#" style="display:none;"><i class="fa fa-caret-left"></i></a></div>').appendTo(wrapper).find("a");
|
||||||
|
scrollLeft.on('mousedown',function(evt) { scrollEventHandler(evt,'-=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||||
|
scrollRight = $('<div class="red-ui-tab-button red-ui-tab-scroll red-ui-tab-scroll-right"><a href="#" style="display:none;"><i class="fa fa-caret-right"></i></a></div>').appendTo(wrapper).find("a");
|
||||||
|
scrollRight.on('mousedown',function(evt) { scrollEventHandler(evt,'+=150') }).on('click',function(evt){ evt.preventDefault();});
|
||||||
|
}
|
||||||
|
function scrollEventHandler(evt,dir) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if ($(this).hasClass('disabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var currentScrollLeft = scrollContainer.scrollLeft();
|
||||||
|
scrollContainer.animate( { scrollLeft: dir }, 300);
|
||||||
|
var interval = setInterval(function() {
|
||||||
|
var newScrollLeft = scrollContainer.scrollLeft()
|
||||||
|
if (newScrollLeft === currentScrollLeft) {
|
||||||
|
clearInterval(interval);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentScrollLeft = newScrollLeft;
|
||||||
|
scrollContainer.animate( { scrollLeft: dir }, 300);
|
||||||
|
},300);
|
||||||
|
$(this).one('mouseup',function() {
|
||||||
|
clearInterval(interval);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ul.children().first().addClass("active");
|
ul.children().first().addClass("active");
|
||||||
ul.children().addClass("red-ui-tab");
|
ul.children().addClass("red-ui-tab");
|
||||||
|
|
||||||
@ -34,6 +77,23 @@ RED.tabs = (function() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateScroll() {
|
||||||
|
if (ul.children().length !== 0) {
|
||||||
|
var sl = scrollContainer.scrollLeft();
|
||||||
|
var scWidth = scrollContainer.width();
|
||||||
|
var ulWidth = ul.width();
|
||||||
|
if (sl === 0) {
|
||||||
|
scrollLeft.hide();
|
||||||
|
} else {
|
||||||
|
scrollLeft.show();
|
||||||
|
}
|
||||||
|
if (sl === ulWidth-scWidth) {
|
||||||
|
scrollRight.hide();
|
||||||
|
} else {
|
||||||
|
scrollRight.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
function onTabDblClick() {
|
function onTabDblClick() {
|
||||||
if (options.ondblclick) {
|
if (options.ondblclick) {
|
||||||
options.ondblclick(tabs[$(this).attr('href').slice(1)]);
|
options.ondblclick(tabs[$(this).attr('href').slice(1)]);
|
||||||
@ -49,6 +109,14 @@ RED.tabs = (function() {
|
|||||||
ul.children().removeClass("active");
|
ul.children().removeClass("active");
|
||||||
ul.children().css({"transition": "width 100ms"});
|
ul.children().css({"transition": "width 100ms"});
|
||||||
link.parent().addClass("active");
|
link.parent().addClass("active");
|
||||||
|
if (options.scrollable) {
|
||||||
|
var pos = link.parent().position().left;
|
||||||
|
if (pos-21 < 0) {
|
||||||
|
scrollContainer.animate( { scrollLeft: '+='+(pos-50) }, 300);
|
||||||
|
} else if (pos + 120 > scrollContainer.width()) {
|
||||||
|
scrollContainer.animate( { scrollLeft: '+='+(pos + 140-scrollContainer.width()) }, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (options.onchange) {
|
if (options.onchange) {
|
||||||
options.onchange(tabs[link.attr('href').slice(1)]);
|
options.onchange(tabs[link.attr('href').slice(1)]);
|
||||||
}
|
}
|
||||||
@ -61,23 +129,29 @@ RED.tabs = (function() {
|
|||||||
|
|
||||||
function updateTabWidths() {
|
function updateTabWidths() {
|
||||||
var tabs = ul.find("li.red-ui-tab");
|
var tabs = ul.find("li.red-ui-tab");
|
||||||
var width = ul.width();
|
var width = wrapper.width();
|
||||||
var tabCount = tabs.size();
|
var tabCount = tabs.size();
|
||||||
var tabWidth = (width-12-(tabCount*6))/tabCount;
|
var tabWidth = (width-12-(tabCount*6))/tabCount;
|
||||||
currentTabWidth = 100*tabWidth/width;
|
currentTabWidth = (100*tabWidth/width)+"%";
|
||||||
currentActiveTabWidth = currentTabWidth+"%";
|
currentActiveTabWidth = currentTabWidth+"%";
|
||||||
|
if (options.scrollable) {
|
||||||
if (options.hasOwnProperty("minimumActiveTabWidth")) {
|
tabWidth = Math.max(tabWidth,140);
|
||||||
|
currentTabWidth = tabWidth+"px";
|
||||||
|
currentActiveTabWidth = 0;
|
||||||
|
var listWidth = Math.max(wrapper.width(),12+(tabWidth+6)*tabCount);
|
||||||
|
ul.width(listWidth);
|
||||||
|
updateScroll();
|
||||||
|
} else if (options.hasOwnProperty("minimumActiveTabWidth")) {
|
||||||
if (tabWidth < options.minimumActiveTabWidth) {
|
if (tabWidth < options.minimumActiveTabWidth) {
|
||||||
tabCount -= 1;
|
tabCount -= 1;
|
||||||
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
|
tabWidth = (width-12-options.minimumActiveTabWidth-(tabCount*6))/tabCount;
|
||||||
currentTabWidth = 100*tabWidth/width;
|
currentTabWidth = (100*tabWidth/width)+"%";
|
||||||
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
|
currentActiveTabWidth = options.minimumActiveTabWidth+"px";
|
||||||
} else {
|
} else {
|
||||||
currentActiveTabWidth = 0;
|
currentActiveTabWidth = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tabs.css({width:currentTabWidth+"%"});
|
tabs.css({width:currentTabWidth});
|
||||||
if (tabWidth < 50) {
|
if (tabWidth < 50) {
|
||||||
ul.find(".red-ui-tab-close").hide();
|
ul.find(".red-ui-tab-close").hide();
|
||||||
ul.find(".red-ui-tab-icon").hide();
|
ul.find(".red-ui-tab-icon").hide();
|
||||||
@ -97,7 +171,9 @@ RED.tabs = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
|
ul.find("li.red-ui-tab a").on("click",onTabClick).on("dblclick",onTabDblClick);
|
||||||
|
setTimeout(function() {
|
||||||
updateTabWidths();
|
updateTabWidths();
|
||||||
|
},0);
|
||||||
|
|
||||||
|
|
||||||
function removeTab(id) {
|
function removeTab(id) {
|
||||||
@ -126,7 +202,8 @@ RED.tabs = (function() {
|
|||||||
if (tab.icon) {
|
if (tab.icon) {
|
||||||
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
$('<img src="'+tab.icon+'" class="red-ui-tab-icon"/>').appendTo(link);
|
||||||
}
|
}
|
||||||
$('<span/>').text(tab.label).appendTo(link);
|
var span = $('<span/>',{class:"bidiAware"}).text(tab.label).appendTo(link);
|
||||||
|
span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label));
|
||||||
|
|
||||||
link.on("click",onTabClick);
|
link.on("click",onTabClick);
|
||||||
link.on("dblclick",onTabDblClick);
|
link.on("dblclick",onTabDblClick);
|
||||||
@ -187,8 +264,8 @@ RED.tabs = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
drag: function(event,ui) {
|
drag: function(event,ui) {
|
||||||
ui.position.left += tabElements[tabDragIndex].left;
|
ui.position.left += tabElements[tabDragIndex].left+scrollContainer.scrollLeft();
|
||||||
var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2;
|
var tabCenter = ui.position.left + tabElements[tabDragIndex].width/2 - scrollContainer.scrollLeft();
|
||||||
for (var i=0;i<tabElements.length;i++) {
|
for (var i=0;i<tabElements.length;i++) {
|
||||||
if (i === tabDragIndex) {
|
if (i === tabDragIndex) {
|
||||||
continue;
|
continue;
|
||||||
@ -209,8 +286,6 @@ RED.tabs = (function() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(ui.position.left,ui.offset.left);
|
|
||||||
},
|
},
|
||||||
stop: function(event,ui) {
|
stop: function(event,ui) {
|
||||||
ul.children().css({position:"relative",left:"",transition:""});
|
ul.children().css({position:"relative",left:"",transition:""});
|
||||||
@ -239,7 +314,7 @@ RED.tabs = (function() {
|
|||||||
tabs[id].label = label;
|
tabs[id].label = label;
|
||||||
var tab = ul.find("a[href='#"+id+"']");
|
var tab = ul.find("a[href='#"+id+"']");
|
||||||
tab.attr("title",label);
|
tab.attr("title",label);
|
||||||
tab.find("span").text(label);
|
tab.find("span").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label));
|
||||||
updateTabWidths();
|
updateTabWidths();
|
||||||
},
|
},
|
||||||
order: function(order) {
|
order: function(order) {
|
@ -35,6 +35,7 @@ RED.deploy = (function() {
|
|||||||
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
|
$("#btn-deploy img").attr("src",deploymentTypes[type].img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentDiff = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* options:
|
* options:
|
||||||
@ -76,7 +77,7 @@ RED.deploy = (function() {
|
|||||||
$('#btn-deploy').click(function() { save(); });
|
$('#btn-deploy').click(function() { save(); });
|
||||||
|
|
||||||
$( "#node-dialog-confirm-deploy" ).dialog({
|
$( "#node-dialog-confirm-deploy" ).dialog({
|
||||||
title: "Confirm deploy",
|
title: RED._('deploy.confirm.button.confirm'),
|
||||||
modal: true,
|
modal: true,
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
width: 550,
|
width: 550,
|
||||||
@ -88,6 +89,15 @@ RED.deploy = (function() {
|
|||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// id: "node-dialog-confirm-deploy-review",
|
||||||
|
// text: RED._("deploy.confirm.button.review"),
|
||||||
|
// class: "primary",
|
||||||
|
// click: function() {
|
||||||
|
// showDiff();
|
||||||
|
// $( this ).dialog( "close" );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
text: RED._("deploy.confirm.button.confirm"),
|
text: RED._("deploy.confirm.button.confirm"),
|
||||||
class: "primary",
|
class: "primary",
|
||||||
@ -97,7 +107,7 @@ RED.deploy = (function() {
|
|||||||
if (ignoreChecked) {
|
if (ignoreChecked) {
|
||||||
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
|
ignoreDeployWarnings[$( "#node-dialog-confirm-deploy-type" ).val()] = true;
|
||||||
}
|
}
|
||||||
save(true);
|
save(true,$( "#node-dialog-confirm-deploy-type" ).val() === "conflict");
|
||||||
$( this ).dialog( "close" );
|
$( this ).dialog( "close" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,6 +119,15 @@ RED.deploy = (function() {
|
|||||||
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
|
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+
|
||||||
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+
|
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+
|
||||||
'</div>');
|
'</div>');
|
||||||
|
},
|
||||||
|
open: function() {
|
||||||
|
if ($( "#node-dialog-confirm-deploy-type" ).val() === "conflict") {
|
||||||
|
// $("#node-dialog-confirm-deploy-review").show();
|
||||||
|
$("#node-dialog-confirm-deploy-hide").parent().hide();
|
||||||
|
} else {
|
||||||
|
// $("#node-dialog-confirm-deploy-review").hide();
|
||||||
|
$("#node-dialog-confirm-deploy-hide").parent().show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,6 +142,199 @@ RED.deploy = (function() {
|
|||||||
$("#btn-deploy").addClass("disabled");
|
$("#btn-deploy").addClass("disabled");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// $("#node-dialog-view-diff").dialog({
|
||||||
|
// title: RED._('deploy.confirm.button.review'),
|
||||||
|
// modal: true,
|
||||||
|
// autoOpen: false,
|
||||||
|
// buttons: [
|
||||||
|
// {
|
||||||
|
// text: RED._("deploy.confirm.button.cancel"),
|
||||||
|
// click: function() {
|
||||||
|
// $( this ).dialog( "close" );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// text: RED._("deploy.confirm.button.merge"),
|
||||||
|
// class: "primary",
|
||||||
|
// click: function() {
|
||||||
|
// $( this ).dialog( "close" );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
// open: function() {
|
||||||
|
// $(this).dialog({width:Math.min($(window).width(),900),height:Math.min($(window).height(),600)});
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// $("#node-dialog-view-diff-diff").editableList({
|
||||||
|
// addButton: false,
|
||||||
|
// scrollOnAdd: false,
|
||||||
|
// addItem: function(container,i,object) {
|
||||||
|
// var tab = object.tab.n;
|
||||||
|
// var tabDiv = $('<div>',{class:"node-diff-tab collapsed"}).appendTo(container);
|
||||||
|
//
|
||||||
|
// var titleRow = $('<div>',{class:"node-diff-tab-title"}).appendTo(tabDiv);
|
||||||
|
// titleRow.click(function(evt) {
|
||||||
|
// evt.preventDefault();
|
||||||
|
// titleRow.parent().toggleClass('collapsed');
|
||||||
|
// })
|
||||||
|
// var chevron = $('<i class="fa fa-angle-down node-diff-chevron ">').appendTo(titleRow);
|
||||||
|
// var title = $('<span>').html(tab.label||tab.id).appendTo(titleRow);
|
||||||
|
//
|
||||||
|
// var stats = $('<span>',{class:"node-diff-tab-stats"}).appendTo(titleRow);
|
||||||
|
//
|
||||||
|
// var addedCount = 0;
|
||||||
|
// var deletedCount = 0;
|
||||||
|
// var changedCount = 0;
|
||||||
|
// var conflictedCount = 0;
|
||||||
|
//
|
||||||
|
// object.tab.nodes.forEach(function(node) {
|
||||||
|
// var realNode = RED.nodes.node(node.id);
|
||||||
|
// var hasChanges = false;
|
||||||
|
// if (currentDiff.added[node.id]) {
|
||||||
|
// addedCount++;
|
||||||
|
// hasChanges = true;
|
||||||
|
// }
|
||||||
|
// if (currentDiff.deleted[node.id]) {
|
||||||
|
// deletedCount++;
|
||||||
|
// hasChanges = true;
|
||||||
|
// }
|
||||||
|
// if (currentDiff.changed[node.id]) {
|
||||||
|
// changedCount++;
|
||||||
|
// hasChanges = true;
|
||||||
|
// }
|
||||||
|
// if (currentDiff.conflicted[node.id]) {
|
||||||
|
// conflictedCount++;
|
||||||
|
// hasChanges = true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (hasChanges) {
|
||||||
|
// var def = RED.nodes.getType(node.type)||{};
|
||||||
|
// var div = $("<div>",{class:"node-diff-node-entry collapsed"}).appendTo(tabDiv);
|
||||||
|
// var nodeTitleDiv = $("<div>",{class:"node-diff-node-entry-title"}).appendTo(div);
|
||||||
|
// nodeTitleDiv.click(function(evt) {
|
||||||
|
// evt.preventDefault();
|
||||||
|
// $(this).parent().toggleClass('collapsed');
|
||||||
|
// })
|
||||||
|
// var newNode = currentDiff.newConfig.all[node.id];
|
||||||
|
// var nodePropertiesDiv = $("<div>",{class:"node-diff-node-entry-properties"}).appendTo(div);
|
||||||
|
//
|
||||||
|
// var nodePropertiesTable = $("<table>").appendTo(nodePropertiesDiv);
|
||||||
|
//
|
||||||
|
// if (node.hasOwnProperty('x')) {
|
||||||
|
// if (newNode.x !== node.x || newNode.y !== node.y) {
|
||||||
|
// var currentPosition = node.x+", "+node.y
|
||||||
|
// var newPosition = newNode.x+", "+newNode.y;
|
||||||
|
// $("<tr><td>position</td><td>"+currentPosition+"</td><td>"+newPosition+"</td></tr>").appendTo(nodePropertiesTable);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// var properties = Object.keys(node).filter(function(p) { return p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
|
||||||
|
// if (def.defaults) {
|
||||||
|
// properties = properties.concat(Object.keys(def.defaults));
|
||||||
|
// }
|
||||||
|
// properties.forEach(function(d) {
|
||||||
|
// var localValue = JSON.stringify(node[d]);
|
||||||
|
// var remoteValue = JSON.stringify(newNode[d]);
|
||||||
|
// var originalValue = realNode._config[d];
|
||||||
|
//
|
||||||
|
// if (remoteValue !== originalValue) {
|
||||||
|
// var formattedProperty = formatNodeProperty(node[d]);
|
||||||
|
// var newFormattedProperty = formatNodeProperty(newNode[d]);
|
||||||
|
// if (localValue === originalValue) {
|
||||||
|
// // no conflict change
|
||||||
|
// } else {
|
||||||
|
// // conflicting change
|
||||||
|
// }
|
||||||
|
// $("<tr><td>"+d+'</td><td class="">'+formattedProperty+'</td><td class="node-diff-property-changed">'+newFormattedProperty+"</td></tr>").appendTo(nodePropertiesTable);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// })
|
||||||
|
// var nodeChevron = $('<i class="fa fa-angle-down node-diff-chevron">').appendTo(nodeTitleDiv);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // var leftColumn = $('<div>',{class:"node-diff-column"}).appendTo(div);
|
||||||
|
// // var rightColumn = $('<div>',{class:"node-diff-column"}).appendTo(div);
|
||||||
|
// // rightColumn.html(" ");
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// var nodeDiv = $("<div>",{class:"node-diff-node-entry-node"}).appendTo(nodeTitleDiv);
|
||||||
|
// var colour = def.color;
|
||||||
|
// var icon_url = "arrow-in.png";
|
||||||
|
// if (node.type === 'tab') {
|
||||||
|
// colour = "#C0DEED";
|
||||||
|
// icon_url = "subflow.png";
|
||||||
|
// } else if (def.category === 'config') {
|
||||||
|
// icon_url = "cog.png";
|
||||||
|
// } else if (node.type === 'unknown') {
|
||||||
|
// icon_url = "alert.png";
|
||||||
|
// } else {
|
||||||
|
// icon_url = def.icon;
|
||||||
|
// }
|
||||||
|
// nodeDiv.css('backgroundColor',colour);
|
||||||
|
//
|
||||||
|
// var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
|
||||||
|
// $('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// var contentDiv = $('<div>',{class:"node-diff-node-description"}).appendTo(nodeTitleDiv);
|
||||||
|
//
|
||||||
|
// $('<span>',{class:"node-diff-node-label"}).html(node.label || node.name || node.id).appendTo(contentDiv);
|
||||||
|
// //$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
|
||||||
|
// //$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// var statsInfo = '<span class="node-diff-count">'+object.tab.nodes.length+" nodes"+
|
||||||
|
// (addedCount+deletedCount+changedCount+conflictedCount > 0 ? " : ":"")+
|
||||||
|
// "</span> "+
|
||||||
|
// ((addedCount > 0)?'<span class="node-diff-added">'+addedCount+' added</span> ':'')+
|
||||||
|
// ((deletedCount > 0)?'<span class="node-diff-deleted">'+deletedCount+' deleted</span> ':'')+
|
||||||
|
// ((changedCount > 0)?'<span class="node-diff-changed">'+changedCount+' changed</span> ':'')+
|
||||||
|
// ((conflictedCount > 0)?'<span class="node-diff-conflicted">'+conflictedCount+' conflicts</span>':'');
|
||||||
|
// stats.html(statsInfo);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// // var node = object.node;
|
||||||
|
// // var realNode = RED.nodes.node(node.id);
|
||||||
|
// // var def = RED.nodes.getType(object.node.type)||{};
|
||||||
|
// // var l = "";
|
||||||
|
// // if (def && def.label && realNode) {
|
||||||
|
// // l = def.label;
|
||||||
|
// // try {
|
||||||
|
// // l = (typeof l === "function" ? l.call(realNode) : l);
|
||||||
|
// // } catch(err) {
|
||||||
|
// // console.log("Definition error: "+node.type+".label",err);
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // l = l||node.label||node.name||node.id||"";
|
||||||
|
// // console.log(node);
|
||||||
|
// // var div = $('<div>').appendTo(container);
|
||||||
|
// // div.html(l);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatNodeProperty(prop) {
|
||||||
|
var formattedProperty = prop;
|
||||||
|
if (formattedProperty === null) {
|
||||||
|
formattedProperty = 'null';
|
||||||
|
} else if (formattedProperty === undefined) {
|
||||||
|
formattedProperty = 'undefined';
|
||||||
|
} else if (typeof formattedProperty === 'object') {
|
||||||
|
formattedProperty = JSON.stringify(formattedProperty);
|
||||||
|
}
|
||||||
|
if (/\n/.test(formattedProperty)) {
|
||||||
|
formattedProperty = "<pre>"+formattedProperty+"</pre>"
|
||||||
|
}
|
||||||
|
return formattedProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeInfo(node) {
|
function getNodeInfo(node) {
|
||||||
@ -160,11 +372,157 @@ RED.deploy = (function() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function save(force) {
|
function resolveConflict(currentNodes) {
|
||||||
|
$( "#node-dialog-confirm-deploy-config" ).hide();
|
||||||
|
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
||||||
|
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
||||||
|
$( "#node-dialog-confirm-deploy-conflict" ).show();
|
||||||
|
$( "#node-dialog-confirm-deploy-type" ).val("conflict");
|
||||||
|
$( "#node-dialog-confirm-deploy" ).dialog( "open" );
|
||||||
|
|
||||||
|
// $("#node-dialog-confirm-deploy-review").append($('<img src="red/images/spin.svg" style="background: rgba(255,255,255,0.8); margin-top: -16px; margin-left: -8px; height:16px; position: absolute; "/>'));
|
||||||
|
// $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",0.4);
|
||||||
|
// $("#node-dialog-confirm-deploy-review").attr("disabled",true).addClass("disabled");
|
||||||
|
// $.ajax({
|
||||||
|
// headers: {
|
||||||
|
// "Accept":"application/json",
|
||||||
|
// },
|
||||||
|
// cache: false,
|
||||||
|
// url: 'flows',
|
||||||
|
// success: function(nodes) {
|
||||||
|
// var newNodes = nodes.flows;
|
||||||
|
// var newRevision = nodes.rev;
|
||||||
|
// generateDiff(currentNodes,newNodes);
|
||||||
|
// $("#node-dialog-confirm-deploy-review").attr("disabled",false).removeClass("disabled");
|
||||||
|
// $("#node-dialog-confirm-deploy-review img").remove();
|
||||||
|
// $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",1);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
// function parseNodes(nodeList) {
|
||||||
|
// var tabOrder = [];
|
||||||
|
// var tabs = {};
|
||||||
|
// var subflows = {};
|
||||||
|
// var globals = [];
|
||||||
|
// var all = {};
|
||||||
|
//
|
||||||
|
// nodeList.forEach(function(node) {
|
||||||
|
// all[node.id] = node;
|
||||||
|
// if (node.type === 'tab') {
|
||||||
|
// tabOrder.push(node.id);
|
||||||
|
// tabs[node.id] = {n:node,nodes:[]};
|
||||||
|
// } else if (node.type === 'subflow') {
|
||||||
|
// subflows[node.id] = {n:node,nodes:[]};
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// nodeList.forEach(function(node) {
|
||||||
|
// if (node.type !== 'tab' && node.type !== 'subflow') {
|
||||||
|
// if (tabs[node.z]) {
|
||||||
|
// tabs[node.z].nodes.push(node);
|
||||||
|
// } else if (subflows[node.z]) {
|
||||||
|
// subflows[node.z].nodes.push(node);
|
||||||
|
// } else {
|
||||||
|
// globals.push(node);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// return {
|
||||||
|
// all: all,
|
||||||
|
// tabOrder: tabOrder,
|
||||||
|
// tabs: tabs,
|
||||||
|
// subflows: subflows,
|
||||||
|
// globals: globals
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function generateDiff(currentNodes,newNodes) {
|
||||||
|
// var currentConfig = parseNodes(currentNodes);
|
||||||
|
// var newConfig = parseNodes(newNodes);
|
||||||
|
// var pending = RED.nodes.pending();
|
||||||
|
// var added = {};
|
||||||
|
// var deleted = {};
|
||||||
|
// var changed = {};
|
||||||
|
// var conflicted = {};
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Object.keys(currentConfig.all).forEach(function(id) {
|
||||||
|
// var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
|
||||||
|
// if (!newConfig.all.hasOwnProperty(id)) {
|
||||||
|
// if (!pending.added.hasOwnProperty(id)) {
|
||||||
|
// deleted[id] = true;
|
||||||
|
// conflicted[id] = node.changed;
|
||||||
|
// }
|
||||||
|
// } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
|
||||||
|
// changed[id] = true;
|
||||||
|
// conflicted[id] = node.changed;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// Object.keys(newConfig.all).forEach(function(id) {
|
||||||
|
// if (!currentConfig.all.hasOwnProperty(id) && !pending.deleted.hasOwnProperty(id)) {
|
||||||
|
// added[id] = true;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// // console.log("Added",added);
|
||||||
|
// // console.log("Deleted",deleted);
|
||||||
|
// // console.log("Changed",changed);
|
||||||
|
// // console.log("Conflicted",conflicted);
|
||||||
|
//
|
||||||
|
// var formatString = function(id) {
|
||||||
|
// return conflicted[id]?"!":(added[id]?"+":(deleted[id]?"-":(changed[id]?"~":" ")));
|
||||||
|
// }
|
||||||
|
// newConfig.tabOrder.forEach(function(tabId) {
|
||||||
|
// var tab = newConfig.tabs[tabId];
|
||||||
|
// console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
|
||||||
|
// tab.nodes.forEach(function(node) {
|
||||||
|
// console.log(" ",formatString(node.id),node.type,node.name || node.id);
|
||||||
|
// })
|
||||||
|
// if (currentConfig.tabs[tabId]) {
|
||||||
|
// currentConfig.tabs[tabId].nodes.forEach(function(node) {
|
||||||
|
// if (deleted[node.id]) {
|
||||||
|
// console.log(" ",formatString(node.id),node.type,node.name || node.id);
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// currentConfig.tabOrder.forEach(function(tabId) {
|
||||||
|
// if (deleted[tabId]) {
|
||||||
|
// console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// currentDiff = {
|
||||||
|
// currentConfig: currentConfig,
|
||||||
|
// newConfig: newConfig,
|
||||||
|
// added: added,
|
||||||
|
// deleted: deleted,
|
||||||
|
// changed: changed,
|
||||||
|
// conflicted: conflicted
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function showDiff() {
|
||||||
|
// if (currentDiff) {
|
||||||
|
// var list = $("#node-dialog-view-diff-diff");
|
||||||
|
// list.editableList('empty');
|
||||||
|
// var currentConfig = currentDiff.currentConfig;
|
||||||
|
// currentConfig.tabOrder.forEach(function(tabId) {
|
||||||
|
// var tab = currentConfig.tabs[tabId];
|
||||||
|
// list.editableList('addItem',{tab:tab})
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// $("#node-dialog-view-diff").dialog("open");
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
function save(skipValidation,force) {
|
||||||
if (RED.nodes.dirty()) {
|
if (RED.nodes.dirty()) {
|
||||||
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
|
//$("#debug-tab-clear").click(); // uncomment this to auto clear debug on deploy
|
||||||
|
|
||||||
if (!force) {
|
if (!skipValidation) {
|
||||||
var hasUnknown = false;
|
var hasUnknown = false;
|
||||||
var hasInvalid = false;
|
var hasInvalid = false;
|
||||||
var hasUnusedConfig = false;
|
var hasUnusedConfig = false;
|
||||||
@ -196,6 +554,7 @@ RED.deploy = (function() {
|
|||||||
$( "#node-dialog-confirm-deploy-config" ).hide();
|
$( "#node-dialog-confirm-deploy-config" ).hide();
|
||||||
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
$( "#node-dialog-confirm-deploy-unknown" ).hide();
|
||||||
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
$( "#node-dialog-confirm-deploy-unused" ).hide();
|
||||||
|
$( "#node-dialog-confirm-deploy-conflict" ).hide();
|
||||||
|
|
||||||
var showWarning = false;
|
var showWarning = false;
|
||||||
|
|
||||||
@ -229,24 +588,28 @@ RED.deploy = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var nns = RED.nodes.createCompleteNodeSet();
|
var nns = RED.nodes.createCompleteNodeSet();
|
||||||
|
|
||||||
$("#btn-deploy-icon").removeClass('fa-download');
|
$("#btn-deploy-icon").removeClass('fa-download');
|
||||||
$("#btn-deploy-icon").addClass('spinner');
|
$("#btn-deploy-icon").addClass('spinner');
|
||||||
RED.nodes.dirty(false);
|
|
||||||
|
var data = {flows:nns};
|
||||||
|
|
||||||
|
if (!force) {
|
||||||
|
data.rev = RED.nodes.version();
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url:"flows",
|
url:"flows",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: JSON.stringify(nns),
|
data: JSON.stringify(data),
|
||||||
contentType: "application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
headers: {
|
headers: {
|
||||||
"Node-RED-Deployment-Type":deploymentType
|
"Node-RED-Deployment-Type":deploymentType
|
||||||
}
|
}
|
||||||
}).done(function(data,textStatus,xhr) {
|
}).done(function(data,textStatus,xhr) {
|
||||||
|
RED.nodes.dirty(false);
|
||||||
|
RED.nodes.version(data.rev);
|
||||||
if (hasUnusedConfig) {
|
if (hasUnusedConfig) {
|
||||||
RED.notify(
|
RED.notify(
|
||||||
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
|
'<p>'+RED._("deploy.successfulDeploy")+'</p>'+
|
||||||
@ -264,10 +627,14 @@ RED.deploy = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
RED.nodes.eachConfig(function (confNode) {
|
RED.nodes.eachConfig(function (confNode) {
|
||||||
|
confNode.changed = false;
|
||||||
if (confNode.credentials) {
|
if (confNode.credentials) {
|
||||||
delete confNode.credentials;
|
delete confNode.credentials;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
RED.nodes.eachWorkspace(function(ws) {
|
||||||
|
ws.changed = false;
|
||||||
|
})
|
||||||
// Once deployed, cannot undo back to a clean state
|
// Once deployed, cannot undo back to a clean state
|
||||||
RED.history.markAllDirty();
|
RED.history.markAllDirty();
|
||||||
RED.view.redraw();
|
RED.view.redraw();
|
||||||
@ -276,6 +643,8 @@ RED.deploy = (function() {
|
|||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
if (xhr.status === 401) {
|
if (xhr.status === 401) {
|
||||||
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
|
||||||
|
} else if (xhr.status === 409) {
|
||||||
|
resolveConflict(nns);
|
||||||
} else if (xhr.responseText) {
|
} else if (xhr.responseText) {
|
||||||
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
|
RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
|
||||||
} else {
|
} else {
|
||||||
@ -287,7 +656,6 @@ RED.deploy = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init
|
init: init
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,11 @@ RED.editor = (function() {
|
|||||||
function validateNodeEditorProperty(node,defaults,property,prefix) {
|
function validateNodeEditorProperty(node,defaults,property,prefix) {
|
||||||
var input = $("#"+prefix+"-"+property);
|
var input = $("#"+prefix+"-"+property);
|
||||||
if (input.length > 0) {
|
if (input.length > 0) {
|
||||||
if (!validateNodeProperty(node, defaults, property,input.val())) {
|
var value = input.val();
|
||||||
|
if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") {
|
||||||
|
value = input.text();
|
||||||
|
}
|
||||||
|
if (!validateNodeProperty(node, defaults, property,value)) {
|
||||||
input.addClass("input-error");
|
input.addClass("input-error");
|
||||||
} else {
|
} else {
|
||||||
input.removeClass("input-error");
|
input.removeClass("input-error");
|
||||||
@ -295,17 +299,30 @@ RED.editor = (function() {
|
|||||||
* @param node - the node being edited
|
* @param node - the node being edited
|
||||||
* @param property - the name of the field
|
* @param property - the name of the field
|
||||||
* @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
|
* @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
|
||||||
|
* @param definition - the definition of the field
|
||||||
*/
|
*/
|
||||||
function preparePropertyEditor(node,property,prefix) {
|
function preparePropertyEditor(node,property,prefix,definition) {
|
||||||
var input = $("#"+prefix+"-"+property);
|
var input = $("#"+prefix+"-"+property);
|
||||||
|
if (input.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (input.attr('type') === "checkbox") {
|
if (input.attr('type') === "checkbox") {
|
||||||
input.prop('checked',node[property]);
|
input.prop('checked',node[property]);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
var val = node[property];
|
var val = node[property];
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
val = "";
|
val = "";
|
||||||
}
|
}
|
||||||
|
if (definition !== undefined && definition[property].hasOwnProperty("format") && definition[property].format !== "" && input[0].nodeName === "DIV") {
|
||||||
|
input.html(RED.text.format.getHtml(val, definition[property].format, {}, false, "en"));
|
||||||
|
RED.text.format.attach(input[0], definition[property].format, {}, false, "en");
|
||||||
|
} else {
|
||||||
input.val(val);
|
input.val(val);
|
||||||
|
if (input[0].nodeName === 'INPUT' || input[0].nodeName === 'TEXTAREA') {
|
||||||
|
RED.text.bidi.prepareInput(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,12 +334,21 @@ RED.editor = (function() {
|
|||||||
* @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
|
* @param prefix - the prefix to use in the input element ids (node-input|node-config-input)
|
||||||
*/
|
*/
|
||||||
function attachPropertyChangeHandler(node,definition,property,prefix) {
|
function attachPropertyChangeHandler(node,definition,property,prefix) {
|
||||||
|
var input = $("#"+prefix+"-"+property);
|
||||||
|
if (definition !== undefined && "format" in definition[property] && definition[property].format !== "" && input[0].nodeName === "DIV") {
|
||||||
|
$("#"+prefix+"-"+property).on('change keyup', function(event,skipValidation) {
|
||||||
|
if (!skipValidation) {
|
||||||
|
validateNodeEditor(node,prefix);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
$("#"+prefix+"-"+property).change(function(event,skipValidation) {
|
$("#"+prefix+"-"+property).change(function(event,skipValidation) {
|
||||||
if (!skipValidation) {
|
if (!skipValidation) {
|
||||||
validateNodeEditor(node,prefix);
|
validateNodeEditor(node,prefix);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the value to each credential field
|
* Assign the value to each credential field
|
||||||
@ -345,7 +371,7 @@ RED.editor = (function() {
|
|||||||
$('#' + prefix + '-' + cred).val('');
|
$('#' + prefix + '-' + cred).val('');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
preparePropertyEditor(credData, cred, prefix);
|
preparePropertyEditor(credData, cred, prefix, credDef);
|
||||||
}
|
}
|
||||||
attachPropertyChangeHandler(node, credDef, cred, prefix);
|
attachPropertyChangeHandler(node, credDef, cred, prefix);
|
||||||
}
|
}
|
||||||
@ -405,10 +431,10 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("Unknown type:", definition.defaults[d].type);
|
console.log("Unknown type:", definition.defaults[d].type);
|
||||||
preparePropertyEditor(node,d,prefix);
|
preparePropertyEditor(node,d,prefix,definition.defaults);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
preparePropertyEditor(node,d,prefix);
|
preparePropertyEditor(node,d,prefix,definition.defaults);
|
||||||
}
|
}
|
||||||
attachPropertyChangeHandler(node,definition.defaults,d,prefix);
|
attachPropertyChangeHandler(node,definition.defaults,d,prefix);
|
||||||
}
|
}
|
||||||
@ -589,6 +615,8 @@ RED.editor = (function() {
|
|||||||
var newValue;
|
var newValue;
|
||||||
if (input.attr('type') === "checkbox") {
|
if (input.attr('type') === "checkbox") {
|
||||||
newValue = input.prop('checked');
|
newValue = input.prop('checked');
|
||||||
|
} else if ("format" in editing_node._def.defaults[d] && editing_node._def.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
||||||
|
newValue = input.text();
|
||||||
} else {
|
} else {
|
||||||
newValue = input.val();
|
newValue = input.val();
|
||||||
}
|
}
|
||||||
@ -768,16 +796,17 @@ RED.editor = (function() {
|
|||||||
} else {
|
} else {
|
||||||
ns = node_def.set.id;
|
ns = node_def.set.id;
|
||||||
}
|
}
|
||||||
var activeWorkspace = RED.nodes.workspace(RED.workspaces.active());
|
var configNodeScope = ""; // default to global
|
||||||
if (!activeWorkspace) {
|
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
||||||
activeWorkspace = RED.nodes.subflow(RED.workspaces.active());
|
if (activeSubflow) {
|
||||||
|
configNodeScope = activeSubflow.id;
|
||||||
}
|
}
|
||||||
if (editing_config_node == null) {
|
if (editing_config_node == null) {
|
||||||
editing_config_node = {
|
editing_config_node = {
|
||||||
id: RED.nodes.id(),
|
id: RED.nodes.id(),
|
||||||
_def: node_def,
|
_def: node_def,
|
||||||
type: type,
|
type: type,
|
||||||
z: activeWorkspace.id,
|
z: configNodeScope,
|
||||||
users: []
|
users: []
|
||||||
}
|
}
|
||||||
for (var d in node_def.defaults) {
|
for (var d in node_def.defaults) {
|
||||||
@ -1155,7 +1184,7 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configNodes.forEach(function(cn) {
|
configNodes.forEach(function(cn) {
|
||||||
select.append('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'>'+cn.__label__+'</option>');
|
select.append('<option value="'+cn.id+'"'+(value==cn.id?" selected":"")+'>'+RED.text.bidi.enforceTextDirectionWithUCC(cn.__label__)+'</option>');
|
||||||
delete cn.__label__;
|
delete cn.__label__;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1197,7 +1226,6 @@ RED.editor = (function() {
|
|||||||
changes['name'] = editing_node.name;
|
changes['name'] = editing_node.name;
|
||||||
editing_node.name = newName;
|
editing_node.name = newName;
|
||||||
changed = true;
|
changed = true;
|
||||||
$("#menu-item-workspace-menu-"+editing_node.id.replace(".","-")).text(newName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var newDescription = subflowEditor.getValue();
|
var newDescription = subflowEditor.getValue();
|
||||||
@ -1290,6 +1318,7 @@ RED.editor = (function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#subflow-input-name").val(subflow.name);
|
$("#subflow-input-name").val(subflow.name);
|
||||||
|
RED.text.bidi.prepareInput($("#subflow-input-name"));
|
||||||
subflowEditor.getSession().setValue(subflow.info||"",-1);
|
subflowEditor.getSession().setValue(subflow.info||"",-1);
|
||||||
var userCount = 0;
|
var userCount = 0;
|
||||||
var subflowType = "subflow:"+editing_node.id;
|
var subflowType = "subflow:"+editing_node.id;
|
||||||
@ -1363,7 +1392,7 @@ RED.editor = (function() {
|
|||||||
if (options.globals) {
|
if (options.globals) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
if (!!session.$worker) {
|
if (!!session.$worker) {
|
||||||
session.$worker.send("setOptions", [{globals: options.globals}]);
|
session.$worker.send("setOptions", [{globals: options.globals, esversion:6}]);
|
||||||
}
|
}
|
||||||
},100);
|
},100);
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,7 @@ RED.keyboard = (function() {
|
|||||||
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
'<div style="vertical-align: top;display:inline-block; box-sizing: border-box; width:50%; padding: 10px;">'+
|
||||||
'<table class="keyboard-shortcuts">'+
|
'<table class="keyboard-shortcuts">'+
|
||||||
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Space</span></td><td>'+RED._("keyboard.toggleSidebar")+'</td></tr>'+
|
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">Space</span></td><td>'+RED._("keyboard.toggleSidebar")+'</td></tr>'+
|
||||||
|
'<tr><td><span class="help-key">Ctrl/⌘</span> + <span class="help-key">.</span></td><td>'+RED._("keyboard.searchBox")+'</td></tr>'+
|
||||||
'<tr><td></td><td></td></tr>'+
|
'<tr><td></td><td></td></tr>'+
|
||||||
'<tr><td><span class="help-key">Delete</span></td><td rowspan="2">'+RED._("keyboard.deleteSelected")+'</td></tr>'+
|
'<tr><td><span class="help-key">Delete</span></td><td rowspan="2">'+RED._("keyboard.deleteSelected")+'</td></tr>'+
|
||||||
'<tr><td><span class="help-key">Backspace</span></td></tr>'+
|
'<tr><td><span class="help-key">Backspace</span></td></tr>'+
|
||||||
|
749
editor/js/ui/palette-editor.js
Normal file
749
editor/js/ui/palette-editor.js
Normal file
@ -0,0 +1,749 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
RED.palette.editor = (function() {
|
||||||
|
|
||||||
|
var editorTabs;
|
||||||
|
var filterInput;
|
||||||
|
var searchInput;
|
||||||
|
var nodeList;
|
||||||
|
var packageList;
|
||||||
|
var loadedList = [];
|
||||||
|
var filteredList = [];
|
||||||
|
|
||||||
|
var typesInUse = {};
|
||||||
|
var nodeEntries = {};
|
||||||
|
var eventTimers = {};
|
||||||
|
var activeFilter = "";
|
||||||
|
|
||||||
|
function delayCallback(start,callback) {
|
||||||
|
var delta = Date.now() - start;
|
||||||
|
if (delta < 300) {
|
||||||
|
delta = 300;
|
||||||
|
} else {
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
callback();
|
||||||
|
},delta);
|
||||||
|
}
|
||||||
|
function changeNodeState(id,state,shade,callback) {
|
||||||
|
shade.show();
|
||||||
|
var start = Date.now();
|
||||||
|
$.ajax({
|
||||||
|
url:"nodes/"+id,
|
||||||
|
type: "PUT",
|
||||||
|
data: JSON.stringify({
|
||||||
|
enabled: state
|
||||||
|
}),
|
||||||
|
contentType: "application/json; charset=utf-8"
|
||||||
|
}).done(function(data,textStatus,xhr) {
|
||||||
|
delayCallback(start,function() {
|
||||||
|
shade.hide();
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}).fail(function(xhr,textStatus,err) {
|
||||||
|
delayCallback(start,function() {
|
||||||
|
shade.hide();
|
||||||
|
callback(xhr);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function installNodeModule(id,shade,callback) {
|
||||||
|
shade.show();
|
||||||
|
$.ajax({
|
||||||
|
url:"nodes",
|
||||||
|
type: "POST",
|
||||||
|
data: JSON.stringify({
|
||||||
|
module: id
|
||||||
|
}),
|
||||||
|
contentType: "application/json; charset=utf-8"
|
||||||
|
}).done(function(data,textStatus,xhr) {
|
||||||
|
shade.hide();
|
||||||
|
callback();
|
||||||
|
}).fail(function(xhr,textStatus,err) {
|
||||||
|
shade.hide();
|
||||||
|
callback(xhr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function removeNodeModule(id,callback) {
|
||||||
|
$.ajax({
|
||||||
|
url:"nodes/"+id,
|
||||||
|
type: "DELETE"
|
||||||
|
}).done(function(data,textStatus,xhr) {
|
||||||
|
callback();
|
||||||
|
}).fail(function(xhr,textStatus,err) {
|
||||||
|
callback(xhr);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function refreshNodeModule(module) {
|
||||||
|
if (!eventTimers.hasOwnProperty(module)) {
|
||||||
|
eventTimers[module] = setTimeout(function() {
|
||||||
|
delete eventTimers[module];
|
||||||
|
_refreshNodeModule(module);
|
||||||
|
},100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getContrastingBorder(rgbColor){
|
||||||
|
var parts = /^rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)[,)]/.exec(rgbColor);
|
||||||
|
if (parts) {
|
||||||
|
var r = parseInt(parts[1]);
|
||||||
|
var g = parseInt(parts[2]);
|
||||||
|
var b = parseInt(parts[3]);
|
||||||
|
var yiq = ((r*299)+(g*587)+(b*114))/1000;
|
||||||
|
if (yiq > 160) {
|
||||||
|
r = Math.floor(r*0.8);
|
||||||
|
g = Math.floor(g*0.8);
|
||||||
|
b = Math.floor(b*0.8);
|
||||||
|
return "rgb("+r+","+g+","+b+")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rgbColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUpdatedAt(dateString) {
|
||||||
|
var now = new Date();
|
||||||
|
var d = new Date(dateString);
|
||||||
|
var delta = (Date.now() - new Date(dateString).getTime())/1000;
|
||||||
|
|
||||||
|
if (delta < 60) {
|
||||||
|
return RED._('palette.editor.times.seconds');
|
||||||
|
}
|
||||||
|
delta = Math.floor(delta/60);
|
||||||
|
if (delta < 10) {
|
||||||
|
return RED._('palette.editor.times.minutes');
|
||||||
|
}
|
||||||
|
if (delta < 60) {
|
||||||
|
return RED._('palette.editor.times.minutesV',{count:delta});
|
||||||
|
}
|
||||||
|
|
||||||
|
delta = Math.floor(delta/60);
|
||||||
|
|
||||||
|
if (delta < 24) {
|
||||||
|
return RED._('palette.editor.times.hoursV',{count:delta});
|
||||||
|
}
|
||||||
|
|
||||||
|
delta = Math.floor(delta/24);
|
||||||
|
|
||||||
|
if (delta < 7) {
|
||||||
|
return RED._('palette.editor.times.daysV',{count:delta})
|
||||||
|
}
|
||||||
|
var weeks = Math.floor(delta/7);
|
||||||
|
var days = delta%7;
|
||||||
|
|
||||||
|
if (weeks < 4) {
|
||||||
|
return RED._('palette.editor.times.weeksV',{count:weeks})
|
||||||
|
}
|
||||||
|
|
||||||
|
var months = Math.floor(weeks/4);
|
||||||
|
weeks = weeks%4;
|
||||||
|
|
||||||
|
if (months < 12) {
|
||||||
|
return RED._('palette.editor.times.monthsV',{count:months})
|
||||||
|
}
|
||||||
|
var years = Math.floor(months/12);
|
||||||
|
months = months%12;
|
||||||
|
|
||||||
|
if (months === 0) {
|
||||||
|
return RED._('palette.editor.times.yearsV',{count:years})
|
||||||
|
} else {
|
||||||
|
return RED._('palette.editor.times.year'+(years>1?'s':'')+'MonthsV',{y:years,count:months})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _refreshNodeModule(module) {
|
||||||
|
if (!nodeEntries.hasOwnProperty(module)) {
|
||||||
|
nodeEntries[module] = {info:RED.nodes.registry.getModule(module)};
|
||||||
|
var index = [module];
|
||||||
|
for (var s in nodeEntries[module].info.sets) {
|
||||||
|
if (nodeEntries[module].info.sets.hasOwnProperty(s)) {
|
||||||
|
index.push(s);
|
||||||
|
index = index.concat(nodeEntries[module].info.sets[s].types)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeEntries[module].index = index.join(",").toLowerCase();
|
||||||
|
|
||||||
|
nodeList.editableList('addItem', nodeEntries[module]);
|
||||||
|
//console.log(nodeList.editableList('items'));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var moduleInfo = nodeEntries[module].info;
|
||||||
|
var nodeEntry = nodeEntries[module].elements;
|
||||||
|
if (nodeEntry) {
|
||||||
|
var activeTypeCount = 0;
|
||||||
|
var typeCount = 0;
|
||||||
|
nodeEntries[module].totalUseCount = 0;
|
||||||
|
nodeEntries[module].setUseCount = {};
|
||||||
|
|
||||||
|
for (var setName in moduleInfo.sets) {
|
||||||
|
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
||||||
|
var inUseCount = 0;
|
||||||
|
var set = moduleInfo.sets[setName];
|
||||||
|
var setElements = nodeEntry.sets[setName];
|
||||||
|
|
||||||
|
if (set.enabled) {
|
||||||
|
activeTypeCount += set.types.length;
|
||||||
|
}
|
||||||
|
typeCount += set.types.length;
|
||||||
|
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
|
||||||
|
var t = moduleInfo.sets[setName].types[i];
|
||||||
|
inUseCount += (typesInUse[t]||0);
|
||||||
|
var swatch = setElements.swatches[t];
|
||||||
|
if (set.enabled) {
|
||||||
|
var def = RED.nodes.getType(t);
|
||||||
|
if (def && def.color) {
|
||||||
|
swatch.css({background:def.color});
|
||||||
|
swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
swatch.css({background:"#eee",border:"1px dashed #999"})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
swatch.css({background:"#eee",border:"1px dashed #999"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeEntries[module].setUseCount[setName] = inUseCount;
|
||||||
|
nodeEntries[module].totalUseCount += inUseCount;
|
||||||
|
|
||||||
|
if (inUseCount > 0) {
|
||||||
|
setElements.enableButton.html(RED._('palette.editor.inuse'));
|
||||||
|
setElements.enableButton.addClass('disabled');
|
||||||
|
} else {
|
||||||
|
setElements.enableButton.removeClass('disabled');
|
||||||
|
if (set.enabled) {
|
||||||
|
setElements.enableButton.html(RED._('palette.editor.disable'));
|
||||||
|
} else {
|
||||||
|
setElements.enableButton.html(RED._('palette.editor.enable'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setElements.setRow.toggleClass("palette-module-set-disabled",!set.enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
||||||
|
nodeEntry.setCount.html(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||||
|
|
||||||
|
if (nodeEntries[module].totalUseCount > 0) {
|
||||||
|
nodeEntry.enableButton.html(RED._('palette.editor.inuse'));
|
||||||
|
nodeEntry.enableButton.addClass('disabled');
|
||||||
|
nodeEntry.removeButton.hide();
|
||||||
|
} else {
|
||||||
|
nodeEntry.enableButton.removeClass('disabled');
|
||||||
|
nodeEntry.removeButton.show();
|
||||||
|
if (activeTypeCount === 0) {
|
||||||
|
nodeEntry.enableButton.html(RED._('palette.editor.enableall'));
|
||||||
|
} else {
|
||||||
|
nodeEntry.enableButton.html(RED._('palette.editor.disableall'));
|
||||||
|
}
|
||||||
|
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
function showPaletteEditor() {
|
||||||
|
if (RED.settings.theme('palette.editable') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$("#header-shade").show();
|
||||||
|
$("#editor-shade").show();
|
||||||
|
$("#sidebar-shade").show();
|
||||||
|
$("#sidebar-separator").hide();
|
||||||
|
$("#main-container").addClass("palette-expanded");
|
||||||
|
setTimeout(function() {
|
||||||
|
editorTabs.resize();
|
||||||
|
},250);
|
||||||
|
RED.events.emit("palette-editor:open");
|
||||||
|
}
|
||||||
|
function hidePaletteEditor() {
|
||||||
|
$("#main-container").removeClass("palette-expanded");
|
||||||
|
$("#header-shade").hide();
|
||||||
|
$("#editor-shade").hide();
|
||||||
|
$("#sidebar-shade").hide();
|
||||||
|
$("#sidebar-separator").show();
|
||||||
|
$("#palette-editor").find('.expanded').each(function(i,el) {
|
||||||
|
$(el).find(".palette-module-content").slideUp();
|
||||||
|
$(el).removeClass('expanded');
|
||||||
|
});
|
||||||
|
filterInput.searchBox('value',"");
|
||||||
|
searchInput.searchBox('value',"");
|
||||||
|
RED.events.emit("palette-editor:close");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterChange(val) {
|
||||||
|
activeFilter = val.toLowerCase();
|
||||||
|
var visible = nodeList.editableList('filter');
|
||||||
|
var size = nodeList.editableList('length');
|
||||||
|
if (val === "") {
|
||||||
|
filterInput.searchBox('count');
|
||||||
|
} else {
|
||||||
|
filterInput.searchBox('count',visible+" / "+size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var catalogueCount;
|
||||||
|
var catalogueLoadStatus = [];
|
||||||
|
var catalogueLoadStart;
|
||||||
|
|
||||||
|
var activeSort = sortModulesAZ;
|
||||||
|
|
||||||
|
function handleCatalogResponse(catalog,index,v) {
|
||||||
|
catalogueLoadStatus.push(v);
|
||||||
|
if (v.modules) {
|
||||||
|
v.modules.forEach(function(m) {
|
||||||
|
m.index = [m.id];
|
||||||
|
if (m.keywords) {
|
||||||
|
m.index = m.index.concat(m.keywords);
|
||||||
|
}
|
||||||
|
if (m.updated_at) {
|
||||||
|
m.timestamp = new Date(m.updated_at).getTime();
|
||||||
|
} else {
|
||||||
|
m.timestamp = 0;
|
||||||
|
}
|
||||||
|
m.index = m.index.join(",").toLowerCase();
|
||||||
|
})
|
||||||
|
loadedList = loadedList.concat(v.modules);
|
||||||
|
}
|
||||||
|
searchInput.searchBox('count',loadedList.length);
|
||||||
|
if (catalogueCount > 1) {
|
||||||
|
$(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>"+catalogueLoadStatus.length+"/"+catalogueCount);
|
||||||
|
}
|
||||||
|
if (catalogueLoadStatus.length === catalogueCount) {
|
||||||
|
var delta = 250-(Date.now() - catalogueLoadStart);
|
||||||
|
setTimeout(function() {
|
||||||
|
$("#palette-module-install-shade").hide();
|
||||||
|
},Math.max(delta,0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initInstallTab() {
|
||||||
|
if (loadedList.length === 0) {
|
||||||
|
loadedList = [];
|
||||||
|
packageList.editableList('empty');
|
||||||
|
$(".palette-module-shade-status").html(RED._('palette.editor.loading'));
|
||||||
|
var catalogues = RED.settings.theme('palette.catalogues')||['http://catalogue.nodered.org/catalogue.json'];
|
||||||
|
catalogueLoadStatus = [];
|
||||||
|
catalogueCount = catalogues.length;
|
||||||
|
if (catalogues.length > 1) {
|
||||||
|
$(".palette-module-shade-status").html(RED._('palette.editor.loading')+"<br>0/"+catalogues.length);
|
||||||
|
}
|
||||||
|
$("#palette-module-install-shade").show();
|
||||||
|
catalogueLoadStart = Date.now();
|
||||||
|
catalogues.forEach(function(catalog,index) {
|
||||||
|
$.getJSON(catalog, {_: new Date().getTime()},function(v) {
|
||||||
|
handleCatalogResponse(catalog,index,v);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshFilteredItems() {
|
||||||
|
packageList.editableList('empty');
|
||||||
|
filteredList.sort(activeSort);
|
||||||
|
for (var i=0;i<Math.min(10,filteredList.length);i++) {
|
||||||
|
packageList.editableList('addItem',filteredList[i]);
|
||||||
|
}
|
||||||
|
if (filteredList.length === 0) {
|
||||||
|
packageList.editableList('addItem',{});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredList.length > 10) {
|
||||||
|
packageList.editableList('addItem',{start:10,more:filteredList.length-10})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function sortModulesAZ(A,B) {
|
||||||
|
return A.info.id.localeCompare(B.info.id);
|
||||||
|
}
|
||||||
|
function sortModulesRecent(A,B) {
|
||||||
|
return -1 * (A.info.timestamp-B.info.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if (RED.settings.theme('palette.editable') === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
editorTabs = RED.tabs.create({
|
||||||
|
id:"palette-editor-tabs",
|
||||||
|
onchange:function(tab) {
|
||||||
|
$("#palette-editor .palette-editor-tab").hide();
|
||||||
|
tab.content.show();
|
||||||
|
if (filterInput) {
|
||||||
|
filterInput.searchBox('value',"");
|
||||||
|
}
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.searchBox('value',"");
|
||||||
|
}
|
||||||
|
if (tab.id === 'install') {
|
||||||
|
initInstallTab();
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.focus();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (filterInput) {
|
||||||
|
filterInput.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minimumActiveTabWidth: 110
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$("#editor-shade").click(function() {
|
||||||
|
if ($("#main-container").hasClass("palette-expanded")) {
|
||||||
|
hidePaletteEditor();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#palette-editor-close").on("click", function(e) {
|
||||||
|
hidePaletteEditor();
|
||||||
|
})
|
||||||
|
|
||||||
|
var modulesTab = $('<div>',{class:"palette-editor-tab"}).appendTo("#palette-editor");
|
||||||
|
|
||||||
|
editorTabs.addTab({
|
||||||
|
id: 'nodes',
|
||||||
|
label: RED._('palette.editor.tab-nodes'),
|
||||||
|
content: modulesTab
|
||||||
|
})
|
||||||
|
|
||||||
|
var filterDiv = $('<div>',{class:"palette-search"}).appendTo(modulesTab);
|
||||||
|
filterInput = $('<input type="text" data-i18n="[placeholder]palette.filter"></input>')
|
||||||
|
.appendTo(filterDiv)
|
||||||
|
.searchBox({
|
||||||
|
delay: 200,
|
||||||
|
change: function() {
|
||||||
|
filterChange($(this).val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
nodeList = $('<ol>',{id:"palette-module-list", style:"position: absolute;top: 35px;bottom: 0;left: 0;right: 0px;"}).appendTo(modulesTab).editableList({
|
||||||
|
addButton: false,
|
||||||
|
scrollOnAdd: false,
|
||||||
|
sort: function(A,B) {
|
||||||
|
return A.info.name.localeCompare(B.info.name);
|
||||||
|
},
|
||||||
|
filter: function(data) {
|
||||||
|
if (activeFilter === "" ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (activeFilter==="")||(data.index.indexOf(activeFilter) > -1);
|
||||||
|
},
|
||||||
|
addItem: function(container,i,object) {
|
||||||
|
var entry = object.info;
|
||||||
|
if (entry) {
|
||||||
|
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||||
|
var titleRow = $('<div class="palette-module-meta palette-module-name"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||||
|
$('<span>').html(entry.name).appendTo(titleRow);
|
||||||
|
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
|
||||||
|
$('<span>').html(entry.version).appendTo(metaRow);
|
||||||
|
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||||
|
var setButton = $('<a href="#" class="editor-button editor-button-small palette-module-set-button"><i class="fa fa-angle-right palette-module-node-chevron"></i> </a>').appendTo(buttonRow);
|
||||||
|
var setCount = $('<span>').appendTo(setButton);
|
||||||
|
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||||
|
var removeButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.remove')).appendTo(buttonGroup);
|
||||||
|
removeButton.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
shade.show();
|
||||||
|
removeNodeModule(entry.name, function(xhr) {
|
||||||
|
console.log(xhr);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (!entry.local) {
|
||||||
|
removeButton.hide();
|
||||||
|
}
|
||||||
|
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.disableall')).appendTo(buttonGroup);
|
||||||
|
|
||||||
|
var contentRow = $('<div>',{class:"palette-module-content"}).appendTo(container);
|
||||||
|
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
|
||||||
|
|
||||||
|
object.elements = {
|
||||||
|
removeButton: removeButton,
|
||||||
|
enableButton: enableButton,
|
||||||
|
setCount: setCount,
|
||||||
|
container: container,
|
||||||
|
shade: shade,
|
||||||
|
sets: {}
|
||||||
|
}
|
||||||
|
setButton.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (container.hasClass('expanded')) {
|
||||||
|
container.removeClass('expanded');
|
||||||
|
contentRow.slideUp();
|
||||||
|
} else {
|
||||||
|
container.addClass('expanded');
|
||||||
|
contentRow.slideDown();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var setList = Object.keys(entry.sets)
|
||||||
|
setList.sort(function(A,B) {
|
||||||
|
return A.toLowerCase().localeCompare(B.toLowerCase());
|
||||||
|
});
|
||||||
|
setList.forEach(function(setName) {
|
||||||
|
var set = entry.sets[setName];
|
||||||
|
var setRow = $('<div>',{class:"palette-module-set"}).appendTo(contentRow);
|
||||||
|
var buttonGroup = $('<div>',{class:"palette-module-set-button-group"}).appendTo(setRow);
|
||||||
|
var typeSwatches = {};
|
||||||
|
set.types.forEach(function(t) {
|
||||||
|
var typeDiv = $('<div>',{class:"palette-module-type"}).appendTo(setRow);
|
||||||
|
typeSwatches[t] = $('<span>',{class:"palette-module-type-swatch"}).appendTo(typeDiv);
|
||||||
|
$('<span>',{class:"palette-module-type-node"}).html(t).appendTo(typeDiv);
|
||||||
|
})
|
||||||
|
|
||||||
|
var enableButton = $('<a href="#" class="editor-button editor-button-small"></a>').appendTo(buttonGroup);
|
||||||
|
enableButton.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (object.setUseCount[setName] === 0) {
|
||||||
|
var currentSet = RED.nodes.registry.getNodeSet(set.id);
|
||||||
|
shade.show();
|
||||||
|
changeNodeState(set.id,!currentSet.enabled,shade,function(xhr){
|
||||||
|
console.log(xhr)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
object.elements.sets[set.name] = {
|
||||||
|
setRow: setRow,
|
||||||
|
enableButton: enableButton,
|
||||||
|
swatches: typeSwatches
|
||||||
|
};
|
||||||
|
});
|
||||||
|
enableButton.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
if (object.totalUseCount === 0) {
|
||||||
|
changeNodeState(entry.name,(container.hasClass('disabled')),shade,function(xhr){
|
||||||
|
console.log(xhr)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
refreshNodeModule(entry.name);
|
||||||
|
} else {
|
||||||
|
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var installTab = $('<div>',{class:"palette-editor-tab hide"}).appendTo("#palette-editor");
|
||||||
|
|
||||||
|
editorTabs.addTab({
|
||||||
|
id: 'install',
|
||||||
|
label: RED._('palette.editor.tab-install'),
|
||||||
|
content: installTab
|
||||||
|
})
|
||||||
|
|
||||||
|
var toolBar = $('<div>',{class:"palette-editor-toolbar"}).appendTo(installTab);
|
||||||
|
|
||||||
|
var searchDiv = $('<div>',{class:"palette-search"}).appendTo(installTab);
|
||||||
|
searchInput = $('<input type="text" data-i18n="[placeholder]palette.search"></input>')
|
||||||
|
.appendTo(searchDiv)
|
||||||
|
.searchBox({
|
||||||
|
delay: 300,
|
||||||
|
change: function() {
|
||||||
|
var searchTerm = $(this).val();
|
||||||
|
if (searchTerm.length > 0) {
|
||||||
|
filteredList = loadedList.filter(function(m) {
|
||||||
|
return (m.index.indexOf(searchTerm) > -1);
|
||||||
|
}).map(function(f) { return {info:f}});
|
||||||
|
refreshFilteredItems();
|
||||||
|
searchInput.searchBox('count',filteredList.length+" / "+loadedList.length);
|
||||||
|
} else {
|
||||||
|
searchInput.searchBox('count',loadedList.length);
|
||||||
|
packageList.editableList('empty');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$('<span>').html(RED._("palette.editor.sort")+' ').appendTo(toolBar);
|
||||||
|
var sortGroup = $('<span class="button-group"></span> ').appendTo(toolBar);
|
||||||
|
var sortAZ = $('<a href="#" class="sidebar-header-button-toggle selected" data-i18n="palette.editor.sortAZ"></a>').appendTo(sortGroup);
|
||||||
|
var sortRecent = $('<a href="#" class="sidebar-header-button-toggle" data-i18n="palette.editor.sortRecent"></a>').appendTo(sortGroup);
|
||||||
|
|
||||||
|
sortAZ.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ($(this).hasClass("selected")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(this).addClass("selected");
|
||||||
|
sortRecent.removeClass("selected");
|
||||||
|
activeSort = sortModulesAZ;
|
||||||
|
refreshFilteredItems();
|
||||||
|
});
|
||||||
|
|
||||||
|
sortRecent.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ($(this).hasClass("selected")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(this).addClass("selected");
|
||||||
|
sortAZ.removeClass("selected");
|
||||||
|
activeSort = sortModulesRecent;
|
||||||
|
refreshFilteredItems();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var refreshSpan = $('<span>').appendTo(toolBar);
|
||||||
|
var refreshButton = $('<a href="#" class="sidebar-header-button"><i class="fa fa-refresh"></i></a>').appendTo(refreshSpan);
|
||||||
|
refreshButton.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
loadedList = [];
|
||||||
|
initInstallTab();
|
||||||
|
})
|
||||||
|
|
||||||
|
packageList = $('<ol>',{style:"position: absolute;top: 78px;bottom: 0;left: 0;right: 0px;"}).appendTo(installTab).editableList({
|
||||||
|
addButton: false,
|
||||||
|
scrollOnAdd: false,
|
||||||
|
addItem: function(container,i,object) {
|
||||||
|
|
||||||
|
if (object.more) {
|
||||||
|
container.addClass('palette-module-more');
|
||||||
|
var moreRow = $('<div>',{class:"palette-module-header palette-module"}).appendTo(container);
|
||||||
|
var moreLink = $('<a href="#"></a>').html(RED._('palette.editor.more',{count:object.more})).appendTo(moreRow);
|
||||||
|
moreLink.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
packageList.editableList('removeItem',object);
|
||||||
|
for (var i=object.start;i<Math.min(object.start+10,object.start+object.more);i++) {
|
||||||
|
packageList.editableList('addItem',filteredList[i]);
|
||||||
|
}
|
||||||
|
if (object.more > 10) {
|
||||||
|
packageList.editableList('addItem',{start:object.start+10, more:object.more-10})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (object.info) {
|
||||||
|
var entry = object.info;
|
||||||
|
var headerRow = $('<div>',{class:"palette-module-header"}).appendTo(container);
|
||||||
|
var titleRow = $('<div class="palette-module-meta"><i class="fa fa-cube"></i></div>').appendTo(headerRow);
|
||||||
|
$('<span>',{class:"palette-module-name"}).html(entry.name||entry.id).appendTo(titleRow);
|
||||||
|
$('<a target="_blank" class="palette-module-link"><i class="fa fa-external-link"></i></a>').attr('href',entry.url).appendTo(titleRow);
|
||||||
|
var descRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||||
|
$('<div>',{class:"palette-module-description"}).html(entry.description).appendTo(descRow);
|
||||||
|
|
||||||
|
var metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
|
||||||
|
$('<span class="palette-module-version"><i class="fa fa-tag"></i> '+entry.version+'</span>').appendTo(metaRow);
|
||||||
|
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
|
||||||
|
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
|
||||||
|
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
|
||||||
|
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
|
||||||
|
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
|
||||||
|
installButton.click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!$(this).hasClass('disabled')) {
|
||||||
|
installNodeModule(entry.id,shade,function(xhr) {
|
||||||
|
if (xhr) {
|
||||||
|
if (xhr.responseJSON) {
|
||||||
|
RED.notify(RED._('palette.editor.errors.installFailed',{module: entry.id,message:xhr.responseJSON.message}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (nodeEntries.hasOwnProperty(entry.id)) {
|
||||||
|
installButton.addClass('disabled');
|
||||||
|
installButton.html(RED._('palette.editor.installed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
object.elements = {
|
||||||
|
installButton:installButton
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('<div id="palette-module-install-shade" class="palette-module-shade hide"><div class="palette-module-shade-status"></div><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(installTab);
|
||||||
|
|
||||||
|
RED.events.on('registry:node-set-enabled', function(ns) {
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-set-disabled', function(ns) {
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-type-added', function(nodeType) {
|
||||||
|
if (!/^subflow:/.test(nodeType)) {
|
||||||
|
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-type-removed', function(nodeType) {
|
||||||
|
if (!/^subflow:/.test(nodeType)) {
|
||||||
|
var ns = RED.nodes.registry.getNodeSetForType(nodeType);
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-set-added', function(ns) {
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
for (var i=0;i<filteredList.length;i++) {
|
||||||
|
if (filteredList[i].info.id === ns.module) {
|
||||||
|
filteredList[i].elements.installButton.hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-set-removed', function(ns) {
|
||||||
|
var module = RED.nodes.registry.getModule(ns.module);
|
||||||
|
if (!module) {
|
||||||
|
var entry = nodeEntries[ns.module];
|
||||||
|
if (entry) {
|
||||||
|
nodeList.editableList('removeItem', entry);
|
||||||
|
delete nodeEntries[ns.module];
|
||||||
|
for (var i=0;i<filteredList.length;i++) {
|
||||||
|
if (filteredList[i].info.id === ns.module) {
|
||||||
|
filteredList[i].elements.installButton.show();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('nodes:add', function(n) {
|
||||||
|
if (!/^subflow:/.test(n.type)) {
|
||||||
|
typesInUse[n.type] = (typesInUse[n.type]||0)+1;
|
||||||
|
if (typesInUse[n.type] === 1) {
|
||||||
|
var ns = RED.nodes.registry.getNodeSetForType(n.type);
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
RED.events.on('nodes:remove', function(n) {
|
||||||
|
if (typesInUse.hasOwnProperty(n.type)) {
|
||||||
|
typesInUse[n.type]--;
|
||||||
|
if (typesInUse[n.type] === 0) {
|
||||||
|
delete typesInUse[n.type];
|
||||||
|
var ns = RED.nodes.registry.getNodeSetForType(n.type);
|
||||||
|
refreshNodeModule(ns.module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
show: showPaletteEditor
|
||||||
|
}
|
||||||
|
})();
|
@ -17,7 +17,7 @@
|
|||||||
RED.palette = (function() {
|
RED.palette = (function() {
|
||||||
|
|
||||||
var exclusion = ['config','unknown','deprecated'];
|
var exclusion = ['config','unknown','deprecated'];
|
||||||
var core = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced'];
|
var coreCategories = ['subflows', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced'];
|
||||||
|
|
||||||
var categoryContainers = {};
|
var categoryContainers = {};
|
||||||
|
|
||||||
@ -91,15 +91,15 @@ RED.palette = (function() {
|
|||||||
el.css({height:multiLineNodeHeight+"px"});
|
el.css({height:multiLineNodeHeight+"px"});
|
||||||
|
|
||||||
var labelElement = el.find(".palette_label");
|
var labelElement = el.find(".palette_label");
|
||||||
labelElement.html(lines);
|
labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines));
|
||||||
|
|
||||||
el.find(".palette_port").css({top:(multiLineNodeHeight/2-5)+"px"});
|
el.find(".palette_port").css({top:(multiLineNodeHeight/2-5)+"px"});
|
||||||
|
|
||||||
var popOverContent;
|
var popOverContent;
|
||||||
try {
|
try {
|
||||||
var l = "<p><b>"+label+"</b></p>";
|
var l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b></p>";
|
||||||
if (label != type) {
|
if (label != type) {
|
||||||
l = "<p><b>"+label+"</b><br/><i>"+type+"</i></p>";
|
l = "<p><b>"+RED.text.bidi.enforceTextDirectionWithUCC(label)+"</b><br/><i>"+type+"</i></p>";
|
||||||
}
|
}
|
||||||
popOverContent = $(l+(info?info:$("script[data-help-name$='"+type+"']").html()||"<p>"+RED._("palette.noInfo")+"</p>").trim())
|
popOverContent = $(l+(info?info:$("script[data-help-name$='"+type+"']").html()||"<p>"+RED._("palette.noInfo")+"</p>").trim())
|
||||||
.filter(function(n) {
|
.filter(function(n) {
|
||||||
@ -174,7 +174,7 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($("#palette-base-category-"+rootCategory).length === 0) {
|
if ($("#palette-base-category-"+rootCategory).length === 0) {
|
||||||
if(core.indexOf(rootCategory) !== -1){
|
if(coreCategories.indexOf(rootCategory) !== -1){
|
||||||
createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory}));
|
createCategoryContainer(rootCategory, RED._("node-red:palette.label."+rootCategory, {defaultValue:rootCategory}));
|
||||||
} else {
|
} else {
|
||||||
var ns = def.set.id;
|
var ns = def.set.id;
|
||||||
@ -363,14 +363,7 @@ RED.palette = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterChange() {
|
function filterChange(val) {
|
||||||
var val = $("#palette-search-input").val();
|
|
||||||
if (val === "") {
|
|
||||||
$("#palette-search-clear").hide();
|
|
||||||
} else {
|
|
||||||
$("#palette-search-clear").show();
|
|
||||||
}
|
|
||||||
|
|
||||||
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
|
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
|
||||||
$("#palette-container .palette_node").each(function(i,el) {
|
$("#palette-container .palette_node").each(function(i,el) {
|
||||||
var currentLabel = $(el).find(".palette_label").text();
|
var currentLabel = $(el).find(".palette_label").text();
|
||||||
@ -395,33 +388,69 @@ RED.palette = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
$(".palette-spinner").show();
|
|
||||||
if (RED.settings.paletteCategories) {
|
RED.events.on('registry:node-type-added', function(nodeType) {
|
||||||
RED.settings.paletteCategories.forEach(function(category){
|
var def = RED.nodes.getType(nodeType);
|
||||||
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
|
addNodeType(nodeType,def);
|
||||||
});
|
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
||||||
} else {
|
def.onpaletteadd.call(def);
|
||||||
core.forEach(function(category){
|
|
||||||
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
$("#palette-search-clear").on("click",function(e) {
|
RED.events.on('registry:node-type-removed', function(nodeType) {
|
||||||
e.preventDefault();
|
removeNodeType(nodeType);
|
||||||
$("#palette-search-input").val("");
|
|
||||||
filterChange();
|
|
||||||
$("#palette-search-input").focus();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#palette-search-input").val("");
|
RED.events.on('registry:node-set-enabled', function(nodeSet) {
|
||||||
$("#palette-search-input").on("keyup",function() {
|
for (var j=0;j<nodeSet.types.length;j++) {
|
||||||
filterChange();
|
showNodeType(nodeSet.types[j]);
|
||||||
|
var def = RED.nodes.getType(nodeSet.types[j]);
|
||||||
|
if (def.onpaletteadd && typeof def.onpaletteadd === "function") {
|
||||||
|
def.onpaletteadd.call(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-set-disabled', function(nodeSet) {
|
||||||
|
for (var j=0;j<nodeSet.types.length;j++) {
|
||||||
|
hideNodeType(nodeSet.types[j]);
|
||||||
|
var def = RED.nodes.getType(nodeSet.types[j]);
|
||||||
|
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
||||||
|
def.onpaletteremove.call(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.events.on('registry:node-set-removed', function(nodeSet) {
|
||||||
|
if (nodeSet.added) {
|
||||||
|
for (var j=0;j<nodeSet.types.length;j++) {
|
||||||
|
removeNodeType(nodeSet.types[j]);
|
||||||
|
var def = RED.nodes.getType(nodeSet.types[j]);
|
||||||
|
if (def.onpaletteremove && typeof def.onpaletteremove === "function") {
|
||||||
|
def.onpaletteremove.call(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#palette-search-input").on("focus",function() {
|
|
||||||
$("body").one("mousedown",function() {
|
$("#palette > .palette-spinner").show();
|
||||||
$("#palette-search-input").blur();
|
|
||||||
});
|
$("#palette-search input").searchBox({
|
||||||
|
delay: 100,
|
||||||
|
change: function() {
|
||||||
|
filterChange($(this).val());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var categoryList = coreCategories;
|
||||||
|
if (RED.settings.paletteCategories) {
|
||||||
|
categoryList = RED.settings.paletteCategories;
|
||||||
|
} else if (RED.settings.theme('palette.categories')) {
|
||||||
|
categoryList = RED.settings.theme('palette.categories');
|
||||||
|
}
|
||||||
|
if (!Array.isArray(categoryList)) {
|
||||||
|
categoryList = coreCategories
|
||||||
|
}
|
||||||
|
categoryList.forEach(function(category){
|
||||||
|
createCategoryContainer(category, RED._("palette.label."+category,{defaultValue:category}));
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#palette-collapse-all").on("click", function(e) {
|
$("#palette-collapse-all").on("click", function(e) {
|
||||||
|
295
editor/js/ui/search.js
Normal file
295
editor/js/ui/search.js
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
RED.search = (function() {
|
||||||
|
|
||||||
|
var disabled = false;
|
||||||
|
var dialog = null;
|
||||||
|
var searchInput;
|
||||||
|
var searchResults;
|
||||||
|
var selected = -1;
|
||||||
|
var visible = false;
|
||||||
|
|
||||||
|
var index = {};
|
||||||
|
var keys = [];
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
function indexNode(n) {
|
||||||
|
var l = "";
|
||||||
|
if (n._def && n._def.label) {
|
||||||
|
l = n._def.label;
|
||||||
|
try {
|
||||||
|
l = (typeof l === "function" ? l.call(n) : l);
|
||||||
|
if (l) {
|
||||||
|
l = (""+l).toLowerCase();
|
||||||
|
index[l] = index[l] || {};
|
||||||
|
index[l][n.id] = {node:n,label:l}
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
console.log("Definition error: "+n.type+".label",err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l = l||n.label||n.name||n.id||"";
|
||||||
|
|
||||||
|
|
||||||
|
var properties = ['id','type','name','label','info'];
|
||||||
|
for (var i=0;i<properties.length;i++) {
|
||||||
|
if (n.hasOwnProperty(properties[i])) {
|
||||||
|
var v = n[properties[i]];
|
||||||
|
if (typeof v === 'string' || typeof v === 'number') {
|
||||||
|
v = (""+v).toLowerCase();
|
||||||
|
index[v] = index[v] || {};
|
||||||
|
index[v][n.id] = {node:n,label:l};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
function indexWorkspace() {
|
||||||
|
index = {};
|
||||||
|
RED.nodes.eachWorkspace(indexNode);
|
||||||
|
RED.nodes.eachSubflow(indexNode);
|
||||||
|
RED.nodes.eachConfig(indexNode);
|
||||||
|
RED.nodes.eachNode(indexNode);
|
||||||
|
keys = Object.keys(index);
|
||||||
|
keys.sort();
|
||||||
|
keys.forEach(function(key) {
|
||||||
|
index[key] = Object.keys(index[key]).map(function(id) {
|
||||||
|
return index[key][id];
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(val) {
|
||||||
|
searchResults.editableList('empty');
|
||||||
|
selected = -1;
|
||||||
|
results = [];
|
||||||
|
if (val.length > 0) {
|
||||||
|
val = val.toLowerCase();
|
||||||
|
var i;
|
||||||
|
var j;
|
||||||
|
var list = [];
|
||||||
|
var nodes = {};
|
||||||
|
for (i=0;i<keys.length;i++) {
|
||||||
|
var key = keys[i];
|
||||||
|
var kpos = keys[i].indexOf(val);
|
||||||
|
if (kpos > -1) {
|
||||||
|
for (j=0;j<index[key].length;j++) {
|
||||||
|
var node = index[key][j];
|
||||||
|
nodes[node.node.id] = nodes[node.node.id] = node;
|
||||||
|
nodes[node.node.id].index = Math.min(nodes[node.node.id].index||Infinity,kpos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list = Object.keys(nodes);
|
||||||
|
list.sort(function(A,B) {
|
||||||
|
return nodes[A].index - nodes[B].index;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i=0;i<list.length;i++) {
|
||||||
|
results.push(nodes[list[i]]);
|
||||||
|
}
|
||||||
|
if (results.length > 0) {
|
||||||
|
for (i=0;i<Math.min(results.length,25);i++) {
|
||||||
|
searchResults.editableList('addItem',results[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
searchResults.editableList('addItem',{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ensureSelectedIsVisible() {
|
||||||
|
var selectedEntry = searchResults.find("li.selected");
|
||||||
|
if (selectedEntry.length === 1) {
|
||||||
|
var scrollWindow = searchResults.parent();
|
||||||
|
var scrollHeight = scrollWindow.height();
|
||||||
|
var scrollOffset = scrollWindow.scrollTop();
|
||||||
|
var y = selectedEntry.position().top;
|
||||||
|
var h = selectedEntry.height();
|
||||||
|
if (y+h > scrollHeight) {
|
||||||
|
scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-10)},50);
|
||||||
|
} else if (y<0) {
|
||||||
|
scrollWindow.animate({scrollTop: '+='+(y-10)},50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDialog() {
|
||||||
|
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#main-container");
|
||||||
|
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
|
||||||
|
searchInput = $('<input type="text" placeholder="search your flows">').appendTo(searchDiv).searchBox({
|
||||||
|
delay: 200,
|
||||||
|
change: function() {
|
||||||
|
search($(this).val());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
searchInput.on('keydown',function(evt) {
|
||||||
|
var children;
|
||||||
|
if (results.length > 0) {
|
||||||
|
if (evt.keyCode === 40) {
|
||||||
|
// Down
|
||||||
|
children = searchResults.children();
|
||||||
|
if (selected < children.length-1) {
|
||||||
|
if (selected > -1) {
|
||||||
|
$(children[selected]).removeClass('selected');
|
||||||
|
}
|
||||||
|
selected++;
|
||||||
|
}
|
||||||
|
$(children[selected]).addClass('selected');
|
||||||
|
ensureSelectedIsVisible();
|
||||||
|
evt.preventDefault();
|
||||||
|
} else if (evt.keyCode === 38) {
|
||||||
|
// Up
|
||||||
|
children = searchResults.children();
|
||||||
|
if (selected > 0) {
|
||||||
|
if (selected < children.length) {
|
||||||
|
$(children[selected]).removeClass('selected');
|
||||||
|
}
|
||||||
|
selected--;
|
||||||
|
}
|
||||||
|
$(children[selected]).addClass('selected');
|
||||||
|
ensureSelectedIsVisible();
|
||||||
|
evt.preventDefault();
|
||||||
|
} else if (evt.keyCode === 13) {
|
||||||
|
// Enter
|
||||||
|
if (results.length > 0) {
|
||||||
|
reveal(results[Math.max(0,selected)].node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog);
|
||||||
|
searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({
|
||||||
|
addButton: false,
|
||||||
|
addItem: function(container,i,object) {
|
||||||
|
var node = object.node;
|
||||||
|
if (node === undefined) {
|
||||||
|
$('<div>',{class:"red-ui-search-empty"}).html(RED._('search.empty')).appendTo(container);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var def = node._def;
|
||||||
|
var div = $('<a>',{href:'#',class:"red-ui-search-result"}).appendTo(container);
|
||||||
|
|
||||||
|
var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(div);
|
||||||
|
var colour = def.color;
|
||||||
|
var icon_url = "arrow-in.png";
|
||||||
|
if (node.type === 'tab') {
|
||||||
|
colour = "#C0DEED";
|
||||||
|
icon_url = "subflow.png";
|
||||||
|
} else if (def.category === 'config') {
|
||||||
|
icon_url = "cog.png";
|
||||||
|
} else if (node.type === 'unknown') {
|
||||||
|
icon_url = "alert.png";
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
icon_url = (typeof def.icon === "function" ? def.icon.call({}) : def.icon);
|
||||||
|
} catch(err) {
|
||||||
|
console.log("Definition error: "+nt+".icon",err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeDiv.css('backgroundColor',colour);
|
||||||
|
|
||||||
|
var iconContainer = $('<div/>',{class:"palette_icon_container"}).appendTo(nodeDiv);
|
||||||
|
$('<div/>',{class:"palette_icon",style:"background-image: url(icons/"+icon_url+")"}).appendTo(iconContainer);
|
||||||
|
|
||||||
|
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
|
||||||
|
if (node.z) {
|
||||||
|
var workspace = RED.nodes.workspace(node.z);
|
||||||
|
if (!workspace) {
|
||||||
|
workspace = RED.nodes.subflow(node.z);
|
||||||
|
workspace = "subflow:"+workspace.name;
|
||||||
|
} else {
|
||||||
|
workspace = "flow:"+workspace.label;
|
||||||
|
}
|
||||||
|
$('<div>',{class:"red-ui-search-result-node-flow"}).html(workspace).appendTo(contentDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('<div>',{class:"red-ui-search-result-node-label"}).html(object.label || node.id).appendTo(contentDiv);
|
||||||
|
$('<div>',{class:"red-ui-search-result-node-type"}).html(node.type).appendTo(contentDiv);
|
||||||
|
$('<div>',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
|
||||||
|
|
||||||
|
div.click(function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
reveal(node);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollOnAdd: false
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function reveal(node) {
|
||||||
|
hide();
|
||||||
|
RED.view.reveal(node.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
if (!visible) {
|
||||||
|
RED.keyboard.add("*",/* ESCAPE */ 27,function(){hide();d3.event.preventDefault();});
|
||||||
|
$("#header-shade").show();
|
||||||
|
$("#editor-shade").show();
|
||||||
|
$("#palette-shade").show();
|
||||||
|
$("#sidebar-shade").show();
|
||||||
|
$("#sidebar-separator").hide();
|
||||||
|
indexWorkspace();
|
||||||
|
if (dialog === null) {
|
||||||
|
createDialog();
|
||||||
|
}
|
||||||
|
dialog.slideDown();
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
searchInput.focus();
|
||||||
|
}
|
||||||
|
function hide() {
|
||||||
|
if (visible) {
|
||||||
|
RED.keyboard.remove(/* ESCAPE */ 27);
|
||||||
|
visible = false;
|
||||||
|
$("#header-shade").hide();
|
||||||
|
$("#editor-shade").hide();
|
||||||
|
$("#palette-shade").hide();
|
||||||
|
$("#sidebar-shade").hide();
|
||||||
|
$("#sidebar-separator").show();
|
||||||
|
if (dialog !== null) {
|
||||||
|
dialog.slideUp(200,function() {
|
||||||
|
searchInput.searchBox('value','');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
RED.keyboard.add("*",/* . */ 190,{ctrl:true},function(){if (!disabled) { show(); } d3.event.preventDefault();});
|
||||||
|
RED.events.on("editor:open",function() { disabled = true; });
|
||||||
|
RED.events.on("editor:close",function() { disabled = false; });
|
||||||
|
RED.events.on("palette-editor:open",function() { disabled = true; });
|
||||||
|
RED.events.on("palette-editor:close",function() { disabled = false; });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$("#header-shade").on('mousedown',hide);
|
||||||
|
$("#editor-shade").on('mousedown',hide);
|
||||||
|
$("#palette-shade").on('mousedown',hide);
|
||||||
|
$("#sidebar-shade").on('mousedown',hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: init,
|
||||||
|
show: show,
|
||||||
|
hide: hide
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -149,7 +149,7 @@ RED.sidebar.config = (function() {
|
|||||||
currentType = node.type;
|
currentType = node.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entry = $('<li class="palette_node config_node"></li>').appendTo(list);
|
var entry = $('<li class="palette_node config_node palette_node_id_'+node.id.replace(/\./g,"-")+'"></li>').appendTo(list);
|
||||||
$('<div class="palette_label"></div>').text(label).appendTo(entry);
|
$('<div class="palette_label"></div>').text(label).appendTo(entry);
|
||||||
|
|
||||||
var iconContainer = $('<div/>',{class:"palette_icon_container palette_icon_container_right"}).text(node.users.length).appendTo(entry);
|
var iconContainer = $('<div/>',{class:"palette_icon_container palette_icon_container_right"}).text(node.users.length).appendTo(entry);
|
||||||
@ -280,8 +280,8 @@ RED.sidebar.config = (function() {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
function show(unused) {
|
function show(id) {
|
||||||
if (unused !== undefined) {
|
if (typeof id === 'boolean') {
|
||||||
if (unused) {
|
if (unused) {
|
||||||
$('#workspace-config-node-filter-unused').click();
|
$('#workspace-config-node-filter-unused').click();
|
||||||
} else {
|
} else {
|
||||||
@ -289,6 +289,36 @@ RED.sidebar.config = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
refreshConfigNodeList();
|
refreshConfigNodeList();
|
||||||
|
if (typeof id === "string") {
|
||||||
|
$('#workspace-config-node-filter-all').click();
|
||||||
|
id = id.replace(/\./g,"-");
|
||||||
|
setTimeout(function() {
|
||||||
|
var node = $(".palette_node_id_"+id);
|
||||||
|
var y = node.position().top;
|
||||||
|
var h = node.height();
|
||||||
|
var scrollWindow = $(".sidebar-node-config");
|
||||||
|
var scrollHeight = scrollWindow.height();
|
||||||
|
|
||||||
|
if (y+h > scrollHeight) {
|
||||||
|
scrollWindow.animate({scrollTop: '-='+(scrollHeight-(y+h)-30)},150);
|
||||||
|
} else if (y<0) {
|
||||||
|
scrollWindow.animate({scrollTop: '+='+(y-10)},150);
|
||||||
|
}
|
||||||
|
var flash = 21;
|
||||||
|
var flashFunc = function() {
|
||||||
|
if ((flash%2)===0) {
|
||||||
|
node.removeClass('node_highlighted');
|
||||||
|
} else {
|
||||||
|
node.addClass('node_highlighted');
|
||||||
|
}
|
||||||
|
flash--;
|
||||||
|
if (flash >= 0) {
|
||||||
|
setTimeout(flashFunc,100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flashFunc();
|
||||||
|
},100);
|
||||||
|
}
|
||||||
RED.sidebar.show("config");
|
RED.sidebar.show("config");
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -70,7 +70,7 @@ RED.sidebar.info = (function() {
|
|||||||
var table = '<table class="node-info"><tbody>';
|
var table = '<table class="node-info"><tbody>';
|
||||||
table += '<tr class="blank"><td colspan="2">'+RED._("sidebar.info.node")+'</td></tr>';
|
table += '<tr class="blank"><td colspan="2">'+RED._("sidebar.info.node")+'</td></tr>';
|
||||||
if (node.type != "subflow" && node.name) {
|
if (node.type != "subflow" && node.name) {
|
||||||
table += "<tr><td>"+RED._("common.label.name")+"</td><td> "+node.name+"</td></tr>";
|
table += '<tr><td>'+RED._("common.label.name")+'</td><td> <span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>';
|
||||||
}
|
}
|
||||||
table += "<tr><td>"+RED._("sidebar.info.type")+"</td><td> "+node.type+"</td></tr>";
|
table += "<tr><td>"+RED._("sidebar.info.type")+"</td><td> "+node.type+"</td></tr>";
|
||||||
table += "<tr><td>"+RED._("sidebar.info.id")+"</td><td> "+node.id+"</td></tr>";
|
table += "<tr><td>"+RED._("sidebar.info.id")+"</td><td> "+node.id+"</td></tr>";
|
||||||
@ -93,7 +93,7 @@ RED.sidebar.info = (function() {
|
|||||||
userCount++;
|
userCount++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
table += "<tr><td>"+RED._("common.label.name")+"</td><td>"+subflowNode.name+"</td></tr>";
|
table += '<tr><td>'+RED._("common.label.name")+'</td><td><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.name)+'">'+subflowNode.name+'</span></td></tr>';
|
||||||
table += "<tr><td>"+RED._("sidebar.info.instances")+"</td><td>"+userCount+"</td></tr>";
|
table += "<tr><td>"+RED._("sidebar.info.instances")+"</td><td>"+userCount+"</td></tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,13 +140,14 @@ RED.sidebar.info = (function() {
|
|||||||
table += "</tbody></table><hr/>";
|
table += "</tbody></table><hr/>";
|
||||||
if (!subflowNode && node.type != "comment") {
|
if (!subflowNode && node.type != "comment") {
|
||||||
var helpText = $("script[data-help-name$='"+node.type+"']").html()||"";
|
var helpText = $("script[data-help-name$='"+node.type+"']").html()||"";
|
||||||
table += '<div class="node-help">'+helpText+"</div>";
|
table += '<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(helpText)+'">'+helpText+'</span></div>';
|
||||||
}
|
}
|
||||||
if (subflowNode) {
|
if (subflowNode) {
|
||||||
table += '<div class="node-help">'+marked(subflowNode.info||"")+'</div>';
|
table += '<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(subflowNode.info||"")+'">'+marked(subflowNode.info||"")+'</span></div>';
|
||||||
} else if (node._def && node._def.info) {
|
} else if (node._def && node._def.info) {
|
||||||
var info = node._def.info;
|
var info = node._def.info;
|
||||||
table += '<div class="node-help">'+marked(typeof info === "function" ? info.call(node) : info)+'</div>';
|
var textInfo = (typeof info === "function" ? info.call(node) : info);
|
||||||
|
table += '<div class="node-help"><span class="bidiAware" dir=\"'+RED.text.bidi.resolveBaseTextDir(textInfo)+'">'+marked(textInfo)+'</span></div>';
|
||||||
//table += '<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>';
|
//table += '<div class="node-help">'+(typeof info === "function" ? info.call(node) : info)+'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,7 @@ RED.tray = (function() {
|
|||||||
|
|
||||||
$("#header-shade").show();
|
$("#header-shade").show();
|
||||||
$("#editor-shade").show();
|
$("#editor-shade").show();
|
||||||
|
$("#palette-shade").show();
|
||||||
$(".sidebar-shade").show();
|
$(".sidebar-shade").show();
|
||||||
|
|
||||||
tray.preferredWidth = Math.max(el.width(),500);
|
tray.preferredWidth = Math.max(el.width(),500);
|
||||||
@ -259,6 +260,7 @@ RED.tray = (function() {
|
|||||||
if (stack.length === 0) {
|
if (stack.length === 0) {
|
||||||
$("#header-shade").hide();
|
$("#header-shade").hide();
|
||||||
$("#editor-shade").hide();
|
$("#editor-shade").hide();
|
||||||
|
$("#palette-shade").hide();
|
||||||
$(".sidebar-shade").hide();
|
$(".sidebar-shade").hide();
|
||||||
RED.events.emit("editor:close");
|
RED.events.emit("editor:close");
|
||||||
RED.view.focus();
|
RED.view.focus();
|
||||||
|
@ -642,6 +642,8 @@ RED.view = (function() {
|
|||||||
mousePos = mouse_position;
|
mousePos = mouse_position;
|
||||||
var minX = 0;
|
var minX = 0;
|
||||||
var minY = 0;
|
var minY = 0;
|
||||||
|
var maxX = space_width;
|
||||||
|
var maxY = space_height;
|
||||||
for (var n = 0; n<moving_set.length; n++) {
|
for (var n = 0; n<moving_set.length; n++) {
|
||||||
node = moving_set[n];
|
node = moving_set[n];
|
||||||
if (d3.event.shiftKey) {
|
if (d3.event.shiftKey) {
|
||||||
@ -653,6 +655,8 @@ RED.view = (function() {
|
|||||||
node.n.dirty = true;
|
node.n.dirty = true;
|
||||||
minX = Math.min(node.n.x-node.n.w/2-5,minX);
|
minX = Math.min(node.n.x-node.n.w/2-5,minX);
|
||||||
minY = Math.min(node.n.y-node.n.h/2-5,minY);
|
minY = Math.min(node.n.y-node.n.h/2-5,minY);
|
||||||
|
maxX = Math.max(node.n.x+node.n.w/2+5,maxX);
|
||||||
|
maxY = Math.max(node.n.y+node.n.h/2+5,maxY);
|
||||||
}
|
}
|
||||||
if (minX !== 0 || minY !== 0) {
|
if (minX !== 0 || minY !== 0) {
|
||||||
for (i = 0; i<moving_set.length; i++) {
|
for (i = 0; i<moving_set.length; i++) {
|
||||||
@ -661,6 +665,13 @@ RED.view = (function() {
|
|||||||
node.n.y -= minY;
|
node.n.y -= minY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (maxX !== space_width || maxY !== space_height) {
|
||||||
|
for (i = 0; i<moving_set.length; i++) {
|
||||||
|
node = moving_set[i];
|
||||||
|
node.n.x -= (maxX - space_width);
|
||||||
|
node.n.y -= (maxY - space_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (snapGrid != d3.event.shiftKey && moving_set.length > 0) {
|
if (snapGrid != d3.event.shiftKey && moving_set.length > 0) {
|
||||||
var gridOffset = [0,0];
|
var gridOffset = [0,0];
|
||||||
node = moving_set[0];
|
node = moving_set[0];
|
||||||
@ -796,7 +807,9 @@ RED.view = (function() {
|
|||||||
if (moving_set.length > 0) {
|
if (moving_set.length > 0) {
|
||||||
var ns = [];
|
var ns = [];
|
||||||
for (var j=0;j<moving_set.length;j++) {
|
for (var j=0;j<moving_set.length;j++) {
|
||||||
ns.push({n:moving_set[j].n,ox:moving_set[j].ox,oy:moving_set[j].oy});
|
ns.push({n:moving_set[j].n,ox:moving_set[j].ox,oy:moving_set[j].oy,changed:moving_set[j].n.changed});
|
||||||
|
moving_set[j].n.dirty = true;
|
||||||
|
moving_set[j].n.changed = true;
|
||||||
}
|
}
|
||||||
historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()};
|
historyEvent = {t:"move",nodes:ns,dirty:RED.nodes.dirty()};
|
||||||
if (activeSpliceLink) {
|
if (activeSpliceLink) {
|
||||||
@ -977,10 +990,13 @@ RED.view = (function() {
|
|||||||
if (moving_set.length > 0) {
|
if (moving_set.length > 0) {
|
||||||
var ns = [];
|
var ns = [];
|
||||||
for (var i=0;i<moving_set.length;i++) {
|
for (var i=0;i<moving_set.length;i++) {
|
||||||
ns.push({n:moving_set[i].n,ox:moving_set[i].ox,oy:moving_set[i].oy});
|
ns.push({n:moving_set[i].n,ox:moving_set[i].ox,oy:moving_set[i].oy,changed:moving_set[i].n.changed});
|
||||||
|
moving_set[i].n.changed = true;
|
||||||
|
moving_set[i].n.dirty = true;
|
||||||
delete moving_set[i].ox;
|
delete moving_set[i].ox;
|
||||||
delete moving_set[i].oy;
|
delete moving_set[i].oy;
|
||||||
}
|
}
|
||||||
|
redraw();
|
||||||
RED.history.push({t:"move",nodes:ns,dirty:RED.nodes.dirty()});
|
RED.history.push({t:"move",nodes:ns,dirty:RED.nodes.dirty()});
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
@ -1379,7 +1395,7 @@ RED.view = (function() {
|
|||||||
options.push({name:"delete",disabled:(moving_set.length===0 && selected_link === null),onselect:function() {deleteSelection();}});
|
options.push({name:"delete",disabled:(moving_set.length===0 && selected_link === null),onselect:function() {deleteSelection();}});
|
||||||
options.push({name:"cut",disabled:(moving_set.length===0),onselect:function() {copySelection();deleteSelection();}});
|
options.push({name:"cut",disabled:(moving_set.length===0),onselect:function() {copySelection();deleteSelection();}});
|
||||||
options.push({name:"copy",disabled:(moving_set.length===0),onselect:function() {copySelection();}});
|
options.push({name:"copy",disabled:(moving_set.length===0),onselect:function() {copySelection();}});
|
||||||
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard,true);}});
|
options.push({name:"paste",disabled:(clipboard.length===0),onselect:function() {importNodes(clipboard,false,true);}});
|
||||||
options.push({name:"edit",disabled:(moving_set.length != 1),onselect:function() { RED.editor.edit(mdn);}});
|
options.push({name:"edit",disabled:(moving_set.length != 1),onselect:function() { RED.editor.edit(mdn);}});
|
||||||
options.push({name:"select",onselect:function() {selectAll();}});
|
options.push({name:"select",onselect:function() {selectAll();}});
|
||||||
options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
|
options.push({name:"undo",disabled:(RED.history.depth() === 0),onselect:function() {RED.history.pop();}});
|
||||||
@ -1793,6 +1809,7 @@ RED.view = (function() {
|
|||||||
l = d._def.label;
|
l = d._def.label;
|
||||||
try {
|
try {
|
||||||
l = (typeof l === "function" ? l.call(d) : l)||"";
|
l = (typeof l === "function" ? l.call(d) : l)||"";
|
||||||
|
l = RED.text.bidi.enforceTextDirectionWithUCC(l);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.log("Definition error: "+d.type+".label",err);
|
console.log("Definition error: "+d.type+".label",err);
|
||||||
l = d.type;
|
l = d.type;
|
||||||
@ -2155,7 +2172,6 @@ RED.view = (function() {
|
|||||||
).classed("link_selected", false);
|
).classed("link_selected", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (d3.event) {
|
if (d3.event) {
|
||||||
d3.event.preventDefault();
|
d3.event.preventDefault();
|
||||||
}
|
}
|
||||||
@ -2184,19 +2200,22 @@ RED.view = (function() {
|
|||||||
* - all "selected"
|
* - all "selected"
|
||||||
* - attached to mouse for placing - "IMPORT_DRAGGING"
|
* - attached to mouse for placing - "IMPORT_DRAGGING"
|
||||||
*/
|
*/
|
||||||
function importNodes(newNodesStr,touchImport) {
|
function importNodes(newNodesStr,addNewFlow,touchImport) {
|
||||||
try {
|
try {
|
||||||
var activeSubflowChanged;
|
var activeSubflowChanged;
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
activeSubflowChanged = activeSubflow.changed;
|
activeSubflowChanged = activeSubflow.changed;
|
||||||
}
|
}
|
||||||
var result = RED.nodes.import(newNodesStr,true);
|
var result = RED.nodes.import(newNodesStr,true,addNewFlow);
|
||||||
if (result) {
|
if (result) {
|
||||||
var new_nodes = result[0];
|
var new_nodes = result[0];
|
||||||
var new_links = result[1];
|
var new_links = result[1];
|
||||||
var new_workspaces = result[2];
|
var new_workspaces = result[2];
|
||||||
var new_subflows = result[3];
|
var new_subflows = result[3];
|
||||||
|
var new_default_workspace = result[4];
|
||||||
|
if (addNewFlow && new_default_workspace) {
|
||||||
|
RED.workspaces.show(new_default_workspace.id);
|
||||||
|
}
|
||||||
var new_ms = new_nodes.filter(function(n) { return n.hasOwnProperty("x") && n.hasOwnProperty("y") && n.z == RED.workspaces.active() }).map(function(n) { return {n:n};});
|
var new_ms = new_nodes.filter(function(n) { return n.hasOwnProperty("x") && n.hasOwnProperty("y") && n.z == RED.workspaces.active() }).map(function(n) { return {n:n};});
|
||||||
var new_node_ids = new_nodes.map(function(n){ return n.id; });
|
var new_node_ids = new_nodes.map(function(n){ return n.id; });
|
||||||
|
|
||||||
@ -2269,6 +2288,9 @@ RED.view = (function() {
|
|||||||
subflows:new_subflows,
|
subflows:new_subflows,
|
||||||
dirty:RED.nodes.dirty()
|
dirty:RED.nodes.dirty()
|
||||||
};
|
};
|
||||||
|
if (new_ms.length === 0) {
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
}
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
var subflowRefresh = RED.subflow.refresh(true);
|
var subflowRefresh = RED.subflow.refresh(true);
|
||||||
if (subflowRefresh) {
|
if (subflowRefresh) {
|
||||||
@ -2373,6 +2395,46 @@ RED.view = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
},
|
||||||
|
reveal: function(id) {
|
||||||
|
if (RED.nodes.workspace(id) || RED.nodes.subflow(id)) {
|
||||||
|
RED.workspaces.show(id);
|
||||||
|
} else {
|
||||||
|
var node = RED.nodes.node(id);
|
||||||
|
if (node._def.category !== 'config' && node.z) {
|
||||||
|
node.highlighted = true;
|
||||||
|
node.dirty = true;
|
||||||
|
RED.workspaces.show(node.z);
|
||||||
|
RED.view.redraw();
|
||||||
|
|
||||||
|
var screenSize = [$("#chart").width(),$("#chart").height()];
|
||||||
|
var scrollPos = [$("#chart").scrollLeft(),$("#chart").scrollTop()];
|
||||||
|
|
||||||
|
if (node.x < scrollPos[0] || node.y < scrollPos[1] || node.x > screenSize[0]+scrollPos[0] || node.y > screenSize[1]+scrollPos[1]) {
|
||||||
|
var deltaX = '-='+((scrollPos[0] - node.x) + screenSize[0]/2);
|
||||||
|
var deltaY = '-='+((scrollPos[1] - node.y) + screenSize[1]/2);
|
||||||
|
$("#chart").animate({
|
||||||
|
scrollLeft: deltaX,
|
||||||
|
scrollTop: deltaY
|
||||||
|
},200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var flash = 22;
|
||||||
|
var flashFunc = function() {
|
||||||
|
flash--;
|
||||||
|
node.highlighted = !node.highlighted;
|
||||||
|
node.dirty = true;
|
||||||
|
RED.view.redraw();
|
||||||
|
if (flash >= 0) {
|
||||||
|
setTimeout(flashFunc,100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flashFunc();
|
||||||
|
} else if (node._def.category === 'config') {
|
||||||
|
RED.sidebar.config.show(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -20,7 +20,7 @@ RED.workspaces = (function() {
|
|||||||
var activeWorkspace = 0;
|
var activeWorkspace = 0;
|
||||||
var workspaceIndex = 0;
|
var workspaceIndex = 0;
|
||||||
|
|
||||||
function addWorkspace(ws) {
|
function addWorkspace(ws,skipHistoryEntry) {
|
||||||
if (ws) {
|
if (ws) {
|
||||||
workspace_tabs.addTab(ws);
|
workspace_tabs.addTab(ws);
|
||||||
workspace_tabs.resize();
|
workspace_tabs.resize();
|
||||||
@ -34,10 +34,13 @@ RED.workspaces = (function() {
|
|||||||
RED.nodes.addWorkspace(ws);
|
RED.nodes.addWorkspace(ws);
|
||||||
workspace_tabs.addTab(ws);
|
workspace_tabs.addTab(ws);
|
||||||
workspace_tabs.activateTab(tabId);
|
workspace_tabs.activateTab(tabId);
|
||||||
|
if (!skipHistoryEntry) {
|
||||||
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
|
RED.history.push({t:'add',workspaces:[ws],dirty:RED.nodes.dirty()});
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
function deleteWorkspace(ws) {
|
function deleteWorkspace(ws) {
|
||||||
if (workspace_tabs.count() == 1) {
|
if (workspace_tabs.count() == 1) {
|
||||||
return;
|
return;
|
||||||
@ -90,11 +93,11 @@ RED.workspaces = (function() {
|
|||||||
node: workspace,
|
node: workspace,
|
||||||
dirty: RED.nodes.dirty()
|
dirty: RED.nodes.dirty()
|
||||||
}
|
}
|
||||||
|
workspace.changed = true;
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
workspace_tabs.renameTab(workspace.id,label);
|
workspace_tabs.renameTab(workspace.id,label);
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
RED.sidebar.config.refresh();
|
RED.sidebar.config.refresh();
|
||||||
$("#menu-item-workspace-menu-"+workspace.id.replace(".","-")).text(label);
|
|
||||||
}
|
}
|
||||||
RED.tray.close();
|
RED.tray.close();
|
||||||
}
|
}
|
||||||
@ -110,6 +113,7 @@ RED.workspaces = (function() {
|
|||||||
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
$('<input type="text" style="display: none;" />').prependTo(dialogForm);
|
||||||
dialogForm.submit(function(e) { e.preventDefault();});
|
dialogForm.submit(function(e) { e.preventDefault();});
|
||||||
$("#node-input-name").val(workspace.label);
|
$("#node-input-name").val(workspace.label);
|
||||||
|
RED.text.bidi.prepareInput($("#node-input-name"))
|
||||||
dialogForm.i18n();
|
dialogForm.i18n();
|
||||||
},
|
},
|
||||||
close: function() {
|
close: function() {
|
||||||
@ -133,6 +137,7 @@ RED.workspaces = (function() {
|
|||||||
activeWorkspace = tab.id;
|
activeWorkspace = tab.id;
|
||||||
event.workspace = activeWorkspace;
|
event.workspace = activeWorkspace;
|
||||||
RED.events.emit("workspace:change",event);
|
RED.events.emit("workspace:change",event);
|
||||||
|
window.location.hash = 'flow/'+tab.id;
|
||||||
RED.sidebar.config.refresh();
|
RED.sidebar.config.refresh();
|
||||||
},
|
},
|
||||||
ondblclick: function(tab) {
|
ondblclick: function(tab) {
|
||||||
@ -143,31 +148,26 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onadd: function(tab) {
|
onadd: function(tab) {
|
||||||
RED.menu.addItem("menu-item-workspace",{
|
|
||||||
id:"menu-item-workspace-menu-"+tab.id.replace(".","-"),
|
|
||||||
label:tab.label,
|
|
||||||
onselect:function() {
|
|
||||||
workspace_tabs.activateTab(tab.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||||
},
|
},
|
||||||
onremove: function(tab) {
|
onremove: function(tab) {
|
||||||
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
RED.menu.setDisabled("menu-item-workspace-delete",workspace_tabs.count() == 1);
|
||||||
RED.menu.removeItem("menu-item-workspace-menu-"+tab.id.replace(".","-"));
|
|
||||||
},
|
},
|
||||||
onreorder: function(oldOrder, newOrder) {
|
onreorder: function(oldOrder, newOrder) {
|
||||||
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
|
RED.history.push({t:'reorder',order:oldOrder,dirty:RED.nodes.dirty()});
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
setWorkspaceOrder(newOrder);
|
setWorkspaceOrder(newOrder);
|
||||||
},
|
},
|
||||||
minimumActiveTabWidth: 150
|
minimumActiveTabWidth: 150,
|
||||||
|
scrollable: true,
|
||||||
|
addButton: function() {
|
||||||
|
addWorkspace();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
createWorkspaceTabs();
|
createWorkspaceTabs();
|
||||||
$('#btn-workspace-add-tab').on("click",function(e) {addWorkspace(); e.preventDefault()});
|
|
||||||
RED.events.on("sidebar:resize",workspace_tabs.resize);
|
RED.events.on("sidebar:resize",workspace_tabs.resize);
|
||||||
|
|
||||||
RED.menu.setAction('menu-item-workspace-delete',function() {
|
RED.menu.setAction('menu-item-workspace-delete',function() {
|
||||||
@ -218,6 +218,8 @@ RED.workspaces = (function() {
|
|||||||
var sf = RED.nodes.subflow(id);
|
var sf = RED.nodes.subflow(id);
|
||||||
if (sf) {
|
if (sf) {
|
||||||
addWorkspace({type:"subflow",id:id,icon:"red/images/subflow_tab.png",label:sf.name, closeable: true});
|
addWorkspace({type:"subflow",id:id,icon:"red/images/subflow_tab.png",label:sf.name, closeable: true});
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
workspace_tabs.activateTab(id);
|
workspace_tabs.activateTab(id);
|
||||||
@ -225,7 +227,6 @@ RED.workspaces = (function() {
|
|||||||
refresh: function() {
|
refresh: function() {
|
||||||
RED.nodes.eachWorkspace(function(ws) {
|
RED.nodes.eachWorkspace(function(ws) {
|
||||||
workspace_tabs.renameTab(ws.id,ws.label);
|
workspace_tabs.renameTab(ws.id,ws.label);
|
||||||
$("#menu-item-workspace-menu-"+ws.id.replace(".","-")).text(ws.label);
|
|
||||||
|
|
||||||
})
|
})
|
||||||
RED.nodes.eachSubflow(function(sf) {
|
RED.nodes.eachSubflow(function(sf) {
|
||||||
|
@ -20,6 +20,7 @@ $form-placeholder-color: #bbbbbb;
|
|||||||
$form-text-color: #444;
|
$form-text-color: #444;
|
||||||
$form-input-focus-color: rgba(85,150,230,0.8);
|
$form-input-focus-color: rgba(85,150,230,0.8);
|
||||||
$form-input-border-color: #ccc;
|
$form-input-border-color: #ccc;
|
||||||
|
$form-input-border-selected-color: #aaa;
|
||||||
|
|
||||||
|
|
||||||
$node-selected-color: #ff7f0e;
|
$node-selected-color: #ff7f0e;
|
||||||
@ -42,13 +43,17 @@ $palette-header-background: #f3f3f3;
|
|||||||
$workspace-button-background: #fff;
|
$workspace-button-background: #fff;
|
||||||
$workspace-button-background-hover: #ddd;
|
$workspace-button-background-hover: #ddd;
|
||||||
$workspace-button-background-active: #efefef;
|
$workspace-button-background-active: #efefef;
|
||||||
$workspace-button-color: #999;
|
$workspace-button-color: #888;
|
||||||
$workspace-button-color-disabled: #ccc;
|
$workspace-button-color-disabled: #ccc;
|
||||||
$workspace-button-color-focus: #999;
|
$workspace-button-color-focus: #999;
|
||||||
$workspace-button-color-hover: #666;
|
$workspace-button-color-hover: #666;
|
||||||
$workspace-button-color-active: #666;
|
$workspace-button-color-active: #666;
|
||||||
$workspace-button-color-selected: #AAA;
|
$workspace-button-color-selected: #AAA;
|
||||||
|
|
||||||
|
$workspace-button-toggle-color: #999;
|
||||||
|
$workspace-button-toggle-color-selected: #888;
|
||||||
|
$workspace-button-toggle-color-disabled: #ddd;
|
||||||
|
|
||||||
$workspace-button-color-focus-outline: rgba(85,150,230,0.2);
|
$workspace-button-color-focus-outline: rgba(85,150,230,0.2);
|
||||||
|
|
||||||
$typedInput-button-background: #efefef;
|
$typedInput-button-background: #efefef;
|
||||||
@ -61,4 +66,4 @@ $editor-button-background-primary-hover: #6E0A1E;
|
|||||||
$editor-button-color: #999;
|
$editor-button-color: #999;
|
||||||
$editor-button-background: #fff;
|
$editor-button-background: #fff;
|
||||||
|
|
||||||
$shade-color: rgba(220,220,220,0.5);
|
$shade-color: rgba(100,100,100,0.5);
|
||||||
|
165
editor/sass/diff.scss
Normal file
165
editor/sass/diff.scss
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
#node-dialog-view-diff {
|
||||||
|
height: 600px;
|
||||||
|
|
||||||
|
.red-ui-editableList-container {
|
||||||
|
border-radius:1px;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
position: absolute;
|
||||||
|
top:10px;
|
||||||
|
bottom:10px;
|
||||||
|
left:10px;
|
||||||
|
right:10px;
|
||||||
|
li {
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.red-ui-editableList-item-content {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.node-diff-tab {
|
||||||
|
border: 1px solid $secondary-border-color;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
.node-diff-tab-title > .node-diff-chevron {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
.node-diff-node-entry {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.node-diff-tab-stats {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-diff-chevron {
|
||||||
|
width: 15px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 3px 5px 3px 5px;
|
||||||
|
transition: transform 0.1s ease-in-out;
|
||||||
|
|
||||||
|
}
|
||||||
|
.node-diff-node-entry {
|
||||||
|
padding: 0 0 0 5px;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
.node-diff-chevron {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
.node-diff-node-entry-properties {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
table-layout:fixed;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
border: 1px solid $secondary-border-color;
|
||||||
|
padding: 3px 5px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-child(1) {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
td:not(:first-child) {
|
||||||
|
width: calc(50% - 150px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.node-diff-column {
|
||||||
|
display:inline-block;
|
||||||
|
height:100%;
|
||||||
|
width:50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
white-space:nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
&:first-child {
|
||||||
|
border-right: 1px solid $secondary-border-color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.node-diff-tab-title {
|
||||||
|
padding: 3px 3px 3px 0;
|
||||||
|
background: #f6f6f6;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-diff-node-entry-node {
|
||||||
|
vertical-align: middle;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 5px;
|
||||||
|
width: 24px;
|
||||||
|
height: 20px;
|
||||||
|
background: #ddd;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #999;
|
||||||
|
background-position: 5% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.palette-icon {
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
.palette_icon_container {
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.node-diff-node-entry-title {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.node-diff-node-entry-properties {
|
||||||
|
margin-left: 30px;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-bottom:8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.node-diff-node-description {
|
||||||
|
color: $form-text-color;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
padding-top: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.node-diff-count { color: #999}
|
||||||
|
.node-diff-added { color: #009900}
|
||||||
|
.node-diff-deleted { color: #f80000}
|
||||||
|
.node-diff-changed { color: #f89406}
|
||||||
|
.node-diff-conflicted { color: purple}
|
@ -76,16 +76,16 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 6px 14px;
|
padding: 6px 14px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
color: $editor-button-color;
|
color: $editor-button-color !important;
|
||||||
background: $editor-button-background;
|
background: $editor-button-background;
|
||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
border-color: $editor-button-background-primary;
|
border-color: $editor-button-background-primary;
|
||||||
color: $editor-button-color-primary;
|
color: $editor-button-color-primary !important;
|
||||||
background: $editor-button-background-primary;
|
background: $editor-button-background-primary;
|
||||||
&.disabled, &.ui-state-disabled {
|
&.disabled, &.ui-state-disabled {
|
||||||
background: none;
|
background: none;
|
||||||
color: $editor-button-color;
|
color: $editor-button-color !important;
|
||||||
border-color: $form-input-border-color;
|
border-color: $form-input-border-color;
|
||||||
}
|
}
|
||||||
&:not(.disabled):not(.ui-button-disabled):hover {
|
&:not(.disabled):not(.ui-button-disabled):hover {
|
||||||
@ -167,7 +167,7 @@
|
|||||||
background: $background-color;
|
background: $background-color;
|
||||||
color: $workspace-button-color;
|
color: $workspace-button-color;
|
||||||
}
|
}
|
||||||
#editor-shade, #header-shade {
|
#palette-shade, #editor-shade, #header-shade, #sidebar-shade {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top:0;
|
top:0;
|
||||||
bottom:0;
|
bottom:0;
|
||||||
@ -176,6 +176,11 @@
|
|||||||
background: $shade-color;
|
background: $shade-color;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
#sidebar-shade {
|
||||||
|
left: -8px;
|
||||||
|
top: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.dialog-form,#dialog-form, #dialog-config-form {
|
.dialog-form,#dialog-form, #dialog-config-form {
|
||||||
@ -196,7 +201,7 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
.form-row input {
|
.form-row input, .form-row div[contenteditable="true"] {
|
||||||
width:70%;
|
width:70%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +235,12 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
&.toggle {
|
||||||
|
@include workspace-button-toggle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.editor-button-small {
|
.editor-button-small {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
@ -239,6 +249,17 @@
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-form {
|
||||||
|
.button-group {
|
||||||
|
.editor-button {
|
||||||
|
&:first-child {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#node-config-dialog-scope-container {
|
#node-config-dialog-scope-container {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
float: right;
|
float: right;
|
||||||
@ -255,7 +276,7 @@
|
|||||||
margin: 1px 0 0 0;
|
margin: 1px 0 0 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
width: 150px;
|
width: 200px;
|
||||||
|
|
||||||
}
|
}
|
||||||
#node-config-dialog-user-count {
|
#node-config-dialog-user-count {
|
||||||
|
@ -157,6 +157,8 @@
|
|||||||
stroke: $node-selected-color !important;
|
stroke: $node-selected-color !important;
|
||||||
}
|
}
|
||||||
.node_highlighted {
|
.node_highlighted {
|
||||||
|
border-color: #dd1616 !important;
|
||||||
|
border-style: dashed !important;
|
||||||
stroke: #dd1616;
|
stroke: #dd1616;
|
||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
stroke-dasharray: 10, 4;
|
stroke-dasharray: 10, 4;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
button,
|
button,
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
|
div[contenteditable="true"],
|
||||||
textarea {
|
textarea {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
@ -33,12 +34,14 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button,
|
button,
|
||||||
|
div[contenteditable="true"],
|
||||||
input {
|
input {
|
||||||
*overflow: visible;
|
*overflow: visible;
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
button::-moz-focus-inner,
|
||||||
|
div[contenteditable="true"]::-moz-focus-inner,
|
||||||
input::-moz-focus-inner {
|
input::-moz-focus-inner {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
@ -110,6 +113,7 @@ legend small {
|
|||||||
|
|
||||||
label,
|
label,
|
||||||
input,
|
input,
|
||||||
|
div[contenteditable="true"],
|
||||||
button,
|
button,
|
||||||
select,
|
select,
|
||||||
textarea {
|
textarea {
|
||||||
@ -119,6 +123,7 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
|
div[contenteditable="true"],
|
||||||
button,
|
button,
|
||||||
select,
|
select,
|
||||||
textarea {
|
textarea {
|
||||||
@ -146,6 +151,7 @@ input[type="url"],
|
|||||||
input[type="search"],
|
input[type="search"],
|
||||||
input[type="tel"],
|
input[type="tel"],
|
||||||
input[type="color"],
|
input[type="color"],
|
||||||
|
div[contenteditable="true"],
|
||||||
.uneditable-input {
|
.uneditable-input {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -161,6 +167,7 @@ input[type="color"],
|
|||||||
|
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea,
|
||||||
|
div[contenteditable="true"],
|
||||||
.uneditable-input {
|
.uneditable-input {
|
||||||
width: 206px;
|
width: 206px;
|
||||||
}
|
}
|
||||||
@ -184,6 +191,7 @@ input[type="url"],
|
|||||||
input[type="search"],
|
input[type="search"],
|
||||||
input[type="tel"],
|
input[type="tel"],
|
||||||
input[type="color"],
|
input[type="color"],
|
||||||
|
div[contenteditable="true"],
|
||||||
.uneditable-input {
|
.uneditable-input {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border: 1px solid $form-input-border-color;
|
border: 1px solid $form-input-border-color;
|
||||||
@ -207,6 +215,7 @@ input[type="url"]:focus,
|
|||||||
input[type="search"]:focus,
|
input[type="search"]:focus,
|
||||||
input[type="tel"]:focus,
|
input[type="tel"]:focus,
|
||||||
input[type="color"]:focus,
|
input[type="color"]:focus,
|
||||||
|
div[contenteditable="true"]:focus,
|
||||||
.uneditable-input:focus {
|
.uneditable-input:focus {
|
||||||
border-color: $form-input-focus-color;
|
border-color: $form-input-focus-color;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
@ -294,11 +303,13 @@ textarea:-moz-placeholder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input:-ms-input-placeholder,
|
input:-ms-input-placeholder,
|
||||||
|
div[contenteditable="true"]:-ms-input-placeholder,
|
||||||
textarea:-ms-input-placeholder {
|
textarea:-ms-input-placeholder {
|
||||||
color: $form-placeholder-color;
|
color: $form-placeholder-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::-webkit-input-placeholder,
|
input::-webkit-input-placeholder,
|
||||||
|
div[contenteditable="true"]::-webkit-input-placeholder,
|
||||||
textarea::-webkit-input-placeholder {
|
textarea::-webkit-input-placeholder {
|
||||||
color: $form-placeholder-color;
|
color: $form-placeholder-color;
|
||||||
}
|
}
|
||||||
@ -384,6 +395,7 @@ textarea[class*="span"],
|
|||||||
|
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea,
|
||||||
|
div[contenteditable="true"],
|
||||||
.uneditable-input {
|
.uneditable-input {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
@ -515,12 +527,14 @@ input[type="checkbox"][readonly] {
|
|||||||
.control-group.warning .checkbox,
|
.control-group.warning .checkbox,
|
||||||
.control-group.warning .radio,
|
.control-group.warning .radio,
|
||||||
.control-group.warning input,
|
.control-group.warning input,
|
||||||
|
.control-group.warning div[contenteditable="true"],
|
||||||
.control-group.warning select,
|
.control-group.warning select,
|
||||||
.control-group.warning textarea {
|
.control-group.warning textarea {
|
||||||
color: #c09853;
|
color: #c09853;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-group.warning input,
|
.control-group.warning input,
|
||||||
|
.control-group.warning div[contenteditable="true"],
|
||||||
.control-group.warning select,
|
.control-group.warning select,
|
||||||
.control-group.warning textarea {
|
.control-group.warning textarea {
|
||||||
border-color: #c09853;
|
border-color: #c09853;
|
||||||
@ -530,6 +544,7 @@ input[type="checkbox"][readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.control-group.warning input:focus,
|
.control-group.warning input:focus,
|
||||||
|
.control-group.warning div[contenteditable="true"]:focus,
|
||||||
.control-group.warning select:focus,
|
.control-group.warning select:focus,
|
||||||
.control-group.warning textarea:focus {
|
.control-group.warning textarea:focus {
|
||||||
border-color: #a47e3c;
|
border-color: #a47e3c;
|
||||||
@ -554,12 +569,14 @@ input[type="checkbox"][readonly] {
|
|||||||
.control-group.error .checkbox,
|
.control-group.error .checkbox,
|
||||||
.control-group.error .radio,
|
.control-group.error .radio,
|
||||||
.control-group.error input,
|
.control-group.error input,
|
||||||
|
.control-group.error div[contenteditable="true"],
|
||||||
.control-group.error select,
|
.control-group.error select,
|
||||||
.control-group.error textarea {
|
.control-group.error textarea {
|
||||||
color: #b94a48;
|
color: #b94a48;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-group.error input,
|
.control-group.error input,
|
||||||
|
.control-group.error div[contenteditable="true"],
|
||||||
.control-group.error select,
|
.control-group.error select,
|
||||||
.control-group.error textarea {
|
.control-group.error textarea {
|
||||||
border-color: #b94a48;
|
border-color: #b94a48;
|
||||||
@ -569,6 +586,7 @@ input[type="checkbox"][readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.control-group.error input:focus,
|
.control-group.error input:focus,
|
||||||
|
.control-group.error div[contenteditable="true"]:focus,
|
||||||
.control-group.error select:focus,
|
.control-group.error select:focus,
|
||||||
.control-group.error textarea:focus {
|
.control-group.error textarea:focus {
|
||||||
border-color: #953b39;
|
border-color: #953b39;
|
||||||
@ -593,12 +611,14 @@ input[type="checkbox"][readonly] {
|
|||||||
.control-group.success .checkbox,
|
.control-group.success .checkbox,
|
||||||
.control-group.success .radio,
|
.control-group.success .radio,
|
||||||
.control-group.success input,
|
.control-group.success input,
|
||||||
|
.control-group.success div[contenteditable="true"],
|
||||||
.control-group.success select,
|
.control-group.success select,
|
||||||
.control-group.success textarea {
|
.control-group.success textarea {
|
||||||
color: #468847;
|
color: #468847;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-group.success input,
|
.control-group.success input,
|
||||||
|
.control-group.success div[contenteditable="true"],
|
||||||
.control-group.success select,
|
.control-group.success select,
|
||||||
.control-group.success textarea {
|
.control-group.success textarea {
|
||||||
border-color: #468847;
|
border-color: #468847;
|
||||||
@ -608,6 +628,7 @@ input[type="checkbox"][readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.control-group.success input:focus,
|
.control-group.success input:focus,
|
||||||
|
.control-group.success div[contenteditable="true"]:focus,
|
||||||
.control-group.success select:focus,
|
.control-group.success select:focus,
|
||||||
.control-group.success textarea:focus {
|
.control-group.success textarea:focus {
|
||||||
border-color: #356635;
|
border-color: #356635;
|
||||||
@ -632,12 +653,14 @@ input[type="checkbox"][readonly] {
|
|||||||
.control-group.info .checkbox,
|
.control-group.info .checkbox,
|
||||||
.control-group.info .radio,
|
.control-group.info .radio,
|
||||||
.control-group.info input,
|
.control-group.info input,
|
||||||
|
.control-group.info div[contenteditable="true"],
|
||||||
.control-group.info select,
|
.control-group.info select,
|
||||||
.control-group.info textarea {
|
.control-group.info textarea {
|
||||||
color: #3a87ad;
|
color: #3a87ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-group.info input,
|
.control-group.info input,
|
||||||
|
.control-group.info div[contenteditable="true"],
|
||||||
.control-group.info select,
|
.control-group.info select,
|
||||||
.control-group.info textarea {
|
.control-group.info textarea {
|
||||||
border-color: #3a87ad;
|
border-color: #3a87ad;
|
||||||
@ -647,6 +670,7 @@ input[type="checkbox"][readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.control-group.info input:focus,
|
.control-group.info input:focus,
|
||||||
|
.control-group.info div[contenteditable="true"]:focus,
|
||||||
.control-group.info select:focus,
|
.control-group.info select:focus,
|
||||||
.control-group.info textarea:focus {
|
.control-group.info textarea:focus {
|
||||||
border-color: #2d6987;
|
border-color: #2d6987;
|
||||||
@ -663,6 +687,7 @@ input[type="checkbox"][readonly] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input:focus:invalid,
|
input:focus:invalid,
|
||||||
|
div[contenteditable="true"]:focus:invalid,
|
||||||
textarea:focus:invalid,
|
textarea:focus:invalid,
|
||||||
select:focus:invalid {
|
select:focus:invalid {
|
||||||
color: #b94a48;
|
color: #b94a48;
|
||||||
@ -670,6 +695,7 @@ select:focus:invalid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input:focus:invalid:focus,
|
input:focus:invalid:focus,
|
||||||
|
div[contenteditable="true"]:focus:invalid:focus,
|
||||||
textarea:focus:invalid:focus,
|
textarea:focus:invalid:focus,
|
||||||
select:focus:invalid:focus {
|
select:focus:invalid:focus {
|
||||||
border-color: #e9322d;
|
border-color: #e9322d;
|
||||||
@ -727,6 +753,8 @@ select:focus:invalid:focus {
|
|||||||
|
|
||||||
.input-append input,
|
.input-append input,
|
||||||
.input-prepend input,
|
.input-prepend input,
|
||||||
|
.input-append div[contenteditable="true"],
|
||||||
|
.input-prepend div[contenteditable="true"],
|
||||||
.input-append select,
|
.input-append select,
|
||||||
.input-prepend select,
|
.input-prepend select,
|
||||||
.input-append .uneditable-input,
|
.input-append .uneditable-input,
|
||||||
@ -740,6 +768,8 @@ select:focus:invalid:focus {
|
|||||||
|
|
||||||
.input-append input,
|
.input-append input,
|
||||||
.input-prepend input,
|
.input-prepend input,
|
||||||
|
.input-append div[contenteditable="true"],
|
||||||
|
.input-prepend div[contenteditable="true"],
|
||||||
.input-append select,
|
.input-append select,
|
||||||
.input-prepend select,
|
.input-prepend select,
|
||||||
.input-append .uneditable-input,
|
.input-append .uneditable-input,
|
||||||
@ -755,6 +785,8 @@ select:focus:invalid:focus {
|
|||||||
|
|
||||||
.input-append input:focus,
|
.input-append input:focus,
|
||||||
.input-prepend input:focus,
|
.input-prepend input:focus,
|
||||||
|
.input-append div[contenteditable="true"]:focus,
|
||||||
|
.input-prepend div[contenteditable="true"]:focus,
|
||||||
.input-append select:focus,
|
.input-append select:focus,
|
||||||
.input-prepend select:focus,
|
.input-prepend select:focus,
|
||||||
.input-append .uneditable-input:focus,
|
.input-append .uneditable-input:focus,
|
||||||
@ -809,6 +841,7 @@ select:focus:invalid:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input-append input,
|
.input-append input,
|
||||||
|
.input-append div[contenteditable="true"],
|
||||||
.input-append select,
|
.input-append select,
|
||||||
.input-append .uneditable-input {
|
.input-append .uneditable-input {
|
||||||
-webkit-border-radius: 4px 0 0 4px;
|
-webkit-border-radius: 4px 0 0 4px;
|
||||||
@ -839,6 +872,7 @@ select:focus:invalid:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.input-prepend.input-append input,
|
.input-prepend.input-append input,
|
||||||
|
.input-prepend.input-append div[contenteditable="true"],
|
||||||
.input-prepend.input-append select,
|
.input-prepend.input-append select,
|
||||||
.input-prepend.input-append .uneditable-input {
|
.input-prepend.input-append .uneditable-input {
|
||||||
-webkit-border-radius: 0;
|
-webkit-border-radius: 0;
|
||||||
@ -923,6 +957,9 @@ input.search-query {
|
|||||||
.form-search input,
|
.form-search input,
|
||||||
.form-inline input,
|
.form-inline input,
|
||||||
.form-horizontal input,
|
.form-horizontal input,
|
||||||
|
.form-search div[contenteditable="true"],
|
||||||
|
.form-inline div[contenteditable="true"],
|
||||||
|
.form-horizontal div[contenteditable="true"],
|
||||||
.form-search textarea,
|
.form-search textarea,
|
||||||
.form-inline textarea,
|
.form-inline textarea,
|
||||||
.form-horizontal textarea,
|
.form-horizontal textarea,
|
||||||
@ -1045,3 +1082,8 @@ legend + .control-group {
|
|||||||
.form-horizontal .form-actions {
|
.form-horizontal .form-actions {
|
||||||
padding-left: 180px;
|
padding-left: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-row div[contenteditable="true"] {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||||
}
|
}
|
||||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button {
|
.ui-widget input, .ui-widget div[contenteditable="true"], .ui-widget select, .ui-widget textarea, .ui-widget button {
|
||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||||
}
|
}
|
||||||
.ui-widget input {
|
.ui-widget input, .ui-widget div[contenteditable="true"] {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,13 +92,18 @@
|
|||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
border-color: $editor-button-background-primary;
|
border-color: $editor-button-background-primary;
|
||||||
color: $editor-button-color-primary;
|
color: $editor-button-color-primary !important;
|
||||||
background: $editor-button-background-primary;
|
background: $editor-button-background-primary;
|
||||||
&:not(.disabled):hover {
|
&:not(.disabled):hover {
|
||||||
border-color: $editor-button-background-primary-hover;
|
border-color: $editor-button-background-primary-hover;
|
||||||
background: $editor-button-background-primary-hover;
|
background: $editor-button-background-primary-hover;
|
||||||
color: $editor-button-color-primary !important;
|
color: $editor-button-color-primary !important;
|
||||||
}
|
}
|
||||||
|
&.disabled {
|
||||||
|
border-color: $form-input-border-color;
|
||||||
|
color: $workspace-button-color-disabled !important;
|
||||||
|
background: $editor-button-background;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 IBM Corp.
|
* Copyright 2015, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -22,6 +22,14 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin enable-selection {
|
||||||
|
-webkit-user-select: auto;
|
||||||
|
-khtml-user-select: auto;
|
||||||
|
-moz-user-select: auto;
|
||||||
|
-ms-user-select: auto;
|
||||||
|
user-select: auto;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin component-border {
|
@mixin component-border {
|
||||||
border: 1px solid $primary-border-color;
|
border: 1px solid $primary-border-color;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -32,38 +40,46 @@
|
|||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: $workspace-button-color;
|
color: $workspace-button-color !important;
|
||||||
background: $workspace-button-background;
|
background: $workspace-button-background;
|
||||||
border: 1px solid $form-input-border-color;
|
border: 1px solid $form-input-border-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin:0;
|
margin:0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: $workspace-button-color-disabled;
|
color: $workspace-button-color-disabled !important;
|
||||||
|
}
|
||||||
|
&:hover, &:focus {
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
&:not(.disabled):hover {
|
&:not(.disabled):hover {
|
||||||
text-decoration: none;
|
color: $workspace-button-color-hover !important;
|
||||||
color: $workspace-button-color-hover;
|
|
||||||
background: $workspace-button-background-hover;
|
background: $workspace-button-background-hover;
|
||||||
}
|
}
|
||||||
&:not(.disabled):focus {
|
&:not(.disabled):focus {
|
||||||
color: $workspace-button-color-focus;
|
color: $workspace-button-color-focus !important;
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
&:not(.disabled):active {
|
&:not(.disabled):active {
|
||||||
color: $workspace-button-color-active;
|
color: $workspace-button-color-active !important;
|
||||||
background: $workspace-button-background-active;
|
background: $workspace-button-background-active;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
&.selected:not(.disabled) {
|
&.selected:not(.disabled) {
|
||||||
color: $workspace-button-color-selected;
|
color: $workspace-button-color-selected !important;
|
||||||
background: $workspace-button-background-active;
|
background: $workspace-button-background-active;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.button-group &:not(:first-child) {
|
.button-group &:not(:first-child) {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
.button-group &:not(:last-child) {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
@ -72,12 +88,18 @@
|
|||||||
}
|
}
|
||||||
@mixin workspace-button-toggle {
|
@mixin workspace-button-toggle {
|
||||||
@include workspace-button;
|
@include workspace-button;
|
||||||
color: $workspace-button-color-selected;
|
color: $workspace-button-toggle-color !important;
|
||||||
background: $workspace-button-background-active;
|
background:$workspace-button-background-active;
|
||||||
|
margin-bottom: 1px;
|
||||||
&.selected:not(.disabled) {
|
&.selected:not(.disabled) {
|
||||||
color: $workspace-button-color;
|
color: $workspace-button-toggle-color-selected !important;
|
||||||
background: $workspace-button-background;
|
background: $workspace-button-background;
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
border-bottom-color: $form-input-border-selected-color;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
color: $workspace-button-toggle-color-disabled !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
232
editor/sass/palette-editor.scss
Normal file
232
editor/sass/palette-editor.scss
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#palette-editor {
|
||||||
|
text-align: left;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 25px;
|
||||||
|
left:0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing:border-box;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
.red-ui-editableList-container {
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
|
||||||
|
li {
|
||||||
|
// border: none;
|
||||||
|
// border-top: 1px solid $primary-border-color;
|
||||||
|
padding: 0px;
|
||||||
|
.disabled {
|
||||||
|
background: #f3f3f3;
|
||||||
|
|
||||||
|
.palette-module-name {
|
||||||
|
font-style: italic;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
.palette-module-version {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.red-ui-editableList-item-content {
|
||||||
|
padding: 12px 8px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
// border-bottom: 1px solid $primary-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.palette-editor-tab {
|
||||||
|
position:absolute;
|
||||||
|
top:115px;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
bottom:0
|
||||||
|
}
|
||||||
|
.palette-editor-toolbar {
|
||||||
|
background: #f3f3f3;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-bottom: 1px solid $primary-border-color;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.palette-module-button-group {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
a {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.palette-module-shade {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
background: $shade-color;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
#palette-module-install-shade {
|
||||||
|
padding-top: 80px;
|
||||||
|
}
|
||||||
|
.palette-module-shade-status {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-module-meta {
|
||||||
|
color: #666;
|
||||||
|
position: relative;
|
||||||
|
&.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
width: 15px;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.palette-module-name {
|
||||||
|
white-space: nowrap;
|
||||||
|
@include enable-selection;
|
||||||
|
}
|
||||||
|
.palette-module-version, .palette-module-updated, .palette-module-link {
|
||||||
|
font-style:italic;
|
||||||
|
font-size: 0.8em;
|
||||||
|
@include enable-selection;
|
||||||
|
}
|
||||||
|
.palette-module-updated {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.palette-module-link {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-module-description {
|
||||||
|
margin-left: 20px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.palette-module-link {
|
||||||
|
}
|
||||||
|
.palette-module-set-button-group {
|
||||||
|
}
|
||||||
|
.palette-module-count {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #eee;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.palette-module-content {
|
||||||
|
display: none;
|
||||||
|
padding: 10px 3px;
|
||||||
|
}
|
||||||
|
i.fa.palette-module-node-chevron {
|
||||||
|
width: 8px;
|
||||||
|
margin-right: 0;
|
||||||
|
transform: rotate(0deg);
|
||||||
|
transition: transform 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
.expanded {
|
||||||
|
i.fa.palette-module-node-chevron {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-module-set-button {
|
||||||
|
background:#f3f3f3 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.palette-module-set {
|
||||||
|
border:1px solid $secondary-border-color;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 5px;
|
||||||
|
position: relative;
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
&:first-child {
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-module-type {
|
||||||
|
color: #666;
|
||||||
|
padding-left: 5px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
@include enable-selection;
|
||||||
|
}
|
||||||
|
.palette-module-type-swatch {
|
||||||
|
display: inline-block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 5px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
}
|
||||||
|
.palette-module-set-button-group {
|
||||||
|
position: absolute;
|
||||||
|
right: 4px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-module-set-disabled {
|
||||||
|
background: #eee;
|
||||||
|
.palette-module-type {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.palette-module-more {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: $tab-background-inactive;
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px 8px;
|
||||||
|
color: #AD1625;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background: $tab-background-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,10 +25,25 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
@include component-border;
|
@include component-border;
|
||||||
|
transition: width 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.palette-expanded {
|
||||||
|
& #palette {
|
||||||
|
width: 380px;
|
||||||
|
box-shadow: 1px 0 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
& #workspace { left: 379px !important; }
|
||||||
|
& #palette-collapse-all { display: none; }
|
||||||
|
& #palette-expand-all { display: none; }
|
||||||
|
& #palette-container { display: none !important; }
|
||||||
|
& #palette-search { display: none !important; }
|
||||||
|
& #palette-edit { background: $workspace-button-background-active }
|
||||||
|
& #palette-editor { display: block !important }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.palette-scroll {
|
.palette-scroll {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 35px;
|
top: 35px;
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -38,15 +53,11 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
box-sizing:border-box;
|
box-sizing:border-box;
|
||||||
}
|
}
|
||||||
.palette-spinner {
|
#palette > .palette-spinner {
|
||||||
padding-top: 40px;
|
padding-top: 80px;
|
||||||
}
|
}
|
||||||
#palette-search {
|
.palette-search {
|
||||||
position: absolute;
|
position: relative;
|
||||||
display: none;
|
|
||||||
top: 0;
|
|
||||||
left:0;
|
|
||||||
right:0;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -55,48 +66,7 @@
|
|||||||
border-bottom: 1px solid $primary-border-color;
|
border-bottom: 1px solid $primary-border-color;
|
||||||
box-sizing:border-box;
|
box-sizing:border-box;
|
||||||
}
|
}
|
||||||
#palette-search i {
|
|
||||||
font-size: 10px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
#palette-search i.fa-search {
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
left: 12px;
|
|
||||||
top: 12px;
|
|
||||||
}
|
|
||||||
#palette-search i.fa-times {
|
|
||||||
position: absolute;
|
|
||||||
right: 7px;
|
|
||||||
top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#palette-search-clear {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 20px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#palette-search input {
|
|
||||||
border-radius: 0;
|
|
||||||
border: none;
|
|
||||||
width: 100%;
|
|
||||||
box-shadow: none;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
padding: 3px 17px 3px 22px;
|
|
||||||
margin: 0px;
|
|
||||||
height: 30px;
|
|
||||||
box-sizing:border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
#palette-search input:focus {
|
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
-webkit-box-shadow: none;
|
|
||||||
}
|
|
||||||
#palette-footer {
|
#palette-footer {
|
||||||
@include component-footer;
|
@include component-footer;
|
||||||
}
|
}
|
||||||
|
106
editor/sass/search.scss
Normal file
106
editor/sass/search.scss
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
.red-ui-search {
|
||||||
|
z-index:1000;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
width: 500px;
|
||||||
|
background: white;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -250px;
|
||||||
|
top: 0px;
|
||||||
|
border: 1px solid $primary-border-color;
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.4);
|
||||||
|
|
||||||
|
ol {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-search-container {
|
||||||
|
padding: 3px;
|
||||||
|
border-bottom: 1px solid $secondary-border-color;
|
||||||
|
}
|
||||||
|
.red-ui-search-results-container {
|
||||||
|
position:relative;
|
||||||
|
height: 300px;
|
||||||
|
padding: 5px;
|
||||||
|
background: $background-color;
|
||||||
|
.red-ui-editableList-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0;
|
||||||
|
background: $background-color;
|
||||||
|
li {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&.selected .red-ui-search-result {
|
||||||
|
border-color: $primary-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-search-result {
|
||||||
|
padding: 8px 2px 8px 5px;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $form-text-color;
|
||||||
|
border: 2px solid white;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
border-color: $primary-border-color;
|
||||||
|
color: $form-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-ui-search-result-node {
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
float:left;
|
||||||
|
height: 25px;
|
||||||
|
background: #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #999;
|
||||||
|
background-position: 5% 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.red-ui-search-result-description {
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.red-ui-search-result-node-label {
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
.red-ui-search-result-node-type {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.red-ui-search-result-node-flow {
|
||||||
|
float:right;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
.red-ui-search-result-node-id {
|
||||||
|
display:none;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
.red-ui-search-empty {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-style: italic;
|
||||||
|
color: $form-placeholder-color;
|
||||||
|
}
|
@ -34,15 +34,20 @@
|
|||||||
|
|
||||||
@import "editor";
|
@import "editor";
|
||||||
@import "library";
|
@import "library";
|
||||||
|
@import "search";
|
||||||
|
|
||||||
@import "tabs";
|
@import "tabs";
|
||||||
@import "tab-config";
|
@import "tab-config";
|
||||||
@import "tab-info";
|
@import "tab-info";
|
||||||
@import "popover";
|
@import "popover";
|
||||||
@import "flow";
|
@import "flow";
|
||||||
|
@import "palette-editor";
|
||||||
|
@import "diff";
|
||||||
|
|
||||||
@import "typedInput";
|
|
||||||
@import "editableList";
|
@import "ui/common/editableList";
|
||||||
|
@import "ui/common/searchBox";
|
||||||
|
@import "ui/common/typedInput";
|
||||||
|
|
||||||
@import "dragdrop";
|
@import "dragdrop";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 IBM Corp.
|
* Copyright 2015, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,20 +14,34 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
ul.red-ui-tabs {
|
.red-ui-tabs {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 35px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.red-ui-tabs-scroll-container {
|
||||||
|
height: 60px;
|
||||||
|
overflow-x: scroll;
|
||||||
|
overflow-y: hidden;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& ul {
|
||||||
|
//background: #9999ff;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding:0;
|
padding:0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: block;
|
display: block;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
box-sizing:border-box;
|
box-sizing:border-box;
|
||||||
white-space: nowrap;
|
|
||||||
border-bottom: 1px solid $primary-border-color;
|
border-bottom: 1px solid $primary-border-color;
|
||||||
background: #fff;
|
white-space: nowrap;
|
||||||
@include disable-selection;
|
@include disable-selection;
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li {
|
li {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-left: 1px solid $primary-border-color;
|
border-left: 1px solid $primary-border-color;
|
||||||
@ -42,19 +56,132 @@ ul.red-ui-tabs li {
|
|||||||
width: 14%;
|
width: 14%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
position: relative;
|
||||||
|
|
||||||
ul.red-ui-tabs li a.red-ui-tab-label {
|
a.red-ui-tab-label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.active) a:hover+a.red-ui-tab-close {
|
||||||
|
background: $tab-background-hover;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
background: $tab-background-active;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: 1px solid #fff;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
a.red-ui-tab-close {
|
||||||
|
color: #aaa;
|
||||||
|
background: $tab-background-active;
|
||||||
|
&:hover {
|
||||||
|
background: $workspace-button-background-hover !important;
|
||||||
|
color: $workspace-button-color-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-tab-icon {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(.active) a:hover {
|
||||||
|
color: $workspace-button-color-hover;
|
||||||
|
background: $tab-background-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.red-ui-tabs-scrollable {
|
||||||
|
padding-left: 21px;
|
||||||
|
padding-right: 21px;
|
||||||
|
}
|
||||||
|
&.red-ui-tabs-add {
|
||||||
|
padding-right: 35px;
|
||||||
|
}
|
||||||
|
&.red-ui-tabs-add.red-ui-tabs-scrollable {
|
||||||
|
padding-right: 59px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ul.red-ui-tabs li {
|
.red-ui-tab-button {
|
||||||
position: relative;
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 35px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid $primary-border-color;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
a {
|
||||||
|
@include workspace-button;
|
||||||
|
line-height: 32px;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-right:3px;
|
||||||
|
margin-left:3px;
|
||||||
|
border: 1px solid $primary-border-color;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.red-ui-tab-scroll {
|
||||||
|
width: 21px;
|
||||||
|
top: 0;
|
||||||
|
a {
|
||||||
|
height: 35px;
|
||||||
|
width: 21px;
|
||||||
|
display: block;
|
||||||
|
color: $link-color;
|
||||||
|
font-size: 22px;
|
||||||
|
text-align: center;
|
||||||
|
margin:0;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-tab-scroll-left {
|
||||||
|
left:0;
|
||||||
|
a {
|
||||||
|
border-right: 1px solid $primary-border-color;
|
||||||
|
// box-shadow: 8px 0px 5px -2px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.red-ui-tab-scroll-right {
|
||||||
|
right: 0px;
|
||||||
|
a {
|
||||||
|
border-left: 1px solid $primary-border-color;
|
||||||
|
// box-shadow: -8px 0px 5px -2px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right {
|
||||||
|
right: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-ui-tab-icon {
|
||||||
|
margin-left: -8px;
|
||||||
|
margin-right: 3px;
|
||||||
|
margin-top: -2px;
|
||||||
|
opacity: 0.1;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
.red-ui-tabs-badges {
|
.red-ui-tabs-badges {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top:2px;
|
top:2px;
|
||||||
@ -96,51 +223,3 @@ ul.red-ui-tabs li {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ul.red-ui-tabs li:not(.active) a:hover+a.red-ui-tab-close {
|
|
||||||
background: $tab-background-hover;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li.active a.red-ui-tab-close {
|
|
||||||
color: #aaa;
|
|
||||||
background: $tab-background-active;
|
|
||||||
&:hover {
|
|
||||||
background: $workspace-button-background-hover !important;
|
|
||||||
color: $workspace-button-color-hover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li:not(.active) a:hover {
|
|
||||||
color: $workspace-button-color-hover;
|
|
||||||
background: $tab-background-hover;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li a:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.red-ui-tabs li.active {
|
|
||||||
background: $tab-background-active;
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom: 1px solid #fff;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
ul.red-ui-tabs li.active a {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red-ui-tab-icon {
|
|
||||||
margin-left: -8px;
|
|
||||||
margin-right: 3px;
|
|
||||||
margin-top: -2px;
|
|
||||||
opacity: 0.1;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
ul.red-ui-tabs li.active .red-ui-tab-icon {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
70
editor/sass/ui/common/searchBox.scss
Normal file
70
editor/sass/ui/common/searchBox.scss
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
.red-ui-searchBox-container {
|
||||||
|
position: relative;
|
||||||
|
i {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
i.fa-search {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
left: 8px;
|
||||||
|
top: 9px;
|
||||||
|
}
|
||||||
|
i.fa-times {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 9px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
padding: 3px 17px 3px 22px;
|
||||||
|
margin: 0px;
|
||||||
|
height: 30px;
|
||||||
|
box-sizing:border-box;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 20px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.red-ui-searchBox-resultCount {
|
||||||
|
position: absolute;
|
||||||
|
right: 18px;
|
||||||
|
top: 4px;
|
||||||
|
background: #eee;
|
||||||
|
color: #666;
|
||||||
|
padding: 1px 8px;
|
||||||
|
font-size: 9px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
23
editor/sass/widgetStyle.scss
Normal file
23
editor/sass/widgetStyle.scss
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2016 IBM Corp.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
@import "colors";
|
||||||
|
@import "mixins";
|
||||||
|
|
||||||
|
@import "forms";
|
||||||
|
@import "jquery";
|
||||||
|
@import "typedInput";
|
||||||
|
@import "editableList";
|
@ -40,39 +40,14 @@
|
|||||||
right: 322px;
|
right: 322px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@include component-border;
|
@include component-border;
|
||||||
|
transition: left 0.2s ease-in-out;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-footer-button {
|
.workspace-footer-button {
|
||||||
@include component-footer-button;
|
@include component-footer-button;
|
||||||
}
|
}
|
||||||
|
|
||||||
#workspace-tabs {
|
|
||||||
margin-right: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#workspace-add-tab {
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 35px;
|
|
||||||
width: 35px;
|
|
||||||
background: #fff;
|
|
||||||
border-bottom: 1px solid $primary-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
#btn-workspace-add-tab {
|
|
||||||
@include workspace-button;
|
|
||||||
line-height: 32px;
|
|
||||||
height: 32px;
|
|
||||||
width: 32px;
|
|
||||||
margin-top: 3px;
|
|
||||||
margin-right:3px;
|
|
||||||
border: 1px solid $primary-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspace-footer {
|
#workspace-footer {
|
||||||
@include component-footer;
|
@include component-footer;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<!--
|
<!--
|
||||||
Copyright 2013, 2015 IBM Corp.
|
Copyright 2013, 2016 IBM Corp.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -43,22 +43,8 @@
|
|||||||
<div id="header-shade" class="hide"></div>
|
<div id="header-shade" class="hide"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="main-container" class="sidebar-closed hide">
|
<div id="main-container" class="sidebar-closed hide">
|
||||||
<div id="palette">
|
|
||||||
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
|
||||||
<div id="palette-search">
|
|
||||||
<i class="fa fa-search"></i><input id="palette-search-input" type="text" data-i18n="[placeholder]palette.filter"><a href="#" id="palette-search-clear"><i class="fa fa-times"></i></a></input>
|
|
||||||
</div>
|
|
||||||
<div id="palette-container" class="palette-scroll"></div>
|
|
||||||
<div id="palette-footer">
|
|
||||||
<a class="palette-button" id="palette-collapse-all" href="#"><i class="fa fa-angle-double-up"></i></a>
|
|
||||||
<a class="palette-button" id="palette-expand-all" href="#"><i class="fa fa-angle-double-down"></i></a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- /palette -->
|
|
||||||
|
|
||||||
<div id="workspace">
|
<div id="workspace">
|
||||||
<ul id="workspace-tabs"></ul>
|
<ul id="workspace-tabs"></ul>
|
||||||
<div id="workspace-add-tab"><a id="btn-workspace-add-tab" href="#"><i class="fa fa-plus"></i></a></div>
|
|
||||||
<div id="chart" tabindex="1"></div>
|
<div id="chart" tabindex="1"></div>
|
||||||
<div id="workspace-toolbar"></div>
|
<div id="workspace-toolbar"></div>
|
||||||
<div id="workspace-footer">
|
<div id="workspace-footer">
|
||||||
@ -66,13 +52,30 @@
|
|||||||
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-zero" href="#"><i class="fa fa-circle-o"></i></a>
|
||||||
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
<a class="workspace-footer-button" id="btn-zoom-in" href="#"><i class="fa fa-plus"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="editor-shade" class="hide"></div>
|
<div id="editor-shade" class="hide"></div>
|
||||||
|
</div>
|
||||||
<div id="editor-stack"></div>
|
<div id="editor-stack"></div>
|
||||||
|
<div id="palette">
|
||||||
|
<img src="red/images/spin.svg" class="palette-spinner hide"/>
|
||||||
|
<div id="palette-search" class="palette-search hide">
|
||||||
|
<input type="text" data-i18n="[placeholder]palette.filter"></input>
|
||||||
|
</div>
|
||||||
|
<div id="palette-editor">
|
||||||
|
<div class="editor-tray-header"><div class="editor-tray-titlebar"><ul class="editor-tray-breadcrumbs"><li data-i18n="palette.editor.title"></li></ul></div><div class="editor-tray-toolbar"><button id="palette-editor-close" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only primary" role="button" aria-disabled="false" data-i18n="common.label.done"></button></div></div>
|
||||||
|
<ul id="palette-editor-tabs"></ul>
|
||||||
|
</div>
|
||||||
|
<div id="palette-container" class="palette-scroll hide"></div>
|
||||||
|
<div id="palette-footer">
|
||||||
|
<a class="palette-button" id="palette-collapse-all" href="#"><i class="fa fa-angle-double-up"></i></a>
|
||||||
|
<a class="palette-button" id="palette-expand-all" href="#"><i class="fa fa-angle-double-down"></i></a>
|
||||||
|
</div>
|
||||||
|
<div id="palette-shade" class="hide"></div>
|
||||||
|
</div><!-- /palette -->
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<ul id="sidebar-tabs"></ul>
|
<ul id="sidebar-tabs"></ul>
|
||||||
<div id="sidebar-content"></div>
|
<div id="sidebar-content"></div>
|
||||||
<div id="sidebar-footer"></div>
|
<div id="sidebar-footer"></div>
|
||||||
|
<div id="sidebar-shade" class="hide"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="sidebar-separator"></div>
|
<div id="sidebar-separator"></div>
|
||||||
@ -90,8 +93,13 @@
|
|||||||
<div id="node-dialog-confirm-deploy-unknown" style="text-align: left; padding-top: 10px;" data-i18n="[prepend]deploy.confirm.unknown;[append]deploy.confirm.confirm">
|
<div id="node-dialog-confirm-deploy-unknown" style="text-align: left; padding-top: 10px;" data-i18n="[prepend]deploy.confirm.unknown;[append]deploy.confirm.confirm">
|
||||||
<ul style="font-size: 0.9em; width: 400px; margin: 10px auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
|
<ul style="font-size: 0.9em; width: 400px; margin: 10px auto; text-align: left;" id="node-dialog-confirm-deploy-unknown-list"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="node-dialog-confirm-deploy-conflict" style="text-align: left; padding-top: 10px;" data-i18n="[prepend]deploy.confirm.conflict;[append]deploy.confirm.confirm">
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="node-dialog-view-diff" class="hide">
|
||||||
|
<ol id="node-dialog-view-diff-diff"></ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="node-dialog-library-save-confirm" class="hide">
|
<div id="node-dialog-library-save-confirm" class="hide">
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
|
@ -168,7 +168,7 @@
|
|||||||
msg.onclick = function() {
|
msg.onclick = function() {
|
||||||
var node = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
var node = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
||||||
if (node) {
|
if (node) {
|
||||||
RED.workspaces.show(node.z);
|
RED.view.reveal(node.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -175,7 +175,7 @@ module.exports = function(RED) {
|
|||||||
node.log(RED._("mqtt.state.connected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
node.log(RED._("mqtt.state.connected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
||||||
for (var id in node.users) {
|
for (var id in node.users) {
|
||||||
if (node.users.hasOwnProperty(id)) {
|
if (node.users.hasOwnProperty(id)) {
|
||||||
node.users[id].status({fill:"green",shape:"dot",text:"common.status.connected"});
|
node.users[id].status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
|
// Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
|
||||||
@ -205,7 +205,7 @@ module.exports = function(RED) {
|
|||||||
node.client.on("reconnect", function() {
|
node.client.on("reconnect", function() {
|
||||||
for (var id in node.users) {
|
for (var id in node.users) {
|
||||||
if (node.users.hasOwnProperty(id)) {
|
if (node.users.hasOwnProperty(id)) {
|
||||||
node.users[id].status({fill:"yellow",shape:"ring",text:"common.status.connecting"});
|
node.users[id].status({fill:"yellow",shape:"ring",text:"node-red:common.status.connecting"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -216,7 +216,7 @@ module.exports = function(RED) {
|
|||||||
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
||||||
for (var id in node.users) {
|
for (var id in node.users) {
|
||||||
if (node.users.hasOwnProperty(id)) {
|
if (node.users.hasOwnProperty(id)) {
|
||||||
node.users[id].status({fill:"red",shape:"ring",text:"common.status.disconnected"});
|
node.users[id].status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (node.connecting) {
|
} else if (node.connecting) {
|
||||||
@ -329,7 +329,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
var node = this;
|
var node = this;
|
||||||
if (this.brokerConn) {
|
if (this.brokerConn) {
|
||||||
this.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
|
this.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
|
||||||
if (this.topic) {
|
if (this.topic) {
|
||||||
node.brokerConn.register(this);
|
node.brokerConn.register(this);
|
||||||
this.brokerConn.subscribe(this.topic,this.qos,function(topic,payload,packet) {
|
this.brokerConn.subscribe(this.topic,this.qos,function(topic,payload,packet) {
|
||||||
@ -341,7 +341,7 @@ module.exports = function(RED) {
|
|||||||
node.send(msg);
|
node.send(msg);
|
||||||
}, this.id);
|
}, this.id);
|
||||||
if (this.brokerConn.connected) {
|
if (this.brokerConn.connected) {
|
||||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -369,7 +369,7 @@ module.exports = function(RED) {
|
|||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
if (this.brokerConn) {
|
if (this.brokerConn) {
|
||||||
this.status({fill:"red",shape:"ring",text:"common.status.disconnected"});
|
this.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
|
||||||
this.on("input",function(msg) {
|
this.on("input",function(msg) {
|
||||||
if (msg.qos) {
|
if (msg.qos) {
|
||||||
msg.qos = parseInt(msg.qos);
|
msg.qos = parseInt(msg.qos);
|
||||||
@ -391,7 +391,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (this.brokerConn.connected) {
|
if (this.brokerConn.connected) {
|
||||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
||||||
}
|
}
|
||||||
node.brokerConn.register(node);
|
node.brokerConn.register(node);
|
||||||
this.on('close', function(done) {
|
this.on('close', function(done) {
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
||||||
<input type="text" id="node-input-url" placeholder="/url">
|
<div id="node-input-url" contenteditable="true" placeholder="/url"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||||
@ -117,7 +117,7 @@ msg.cookies = {
|
|||||||
color:"rgb(231, 231, 174)",
|
color:"rgb(231, 231, 174)",
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
url: {value:"",required:true},
|
url: {value:"",required:true,format:"url"},
|
||||||
method: {value:"get",required:true},
|
method: {value:"get",required:true},
|
||||||
swaggerDoc: {type:"swagger-doc", required:false}
|
swaggerDoc: {type:"swagger-doc", required:false}
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
|
||||||
<input type="text" id="node-input-url" placeholder="http://">
|
<div id="node-input-url" contenteditable="true" placeholder="http://"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
@ -102,7 +102,7 @@
|
|||||||
name: {value:""},
|
name: {value:""},
|
||||||
method:{value:"GET"},
|
method:{value:"GET"},
|
||||||
ret: {value:"txt"},
|
ret: {value:"txt"},
|
||||||
url:{value:""},
|
url:{value:"",format:"url"},
|
||||||
tls: {type:"tls-config",required: false}
|
tls: {type:"tls-config",required: false}
|
||||||
},
|
},
|
||||||
credentials: {
|
credentials: {
|
||||||
|
@ -74,6 +74,8 @@ module.exports = function(RED) {
|
|||||||
var opts = urllib.parse(url);
|
var opts = urllib.parse(url);
|
||||||
opts.method = method;
|
opts.method = method;
|
||||||
opts.headers = {};
|
opts.headers = {};
|
||||||
|
var ctSet = "Content-Type"; // set default camel case
|
||||||
|
var clSet = "Content-Length";
|
||||||
if (msg.headers) {
|
if (msg.headers) {
|
||||||
for (var v in msg.headers) {
|
for (var v in msg.headers) {
|
||||||
if (msg.headers.hasOwnProperty(v)) {
|
if (msg.headers.hasOwnProperty(v)) {
|
||||||
@ -83,6 +85,8 @@ module.exports = function(RED) {
|
|||||||
// function. Otherwise leave them alone.
|
// function. Otherwise leave them alone.
|
||||||
name = v;
|
name = v;
|
||||||
}
|
}
|
||||||
|
else if (name === 'content-type') { ctSet = v; }
|
||||||
|
else { clSet = v; }
|
||||||
opts.headers[name] = msg.headers[v];
|
opts.headers[name] = msg.headers[v];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,18 +107,27 @@ module.exports = function(RED) {
|
|||||||
} else {
|
} else {
|
||||||
payload = JSON.stringify(msg.payload);
|
payload = JSON.stringify(msg.payload);
|
||||||
if (opts.headers['content-type'] == null) {
|
if (opts.headers['content-type'] == null) {
|
||||||
opts.headers['content-type'] = "application/json";
|
opts.headers[ctSet] = "application/json";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opts.headers['content-length'] == null) {
|
if (opts.headers['content-length'] == null) {
|
||||||
if (Buffer.isBuffer(payload)) {
|
if (Buffer.isBuffer(payload)) {
|
||||||
opts.headers['content-length'] = payload.length;
|
opts.headers[clSet] = payload.length;
|
||||||
} else {
|
} else {
|
||||||
opts.headers['content-length'] = Buffer.byteLength(payload);
|
opts.headers[clSet] = Buffer.byteLength(payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// revert to user supplied Capitalisation if needed.
|
||||||
|
if (opts.headers.hasOwnProperty('content-type') && (ctSet !== 'content-type')) {
|
||||||
|
opts.headers[ctSet] = opts.headers['content-type'];
|
||||||
|
delete opts.headers['content-type'];
|
||||||
|
}
|
||||||
|
if (opts.headers.hasOwnProperty('content-length') && (clSet !== 'content-length')) {
|
||||||
|
opts.headers[clSet] = opts.headers['content-length'];
|
||||||
|
delete opts.headers['content-length'];
|
||||||
|
}
|
||||||
var urltotest = url;
|
var urltotest = url;
|
||||||
var noproxy;
|
var noproxy;
|
||||||
if (noprox) {
|
if (noprox) {
|
||||||
@ -135,7 +148,6 @@ module.exports = function(RED) {
|
|||||||
opts.path = opts.pathname = path;
|
opts.path = opts.pathname = path;
|
||||||
opts.headers = heads;
|
opts.headers = heads;
|
||||||
opts.method = method;
|
opts.method = method;
|
||||||
//console.log(opts);
|
|
||||||
urltotest = match[0];
|
urltotest = match[0];
|
||||||
}
|
}
|
||||||
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
else { node.warn("Bad proxy url: "+process.env.http_proxy); }
|
||||||
|
@ -145,7 +145,7 @@
|
|||||||
RED.nodes.registerType('websocket-listener',{
|
RED.nodes.registerType('websocket-listener',{
|
||||||
category: 'config',
|
category: 'config',
|
||||||
defaults: {
|
defaults: {
|
||||||
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
|
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/),format:"filepath" },
|
||||||
wholemsg: {value:"false"}
|
wholemsg: {value:"false"}
|
||||||
},
|
},
|
||||||
inputs:0,
|
inputs:0,
|
||||||
@ -179,7 +179,7 @@
|
|||||||
RED.nodes.registerType('websocket-client',{
|
RED.nodes.registerType('websocket-client',{
|
||||||
category: 'config',
|
category: 'config',
|
||||||
defaults: {
|
defaults: {
|
||||||
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
|
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/),format:"filepath" },
|
||||||
wholemsg: {value:"false"}
|
wholemsg: {value:"false"}
|
||||||
},
|
},
|
||||||
inputs:0,
|
inputs:0,
|
||||||
@ -232,7 +232,7 @@
|
|||||||
<script type="text/x-red" data-template-name="websocket-listener">
|
<script type="text/x-red" data-template-name="websocket-listener">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
|
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
|
||||||
<input type="text" id="node-config-input-path" placeholder="/ws/example">
|
<div id="node-config-input-path" contenteditable="true" placeholder="/ws/example"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-wholemsg"> </label>
|
<label for="node-config-input-wholemsg"> </label>
|
||||||
@ -255,7 +255,7 @@
|
|||||||
<script type="text/x-red" data-template-name="websocket-client">
|
<script type="text/x-red" data-template-name="websocket-client">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
|
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
|
||||||
<input type="text" id="node-config-input-path" placeholder="ws://example.com/ws">
|
<div id="node-config-input-path" contenteditable="true" placeholder="ws://example.com/ws"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-config-input-wholemsg"> </label>
|
<label for="node-config-input-wholemsg"> </label>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<script type="text/x-red" data-template-name="watch">
|
<script type="text/x-red" data-template-name="watch">
|
||||||
<div class="form-row node-input-filename">
|
<div class="form-row node-input-filename">
|
||||||
<label for="node-input-files"><i class="fa fa-file"></i> <span data-i18n="watch.label.files"></span></label>
|
<label for="node-input-files"><i class="fa fa-file"></i> <span data-i18n="watch.label.files"></span></label>
|
||||||
<input type="text" id="node-input-files" data-i18n="[placeholder]watch.placeholder.files">
|
<div id="node-input-files" contenteditable="true" tabindex="1" data-i18n="[placeholder]watch.placeholder.files"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
||||||
@ -46,7 +46,7 @@
|
|||||||
category: 'advanced-input',
|
category: 'advanced-input',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
files: {value:"",required:true}
|
files: {value:"",required:true, format:"filepath"}
|
||||||
},
|
},
|
||||||
color:"BurlyWood",
|
color:"BurlyWood",
|
||||||
inputs:0,
|
inputs:0,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<script type="text/x-red" data-template-name="tail">
|
<script type="text/x-red" data-template-name="tail">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="tail.label.filename"></span></label>
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="tail.label.filename"></span></label>
|
||||||
<input type="text" id="node-input-filename">
|
<div id="node-input-filename" contenteditable="true"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-filetype"><i class="fa fa-file-text-o"></i> <span data-i18n="tail.label.type"></span></label>
|
<label for="node-input-filetype"><i class="fa fa-file-text-o"></i> <span data-i18n="tail.label.type"></span></label>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
name: {value:""},
|
name: {value:""},
|
||||||
filetype: {value:"text"},
|
filetype: {value:"text"},
|
||||||
split: {value:false},
|
split: {value:false},
|
||||||
filename: {value:"",required:true}
|
filename: {value:"",required:true,format:"filepath"}
|
||||||
},
|
},
|
||||||
color:"BurlyWood",
|
color:"BurlyWood",
|
||||||
inputs:0,
|
inputs:0,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<script type="text/x-red" data-template-name="file">
|
<script type="text/x-red" data-template-name="file">
|
||||||
<div class="form-row node-input-filename">
|
<div class="form-row node-input-filename">
|
||||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||||
<input type="text" id="node-input-filename">
|
<div id="node-input-filename" contenteditable="true"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
<script type="text/x-red" data-template-name="file in">
|
<script type="text/x-red" data-template-name="file in">
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
||||||
<input type="text" id="node-input-filename" data-i18n="[placeholder]file.label.filename">
|
<div id="node-input-filename" contenteditable="true" data-i18n="[placeholder]file.label.filename"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
||||||
@ -83,7 +83,7 @@
|
|||||||
category: 'storage-output',
|
category: 'storage-output',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:""},
|
filename: {value:"",format:"filepath"},
|
||||||
appendNewline: {value:true},
|
appendNewline: {value:true},
|
||||||
createDir: {value:false},
|
createDir: {value:false},
|
||||||
overwriteFile: {value:"false"}
|
overwriteFile: {value:"false"}
|
||||||
@ -115,7 +115,7 @@
|
|||||||
category: 'storage-input',
|
category: 'storage-input',
|
||||||
defaults: {
|
defaults: {
|
||||||
name: {value:""},
|
name: {value:""},
|
||||||
filename: {value:""},
|
filename: {value:"",format:"filepath"},
|
||||||
format: {value:"utf8"},
|
format: {value:"utf8"},
|
||||||
},
|
},
|
||||||
color:"BurlyWood",
|
color:"BurlyWood",
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
"node-red-node-rbe":"0.1.*"
|
"node-red-node-rbe":"0.1.*"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"node-red-node-serialport":"0.2.*",
|
"node-red-node-serialport":"0.3.*",
|
||||||
"bcrypt":"0.8.7"
|
"bcrypt":"0.8.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014, 2015 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -25,13 +25,23 @@ module.exports = {
|
|||||||
log = runtime.log;
|
log = runtime.log;
|
||||||
},
|
},
|
||||||
get: function(req,res) {
|
get: function(req,res) {
|
||||||
log.audit({event: "flows.get"},req);
|
var version = req.get("Node-RED-API-Version")||"v1";
|
||||||
|
if (version === "v1") {
|
||||||
|
log.audit({event: "flows.get",version:"v1"},req);
|
||||||
|
res.json(redNodes.getFlows().flows);
|
||||||
|
} else if (version === "v2") {
|
||||||
|
log.audit({event: "flows.get",version:"v2"},req);
|
||||||
res.json(redNodes.getFlows());
|
res.json(redNodes.getFlows());
|
||||||
|
} else {
|
||||||
|
log.audit({event: "flows.get",version:version,error:"bad_api_version"},req);
|
||||||
|
res.status(400).json({error:"bad_api_version"});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
post: function(req,res) {
|
post: function(req,res) {
|
||||||
|
var version = req.get("Node-RED-API-Version")||"v1";
|
||||||
var flows = req.body;
|
var flows = req.body;
|
||||||
var deploymentType = req.get("Node-RED-Deployment-Type")||"full";
|
var deploymentType = req.get("Node-RED-Deployment-Type")||"full";
|
||||||
log.audit({event: "flows.set",type:deploymentType},req);
|
log.audit({event: "flows.set",type:deploymentType,version:version},req);
|
||||||
if (deploymentType === 'reload') {
|
if (deploymentType === 'reload') {
|
||||||
redNodes.loadFlows().then(function() {
|
redNodes.loadFlows().then(function() {
|
||||||
res.status(204).end();
|
res.status(204).end();
|
||||||
@ -41,8 +51,28 @@ module.exports = {
|
|||||||
res.status(500).json({error:"unexpected_error", message:err.message});
|
res.status(500).json({error:"unexpected_error", message:err.message});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
redNodes.setFlows(flows,deploymentType).then(function() {
|
var flowConfig = flows;
|
||||||
|
if (version === "v2") {
|
||||||
|
flowConfig = flows.flows;
|
||||||
|
if (flows.hasOwnProperty('rev')) {
|
||||||
|
var currentVersion = redNodes.getFlows().rev;
|
||||||
|
if (currentVersion !== flows.rev) {
|
||||||
|
//TODO: log warning
|
||||||
|
return res.status(409).json({error:"version_mismatch"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (version !== 'v1') {
|
||||||
|
log.audit({event: "flows.set",version:version,error:"bad_api_version"},req);
|
||||||
|
return res.status(400).json({error:"bad_api_version"});
|
||||||
|
}
|
||||||
|
redNodes.setFlows(flowConfig,deploymentType).then(function(flowId) {
|
||||||
|
if (version === "v1") {
|
||||||
res.status(204).end();
|
res.status(204).end();
|
||||||
|
} else if (version === "v2") {
|
||||||
|
res.json({rev:flowId});
|
||||||
|
} else {
|
||||||
|
// TODO: invalid version
|
||||||
|
}
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
log.warn(log._("api.flows.error-save",{message:err.message}));
|
log.warn(log._("api.flows.error-save",{message:err.message}));
|
||||||
log.warn(err.stack);
|
log.warn(err.stack);
|
||||||
|
@ -25,7 +25,12 @@
|
|||||||
"view": {
|
"view": {
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"showGrid": "Show grid",
|
"showGrid": "Show grid",
|
||||||
"snapGrid": "Snap to grid"
|
"snapGrid": "Snap to grid",
|
||||||
|
"textDir": "Text Direction",
|
||||||
|
"defaultDir": "Default",
|
||||||
|
"ltr": "Left-to-right",
|
||||||
|
"rtl": "Right-to-left",
|
||||||
|
"auto": "Contextual"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"show": "Show sidebar"
|
"show": "Show sidebar"
|
||||||
@ -34,6 +39,7 @@
|
|||||||
"displayConfig": "Configuration nodes",
|
"displayConfig": "Configuration nodes",
|
||||||
"import": "Import",
|
"import": "Import",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
|
"search": "Search flows",
|
||||||
"clipboard": "Clipboard",
|
"clipboard": "Clipboard",
|
||||||
"library": "Library",
|
"library": "Library",
|
||||||
"examples": "Examples",
|
"examples": "Examples",
|
||||||
@ -44,9 +50,10 @@
|
|||||||
"add": "Add",
|
"add": "Add",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"keyboardShortcuts": "Keyboard Shortcuts",
|
"keyboardShortcuts": "Keyboard shortcuts",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Logout"
|
"logout": "Logout",
|
||||||
|
"editPalette":"Manage palette"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
@ -72,16 +79,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"clipboard": {
|
"clipboard": {
|
||||||
"nodes": "Nodes:",
|
"nodes": "Nodes",
|
||||||
"selectNodes": "Select the text above and copy to the clipboard.",
|
"selectNodes": "Select the text above and copy to the clipboard.",
|
||||||
"pasteNodes": "Paste nodes here",
|
"pasteNodes": "Paste nodes here",
|
||||||
"importNodes": "Import nodes",
|
"importNodes": "Import nodes",
|
||||||
"exportNodes": "Export nodes to clipboard",
|
"exportNodes": "Export nodes to clipboard",
|
||||||
"importUnrecognised": "Imported unrecognised type:",
|
"importUnrecognised": "Imported unrecognised type:",
|
||||||
"importUnrecognised_plural": "Imported unrecognised types:",
|
"importUnrecognised_plural": "Imported unrecognised types:",
|
||||||
|
"nodesExported": "Nodes exported to clipboard",
|
||||||
"nodeCopied": "__count__ node copied",
|
"nodeCopied": "__count__ node copied",
|
||||||
"nodeCopied_plural": "__count__ nodes copied",
|
"nodeCopied_plural": "__count__ nodes copied",
|
||||||
"invalidFlow": "Invalid flow: __message__"
|
"invalidFlow": "Invalid flow: __message__",
|
||||||
|
"export": {
|
||||||
|
"selected":"selected nodes",
|
||||||
|
"current":"current flow",
|
||||||
|
"all":"all flows",
|
||||||
|
"compact":"compact",
|
||||||
|
"formatted":"formatted",
|
||||||
|
"copy": "Export to clipboard"
|
||||||
|
},
|
||||||
|
"import": {
|
||||||
|
"import": "Import to",
|
||||||
|
"newFlow": "new flow"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"deploy": {
|
"deploy": {
|
||||||
"deploy": "Deploy",
|
"deploy": "Deploy",
|
||||||
@ -101,12 +121,15 @@
|
|||||||
"confirm": {
|
"confirm": {
|
||||||
"button": {
|
"button": {
|
||||||
"confirm": "Confirm deploy",
|
"confirm": "Confirm deploy",
|
||||||
"cancel": "Cancel"
|
"review": "Review differences",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"merge": "Merge changes"
|
||||||
},
|
},
|
||||||
"undeployedChanges": "You have undeployed changes.\n\nLeaving this page will lose these changes.",
|
"undeployedChanges": "You have undeployed changes.\n\nLeaving this page will lose these changes.",
|
||||||
"improperlyConfigured": "The workspace contains some nodes that are not properly configured:",
|
"improperlyConfigured": "The workspace contains some nodes that are not properly configured:",
|
||||||
"unknown": "The workspace contains some unknown node types:",
|
"unknown": "The workspace contains some unknown node types:",
|
||||||
"confirm": "Are you sure you want to deploy?"
|
"confirm": "Are you sure you want to deploy?",
|
||||||
|
"conflict": "The server is running a more recent set of flows."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"subflow": {
|
"subflow": {
|
||||||
@ -146,7 +169,7 @@
|
|||||||
"addRemoveNode": "Add/remove node from selection",
|
"addRemoveNode": "Add/remove node from selection",
|
||||||
"deleteSelected": "Delete selected nodes or link",
|
"deleteSelected": "Delete selected nodes or link",
|
||||||
"importNode": "Import nodes",
|
"importNode": "Import nodes",
|
||||||
"exportNode": "Export selected nodes",
|
"exportNode": "Export nodes",
|
||||||
"nudgeNode": "Move selected node(s) by a small amount",
|
"nudgeNode": "Move selected node(s) by a small amount",
|
||||||
"moveNode": "Move selected node(s) by a large amount",
|
"moveNode": "Move selected node(s) by a large amount",
|
||||||
"toggleSidebar": "Toggle sidebar",
|
"toggleSidebar": "Toggle sidebar",
|
||||||
@ -154,7 +177,8 @@
|
|||||||
"copyNode": "Copy selected nodes",
|
"copyNode": "Copy selected nodes",
|
||||||
"cutNode": "Cut selected nodes",
|
"cutNode": "Cut selected nodes",
|
||||||
"pasteNode": "Paste nodes",
|
"pasteNode": "Paste nodes",
|
||||||
"undoChange": "Undo the last change performed"
|
"undoChange": "Undo the last change performed",
|
||||||
|
"searchBox": "Open search box"
|
||||||
},
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"openLibrary": "Open Library...",
|
"openLibrary": "Open Library...",
|
||||||
@ -180,6 +204,7 @@
|
|||||||
"palette": {
|
"palette": {
|
||||||
"noInfo": "no information available",
|
"noInfo": "no information available",
|
||||||
"filter": "filter nodes",
|
"filter": "filter nodes",
|
||||||
|
"search": "search modules",
|
||||||
"label": {
|
"label": {
|
||||||
"subflows": "subflows",
|
"subflows": "subflows",
|
||||||
"input": "input",
|
"input": "input",
|
||||||
@ -199,6 +224,50 @@
|
|||||||
"nodeEnabled_plural": "Nodes enabled:",
|
"nodeEnabled_plural": "Nodes enabled:",
|
||||||
"nodeDisabled": "Node disabled:",
|
"nodeDisabled": "Node disabled:",
|
||||||
"nodeDisabled_plural": "Nodes disabled:"
|
"nodeDisabled_plural": "Nodes disabled:"
|
||||||
|
},
|
||||||
|
"editor": {
|
||||||
|
"title": "Manage palette",
|
||||||
|
"times": {
|
||||||
|
"seconds": "seconds ago",
|
||||||
|
"minutes": "minutes ago",
|
||||||
|
"minutesV": "__count__ minutes ago",
|
||||||
|
"hoursV": "__count__ hour ago",
|
||||||
|
"hoursV_plural": "__count__ hours ago",
|
||||||
|
"daysV": "__count__ day ago",
|
||||||
|
"daysV_plural": "__count__ days ago",
|
||||||
|
"weeksV": "__count__ week ago",
|
||||||
|
"weeksV_plural": "__count__ weeks ago",
|
||||||
|
"monthsV": "__count__ month ago",
|
||||||
|
"monthsV_plural": "__count__ months ago",
|
||||||
|
"yearsV": "__count__ year ago",
|
||||||
|
"yearsV_plural": "__count__ years ago",
|
||||||
|
|
||||||
|
"yearMonthsV": "__y__ year, __count__ month ago",
|
||||||
|
"yearMonthsV_plural": "__y__ year, __count__ months ago",
|
||||||
|
"yearsMonthsV": "__y__ years, __count__ month ago",
|
||||||
|
"yearsMonthsV_plural": "__y__ years, __count__ months ago"
|
||||||
|
},
|
||||||
|
"nodeCount": "__label__ node",
|
||||||
|
"nodeCount_plural": "__label__ nodes",
|
||||||
|
"inuse": "in use",
|
||||||
|
"enableall": "enable all",
|
||||||
|
"disableall": "disable all",
|
||||||
|
"enable": "enable",
|
||||||
|
"disable": "disable",
|
||||||
|
"remove": "remove",
|
||||||
|
"install": "install",
|
||||||
|
"installed": "installed",
|
||||||
|
"loading": "Loading catalogues...",
|
||||||
|
"tab-nodes": "Nodes",
|
||||||
|
"tab-install": "Install",
|
||||||
|
"sort": "sort:",
|
||||||
|
"sortAZ": "a-z",
|
||||||
|
"sortRecent": "recent",
|
||||||
|
"more": "+ __count__ more",
|
||||||
|
"errors": {
|
||||||
|
"installFailed": "Failed to install: __module__<br>__message__<br>Check the log for more information"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
@ -218,13 +287,17 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"name": "Configuration nodes",
|
"name": "Configuration nodes",
|
||||||
"label": "config",
|
"label": "config",
|
||||||
"global": "Global",
|
"global": "On all flows",
|
||||||
"none": "none",
|
"none": "none",
|
||||||
"subflows": "subflows",
|
"subflows": "subflows",
|
||||||
"flows": "flows",
|
"flows": "flows",
|
||||||
"filterUnused":"unused",
|
"filterUnused":"unused",
|
||||||
"filterAll":"all",
|
"filterAll":"all",
|
||||||
"filtered": "__count__ hidden"
|
"filtered": "__count__ hidden"
|
||||||
|
},
|
||||||
|
"palette": {
|
||||||
|
"name": "Palette management",
|
||||||
|
"label": "palette"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typedInput": {
|
"typedInput": {
|
||||||
@ -239,5 +312,8 @@
|
|||||||
},
|
},
|
||||||
"editableList": {
|
"editableList": {
|
||||||
"add": "add"
|
"add": "add"
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"empty": "No matches found"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 IBM Corp.
|
* Copyright 2015, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -161,6 +161,9 @@ module.exports = {
|
|||||||
themeSettings.menu = theme.menu;
|
themeSettings.menu = theme.menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theme.hasOwnProperty("palette")) {
|
||||||
|
themeSettings.palette = theme.palette;
|
||||||
|
}
|
||||||
return themeApp;
|
return themeApp;
|
||||||
},
|
},
|
||||||
context: function() {
|
context: function() {
|
||||||
|
@ -83,7 +83,7 @@ function start() {
|
|||||||
.then(function() {
|
.then(function() {
|
||||||
return i18n.registerMessageCatalog("runtime",path.resolve(path.join(__dirname,"locales")),"runtime.json")
|
return i18n.registerMessageCatalog("runtime",path.resolve(path.join(__dirname,"locales")),"runtime.json")
|
||||||
})
|
})
|
||||||
.then(function() { return storage.init(settings)})
|
.then(function() { return storage.init(runtime)})
|
||||||
.then(function() { return settings.load(storage)})
|
.then(function() { return settings.load(storage)})
|
||||||
.then(function() {
|
.then(function() {
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"error":"Error loading credentials: __message__",
|
"error":"Error loading credentials: __message__",
|
||||||
|
"error-saving":"Error saving credentials: __message__",
|
||||||
"not-registered": "Credential type '__type__' is not registered"
|
"not-registered": "Credential type '__type__' is not registered"
|
||||||
},
|
},
|
||||||
"flows": {
|
"flows": {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014, 2015 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -15,26 +15,141 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
var when = require("when");
|
var when = require("when");
|
||||||
|
var crypto = require('crypto');
|
||||||
|
var settings;
|
||||||
|
var log;
|
||||||
|
|
||||||
var log = require("../log");
|
var encryptedCredentials = null;
|
||||||
|
|
||||||
var credentialCache = {};
|
var credentialCache = {};
|
||||||
var storage = null;
|
|
||||||
var credentialsDef = {};
|
var credentialsDef = {};
|
||||||
|
var dirty = false;
|
||||||
|
|
||||||
module.exports = {
|
var removeDefaultKey = false;
|
||||||
init: function (_storage) {
|
var encryptionEnabled = null;
|
||||||
storage = _storage;
|
var encryptionAlgorithm = "aes-256-ctr";
|
||||||
|
var encryptionKey;
|
||||||
|
|
||||||
|
function decryptCredentials(key,credentials) {
|
||||||
|
var creds = credentials["$"];
|
||||||
|
var initVector = new Buffer(creds.substring(0, 32),'hex');
|
||||||
|
creds = creds.substring(32);
|
||||||
|
var decipher = crypto.createDecipheriv(encryptionAlgorithm, key, initVector);
|
||||||
|
var decrypted = decipher.update(creds, 'base64', 'utf8') + decipher.final('utf8');
|
||||||
|
return JSON.parse(decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
var api = module.exports = {
|
||||||
|
init: function(runtime) {
|
||||||
|
log = runtime.log;
|
||||||
|
settings = runtime.settings;
|
||||||
|
dirty = false;
|
||||||
|
credentialCache = {};
|
||||||
|
credentialsDef = {};
|
||||||
|
encryptionEnabled = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the credentials from storage.
|
* Sets the credentials from storage.
|
||||||
*/
|
*/
|
||||||
load: function () {
|
load: function (credentials) {
|
||||||
return storage.getCredentials().then(function (creds) {
|
dirty = false;
|
||||||
credentialCache = creds;
|
/*
|
||||||
}).otherwise(function (err) {
|
- if encryptionEnabled === null, check the current configuration
|
||||||
log.warn(log._("nodes.credentials.error",{message: err}));
|
*/
|
||||||
|
var credentialsEncrypted = credentials.hasOwnProperty("$") && Object.keys(credentials).length === 1;
|
||||||
|
var setupEncryptionPromise = when.resolve();
|
||||||
|
if (encryptionEnabled === null) {
|
||||||
|
var defaultKey;
|
||||||
|
try {
|
||||||
|
defaultKey = settings.get('_credentialSecret');
|
||||||
|
} catch(err) {
|
||||||
|
}
|
||||||
|
if (defaultKey) {
|
||||||
|
defaultKey = crypto.createHash('sha256').update(defaultKey).digest();
|
||||||
|
}
|
||||||
|
var userKey;
|
||||||
|
try {
|
||||||
|
userKey = settings.get('credentialSecret');
|
||||||
|
} catch(err) {
|
||||||
|
userKey = false;
|
||||||
|
}
|
||||||
|
if (userKey === false) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : user disabled encryption");
|
||||||
|
// User has disabled encryption
|
||||||
|
encryptionEnabled = false;
|
||||||
|
// Check if we have a generated _credSecret to decrypt with and remove
|
||||||
|
if (defaultKey) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : default key present. Will migrate");
|
||||||
|
if (credentialsEncrypted) {
|
||||||
|
try {
|
||||||
|
credentials = decryptCredentials(defaultKey,credentials)
|
||||||
|
} catch(err) {
|
||||||
|
credentials = {};
|
||||||
|
log.warn(log._("nodes.credentials.error",{message:err.toString()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty = true;
|
||||||
|
removeDefaultKey = true;
|
||||||
|
}
|
||||||
|
} else if (typeof userKey === 'string') {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : user provided key");
|
||||||
|
// User has provided own encryption key, get the 32-byte hash of it
|
||||||
|
encryptionKey = crypto.createHash('sha256').update(userKey).digest();
|
||||||
|
encryptionEnabled = true;
|
||||||
|
|
||||||
|
if (defaultKey) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : default key present. Will migrate");
|
||||||
|
// User has provided their own key, but we already have a default key
|
||||||
|
// Decrypt using default key
|
||||||
|
if (credentialsEncrypted) {
|
||||||
|
try {
|
||||||
|
credentials = decryptCredentials(defaultKey,credentials)
|
||||||
|
} catch(err) {
|
||||||
|
credentials = {};
|
||||||
|
log.warn(log._("nodes.credentials.error",{message:err.toString()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty = true;
|
||||||
|
removeDefaultKey = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : no user key present");
|
||||||
|
// User has not provide their own key
|
||||||
|
encryptionKey = defaultKey;
|
||||||
|
encryptionEnabled = true;
|
||||||
|
if (encryptionKey === undefined) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : no default key present - generating one");
|
||||||
|
// No user-provided key, no generated key
|
||||||
|
// Generate a new key
|
||||||
|
defaultKey = crypto.randomBytes(32).toString('hex');
|
||||||
|
try {
|
||||||
|
setupEncryptionPromise = settings.set('_credentialSecret',defaultKey);
|
||||||
|
encryptionKey = crypto.createHash('sha256').update(defaultKey).digest();
|
||||||
|
} catch(err) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : settings unavailable - disabling encryption");
|
||||||
|
// Settings unavailable
|
||||||
|
encryptionEnabled = false;
|
||||||
|
encryptionKey = null;
|
||||||
|
}
|
||||||
|
dirty = true;
|
||||||
|
} else {
|
||||||
|
log.debug("red/runtime/nodes/credentials.load : using default key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setupEncryptionPromise.then(function() {
|
||||||
|
if (credentials.hasOwnProperty("$")) {
|
||||||
|
// These are encrypted credentials
|
||||||
|
try {
|
||||||
|
credentialCache = decryptCredentials(encryptionKey,credentials)
|
||||||
|
} catch(err) {
|
||||||
|
credentialCache = {};
|
||||||
|
dirty = true;
|
||||||
|
log.warn(log._("nodes.credentials.error",{message:err.toString()}))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
credentialCache = credentials;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -42,11 +157,12 @@ module.exports = {
|
|||||||
* Adds a set of credentials for the given node id.
|
* Adds a set of credentials for the given node id.
|
||||||
* @param id the node id for the credentials
|
* @param id the node id for the credentials
|
||||||
* @param creds an object of credential key/value pairs
|
* @param creds an object of credential key/value pairs
|
||||||
* @return a promise for the saving of credentials to storage
|
* @return a promise for backwards compatibility TODO: can this be removed?
|
||||||
*/
|
*/
|
||||||
add: function (id, creds) {
|
add: function (id, creds) {
|
||||||
credentialCache[id] = creds;
|
credentialCache[id] = creds;
|
||||||
return storage.saveCredentials(credentialCache);
|
dirty = true;
|
||||||
|
return when.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +181,7 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
delete: function (id) {
|
delete: function (id) {
|
||||||
delete credentialCache[id];
|
delete credentialCache[id];
|
||||||
storage.saveCredentials(credentialCache);
|
dirty = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,6 +193,9 @@ module.exports = {
|
|||||||
var existingIds = {};
|
var existingIds = {};
|
||||||
config.forEach(function(n) {
|
config.forEach(function(n) {
|
||||||
existingIds[n.id] = true;
|
existingIds[n.id] = true;
|
||||||
|
if (n.credentials) {
|
||||||
|
api.extract(n);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
var deletedCredentials = false;
|
var deletedCredentials = false;
|
||||||
for (var c in credentialCache) {
|
for (var c in credentialCache) {
|
||||||
@ -88,10 +207,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (deletedCredentials) {
|
if (deletedCredentials) {
|
||||||
return storage.saveCredentials(credentialCache);
|
dirty = true;
|
||||||
} else {
|
|
||||||
return when.resolve();
|
|
||||||
}
|
}
|
||||||
|
return when.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,17 +264,10 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
credentialCache[nodeID] = savedCredentials;
|
credentialCache[nodeID] = savedCredentials;
|
||||||
|
dirty = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the credentials to storage
|
|
||||||
* @return a promise for the saving of credentials to storage
|
|
||||||
*/
|
|
||||||
save: function () {
|
|
||||||
return storage.saveCredentials(credentialCache);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the credential definition for the given node type
|
* Gets the credential definition for the given node type
|
||||||
* @param type the node type
|
* @param type the node type
|
||||||
@ -164,5 +275,33 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
getDefinition: function (type) {
|
getDefinition: function (type) {
|
||||||
return credentialsDef[type];
|
return credentialsDef[type];
|
||||||
|
},
|
||||||
|
|
||||||
|
dirty: function() {
|
||||||
|
return dirty;
|
||||||
|
},
|
||||||
|
|
||||||
|
export: function() {
|
||||||
|
var result = credentialCache;
|
||||||
|
if (dirty && encryptionEnabled) {
|
||||||
|
try {
|
||||||
|
log.debug("red/runtime/nodes/credentials.export : encrypting");
|
||||||
|
var initVector = crypto.randomBytes(16);
|
||||||
|
var cipher = crypto.createCipheriv(encryptionAlgorithm, encryptionKey, initVector);
|
||||||
|
result = {"$":initVector.toString('hex') + cipher.update(JSON.stringify(credentialCache), 'utf8', 'base64') + cipher.final('base64')};
|
||||||
|
} catch(err) {
|
||||||
|
log.warn(log._("nodes.credentials.error-saving",{message:err.toString()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirty = false;
|
||||||
|
if (removeDefaultKey) {
|
||||||
|
log.debug("red/runtime/nodes/credentials.export : removing unused default key");
|
||||||
|
return settings.delete('_credentialSecret').then(function() {
|
||||||
|
removeDefaultKey = false;
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return when.resolve(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,12 @@ var subflowInstanceNodeMap = {};
|
|||||||
|
|
||||||
var typeEventRegistered = false;
|
var typeEventRegistered = false;
|
||||||
|
|
||||||
function init(_settings, _storage) {
|
function init(runtime) {
|
||||||
if (started) {
|
if (started) {
|
||||||
throw new Error("Cannot init without a stop");
|
throw new Error("Cannot init without a stop");
|
||||||
}
|
}
|
||||||
settings = _settings;
|
settings = runtime.settings;
|
||||||
storage = _storage;
|
storage = runtime.storage;
|
||||||
started = false;
|
started = false;
|
||||||
if (!typeEventRegistered) {
|
if (!typeEventRegistered) {
|
||||||
events.on('type-registered',function(type) {
|
events.on('type-registered',function(type) {
|
||||||
@ -66,64 +66,75 @@ function init(_settings, _storage) {
|
|||||||
typeEventRegistered = true;
|
typeEventRegistered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function load() {
|
|
||||||
return storage.getFlows().then(function(flows) {
|
function loadFlows() {
|
||||||
return credentials.load().then(function() {
|
return storage.getFlows().then(function(config) {
|
||||||
return setConfig(flows,"load");
|
return credentials.load(config.credentials).then(function() {
|
||||||
|
return config;
|
||||||
});
|
});
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
log.warn(log._("nodes.flows.error",{message:err.toString()}));
|
log.warn(log._("nodes.flows.error",{message:err.toString()}));
|
||||||
console.log(err.stack);
|
console.log(err.stack);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function load() {
|
||||||
|
return setFlows(null,"load",false);
|
||||||
|
}
|
||||||
|
|
||||||
function setConfig(_config,type,muteLog) {
|
/*
|
||||||
var config = clone(_config);
|
* _config - new node array configuration
|
||||||
|
* type - full/nodes/flows/load (default full)
|
||||||
|
* muteLog - don't emit the standard log messages (used for individual flow api)
|
||||||
|
*/
|
||||||
|
function setFlows(_config,type,muteLog) {
|
||||||
type = type||"full";
|
type = type||"full";
|
||||||
|
|
||||||
var credentialsChanged = false;
|
|
||||||
var credentialSavePromise = null;
|
|
||||||
var configSavePromise = null;
|
var configSavePromise = null;
|
||||||
|
var config = null;
|
||||||
var diff;
|
var diff;
|
||||||
var newFlowConfig = flowUtil.parseConfig(clone(config));
|
var newFlowConfig;
|
||||||
if (type !== 'full' && type !== 'load') {
|
|
||||||
|
if (type === "load") {
|
||||||
|
configSavePromise = loadFlows().then(function(_config) {
|
||||||
|
config = clone(_config.flows);
|
||||||
|
newFlowConfig = flowUtil.parseConfig(clone(config));
|
||||||
|
type = "full";
|
||||||
|
return _config.rev;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
config = clone(_config);
|
||||||
|
newFlowConfig = flowUtil.parseConfig(clone(config));
|
||||||
|
if (type !== 'full') {
|
||||||
diff = flowUtil.diffConfigs(activeFlowConfig,newFlowConfig);
|
diff = flowUtil.diffConfigs(activeFlowConfig,newFlowConfig);
|
||||||
}
|
}
|
||||||
config.forEach(function(node) {
|
credentials.clean(config);
|
||||||
if (node.credentials) {
|
var credsDirty = credentials.dirty();
|
||||||
credentials.extract(node);
|
configSavePromise = credentials.export().then(function(creds) {
|
||||||
credentialsChanged = true;
|
var saveConfig = {
|
||||||
|
flows: config,
|
||||||
|
credentialsDirty:credsDirty,
|
||||||
|
credentials: creds
|
||||||
}
|
}
|
||||||
});
|
return storage.saveFlows(saveConfig);
|
||||||
if (credentialsChanged) {
|
|
||||||
credentialSavePromise = credentials.save();
|
|
||||||
} else {
|
|
||||||
credentialSavePromise = when.resolve();
|
|
||||||
}
|
|
||||||
if (type === 'load') {
|
|
||||||
configSavePromise = credentialSavePromise;
|
|
||||||
type = 'full';
|
|
||||||
} else {
|
|
||||||
configSavePromise = credentialSavePromise.then(function() {
|
|
||||||
return storage.saveFlows(config);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return configSavePromise
|
return configSavePromise
|
||||||
.then(function() {
|
.then(function(flowRevision) {
|
||||||
activeConfig = config;
|
activeConfig = {
|
||||||
|
flows:config,
|
||||||
|
rev:flowRevision
|
||||||
|
};
|
||||||
activeFlowConfig = newFlowConfig;
|
activeFlowConfig = newFlowConfig;
|
||||||
return credentials.clean(activeConfig).then(function() {
|
|
||||||
if (started) {
|
if (started) {
|
||||||
return stop(type,diff,muteLog).then(function() {
|
return stop(type,diff,muteLog).then(function() {
|
||||||
context.clean(activeFlowConfig);
|
context.clean(activeFlowConfig);
|
||||||
start(type,diff,muteLog);
|
start(type,diff,muteLog);
|
||||||
|
return flowRevision;
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNode(id) {
|
function getNode(id) {
|
||||||
@ -150,7 +161,7 @@ function eachNode(cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConfig() {
|
function getFlows() {
|
||||||
return activeConfig;
|
return activeConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +359,8 @@ function checkTypeInUse(id) {
|
|||||||
throw new Error(log._("nodes.index.unrecognised-id", {id:id}));
|
throw new Error(log._("nodes.index.unrecognised-id", {id:id}));
|
||||||
} else {
|
} else {
|
||||||
var inUse = {};
|
var inUse = {};
|
||||||
var config = getConfig();
|
var config = getFlows();
|
||||||
config.forEach(function(n) {
|
config.flows.forEach(function(n) {
|
||||||
inUse[n.type] = (inUse[n.type]||0)+1;
|
inUse[n.type] = (inUse[n.type]||0)+1;
|
||||||
});
|
});
|
||||||
var nodesInUse = [];
|
var nodesInUse = [];
|
||||||
@ -425,10 +436,10 @@ function addFlow(flow) {
|
|||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newConfig = clone(activeConfig);
|
var newConfig = clone(activeConfig.flows);
|
||||||
newConfig = newConfig.concat(nodes);
|
newConfig = newConfig.concat(nodes);
|
||||||
|
|
||||||
return setConfig(newConfig,'flows',true).then(function() {
|
return setFlows(newConfig,'flows',true).then(function() {
|
||||||
log.info(log._("nodes.flows.added-flow",{label:(flow.label?flow.label+" ":"")+"["+flow.id+"]"}));
|
log.info(log._("nodes.flows.added-flow",{label:(flow.label?flow.label+" ":"")+"["+flow.id+"]"}));
|
||||||
return flow.id;
|
return flow.id;
|
||||||
});
|
});
|
||||||
@ -508,7 +519,7 @@ function updateFlow(id,newFlow) {
|
|||||||
}
|
}
|
||||||
label = activeFlowConfig.flows[id].label;
|
label = activeFlowConfig.flows[id].label;
|
||||||
}
|
}
|
||||||
var newConfig = clone(activeConfig);
|
var newConfig = clone(activeConfig.flows);
|
||||||
var nodes;
|
var nodes;
|
||||||
|
|
||||||
if (id === 'global') {
|
if (id === 'global') {
|
||||||
@ -546,7 +557,7 @@ function updateFlow(id,newFlow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newConfig = newConfig.concat(nodes);
|
newConfig = newConfig.concat(nodes);
|
||||||
return setConfig(newConfig,'flows',true).then(function() {
|
return setFlows(newConfig,'flows',true).then(function() {
|
||||||
log.info(log._("nodes.flows.updated-flow",{label:(label?label+" ":"")+"["+id+"]"}));
|
log.info(log._("nodes.flows.updated-flow",{label:(label?label+" ":"")+"["+id+"]"}));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -563,12 +574,12 @@ function removeFlow(id) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newConfig = clone(activeConfig);
|
var newConfig = clone(activeConfig.flows);
|
||||||
newConfig = newConfig.filter(function(node) {
|
newConfig = newConfig.filter(function(node) {
|
||||||
return node.z !== id && node.id !== id;
|
return node.z !== id && node.id !== id;
|
||||||
});
|
});
|
||||||
|
|
||||||
return setConfig(newConfig,'flows',true).then(function() {
|
return setFlows(newConfig,'flows',true).then(function() {
|
||||||
log.info(log._("nodes.flows.removed-flow",{label:(flow.label?flow.label+" ":"")+"["+flow.id+"]"}));
|
log.info(log._("nodes.flows.removed-flow",{label:(flow.label?flow.label+" ":"")+"["+flow.id+"]"}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -588,7 +599,7 @@ module.exports = {
|
|||||||
/**
|
/**
|
||||||
* Gets the current flow configuration
|
* Gets the current flow configuration
|
||||||
*/
|
*/
|
||||||
getFlows: getConfig,
|
getFlows: getFlows,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current active config.
|
* Sets the current active config.
|
||||||
@ -596,7 +607,7 @@ module.exports = {
|
|||||||
* @param type the type of deployment to do: full (default), nodes, flows, load
|
* @param type the type of deployment to do: full (default), nodes, flows, load
|
||||||
* @return a promise for the saving/starting of the new flow
|
* @return a promise for the saving/starting of the new flow
|
||||||
*/
|
*/
|
||||||
setFlows: setConfig,
|
setFlows: setFlows,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the current flow configuration
|
* Starts the current flow configuration
|
||||||
|
@ -77,8 +77,8 @@ function createNode(node,def) {
|
|||||||
|
|
||||||
function init(runtime) {
|
function init(runtime) {
|
||||||
settings = runtime.settings;
|
settings = runtime.settings;
|
||||||
credentials.init(runtime.storage);
|
credentials.init(runtime);
|
||||||
flows.init(runtime.settings,runtime.storage);
|
flows.init(runtime);
|
||||||
registry.init(runtime);
|
registry.init(runtime);
|
||||||
context.init(runtime.settings);
|
context.init(runtime.settings);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,8 @@ function loadNodeConfig(fileInfo) {
|
|||||||
template: file.replace(/\.js$/,".html"),
|
template: file.replace(/\.js$/,".html"),
|
||||||
enabled: isEnabled,
|
enabled: isEnabled,
|
||||||
loaded:false,
|
loaded:false,
|
||||||
version: version
|
version: version,
|
||||||
|
local: fileInfo.local
|
||||||
};
|
};
|
||||||
if (fileInfo.hasOwnProperty("types")) {
|
if (fileInfo.hasOwnProperty("types")) {
|
||||||
node.types = fileInfo.types;
|
node.types = fileInfo.types;
|
||||||
|
@ -141,7 +141,8 @@ function scanTreeForNodesModules(moduleName) {
|
|||||||
|
|
||||||
if (settings.userDir) {
|
if (settings.userDir) {
|
||||||
userDir = path.join(settings.userDir,"node_modules");
|
userDir = path.join(settings.userDir,"node_modules");
|
||||||
results = results.concat(scanDirForNodesModules(userDir,moduleName));
|
results = scanDirForNodesModules(userDir,moduleName);
|
||||||
|
results.forEach(function(r) { r.local = true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir) {
|
if (dir) {
|
||||||
@ -240,12 +241,14 @@ function getNodeFiles(disableNodePathScan) {
|
|||||||
nodeList[moduleFile.package.name] = {
|
nodeList[moduleFile.package.name] = {
|
||||||
name: moduleFile.package.name,
|
name: moduleFile.package.name,
|
||||||
version: moduleFile.package.version,
|
version: moduleFile.package.version,
|
||||||
|
local: moduleFile.local||false,
|
||||||
nodes: {}
|
nodes: {}
|
||||||
};
|
};
|
||||||
if (moduleFile.package['node-red'].version) {
|
if (moduleFile.package['node-red'].version) {
|
||||||
nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
|
nodeList[moduleFile.package.name].redVersion = moduleFile.package['node-red'].version;
|
||||||
}
|
}
|
||||||
nodeModuleFiles.forEach(function(node) {
|
nodeModuleFiles.forEach(function(node) {
|
||||||
|
node.local = moduleFile.local||false;
|
||||||
nodeList[moduleFile.package.name].nodes[node.name] = node;
|
nodeList[moduleFile.package.name].nodes[node.name] = node;
|
||||||
});
|
});
|
||||||
nodeFiles = nodeFiles.concat(nodeModuleFiles);
|
nodeFiles = nodeFiles.concat(nodeModuleFiles);
|
||||||
|
@ -56,7 +56,8 @@ function filterNodeInfo(n) {
|
|||||||
id: n.id||n.module+"/"+n.name,
|
id: n.id||n.module+"/"+n.name,
|
||||||
name: n.name,
|
name: n.name,
|
||||||
types: n.types,
|
types: n.types,
|
||||||
enabled: n.enabled
|
enabled: n.enabled,
|
||||||
|
local: n.local||false
|
||||||
};
|
};
|
||||||
if (n.hasOwnProperty("module")) {
|
if (n.hasOwnProperty("module")) {
|
||||||
r.module = n.module;
|
r.module = n.module;
|
||||||
@ -90,6 +91,7 @@ function saveNodeList() {
|
|||||||
moduleList[module] = {
|
moduleList[module] = {
|
||||||
name: module,
|
name: module,
|
||||||
version: moduleConfigs[module].version,
|
version: moduleConfigs[module].version,
|
||||||
|
local: moduleConfigs[module].local||false,
|
||||||
nodes: {}
|
nodes: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -179,6 +181,7 @@ function addNodeSet(id,set,version) {
|
|||||||
if (version) {
|
if (version) {
|
||||||
moduleConfigs[set.module].version = version;
|
moduleConfigs[set.module].version = version;
|
||||||
}
|
}
|
||||||
|
moduleConfigs[set.module].local = set.local;
|
||||||
|
|
||||||
moduleConfigs[set.module].nodes[set.name] = set;
|
moduleConfigs[set.module].nodes[set.name] = set;
|
||||||
nodeList.push(id);
|
nodeList.push(id);
|
||||||
@ -306,6 +309,7 @@ function getModuleInfo(module) {
|
|||||||
var m = {
|
var m = {
|
||||||
name: module,
|
name: module,
|
||||||
version: moduleConfigs[module].version,
|
version: moduleConfigs[module].version,
|
||||||
|
local: moduleConfigs[module].local,
|
||||||
nodes: []
|
nodes: []
|
||||||
};
|
};
|
||||||
for (var i = 0; i < nodes.length; ++i) {
|
for (var i = 0; i < nodes.length; ++i) {
|
||||||
|
@ -71,6 +71,19 @@ var persistentSettings = {
|
|||||||
return storage.saveSettings(globalSettings);
|
return storage.saveSettings(globalSettings);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
delete: function(prop) {
|
||||||
|
if (userSettings.hasOwnProperty(prop)) {
|
||||||
|
throw new Error(log._("settings.property-read-only", {prop:prop}));
|
||||||
|
}
|
||||||
|
if (globalSettings === null) {
|
||||||
|
throw new Error(log._("settings.not-available"));
|
||||||
|
}
|
||||||
|
if (globalSettings.hasOwnProperty(prop)) {
|
||||||
|
delete globalSettings[prop];
|
||||||
|
return storage.saveSettings(globalSettings);
|
||||||
|
}
|
||||||
|
return when.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
available: function() {
|
available: function() {
|
||||||
return (globalSettings !== null);
|
return (globalSettings !== null);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2013, 2015 IBM Corp.
|
* Copyright 2013, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
var when = require('when');
|
var when = require('when');
|
||||||
var Path = require('path');
|
var Path = require('path');
|
||||||
|
var crypto = require('crypto');
|
||||||
|
|
||||||
var log = require("../log");
|
var log = require("../log");
|
||||||
|
|
||||||
|
var runtime;
|
||||||
var storageModule;
|
var storageModule;
|
||||||
var settingsAvailable;
|
var settingsAvailable;
|
||||||
var sessionsAvailable;
|
var sessionsAvailable;
|
||||||
@ -42,28 +45,52 @@ function is_malicious(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var storageModuleInterface = {
|
var storageModuleInterface = {
|
||||||
init: function(settings) {
|
init: function(_runtime) {
|
||||||
|
runtime = _runtime;
|
||||||
try {
|
try {
|
||||||
storageModule = moduleSelector(settings);
|
storageModule = moduleSelector(runtime.settings);
|
||||||
settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings");
|
settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings");
|
||||||
sessionsAvailable = storageModule.hasOwnProperty("getSessions") && storageModule.hasOwnProperty("saveSessions");
|
sessionsAvailable = storageModule.hasOwnProperty("getSessions") && storageModule.hasOwnProperty("saveSessions");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return when.reject(e);
|
return when.reject(e);
|
||||||
}
|
}
|
||||||
return storageModule.init(settings);
|
return storageModule.init(runtime.settings);
|
||||||
},
|
},
|
||||||
getFlows: function() {
|
getFlows: function() {
|
||||||
return storageModule.getFlows();
|
return storageModule.getFlows().then(function(flows) {
|
||||||
|
return storageModule.getCredentials().then(function(creds) {
|
||||||
|
var result = {
|
||||||
|
flows: flows,
|
||||||
|
credentials: creds
|
||||||
|
};
|
||||||
|
result.rev = crypto.createHash('md5').update(JSON.stringify(result)).digest("hex");
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
});
|
||||||
},
|
},
|
||||||
saveFlows: function(flows) {
|
saveFlows: function(config) {
|
||||||
return storageModule.saveFlows(flows);
|
var flows = config.flows;
|
||||||
},
|
var credentials = config.credentials;
|
||||||
getCredentials: function() {
|
var credentialSavePromise;
|
||||||
return storageModule.getCredentials();
|
if (config.credentialsDirty) {
|
||||||
},
|
credentialSavePromise = storageModule.saveCredentials(credentials);
|
||||||
saveCredentials: function(credentials) {
|
} else {
|
||||||
return storageModule.saveCredentials(credentials);
|
credentialSavePromise = when.resolve();
|
||||||
|
}
|
||||||
|
delete config.credentialsDirty;
|
||||||
|
|
||||||
|
return credentialSavePromise.then(function() {
|
||||||
|
return storageModule.saveFlows(flows).then(function() {
|
||||||
|
return crypto.createHash('md5').update(JSON.stringify(config)).digest("hex");
|
||||||
|
})
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
// getCredentials: function() {
|
||||||
|
// return storageModule.getCredentials();
|
||||||
|
// },
|
||||||
|
// saveCredentials: function(credentials) {
|
||||||
|
// return storageModule.saveCredentials(credentials);
|
||||||
|
// },
|
||||||
getSettings: function() {
|
getSettings: function() {
|
||||||
if (settingsAvailable) {
|
if (settingsAvailable) {
|
||||||
return storageModule.getSettings();
|
return storageModule.getSettings();
|
||||||
|
@ -54,6 +54,14 @@ module.exports = {
|
|||||||
// property to true:
|
// property to true:
|
||||||
//flowFilePretty: true,
|
//flowFilePretty: true,
|
||||||
|
|
||||||
|
// By default, credentials are encrypted in storage using a generated key. To
|
||||||
|
// specify your own secret, set the following property.
|
||||||
|
// If you want to disable encryption of credentials, set this property to false.
|
||||||
|
// Note: once you set this property, do not change it - doing so will prevent
|
||||||
|
// node-red from being able to decrypt your existing credentials and they will be
|
||||||
|
// lost.
|
||||||
|
//credentialSecret: "a-secret-key",
|
||||||
|
|
||||||
// By default, all user data is stored in the Node-RED install directory. To
|
// By default, all user data is stored in the Node-RED install directory. To
|
||||||
// use a different location, the following property can be used
|
// use a different location, the following property can be used
|
||||||
//userDir: '/home/nol/.node-red/',
|
//userDir: '/home/nol/.node-red/',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -72,18 +72,8 @@ module.exports = {
|
|||||||
|
|
||||||
var storage = {
|
var storage = {
|
||||||
getFlows: function() {
|
getFlows: function() {
|
||||||
var defer = when.defer();
|
return when.resolve({flows:testFlows,credentials:testCredentials});
|
||||||
defer.resolve(testFlows);
|
}
|
||||||
return defer.promise;
|
|
||||||
},
|
|
||||||
getCredentials: function() {
|
|
||||||
var defer = when.defer();
|
|
||||||
defer.resolve(testCredentials);
|
|
||||||
return defer.promise;
|
|
||||||
},
|
|
||||||
saveCredentials: function() {
|
|
||||||
// do nothing
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var settings = {
|
var settings = {
|
||||||
@ -102,8 +92,7 @@ module.exports = {
|
|||||||
return messageId;
|
return messageId;
|
||||||
};
|
};
|
||||||
|
|
||||||
redNodes.init({settings:settings, storage:storage});
|
redNodes.init({settings:settings, storage:storage,log:log});
|
||||||
credentials.init(storage,express());
|
|
||||||
RED.nodes.registerType("helper", helperNode);
|
RED.nodes.registerType("helper", helperNode);
|
||||||
if (Array.isArray(testNode)) {
|
if (Array.isArray(testNode)) {
|
||||||
for (i = 0; i < testNode.length; i++) {
|
for (i = 0; i < testNode.length; i++) {
|
||||||
@ -114,7 +103,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
should.deepEqual(testFlows, flows.getFlows());
|
should.deepEqual(testFlows, flows.getFlows().flows);
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -34,12 +34,12 @@ describe("flows api", function() {
|
|||||||
app.post("/flows",flows.post);
|
app.post("/flows",flows.post);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns flow', function(done) {
|
it('returns flow - v1', function(done) {
|
||||||
flows.init({
|
flows.init({
|
||||||
settings: {},
|
settings: {},
|
||||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
nodes:{
|
nodes:{
|
||||||
getFlows: function() { return [1,2,3]; }
|
getFlows: function() { return {rev:"123",flows:[1,2,3]}; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
request(app)
|
request(app)
|
||||||
@ -50,13 +50,60 @@ describe("flows api", function() {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
res.body.should.be.an.Array;
|
try {
|
||||||
res.body.should.have.lengthOf(3);
|
res.body.should.have.lengthOf(3);
|
||||||
done();
|
done();
|
||||||
|
} catch(e) {
|
||||||
|
return done(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('returns flow - v2', function(done) {
|
||||||
it('sets flows - default', function(done) {
|
flows.init({
|
||||||
|
settings: {},
|
||||||
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
|
nodes:{
|
||||||
|
getFlows: function() { return {rev:"123",flows:[1,2,3]}; }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request(app)
|
||||||
|
.get('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','v2')
|
||||||
|
.expect(200)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
res.body.should.have.a.property('rev','123');
|
||||||
|
res.body.should.have.a.property('flows');
|
||||||
|
res.body.flows.should.have.lengthOf(3);
|
||||||
|
done();
|
||||||
|
} catch(e) {
|
||||||
|
return done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('returns flow - bad version', function(done) {
|
||||||
|
request(app)
|
||||||
|
.get('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','xxx')
|
||||||
|
.expect(400)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
res.body.should.have.a.property('error','bad_api_version');
|
||||||
|
done();
|
||||||
|
} catch(e) {
|
||||||
|
return done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('sets flows - default - v1', function(done) {
|
||||||
var setFlows = sinon.spy(function() { return when.resolve();});
|
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||||
flows.init({
|
flows.init({
|
||||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
@ -77,7 +124,7 @@ describe("flows api", function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('sets flows - non-default', function(done) {
|
it('sets flows - non-default - v1', function(done) {
|
||||||
var setFlows = sinon.spy(function() { return when.resolve();});
|
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||||
flows.init({
|
flows.init({
|
||||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
@ -100,6 +147,96 @@ describe("flows api", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('set flows - rejects mismatched revision - v2', function(done) {
|
||||||
|
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||||
|
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||||
|
flows.init({
|
||||||
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
|
nodes:{
|
||||||
|
setFlows: setFlows,
|
||||||
|
getFlows: getFlows
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request(app)
|
||||||
|
.post('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','v2')
|
||||||
|
.send({rev:456,flows:[4,5,6]})
|
||||||
|
.expect(409)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
res.body.should.have.property("error","version_mismatch");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('set flows - rev provided - v2', function(done) {
|
||||||
|
var setFlows = sinon.spy(function() { return when.resolve(456);});
|
||||||
|
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||||
|
flows.init({
|
||||||
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
|
nodes:{
|
||||||
|
setFlows: setFlows,
|
||||||
|
getFlows: getFlows
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request(app)
|
||||||
|
.post('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','v2')
|
||||||
|
.send({rev:123,flows:[4,5,6]})
|
||||||
|
.expect(200)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
res.body.should.have.property("rev",456);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('set flows - no rev provided - v2', function(done) {
|
||||||
|
var setFlows = sinon.spy(function() { return when.resolve(456);});
|
||||||
|
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||||
|
flows.init({
|
||||||
|
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||||
|
nodes:{
|
||||||
|
setFlows: setFlows,
|
||||||
|
getFlows: getFlows
|
||||||
|
}
|
||||||
|
});
|
||||||
|
request(app)
|
||||||
|
.post('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','v2')
|
||||||
|
.send({flows:[4,5,6]})
|
||||||
|
.expect(200)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
res.body.should.have.property("rev",456);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('sets flow - bad version', function(done) {
|
||||||
|
request(app)
|
||||||
|
.post('/flows')
|
||||||
|
.set('Accept', 'application/json')
|
||||||
|
.set('Node-RED-API-Version','xxx')
|
||||||
|
.expect(400)
|
||||||
|
.end(function(err,res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
res.body.should.have.a.property('error','bad_api_version');
|
||||||
|
done();
|
||||||
|
} catch(e) {
|
||||||
|
return done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
it('reloads flows', function(done) {
|
it('reloads flows', function(done) {
|
||||||
var loadFlows = sinon.spy(function() { return when.resolve(); });
|
var loadFlows = sinon.spy(function() { return when.resolve(); });
|
||||||
flows.init({
|
flows.init({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014, 2015 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,34 +19,30 @@ var sinon = require("sinon");
|
|||||||
var when = require("when");
|
var when = require("when");
|
||||||
var util = require("util");
|
var util = require("util");
|
||||||
|
|
||||||
var express = require("express");
|
|
||||||
var request = require("supertest");
|
|
||||||
|
|
||||||
var index = require("../../../../red/runtime/nodes/index");
|
var index = require("../../../../red/runtime/nodes/index");
|
||||||
var credentials = require("../../../../red/runtime/nodes/credentials");
|
var credentials = require("../../../../red/runtime/nodes/credentials");
|
||||||
var log = require("../../../../red/runtime/log");
|
var log = require("../../../../red/runtime/log");
|
||||||
var auth = require("../../../../red/api/auth");
|
|
||||||
|
|
||||||
|
|
||||||
describe('Credentials', function() {
|
describe('red/runtime/nodes/credentials', function() {
|
||||||
|
|
||||||
|
var encryptionDisabledSettings = {
|
||||||
|
get: function(key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
index.clearRegistry();
|
index.clearRegistry();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads from storage',function(done) {
|
it('loads provided credentials',function(done) {
|
||||||
|
credentials.init({
|
||||||
var storage = {
|
log: log,
|
||||||
getCredentials: function() {
|
settings: encryptionDisabledSettings
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
resolve({"a":{"b":1,"c":2}});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
credentials.init(storage);
|
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
|
|
||||||
credentials.load().then(function() {
|
|
||||||
|
|
||||||
credentials.get("a").should.have.property('b',1);
|
credentials.get("a").should.have.property('b',1);
|
||||||
credentials.get("a").should.have.property('c',2);
|
credentials.get("a").should.have.property('c',2);
|
||||||
@ -54,182 +50,120 @@ describe('Credentials', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('adds a new credential',function(done) {
|
||||||
it('saves to storage', function(done) {
|
credentials.init({
|
||||||
var storage = {
|
log: log,
|
||||||
saveCredentials: function(creds) {
|
settings: encryptionDisabledSettings
|
||||||
return when.resolve("saveCalled");
|
});
|
||||||
}
|
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
};
|
credentials.dirty().should.be.false();
|
||||||
credentials.init(storage);
|
should.not.exist(credentials.get("b"));
|
||||||
credentials.save().then(function(res) {
|
credentials.add("b",{"foo":"bar"}).then(function() {
|
||||||
res.should.equal("saveCalled");
|
credentials.get("b").should.have.property("foo","bar");
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('saves to storage when new cred added', function(done) {
|
|
||||||
var storage = {
|
|
||||||
getCredentials: function() {
|
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
resolve({"a":{"b":1,"c":2}});
|
|
||||||
});
|
});
|
||||||
},
|
it('deletes an existing credential',function(done) {
|
||||||
saveCredentials: function(creds) {
|
credentials.init({
|
||||||
return when(true);
|
log: log,
|
||||||
}
|
settings: encryptionDisabledSettings
|
||||||
};
|
|
||||||
sinon.spy(storage,"saveCredentials");
|
|
||||||
credentials.init(storage);
|
|
||||||
credentials.load().then(function() {
|
|
||||||
should.not.exist(credentials.get("b"))
|
|
||||||
credentials.add('b',{"d":3});
|
|
||||||
storage.saveCredentials.callCount.should.be.exactly(1);
|
|
||||||
credentials.get("b").should.have.property('d',3);
|
|
||||||
storage.saveCredentials.restore();
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
credentials.load({"a":{"b":1,"c":2}}).then(function() {
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
it('deletes from storage', function(done) {
|
credentials.delete("a");
|
||||||
var storage = {
|
|
||||||
getCredentials: function() {
|
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
resolve({"a":{"b":1,"c":2}});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
saveCredentials: function(creds) {
|
|
||||||
return when(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sinon.spy(storage,"saveCredentials");
|
|
||||||
credentials.init(storage);
|
|
||||||
credentials.load().then(function() {
|
|
||||||
should.exist(credentials.get("a"))
|
|
||||||
credentials.delete('a');
|
|
||||||
storage.saveCredentials.callCount.should.be.exactly(1);
|
|
||||||
should.not.exist(credentials.get("a"));
|
should.not.exist(credentials.get("a"));
|
||||||
storage.saveCredentials.restore();
|
credentials.dirty().should.be.true();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clean up from storage', function(done) {
|
it('exports the credentials, clearing dirty flag', function(done) {
|
||||||
var storage = {
|
credentials.init({
|
||||||
getCredentials: function() {
|
log: log,
|
||||||
return when.promise(function(resolve,reject) {
|
settings: encryptionDisabledSettings
|
||||||
resolve({"a":{"b":1,"c":2}});
|
|
||||||
});
|
});
|
||||||
},
|
var creds = {"a":{"b":1,"c":2}};
|
||||||
saveCredentials: function(creds) {
|
credentials.load(creds).then(function() {
|
||||||
return when(true);
|
credentials.add("b",{"foo":"bar"}).then(function() {
|
||||||
}
|
credentials.dirty().should.be.true();
|
||||||
};
|
credentials.export().then(function(exported) {
|
||||||
sinon.spy(storage,"saveCredentials");
|
exported.should.eql(creds);
|
||||||
credentials.init(storage);
|
credentials.dirty().should.be.false();
|
||||||
credentials.load().then(function() {
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#clean",function() {
|
||||||
|
it("removes credentials of unknown nodes",function(done) {
|
||||||
|
credentials.init({
|
||||||
|
log: log,
|
||||||
|
settings: encryptionDisabledSettings
|
||||||
|
});
|
||||||
|
var creds = {"a":{"b":1,"c":2},"b":{"d":3}};
|
||||||
|
credentials.load(creds).then(function() {
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
should.exist(credentials.get("a"));
|
should.exist(credentials.get("a"));
|
||||||
credentials.clean([]);
|
should.exist(credentials.get("b"));
|
||||||
storage.saveCredentials.callCount.should.be.exactly(1);
|
credentials.clean([{id:"b"}]).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
should.not.exist(credentials.get("a"));
|
should.not.exist(credentials.get("a"));
|
||||||
storage.saveCredentials.restore();
|
should.exist(credentials.get("b"));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handle error loading from storage', function(done) {
|
|
||||||
var storage = {
|
|
||||||
getCredentials: function() {
|
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
reject("test forcing failure");
|
|
||||||
});
|
});
|
||||||
},
|
it("extracts credentials of known nodes",function(done) {
|
||||||
saveCredentials: function(creds) {
|
credentials.init({
|
||||||
return when(true);
|
log: log,
|
||||||
}
|
settings: encryptionDisabledSettings
|
||||||
};
|
});
|
||||||
var logmsg = 'nothing logged yet';
|
credentials.register("testNode",{"b":"text","c":"password"})
|
||||||
sinon.stub(log, 'warn', function(msg) {
|
var creds = {"a":{"b":1,"c":2}};
|
||||||
logmsg = msg;
|
var newConfig = [{id:"a",type:"testNode",credentials:{"b":"newBValue","c":"newCValue"}}];
|
||||||
|
credentials.load(creds).then(function() {
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
credentials.clean(newConfig).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
credentials.get("a").should.have.property('b',"newBValue");
|
||||||
|
credentials.get("a").should.have.property('c',"newCValue");
|
||||||
|
should.not.exist(newConfig[0].credentials);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
credentials.init(storage);
|
|
||||||
credentials.load().then(function() {
|
});
|
||||||
log.warn.calledOnce.should.be.true;
|
|
||||||
|
it('warns if a node has no credential definition', function(done) {
|
||||||
|
credentials.init({
|
||||||
|
log: log,
|
||||||
|
settings: encryptionDisabledSettings
|
||||||
|
});
|
||||||
|
credentials.load({}).then(function() {
|
||||||
|
var node = {id:"node",type:"test",credentials:{
|
||||||
|
user1:"newUser",
|
||||||
|
password1:"newPassword"
|
||||||
|
}};
|
||||||
|
sinon.spy(log,"warn");
|
||||||
|
credentials.extract(node);
|
||||||
|
log.warn.called.should.be.true();
|
||||||
|
should.not.exist(node.credentials);
|
||||||
log.warn.restore();
|
log.warn.restore();
|
||||||
done();
|
done();
|
||||||
}).otherwise(function(err){
|
|
||||||
log.warn.restore();
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
|
||||||
it('credential type is not registered when extract', function(done) {
|
it('extract credential updates in the provided node', function(done) {
|
||||||
var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
|
credentials.init({
|
||||||
var storage = {
|
log: log,
|
||||||
getFlows: function() {
|
settings: encryptionDisabledSettings
|
||||||
var defer = when.defer();
|
|
||||||
defer.resolve(testFlows);
|
|
||||||
return defer.promise;
|
|
||||||
},
|
|
||||||
getCredentials: function() {
|
|
||||||
return when.promise(function(resolve,reject) {
|
|
||||||
resolve({"tab1":{"b":1,"c":2}});
|
|
||||||
});
|
});
|
||||||
},
|
var defintion = {
|
||||||
saveFlows: function(conf) {
|
|
||||||
var defer = when.defer();
|
|
||||||
defer.resolve();
|
|
||||||
should.deepEqual(testFlows, conf);
|
|
||||||
return defer.promise;
|
|
||||||
},
|
|
||||||
saveCredentials: function(creds) {
|
|
||||||
return when(true);
|
|
||||||
},
|
|
||||||
getSettings: function() {
|
|
||||||
return when({});
|
|
||||||
},
|
|
||||||
saveSettings: function(s) {
|
|
||||||
return when();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function TestNode(n) {
|
|
||||||
index.createNode(this, n);
|
|
||||||
|
|
||||||
this.id = 'tab1';
|
|
||||||
this.type = 'test';
|
|
||||||
this.name = 'barney';
|
|
||||||
var node = this;
|
|
||||||
|
|
||||||
this.on("log", function() {
|
|
||||||
// do nothing
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var logmsg = 'nothing logged yet';
|
|
||||||
sinon.stub(log, 'warn', function(msg) {
|
|
||||||
logmsg = msg;
|
|
||||||
});
|
|
||||||
var settings = {
|
|
||||||
available: function() { return false;}
|
|
||||||
}
|
|
||||||
index.init({settings:settings, storage:storage});
|
|
||||||
index.registerType('test', TestNode);
|
|
||||||
index.loadFlows().then(function() {
|
|
||||||
var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});
|
|
||||||
credentials.extract(testnode);
|
|
||||||
log.warn.calledOnce.should.be.true;
|
|
||||||
log.warn.restore();
|
|
||||||
done();
|
|
||||||
}).otherwise(function(err){
|
|
||||||
log.warn.restore();
|
|
||||||
done(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('extract and store credential updates in the provided node', function(done) {
|
|
||||||
credentials.init({saveCredentials:function(){}},express());
|
|
||||||
credentials.register("test",{
|
|
||||||
user1:{type:"text"},
|
user1:{type:"text"},
|
||||||
password1:{type:"password"},
|
password1:{type:"password"},
|
||||||
user2:{type:"text"},
|
user2:{type:"text"},
|
||||||
@ -237,8 +171,12 @@ describe('Credentials', function() {
|
|||||||
user3:{type:"text"},
|
user3:{type:"text"},
|
||||||
password3:{type:"password"}
|
password3:{type:"password"}
|
||||||
|
|
||||||
});
|
};
|
||||||
credentials.add("node",{user1:"abc",password1:"123",user2:"def",password2:"456",user3:"ghi",password3:"789"});
|
credentials.register("test",defintion);
|
||||||
|
var def = credentials.getDefinition("test");
|
||||||
|
defintion.should.eql(def);
|
||||||
|
|
||||||
|
credentials.load({"node":{user1:"abc",password1:"123",user2:"def",password2:"456",user3:"ghi",password3:"789"}}).then(function() {
|
||||||
var node = {id:"node",type:"test",credentials:{
|
var node = {id:"node",type:"test",credentials:{
|
||||||
// user1 unchanged
|
// user1 unchanged
|
||||||
password1:"__PWRD__",
|
password1:"__PWRD__",
|
||||||
@ -247,10 +185,12 @@ describe('Credentials', function() {
|
|||||||
user3:"newUser",
|
user3:"newUser",
|
||||||
password3:"newPassword"
|
password3:"newPassword"
|
||||||
}};
|
}};
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
credentials.extract(node);
|
credentials.extract(node);
|
||||||
|
|
||||||
node.should.not.have.a.property("credentials");
|
node.should.not.have.a.property("credentials");
|
||||||
|
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
var newCreds = credentials.get("node");
|
var newCreds = credentials.get("node");
|
||||||
newCreds.should.have.a.property("user1","abc");
|
newCreds.should.have.a.property("user1","abc");
|
||||||
newCreds.should.have.a.property("password1","123");
|
newCreds.should.have.a.property("password1","123");
|
||||||
@ -261,4 +201,271 @@ describe('Credentials', function() {
|
|||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
it('extract ignores node without credentials', function(done) {
|
||||||
|
credentials.init({
|
||||||
|
log: log,
|
||||||
|
settings: encryptionDisabledSettings
|
||||||
|
});
|
||||||
|
credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
|
||||||
|
var node = {id:"node",type:"test"};
|
||||||
|
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
credentials.extract(node);
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("encryption",function() {
|
||||||
|
var settings = {};
|
||||||
|
var runtime = {
|
||||||
|
log: log,
|
||||||
|
settings: {
|
||||||
|
get: function(key) {
|
||||||
|
return settings[key];
|
||||||
|
},
|
||||||
|
set: function(key,value) {
|
||||||
|
settings[key] = value;
|
||||||
|
return when.resolve();
|
||||||
|
},
|
||||||
|
delete: function(key) {
|
||||||
|
delete settings[key];
|
||||||
|
return when.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it('migrates to encrypted and generates default key', function(done) {
|
||||||
|
settings = {};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
|
||||||
|
settings.should.have.a.property("_credentialSecret");
|
||||||
|
settings._credentialSecret.should.have.a.length(64);
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('uses default key', function(done) {
|
||||||
|
settings = {
|
||||||
|
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
credentials.add("node",{user1:"def",password1:"456"});
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.get("node").should.have.a.property("user1","def");
|
||||||
|
credentials.get("node").should.have.a.property("password1","456");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('uses user key', function(done) {
|
||||||
|
settings = {
|
||||||
|
credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.add("node",{user1:"def",password1:"456"});
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.get("node").should.have.a.property("user1","def");
|
||||||
|
credentials.get("node").should.have.a.property("password1","456");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('uses user key - when settings are otherwise unavailable', function(done) {
|
||||||
|
var runtime = {
|
||||||
|
log: log,
|
||||||
|
settings: {
|
||||||
|
get: function(key) {
|
||||||
|
if (key === 'credentialSecret') {
|
||||||
|
return "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a";
|
||||||
|
}
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
set: function(key,value) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.add("node",{user1:"def",password1:"456"});
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.get("node").should.have.a.property("user1","def");
|
||||||
|
credentials.get("node").should.have.a.property("password1","456");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('migrates from default key to user key', function(done) {
|
||||||
|
settings = {
|
||||||
|
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
|
||||||
|
credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
settings.should.not.have.a.property("_credentialSecret");
|
||||||
|
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.get("node").should.have.a.property("user1","abc");
|
||||||
|
credentials.get("node").should.have.a.property("password1","123");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('migrates from default key to user key - unencrypted original', function(done) {
|
||||||
|
settings = {
|
||||||
|
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
|
||||||
|
credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var unencryptedFlows = {"node":{user1:"abc",password1:"123"}};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(unencryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.have.a.property("$");
|
||||||
|
settings.should.not.have.a.property("_credentialSecret");
|
||||||
|
|
||||||
|
// reset everything - but with _credentialSecret still set
|
||||||
|
credentials.init(runtime);
|
||||||
|
// load the freshly encrypted version
|
||||||
|
credentials.load(result).then(function() {
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.get("node").should.have.a.property("user1","abc");
|
||||||
|
credentials.get("node").should.have.a.property("password1","123");
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('migrates from default key to unencrypted', function(done) {
|
||||||
|
settings = {
|
||||||
|
_credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
|
||||||
|
credentialSecret: false
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.not.have.a.property("$");
|
||||||
|
settings.should.not.have.a.property("_credentialSecret");
|
||||||
|
result.should.eql({"node":{user1:"abc",password1:"123"}});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handles bad default key - resets credentials', function(done) {
|
||||||
|
settings = {
|
||||||
|
_credentialSecret: "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
should.not.exist(credentials.get("node"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handles bad user key - resets credentials', function(done) {
|
||||||
|
settings = {
|
||||||
|
credentialSecret: "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb"
|
||||||
|
};
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load(cryptedFlows).then(function() {
|
||||||
|
credentials.dirty().should.be.true();
|
||||||
|
should.not.exist(credentials.get("node"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unavailable settings - leaves creds unencrypted', function(done) {
|
||||||
|
var runtime = {
|
||||||
|
log: log,
|
||||||
|
settings: {
|
||||||
|
get: function(key) {
|
||||||
|
throw new Error();
|
||||||
|
},
|
||||||
|
set: function(key,value) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// {"node":{user1:"abc",password1:"123"}}
|
||||||
|
credentials.init(runtime);
|
||||||
|
credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
|
||||||
|
credentials.dirty().should.be.false();
|
||||||
|
should.exist(credentials.get("node"));
|
||||||
|
credentials.export().then(function(result) {
|
||||||
|
result.should.not.have.a.property("$");
|
||||||
|
result.should.have.a.property("node");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014, 2015 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -30,8 +30,6 @@ describe('flows/index', function() {
|
|||||||
|
|
||||||
var storage;
|
var storage;
|
||||||
var eventsOn;
|
var eventsOn;
|
||||||
var credentialsExtract;
|
|
||||||
var credentialsSave;
|
|
||||||
var credentialsClean;
|
var credentialsClean;
|
||||||
var credentialsLoad;
|
var credentialsLoad;
|
||||||
|
|
||||||
@ -50,13 +48,10 @@ describe('flows/index', function() {
|
|||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
eventsOn = sinon.spy(events,"on");
|
eventsOn = sinon.spy(events,"on");
|
||||||
credentialsExtract = sinon.stub(credentials,"extract",function(conf) {
|
|
||||||
delete conf.credentials;
|
|
||||||
});
|
|
||||||
credentialsSave = sinon.stub(credentials,"save",function() {
|
|
||||||
return when.resolve();
|
|
||||||
});
|
|
||||||
credentialsClean = sinon.stub(credentials,"clean",function(conf) {
|
credentialsClean = sinon.stub(credentials,"clean",function(conf) {
|
||||||
|
conf.forEach(function(n) {
|
||||||
|
delete n.credentials;
|
||||||
|
});
|
||||||
return when.resolve();
|
return when.resolve();
|
||||||
});
|
});
|
||||||
credentialsLoad = sinon.stub(credentials,"load",function() {
|
credentialsLoad = sinon.stub(credentials,"load",function() {
|
||||||
@ -97,8 +92,6 @@ describe('flows/index', function() {
|
|||||||
|
|
||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
eventsOn.restore();
|
eventsOn.restore();
|
||||||
credentialsExtract.restore();
|
|
||||||
credentialsSave.restore();
|
|
||||||
credentialsClean.restore();
|
credentialsClean.restore();
|
||||||
credentialsLoad.restore();
|
credentialsLoad.restore();
|
||||||
flowCreate.restore();
|
flowCreate.restore();
|
||||||
@ -119,28 +112,35 @@ describe('flows/index', function() {
|
|||||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.setFlows(originalConfig).then(function() {
|
flows.setFlows(originalConfig).then(function() {
|
||||||
credentialsExtract.called.should.be.false;
|
|
||||||
credentialsClean.called.should.be.true;
|
credentialsClean.called.should.be.true;
|
||||||
storage.hasOwnProperty('conf').should.be.true;
|
storage.hasOwnProperty('conf').should.be.true;
|
||||||
flows.getFlows().should.eql(originalConfig);
|
flows.getFlows().flows.should.eql(originalConfig);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
it('sets the full flow for type load', function(done) {
|
it('loads the full flow for type load', function(done) {
|
||||||
var originalConfig = [
|
var originalConfig = [
|
||||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
flows.init({},storage);
|
var loadStorage = {
|
||||||
|
saveFlows: function(conf) {
|
||||||
|
loadStorage.conf = conf;
|
||||||
|
return when.resolve(456);
|
||||||
|
},
|
||||||
|
getFlows: function() {
|
||||||
|
return when.resolve({flows:originalConfig,rev:123})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flows.init({settings:{},storage:loadStorage});
|
||||||
flows.setFlows(originalConfig,"load").then(function() {
|
flows.setFlows(originalConfig,"load").then(function() {
|
||||||
credentialsExtract.called.should.be.false;
|
credentialsClean.called.should.be.false;
|
||||||
credentialsClean.called.should.be.true;
|
|
||||||
// 'load' type does not trigger a save
|
// 'load' type does not trigger a save
|
||||||
storage.hasOwnProperty('conf').should.be.false;
|
loadStorage.hasOwnProperty('conf').should.be.false;
|
||||||
flows.getFlows().should.eql(originalConfig);
|
flows.getFlows().flows.should.eql(originalConfig);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -148,19 +148,18 @@ describe('flows/index', function() {
|
|||||||
|
|
||||||
it('extracts credentials from the full flow', function(done) {
|
it('extracts credentials from the full flow', function(done) {
|
||||||
var originalConfig = [
|
var originalConfig = [
|
||||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[],credentials:{}},
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[],credentials:{"a":1}},
|
||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.setFlows(originalConfig).then(function() {
|
flows.setFlows(originalConfig).then(function() {
|
||||||
credentialsExtract.called.should.be.true;
|
|
||||||
credentialsClean.called.should.be.true;
|
credentialsClean.called.should.be.true;
|
||||||
storage.hasOwnProperty('conf').should.be.true;
|
storage.hasOwnProperty('conf').should.be.true;
|
||||||
var cleanedFlows = flows.getFlows();
|
var cleanedFlows = flows.getFlows();
|
||||||
storage.conf.should.eql(cleanedFlows);
|
storage.conf.flows.should.eql(cleanedFlows.flows);
|
||||||
cleanedFlows.should.not.eql(originalConfig);
|
cleanedFlows.flows.should.not.eql(originalConfig);
|
||||||
cleanedFlows[0].credentials = {};
|
cleanedFlows.flows[0].credentials = {"a":1};
|
||||||
cleanedFlows.should.eql(originalConfig);
|
cleanedFlows.flows.should.eql(originalConfig);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -175,12 +174,12 @@ describe('flows/index', function() {
|
|||||||
newConfig.push({id:"t2",type:"tab"});
|
newConfig.push({id:"t2",type:"tab"});
|
||||||
newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
|
newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
flows.setFlows(newConfig,"nodes").then(function() {
|
flows.setFlows(newConfig,"nodes").then(function() {
|
||||||
flows.getFlows().should.eql(newConfig);
|
flows.getFlows().flows.should.eql(newConfig);
|
||||||
flowCreate.flows['t1'].update.called.should.be.true;
|
flowCreate.flows['t1'].update.called.should.be.true;
|
||||||
flowCreate.flows['t2'].start.called.should.be.true;
|
flowCreate.flows['t2'].start.called.should.be.true;
|
||||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
||||||
@ -188,7 +187,7 @@ describe('flows/index', function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -204,12 +203,12 @@ describe('flows/index', function() {
|
|||||||
newConfig.push({id:"t2",type:"tab"});
|
newConfig.push({id:"t2",type:"tab"});
|
||||||
newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
|
newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
flows.setFlows(newConfig,"nodes").then(function() {
|
flows.setFlows(newConfig,"nodes").then(function() {
|
||||||
flows.getFlows().should.eql(newConfig);
|
flows.getFlows().flows.should.eql(newConfig);
|
||||||
flowCreate.flows['t1'].update.called.should.be.true;
|
flowCreate.flows['t1'].update.called.should.be.true;
|
||||||
flowCreate.flows['t2'].start.called.should.be.true;
|
flowCreate.flows['t2'].start.called.should.be.true;
|
||||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
||||||
@ -217,7 +216,7 @@ describe('flows/index', function() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -232,16 +231,14 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
credentialsExtract.called.should.be.false;
|
|
||||||
credentialsLoad.called.should.be.true;
|
credentialsLoad.called.should.be.true;
|
||||||
credentialsClean.called.should.be.true;
|
|
||||||
// 'load' type does not trigger a save
|
// 'load' type does not trigger a save
|
||||||
storage.hasOwnProperty('conf').should.be.false;
|
storage.hasOwnProperty('conf').should.be.false;
|
||||||
flows.getFlows().should.eql(originalConfig);
|
flows.getFlows().flows.should.eql(originalConfig);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -254,7 +251,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
@ -262,7 +259,7 @@ describe('flows/index', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -274,10 +271,10 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
flowCreate.called.should.be.false;
|
flowCreate.called.should.be.false;
|
||||||
@ -293,9 +290,9 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
flowCreate.called.should.be.false;
|
flowCreate.called.should.be.false;
|
||||||
@ -316,7 +313,7 @@ describe('flows/index', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#get',function() {
|
describe.skip('#get',function() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -327,9 +324,9 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
flows.eachNode(function(node) {
|
flows.eachNode(function(node) {
|
||||||
@ -351,7 +348,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
@ -360,7 +357,7 @@ describe('flows/index', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -376,7 +373,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
@ -391,7 +388,7 @@ describe('flows/index', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -404,7 +401,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
@ -413,7 +410,7 @@ describe('flows/index', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -430,7 +427,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
|
|
||||||
events.once('nodes-started',function() {
|
events.once('nodes-started',function() {
|
||||||
@ -445,7 +442,7 @@ describe('flows/index', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.startFlows();
|
flows.startFlows();
|
||||||
});
|
});
|
||||||
@ -473,7 +470,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.setFlows(originalConfig).then(function() {
|
flows.setFlows(originalConfig).then(function() {
|
||||||
flows.checkTypeInUse("unused-module");
|
flows.checkTypeInUse("unused-module");
|
||||||
done();
|
done();
|
||||||
@ -484,7 +481,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.setFlows(originalConfig).then(function() {
|
flows.setFlows(originalConfig).then(function() {
|
||||||
/*jshint immed: false */
|
/*jshint immed: false */
|
||||||
try {
|
try {
|
||||||
@ -505,9 +502,9 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
flows.addFlow({
|
flows.addFlow({
|
||||||
label:'new flow',
|
label:'new flow',
|
||||||
@ -529,12 +526,12 @@ describe('flows/index', function() {
|
|||||||
{id:"t1",type:"tab"}
|
{id:"t1",type:"tab"}
|
||||||
];
|
];
|
||||||
storage.getFlows = function() {
|
storage.getFlows = function() {
|
||||||
return when.resolve(originalConfig);
|
return when.resolve({flows:originalConfig});
|
||||||
}
|
}
|
||||||
storage.setFlows = function() {
|
storage.setFlows = function() {
|
||||||
return when.resolve();
|
return when.resolve();
|
||||||
}
|
}
|
||||||
flows.init({},storage);
|
flows.init({settings:{},storage:storage});
|
||||||
flows.load().then(function() {
|
flows.load().then(function() {
|
||||||
return flows.startFlows();
|
return flows.startFlows();
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
@ -547,7 +544,7 @@ describe('flows/index', function() {
|
|||||||
{id:"t2-3",z:"t1",type:"test"}
|
{id:"t2-3",z:"t1",type:"test"}
|
||||||
]
|
]
|
||||||
}).then(function(id) {
|
}).then(function(id) {
|
||||||
flows.getFlows().should.have.lengthOf(6);
|
flows.getFlows().flows.should.have.lengthOf(6);
|
||||||
var createdFlows = Object.keys(flowCreate.flows);
|
var createdFlows = Object.keys(flowCreate.flows);
|
||||||
createdFlows.should.have.lengthOf(3);
|
createdFlows.should.have.lengthOf(3);
|
||||||
createdFlows[2].should.eql(id);
|
createdFlows[2].should.eql(id);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -39,29 +39,26 @@ describe("red/nodes/index", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
|
var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
|
||||||
|
var testCredentials = {"tab1":{"b":1,"c":2}};
|
||||||
var storage = {
|
var storage = {
|
||||||
getFlows: function() {
|
getFlows: function() {
|
||||||
return when(testFlows);
|
return when({red:123,flows:testFlows,credentials:testCredentials});
|
||||||
},
|
|
||||||
getCredentials: function() {
|
|
||||||
return when({"tab1":{"b":1,"c":2}});
|
|
||||||
},
|
},
|
||||||
saveFlows: function(conf) {
|
saveFlows: function(conf) {
|
||||||
should.deepEqual(testFlows, conf);
|
should.deepEqual(testFlows, conf.flows);
|
||||||
return when();
|
return when.resolve(123);
|
||||||
},
|
|
||||||
saveCredentials: function(creds) {
|
|
||||||
return when(true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var settings = {
|
var settings = {
|
||||||
available: function() { return false }
|
available: function() { return false },
|
||||||
|
get: function() { return false }
|
||||||
};
|
};
|
||||||
|
|
||||||
var runtime = {
|
var runtime = {
|
||||||
settings: settings,
|
settings: settings,
|
||||||
storage: storage
|
storage: storage,
|
||||||
|
log: {debug:function(){},warn:function(){}}
|
||||||
};
|
};
|
||||||
|
|
||||||
function TestNode(n) {
|
function TestNode(n) {
|
||||||
@ -88,7 +85,9 @@ describe("red/nodes/index", function() {
|
|||||||
it('flows should be initialised',function(done) {
|
it('flows should be initialised',function(done) {
|
||||||
index.init(runtime);
|
index.init(runtime);
|
||||||
index.loadFlows().then(function() {
|
index.loadFlows().then(function() {
|
||||||
should.deepEqual(testFlows, index.getFlows());
|
console.log(testFlows);
|
||||||
|
console.log(index.getFlows());
|
||||||
|
should.deepEqual(testFlows, index.getFlows().flows);
|
||||||
done();
|
done();
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
done(err);
|
done(err);
|
||||||
@ -177,8 +176,8 @@ describe("red/nodes/index", function() {
|
|||||||
index.registerType('test', TestNode);
|
index.registerType('test', TestNode);
|
||||||
index.loadFlows().then(function() {
|
index.loadFlows().then(function() {
|
||||||
var info = index.disableNode("5678");
|
var info = index.disableNode("5678");
|
||||||
registry.disableNode.calledOnce.should.be.true;
|
registry.disableNode.calledOnce.should.be.true();
|
||||||
registry.disableNode.calledWith("5678").should.be.true;
|
registry.disableNode.calledWith("5678").should.be.true();
|
||||||
info.should.eql(randomNodeInfo);
|
info.should.eql(randomNodeInfo);
|
||||||
done();
|
done();
|
||||||
}).otherwise(function(err) {
|
}).otherwise(function(err) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2014, 2015 IBM Corp.
|
* Copyright 2014, 2016 IBM Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -22,7 +22,9 @@ describe("red/storage/index", function() {
|
|||||||
it('rejects the promise when settings suggest loading a bad module', function(done) {
|
it('rejects the promise when settings suggest loading a bad module', function(done) {
|
||||||
|
|
||||||
var wrongModule = {
|
var wrongModule = {
|
||||||
|
settings:{
|
||||||
storageModule : "thisaintloading"
|
storageModule : "thisaintloading"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
storage.init(wrongModule).then( function() {
|
storage.init(wrongModule).then( function() {
|
||||||
@ -48,7 +50,9 @@ describe("red/storage/index", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var setsBooleanModule = {
|
var setsBooleanModule = {
|
||||||
|
settings: {
|
||||||
storageModule : moduleWithBooleanSettingInit
|
storageModule : moduleWithBooleanSettingInit
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
storage.init(setsBooleanModule);
|
storage.init(setsBooleanModule);
|
||||||
@ -71,12 +75,15 @@ describe("red/storage/index", function() {
|
|||||||
},
|
},
|
||||||
getFlows : function() {
|
getFlows : function() {
|
||||||
calledFlagGetFlows = true;
|
calledFlagGetFlows = true;
|
||||||
|
return when.resolve([]);
|
||||||
},
|
},
|
||||||
saveFlows : function (flows) {
|
saveFlows : function (flows) {
|
||||||
flows.should.be.true;
|
flows.should.be.true;
|
||||||
|
return when.resolve("");
|
||||||
},
|
},
|
||||||
getCredentials : function() {
|
getCredentials : function() {
|
||||||
calledFlagGetCredentials = true;
|
calledFlagGetCredentials = true;
|
||||||
|
return when.resolve({});
|
||||||
},
|
},
|
||||||
saveCredentials : function(credentials) {
|
saveCredentials : function(credentials) {
|
||||||
credentials.should.be.true;
|
credentials.should.be.true;
|
||||||
@ -116,14 +123,14 @@ describe("red/storage/index", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var moduleToLoad = {
|
var moduleToLoad = {
|
||||||
|
settings: {
|
||||||
storageModule : interfaceCheckerModule
|
storageModule : interfaceCheckerModule
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
storage.init(moduleToLoad);
|
storage.init(moduleToLoad);
|
||||||
storage.getFlows();
|
storage.getFlows();
|
||||||
storage.saveFlows(true);
|
storage.saveFlows({flows:[],credentials:{}});
|
||||||
storage.getCredentials();
|
|
||||||
storage.saveCredentials(true);
|
|
||||||
storage.getSettings();
|
storage.getSettings();
|
||||||
storage.saveSettings(true);
|
storage.saveSettings(true);
|
||||||
storage.getSessions();
|
storage.getSessions();
|
||||||
@ -172,7 +179,9 @@ describe("red/storage/index", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var moduleToLoad = {
|
var moduleToLoad = {
|
||||||
|
settings: {
|
||||||
storageModule : interfaceCheckerModule
|
storageModule : interfaceCheckerModule
|
||||||
|
}
|
||||||
};
|
};
|
||||||
before(function() {
|
before(function() {
|
||||||
storage.init(moduleToLoad);
|
storage.init(moduleToLoad);
|
||||||
@ -220,7 +229,7 @@ describe("red/storage/index", function() {
|
|||||||
var interfaceCheckerModule = {
|
var interfaceCheckerModule = {
|
||||||
init : function () {}
|
init : function () {}
|
||||||
};
|
};
|
||||||
storage.init({storageModule: interfaceCheckerModule});
|
storage.init({settings:{storageModule: interfaceCheckerModule}});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('defaults missing getSettings',function(done) {
|
it('defaults missing getSettings',function(done) {
|
||||||
|
Loading…
Reference in New Issue
Block a user