diff --git a/public/red/main.js b/public/red/main.js
index e77c684df..48744b694 100644
--- a/public/red/main.js
+++ b/public/red/main.js
@@ -15,6 +15,14 @@
**/
var RED = (function() {
+ var deploymentTypes = {
+ "full":{label:"Deploy",img:"images/deploy-full-o.png"},
+ "nodes":{label:"Deploy modified nodes",img:"images/deploy-nodes-o.png"},
+ "flows":{label:"Deploy modified flows",img:"images/deploy-flows-o.png"}
+ }
+ var deploymentType = "full";
+
+
function hideDropTarget() {
$("#dropTarget").hide();
RED.keyboard.remove(/* ESCAPE */ 27);
@@ -82,7 +90,10 @@ var RED = (function() {
url:"flows",
type: "POST",
data: JSON.stringify(nns),
- contentType: "application/json; charset=utf-8"
+ contentType: "application/json; charset=utf-8",
+ headers: {
+ "Node-RED-Deployment-Type":deploymentType
+ }
}).done(function(data,textStatus,xhr) {
RED.notify("Successfully deployed","success");
RED.nodes.eachNode(function(node) {
@@ -280,36 +291,50 @@ var RED = (function() {
dialog.modal();
}
+
+ function changeDeploymentType(type) {
+ deploymentType = type;
+ $("#btn-deploy img").attr("src",deploymentTypes[type].img);
+ //$("#btn-deploy span").text(deploymentTypes[type].label);
+ }
+
$(function() {
RED.menu.init({id:"btn-sidemenu",
options: [
- {id:"btn-sidebar",icon:"fa fa-columns",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
+ {id:"btn-sidebar",_icon:"fa fa-columns",label:"Sidebar",toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true},
+ {id:"btn-node-status",_icon:"fa fa-info",label:"Node Status",toggle:true,onselect:toggleStatus},
null,
- {id:"btn-node-status",icon:"fa fa-info",label:"Node Status",toggle:true,onselect:toggleStatus},
- null,
- {id:"btn-import-menu",icon:"fa fa-sign-in",label:"Import...",options:[
- {id:"btn-import-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",onselect:RED.view.showImportNodesDialog},
- {id:"btn-import-library",icon:"fa fa-book",label:"Library",options:[]}
+ {id:"btn-import-menu",_icon:"fa fa-sign-in",label:"Import...",options:[
+ {id:"btn-import-clipboard",_icon:"fa fa-clipboard",label:"Clipboard...",onselect:RED.view.showImportNodesDialog},
+ {id:"btn-import-library",_icon:"fa fa-book",label:"Library",options:[]}
]},
- {id:"btn-export-menu",icon:"fa fa-sign-out",label:"Export...",disabled:true,options:[
- {id:"btn-export-clipboard",icon:"fa fa-clipboard",label:"Clipboard...",disabled:true,onselect:RED.view.showExportNodesDialog},
- {id:"btn-export-library",icon:"fa fa-book",label:"Library...",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
+ {id:"btn-export-menu",_icon:"fa fa-sign-out",label:"Export...",disabled:true,options:[
+ {id:"btn-export-clipboard",_icon:"fa fa-clipboard",label:"Clipboard...",disabled:true,onselect:RED.view.showExportNodesDialog},
+ {id:"btn-export-library",_icon:"fa fa-book",label:"Library...",disabled:true,onselect:RED.view.showExportNodesLibraryDialog}
]},
null,
- {id:"btn-config-nodes",icon:"fa fa-th-list",label:"Configuration nodes...",onselect:RED.sidebar.config.show},
+ {id:"btn-config-nodes",_icon:"fa fa-th-list",label:"Configuration nodes...",onselect:RED.sidebar.config.show},
null,
- {id:"btn-create-subflow",icon:"fa fa-share-alt",label:"Create subflow",onselect:RED.view.createSubflow},
- {id:"btn-convert-subflow",icon:"fa fa-share-alt",label:"Convert to subflow",disabled:true,onselect:RED.view.convertToSubflow},
+ {id:"btn-create-subflow",_icon:"fa fa-share-alt",label:"Create subflow",onselect:RED.view.createSubflow},
+ {id:"btn-convert-subflow",_icon:"fa fa-share-alt",label:"Convert to subflow",disabled:true,onselect:RED.view.convertToSubflow},
null,
- {id:"btn-workspace-menu",icon:"fa fa-th-large",label:"Workspaces",options:[
- {id:"btn-workspace-add",icon:"fa fa-plus",label:"Add"},
- {id:"btn-workspace-edit",icon:"fa fa-pencil",label:"Rename"},
- {id:"btn-workspace-delete",icon:"fa fa-minus",label:"Delete"},
+ {id:"btn-workspace-menu",_icon:"fa fa-th-large",label:"Workspaces",options:[
+ {id:"btn-workspace-add",_icon:"fa fa-plus",label:"Add"},
+ {id:"btn-workspace-edit",_icon:"fa fa-pencil",label:"Rename"},
+ {id:"btn-workspace-delete",_icon:"fa fa-minus",label:"Delete"},
null
]},
null,
- {id:"btn-keyboard-shortcuts",icon:"fa fa-keyboard-o",label:"Keyboard Shortcuts",onselect:showHelp},
- {id:"btn-help",icon:"fa fa-question",label:"Help...", href:"http://nodered.org/docs"}
+ {id:"btn-keyboard-shortcuts",_icon:"fa fa-keyboard-o",label:"Keyboard Shortcuts",onselect:showHelp},
+ {id:"btn-help",_icon:"fa fa-question",label:"Help...", href:"http://nodered.org/docs"}
+ ]
+ });
+
+ RED.menu.init({id:"btn-deploy-options",
+ options: [
+ {id:"btn-deploy-full",toggle:"deploy-type",icon:"images/deploy-full.png",label:"Full",sublabel:"Deploys everything in the workspace",onselect:function(s) { if(s){changeDeploymentType("full")}}},
+ {id:"btn-deploy-flow",toggle:"deploy-type",icon:"images/deploy-flows.png",label:"Modified Flows",sublabel:"Only deploys flows that contain changed nodes", onselect:function(s) {if(s){changeDeploymentType("flows")}}},
+ {id:"btn-deploy-node",toggle:"deploy-type",icon:"images/deploy-nodes.png",label:"Modified Nodes",sublabel:"Only deploys nodes that have changed",onselect:function(s) { if(s){changeDeploymentType("nodes")}}}
]
});
diff --git a/public/red/nodes.js b/public/red/nodes.js
index 635184031..aaab94243 100644
--- a/public/red/nodes.js
+++ b/public/red/nodes.js
@@ -343,14 +343,23 @@ RED.nodes = (function() {
}
}
if(exportCreds && n.credentials) {
+ var credentialSet = {};
node.credentials = {};
for (var cred in n._def.credentials) {
if (n._def.credentials.hasOwnProperty(cred)) {
- if (n.credentials[cred] != null) {
- node.credentials[cred] = n.credentials[cred];
+ if (n._def.credentials[cred].type == 'password') {
+ if (n.credentials["has_"+cred] != n.credentials._["has_"+cred] ||
+ (n.credentials["has_"+cred] && n.credentials[cred])) {
+ credentialSet[cred] = n.credentials[cred];
+ }
+ } else if (n.credentials[cred] != null && n.credentials[cred] != n.credentials._[cred]) {
+ credentialSet[cred] = n.credentials[cred];
}
}
}
+ if (Object.keys(credentialSet).length > 0) {
+ node.credentials = credentialSet;
+ }
}
}
if (n._def.category != "config") {
@@ -385,7 +394,7 @@ RED.nodes = (function() {
var wires = links.filter(function(d) { return d.source === p });
for (var i=0;i
');
} else {
item = $('');
- var link = $(''+
- (opt.toggle?'':'')+
- (opt.icon?' ':'')+
- opt.label+
- '').appendTo(item);
+
+ var linkContent = '';
+ if (opt.toggle) {
+ linkContent += '';
+ linkContent += '';
+
+ }
+ if (opt.icon !== undefined) {
+ if (/\.png/.test(opt.icon)) {
+ linkContent += ' ';
+ } else {
+ linkContent += ' ';
+ }
+ }
+
+ if (opt.sublabel) {
+ linkContent += ''
+ } else {
+ linkContent += ''
+ }
+
+ linkContent += '';
+
+ var link = $(linkContent).appendTo(item);
menuItems[opt.id] = opt;
@@ -59,7 +79,22 @@ RED.menu = (function() {
return;
}
if (opt.toggle) {
- setSelected(opt.id, !isSelected(opt.id));
+ var selected = isSelected(opt.id);
+ if (typeof opt.toggle === "string") {
+ if (!selected) {
+ for (var m in menuItems) {
+ if (menuItems.hasOwnProperty(m)) {
+ var mi = menuItems[m];
+ if (mi.id != opt.id && opt.toggle == mi.toggle) {
+ setSelected(mi.id,false);
+ }
+ }
+ }
+ setSelected(opt.id,true);
+ }
+ } else {
+ setSelected(opt.id, !selected);
+ }
} else {
opt.onselect.call(opt);
}
@@ -67,6 +102,11 @@ RED.menu = (function() {
setState();
} else if (opt.href) {
link.attr("target","_blank").attr("href",opt.href);
+ } else if (!opt.options) {
+ item.addClass("disabled");
+ link.click(function(event) {
+ event.preventDefault();
+ });
}
if (opt.options) {
item.addClass("dropdown-submenu pull-left");
@@ -79,6 +119,17 @@ RED.menu = (function() {
if (opt.disabled) {
item.addClass("disabled");
}
+ if (opt.tip) {
+ item.popover({
+ placement:"left",
+ trigger: "hover",
+ delay: { show: 350, hide: 20 },
+ html: true,
+ container:'body',
+ content: opt.tip
+ });
+ }
+
}
@@ -88,8 +139,8 @@ RED.menu = (function() {
function createMenu(options) {
var button = $("#"+options.id);
-
- var topMenu = $("",{class:"dropdown-menu"}).insertAfter(button);
+
+ var topMenu = $("",{id:options.id+"-submenu", class:"dropdown-menu pull-right"}).insertAfter(button);
for (var i=0;i li {
+ display: inline-block;
+ padding: 0;
+ margin: 0;
+ position: relative;
+}
+
.button {
-webkit-user-select: none;
-khtml-user-select: none;
@@ -83,48 +98,120 @@ span.logo img {
}
#header .button {
- line-height: 22px;
+ min-width: 20px;
+ text-align: center;
+ line-height: 40px;
display: inline-block;
font-size: 14px;
- padding: 4px 12px;
+ padding: 0px 12px;
text-decoration: none;
- border-radius: 3px;
- color: #ccc;
- margin: auto 10px;
+ color: #C7C7C7;
+ margin: auto 5px;
vertical-align: middle;
+ border-left: 2px solid #000;
+ border-right: 2px solid #000;
}
#header .button:not(.disabled):hover {
- box-shadow: 0 0 2px #fff;
-}
-#btn-deploy:not(.disabled):hover {
- background: #ca3f39;
+ border-color: #323232;
}
#btn-deploy {
- color: #fff !important;
- background: #d24741;
- box-shadow: 0 0 2px #fff;
+ background: #8C101C; /*#d24741;*/
+ color: #eee !important;
+}
+#btn-deploy + a {
+ background: #8C101C; /*#BA403B;*/
+ color: #eee;
+}
+#btn-deploy + a:hover {
+ background: #6E0A1E; /*#AD3C38;*/
+ color: #eee;
+}
+#btn-deploy + a:active {
+ background: #4C0A17; /*#aa1f19;*/
+ color: #ccc;
+}
+span.deploy-button-group.open > #btn-deploy + a {
+ background: #121212 !important;
+}
+
+#btn-deploy:not(.disabled):hover {
+ background: #6E0A1E; /*#ca3f39;*/
+}
+
+
+#btn-deploy:not(.disabled):active {
+ background: #4C0A17 /*#aa1f19*/ !important;
}
#btn-deploy:not(.disabled):active {
- background: #aa1f19 !important;
color: #ccc !important;
- box-shadow: 0 0 2px #999;
}
+
#btn-deploy.disabled {
cursor: default;
- background: #444 ;
+ background: #444;
color: #999 !important;
}
+#btn-deploy.disabled + a {
+ background: #444;
+ color: #ddd;
+}
+#btn-deploy.disabled + a:hover {
+ background: #555;
+ color: #ddd;
+}
+#btn-deploy.disabled + a:active {
+ background: #444;
+ color: #ddd;
+}
+span.deploy-button-group.open > #btn-deploy.disabled + a {
+ background: #121212 !important;
+}
+
+
+#btn-deploy img {
+ margin-right: 8px;
+}
+#btn-deploy.disabled img {
+ opacity: 0.3;
+}
+
+.button-group {
+ display: inline-block;
+ margin: auto 10px;
+ vertical-align: middle;
+ background: #555;
+ clear: both;
+}
+.button-group > a {
+ float: left;
+ line-height: 22px;
+ font-size: 14px;
+ text-decoration: none;
+ display: inline-block;
+ padding: 4px 8px;
+ color: #ccc;
+ margin: 0;
+}
+.button-group > a:last-child {
+}
+
#btn-sidemenu {
font-size: 20px !important;
}
#btn-sidemenu:active, #btn-sidemenu.active {
- background: #333 ;
+ background: #121212;
}
#header .button:focus {
outline: none;
}
+li.open #btn-sidemenu {
+ background: #121212;
+ border-color: #121212;
+}
+
+
#workspace-toolbar .button {
line-height: 18px;
@@ -739,47 +826,39 @@ div.node-info {
.hidden {
display: none;
}
-/*
-.dropdown-menu {
- font-size: 14px;
- background: #000;
-}
-.dropdown-menu .divider {
- background: #666;
- border-bottom: #666;
-}
-.dropdown-menu>li>a {
- color: #ddd;
-}
-.dropdown-submenu>ul {
- border: 1px solid white;
- border-radius: 6px !important;
-}
-.dropdown-menu li.disabled a {
- color: #666;
-}
-.dropdown-menu li.disabled a:hover {
- background: none;
-}
-*/
+
.dropdown-menu>li>a:hover, .dropdown-menu>li>a:focus, .dropdown-submenu:hover>a, .dropdown-submenu:focus>a {
background: #999;
}
-.dropdown-menu * .fa-check {
+.dropdown-menu * .fa-check-square {
display: none;
- margin-right: -15px;
+ color: #e0e0e0;
+ margin-left: -25px;
margin-top: 3px;
}
-.dropdown-menu * a.active > .fa-check {
+.dropdown-menu * a.active > .fa-check-square {
display: inline-block;
}
+.dropdown-menu * .fa-square {
+ display: inline-block;
+ color: #e0e0e0;
+ margin-left: -25px;
+ margin-top: 3px;
+}
+.dropdown-menu * a.active > .fa-square {
+ display: none;
+}
+
+
.dropdown-menu>li.disabled>a:hover>[class^="icon-"] {
background-image: url("bootstrap/img/glyphicons-halflings.png") !important;
}
/** Fix for unreachable dropdown menu **/
.dropdown-menu {
+ border-radius: 0;
width: 200px !important;
+ margin-left: 0px !important;
}
.dropdown-menu > li > a > i {
width: 10px;
@@ -792,8 +871,32 @@ div.node-info {
white-space: normal !important;
}
-.popover-title { display: none; }
+.dropdown-submenu>a:after {
+ display: none;
+}
+.dropdown-submenu>a:before {
+ display: block;
+ float: left;
+ width: 0;
+ height: 0;
+ margin-top: 5px;
+ margin-left: -30px;
+ border-color: transparent;
+ border-right-color: #e0e0e0;
+ border-style: solid;
+ border-width: 5px 5px 5px 0;
+ content: " ";
+}
+.dropdown-submenu.disabled > a:before {
+ border-right-color: #444;
+}
+.dropdown-submenu.pull-left>.dropdown-menu {
+ border-radius: 0;
+}
+
+
+.popover-title { display: none; }
.leftButton {
margin-right: 200px !important;
@@ -1070,3 +1173,73 @@ i.spinner {
display: none;
}
+#header ul.dropdown-menu {
+ background: #121212;
+ width: 250px !important;
+ margin-top: 0;
+}
+
+#header ul.dropdown-menu li a {
+ color: #C7C7C7;
+ padding: 3px 40px;
+}
+
+#header ul.dropdown-menu li a img {
+ margin-right: 10px;
+ padding: 4px;
+ border: 3px solid rgba(0,0,0,0);
+}
+
+#header ul.dropdown-menu li a.active img {
+ border: 3px solid #777677;
+}
+
+#header ul.dropdown-menu li a span.menu-label-container {
+ width: 180px;
+ vertical-align: top;
+ display: inline-block;
+ text-indent: 0px;
+}
+#header ul.dropdown-menu li a span.menu-label {
+ font-size: 14px;
+ display: inline-block;
+ text-indent: 0px;
+}
+#header ul.dropdown-menu li a span.menu-sublabel {
+ color: #aeaeae;
+ font-size: 13px;
+ display: inline-block;
+ text-indent: 0px;
+}
+
+#header ul.dropdown-menu > li:hover > a,
+#header ul.dropdown-menu > li:focus > a {
+ background: #323232 !important;
+}
+
+#header ul.dropdown-menu li.divider {
+ background: #464646;
+ border-bottom-color: #323232;
+}
+#header ul.dropdown-menu li.disabled a {
+ color: #666;
+}
+
+/* Deploy menu customisations */
+#header ul#btn-deploy-options-submenu {
+ width: 300px !important;
+}
+#header ul#btn-deploy-options-submenu li a span.menu-label {
+ font-size: 16px;
+ display: inline-block;
+ text-indent: 0px;
+}
+#header ul#btn-deploy-options-submenu li a {
+ padding: 10px 30px;
+ color: #fff;
+}
+#header ul#btn-deploy-options-submenu li a > i.fa {
+ display: none !important;
+}
+
+
diff --git a/red/api/flows.js b/red/api/flows.js
index 9be6763b0..9b43e20c0 100644
--- a/red/api/flows.js
+++ b/red/api/flows.js
@@ -28,11 +28,13 @@ module.exports = {
},
post: function(req,res) {
var flows = req.body;
- redNodes.setFlows(flows).then(function() {
+ var deploymentType = req.get("Node-RED-Deployment-Type")||"full";
+ redNodes.setFlows(flows,deploymentType).then(function() {
res.send(204);
}).otherwise(function(err) {
util.log("[red] Error saving flows : "+err);
res.send(500,err.message);
+ console.log(err.stack);
});
}
}
diff --git a/red/nodes/Flow.js b/red/nodes/Flow.js
new file mode 100644
index 000000000..76e603d46
--- /dev/null
+++ b/red/nodes/Flow.js
@@ -0,0 +1,654 @@
+/**
+ * Copyright 2015 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.
+ **/
+
+var util = require("util");
+var when = require("when");
+var clone = require("clone");
+
+var typeRegistry = require("./registry");
+var credentials = require("./credentials");
+var redUtil = require("../util");
+var events = require("../events");
+
+function getID() {
+ return (1+Math.random()*4294967295).toString(16);
+}
+
+function createNode(type,config) {
+ var nn = null;
+ var nt = typeRegistry.get(type);
+ if (nt) {
+ try {
+ nn = new nt(clone(config));
+ }
+ catch (err) {
+ util.log("[red] "+type+" : "+err);
+ }
+ } else {
+ util.log("[red] unknown type: "+type);
+ }
+ return nn;
+}
+
+
+function createSubflow(sf,sfn,subflows) {
+ //console.log("CREATE SUBFLOW",sf.config.id,sfn.id);
+ var nodes = [];
+ var node_map = {};
+ var newNodes = [];
+ var node;
+ var wires;
+ var i,j,k;
+
+ // Clone all of the subflow node definitions and give them new IDs
+ for (i=0;i 0) {
+ throw new Error("missing types");
+ }
+
+ events.emit("nodes-starting");
+
+ for (var id in this.nodes) {
+ if (this.nodes.hasOwnProperty(id)) {
+ var node = this.nodes[id];
+ if (!node.subflow) {
+ if (!this.activeNodes[id]) {
+ this.activeNodes[id] = createNode(node.type,node.config);
+ //console.log(id,"created");
+ } else {
+ //console.log(id,"already running");
+ }
+ } else {
+ if (!this.subflowInstanceNodes[id]) {
+ var nodes = createSubflow(this.subflows[node.subflow],node.config,this.subflows);
+ this.subflowInstanceNodes[id] = nodes.map(function(n) { return n.id});
+ for (var i=0;i 0) {
+ var i = this.missingTypes.indexOf(type);
+ if (i != -1) {
+ this.missingTypes.splice(i,1);
+ if (this.missingTypes.length === 0 && this.started) {
+ this.start();
+ }
+ }
+ }
+
+}
+
+Flow.prototype.getNode = function(id) {
+ return this.activeNodes[id];
+}
+
+Flow.prototype.getFlow = function() {
+ //console.log(this.config);
+ return this.config;
+}
+
+Flow.prototype.eachNode = function(callback) {
+ for (var id in this.activeNodes) {
+ if (this.activeNodes.hasOwnProperty(id)) {
+ callback(this.activeNodes[id]);
+ }
+ }
+}
+
+Flow.prototype.applyConfig = function(config,type) {
+
+ var activeNodesToStop = [];
+ var nodesToRewire = [];
+
+ if (type && type!="full") {
+ var diff = this.diffFlow(config);
+ //console.log(diff);
+ //var diff = {
+ // deleted:[]
+ // changed:[]
+ // linked:[]
+ // wiringChanged: []
+ //}
+
+ var nodesToStop = [];
+ var nodesToCreate = [];
+ nodesToRewire = diff.wiringChanged;
+
+ if (type == "nodes") {
+ nodesToStop = diff.deleted.concat(diff.changed);
+ nodesToCreate = diff.changed;
+ } else if (type == "flows") {
+ nodesToStop = diff.deleted.concat(diff.changed).concat(diff.linked);
+ nodesToCreate = diff.changed.concat(diff.linked);
+ }
+
+ for (var i=0;i 0) {
+ var subflowId = changedSubflowStack.pop();
+
+ config.forEach(function(node) {
+ if (node.type == "subflow:"+subflowId) {
+ if (!changedNodes[node.id]) {
+ changedNodes[node.id] = node;
+ checkSubflowMembership(configNodes,node.id);
+ }
+ }
+ });
+
+ }
+
+ config.forEach(function(node) {
+ buildNodeLinks(newLinks,node,configNodes);
+ });
+
+ var markLinkedNodes = function(linkChanged,otherChangedNodes,linkMap,allNodes) {
+ var stack = Object.keys(changedNodes).concat(Object.keys(otherChangedNodes));
+ var visited = {};
+
+ while(stack.length > 0) {
+ var id = stack.pop();
+ var linkedNodes = linkMap[id];
+ if (linkedNodes) {
+ for (var i=0;i 0) {
- var i = missingTypes.indexOf(type);
- if (i != -1) {
- missingTypes.splice(i,1);
- util.log("[red] Missing type registered: "+type);
- if (missingTypes.length === 0) {
- parseConfig();
- }
- }
+ if (activeFlow) {
+ if (activeFlow.typeRegistered(type)) {
+ util.log("[red] Missing type registered: "+type);
}
+ }
});
-
-function getID() {
- return (1+Math.random()*4294967295).toString(16);
-}
-
-function createSubflow(sf,sfn) {
- var node_map = {};
- var newNodes = [];
- var node;
- var wires;
- var i,j,k;
-
- // Clone all of the subflow node definitions and give them new IDs
- for (i=0;i 0) {
- util.log("[red] Waiting for missing types to be registered:");
- for (i=0;i 0) {
- util.log("[red] Stopping flows");
- }
- return flowNodes.clear();
-}
var flowNodes = module.exports = {
init: function(_storage) {
@@ -238,13 +54,12 @@ var flowNodes = module.exports = {
load: function() {
return storage.getFlows().then(function(flows) {
return credentials.load().then(function() {
- activeConfig = flows;
- if (activeConfig && activeConfig.length > 0) {
- parseConfig();
- }
+ activeFlow = new Flow(flows);
+ flowNodes.startFlows();
});
}).otherwise(function(err) {
util.log("[red] Error loading flows : "+err);
+ console.log(err.stack);
});
},
@@ -253,7 +68,7 @@ var flowNodes = module.exports = {
* @param n the node to add
*/
add: function(n) {
- nodes[n.id] = n;
+ //console.log("ADDED NODE:",n.id,n.type,n.name||"");
n.on("log",log.log);
},
@@ -263,77 +78,118 @@ var flowNodes = module.exports = {
* @return the node
*/
get: function(i) {
- return nodes[i];
+ return activeFlow.getNode(i);
+ },
+
+ eachNode: function(cb) {
+ activeFlow.eachNode(cb);
},
/**
* Stops all active nodes and clears the active set
* @return a promise for the stopping of all active nodes
*/
- clear: function() {
- return when.promise(function(resolve) {
- events.emit("nodes-stopping");
- var promises = [];
- for (var n in nodes) {
- if (nodes.hasOwnProperty(n)) {
- try {
- var p = nodes[n].close();
- if (p) {
- promises.push(p);
- }
- } catch(err) {
- nodes[n].error(err);
- }
- }
- }
- when.settle(promises).then(function() {
- events.emit("nodes-stopped");
- nodes = {};
- resolve();
- });
- });
- },
-
- /**
- * Provides an iterator over the active set of nodes
- * @param cb a function to be called for each node in the active set
- */
- each: function(cb) {
- for (var n in nodes) {
- if (nodes.hasOwnProperty(n)) {
- cb(nodes[n]);
- }
- }
- },
+ //clear: function(nodesToStop) {
+ // var stopList;
+ // if (nodesToStop == null) {
+ // stopList = Object.keys(nodes);
+ // } else {
+ // stopList = Object.keys(nodesToStop);
+ // }
+ // console.log(stopList);
+ // return when.promise(function(resolve) {
+ // events.emit("nodes-stopping");
+ // var promises = [];
+ // console.log("running nodes:",Object.keys(nodes).length);
+ // for (var i=0;i 0) {
+ util.log("[red] Waiting for missing types to be registered:");
+ for (var i=0;i