From 41a0af032c47993acd49681c71c37f5842b90958 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 14 Jun 2019 22:12:47 +0100 Subject: [PATCH 1/3] Enable individual flow nodes to be disabled --- .../@node-red/editor-client/src/js/nodes.js | 7 ++- .../src/js/ui/common/toggleButton.js | 3 +- .../editor-client/src/js/ui/editor.js | 61 +++++++++++-------- .../@node-red/editor-client/src/js/ui/view.js | 2 + .../editor-client/src/sass/editor.scss | 21 ++++--- .../editor-client/src/sass/flow.scss | 19 ++++-- .../editor-client/src/sass/mixins.scss | 2 +- .../@node-red/runtime/lib/nodes/flows/Flow.js | 60 +++++++++--------- 8 files changed, 106 insertions(+), 69 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 4a1c6e9a0..7e189ba91 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -463,7 +463,9 @@ RED.nodes = (function() { node.id = n.id; node.type = n.type; node.z = n.z; - + if (n.d === true) { + node.d = true; + } if (node.type == "unknown") { for (var p in n._orig) { if (n._orig.hasOwnProperty(p)) { @@ -1016,6 +1018,9 @@ RED.nodes = (function() { if (n.hasOwnProperty('l')) { node.l = n.l; } + if (n.hasOwnProperty('d')) { + node.d = n.d; + } if (createNewIds) { if (subflow_blacklist[n.z]) { continue; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js index 1a52183d3..999606912 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/toggleButton.js @@ -42,12 +42,11 @@ var enabledLabel = this.options.enabledLabel || RED._("editor:workspace.enabled"); var disabledLabel = this.options.disabledLabel || RED._("editor:workspace.disabled"); - this.element.addClass("red-ui-toggleButton"); this.element.css("display","none"); this.element.on("focus", function() { that.button.focus(); }); - this.button = $(''); + this.button = $(''); if (this.options.class) { this.button.addClass(this.options.class) } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index b64bb8e5c..336b80e9c 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -955,34 +955,19 @@ RED.editor = (function() { $('
'+ ''+ - ' '+ - ''+ + ''+ '
').appendTo(dialogForm); - var setToggleState = function(state) { - var i = $("#node-input-show-label-btn-i"); - if (!state) { - i.addClass('fa-toggle-off'); - i.removeClass('fa-toggle-on'); - $("#node-input-show-label").prop("checked",false); - $("#node-input-show-label-label").text(RED._("editor.hide")); - } else { - i.addClass('fa-toggle-on'); - i.removeClass('fa-toggle-off'); - $("#node-input-show-label").prop("checked",true); - $("#node-input-show-label-label").text(RED._("editor.show")); - } - } - dialogForm.find('#node-input-show-label-btn').on("click",function(e) { - e.preventDefault(); - var i = $("#node-input-show-label-btn-i"); - setToggleState(i.hasClass('fa-toggle-off')); + $("#node-input-show-label").toggleButton({ + enabledLabel: RED._("editor.show"), + disabledLabel: RED._("editor.hide") }) + if (!node.hasOwnProperty("l")) { // Show label if type not link node.l = !/^link (in|out)$/.test(node._def.type); } - setToggleState(node.l); + $("#node-input-show-label").prop("checked",node.l).trigger("change"); // If a node has icon property in defaults, the icon of the node cannot be modified. (e.g, ui_button node in dashboard) if ((!node._def.defaults || !node._def.defaults.hasOwnProperty("icon"))) { @@ -1396,6 +1381,20 @@ RED.editor = (function() { node.l = true; } } + if ($("#node-input-node-disabled").prop('checked')) { + if (node.d !== true) { + changes.d = node.d; + changed = true; + node.d = true; + } + } else { + if (node.d === true) { + changes.d = node.d; + changed = true; + delete node.d; + } + } + node.resize = true; var oldInfo = node.info; @@ -1498,6 +1497,12 @@ RED.editor = (function() { var trayBody = tray.find('.red-ui-tray-body'); trayBody.parent().css('overflow','hidden'); + var trayFooterLeft = $('').appendTo(trayFooter) + + $('').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({ + invertState: true + }) + var editorTabEl = $('').appendTo(trayBody); var editorContent = $('
').appendTo(trayBody); @@ -1675,9 +1680,15 @@ RED.editor = (function() { var trayHeader = tray.find(".red-ui-tray-header"); var trayBody = tray.find('.red-ui-tray-body'); var trayFooter = tray.find(".red-ui-tray-footer"); - var userCountDiv; + + var trayFooterLeft = $('').appendTo(trayFooter) + + $('').appendTo(trayFooterLeft).toggleButton({ + invertState: true + }) + if (node_def.hasUsers !== false) { - userCountDiv = $('').prependTo(trayFooter); + $(' ').css("margin-left", "10px").appendTo(trayFooterLeft); } trayFooter.append(''); @@ -1771,8 +1782,8 @@ RED.editor = (function() { } }); } - if (node_def.hasUsers !== false && userCountDiv) { - userCountDiv.find("span").text(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show(); + if (node_def.hasUsers !== false) { + $("#red-ui-editor-config-user-count").text(RED._("editor.nodesUse", {count:editing_config_node.users.length})).parent().show(); } trayBody.i18n(); trayFooter.i18n(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index d5a76eacd..cdc8bd311 100755 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -2929,6 +2929,7 @@ RED.view = (function() { d.resize = false; } var thisNode = d3.select(this); + thisNode.classed("red-ui-flow-node-disabled", function(d) { return d.d === true}); thisNode.classed("red-ui-flow-subflow",function(d) { return activeSubflow != null; }) //thisNode.selectAll(".centerDot").attr({"cx":function(d) { return d.w/2;},"cy":function(d){return d.h/2}}); @@ -3248,6 +3249,7 @@ RED.view = (function() { } return path; }); + link.classed("red-ui-flow-node-disabled", function(d) { return d.source.d || d.target.d; }); } }) diff --git a/packages/node_modules/@node-red/editor-client/src/sass/editor.scss b/packages/node_modules/@node-red/editor-client/src/sass/editor.scss index 83c72b07b..6338eb73e 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/editor.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/editor.scss @@ -79,15 +79,20 @@ .red-ui-tray-footer { @include component-footer; height: 35px; - font-size: 12px !important; + font-size: 14px !important; line-height: 35px; vertical-align: middle; - button { - @include editor-button; - padding: 3px 7px; - font-size: 11px; + button.red-ui-button { + padding: 0px 8px; + height: 26px; + line-height: 26px; + &.toggle:not(.selected) { + color: $workspace-button-color-selected !important; + background: $workspace-button-background-active; + } } + .red-ui-tray-footer-left { display:inline-block; margin-right: 20px; @@ -563,8 +568,6 @@ button.red-ui-button-small } - - .red-ui-editor-type-json-editor-item-handle { cursor: move; } @@ -572,3 +575,7 @@ button.red-ui-button-small position: relative; height: calc(100% - 40px); } + +button.red-ui-toggleButton.toggle { + text-align: left; +} diff --git a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss index 4f24a6f11..c440ab4a8 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss @@ -146,11 +146,11 @@ g.red-ui-flow-node-selected { border-style: dashed !important; stroke: $node-selected-color; stroke-width: 2; - stroke-dasharray: 10, 4; + stroke-dasharray: 8, 3; } .red-ui-flow-subflow .red-ui-flow-node { - stroke-dasharray:8, 3; + stroke-dasharray:8, 2; } .red-ui-workspace-disabled { .red-ui-flow-link-line { @@ -159,10 +159,21 @@ g.red-ui-flow-node-selected { stroke: $link-subflow-color; } .red-ui-flow-node { - stroke-dasharray: 10,4; + stroke-dasharray: 8, 3; + fill-opacity: 0.6; + } +} +.red-ui-flow-node-disabled { + &.red-ui-flow-node, .red-ui-flow-node { + stroke-dasharray: 8, 3; + fill-opacity: 0.6; + } + &.red-ui-flow-link-line { + stroke-dasharray: 10,5 !important; + stroke-width: 2 !important; + stroke: $link-subflow-color; } } - @each $current-color in red green yellow blue grey { .red-ui-flow-node-status-dot-#{$current-color} { fill: map-get($node-status-colors,$current-color); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss b/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss index 91978057e..dda9ef384 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss @@ -192,7 +192,7 @@ right: 0; height: 25px; line-height: 25px; - padding: 0 10px; + padding: 0 6px; user-select: none; .button-group:not(:last-child) { diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js index 8b0341463..d200a6684 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js @@ -171,37 +171,39 @@ class Flow { for (id in this.flow.nodes) { if (this.flow.nodes.hasOwnProperty(id)) { node = this.flow.nodes[id]; - if (!node.subflow) { - if (!this.activeNodes[id]) { - newNode = flowUtil.createNode(this,node); - if (newNode) { - this.activeNodes[id] = newNode; + if (node.d !== true) { + if (!node.subflow) { + if (!this.activeNodes[id]) { + newNode = flowUtil.createNode(this,node); + if (newNode) { + this.activeNodes[id] = newNode; + } } - } - } else { - if (!this.subflowInstanceNodes[id]) { - try { - var subflowDefinition = this.flow.subflows[node.subflow]||this.global.subflows[node.subflow] - // console.log("NEED TO CREATE A SUBFLOW",id,node.subflow); - this.subflowInstanceNodes[id] = true; - var subflow = Subflow.create( - this, - this.global, - subflowDefinition, - node - ); - this.subflowInstanceNodes[id] = subflow; - subflow.start(); - this.activeNodes[id] = subflow.node; + } else { + if (!this.subflowInstanceNodes[id]) { + try { + var subflowDefinition = this.flow.subflows[node.subflow]||this.global.subflows[node.subflow] + // console.log("NEED TO CREATE A SUBFLOW",id,node.subflow); + this.subflowInstanceNodes[id] = true; + var subflow = Subflow.create( + this, + this.global, + subflowDefinition, + node + ); + this.subflowInstanceNodes[id] = subflow; + subflow.start(); + this.activeNodes[id] = subflow.node; - // this.subflowInstanceNodes[id] = nodes.map(function(n) { return n.id}); - // for (var i=0;i Date: Mon, 17 Jun 2019 22:46:34 +0100 Subject: [PATCH 2/3] Allow config nodes to be disabled, tidy css and add actions --- .../@node-red/editor-client/src/js/nodes.js | 3 ++ .../editor-client/src/js/ui/editor.js | 18 ++++++- .../editor-client/src/js/ui/tab-config.js | 7 ++- .../@node-red/editor-client/src/js/ui/view.js | 48 +++++++++++++++++- .../editor-client/src/js/ui/workspaces.js | 7 ++- .../editor-client/src/sass/colors.scss | 6 +-- .../editor-client/src/sass/flow.scss | 42 +++++++++------- .../editor-client/src/sass/tab-config.scss | 10 +++- .../@node-red/runtime/lib/nodes/flows/Flow.js | 50 ++++++++++++------- 9 files changed, 142 insertions(+), 49 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 7e189ba91..5c544e7b7 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -969,6 +969,9 @@ RED.nodes = (function() { users:[], _config:{} }; + if (n.hasOwnProperty('d')) { + configNode.d = n.d; + } for (d in def.defaults) { if (def.defaults.hasOwnProperty(d)) { configNode[d] = n[d]; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 336b80e9c..1b3ccea52 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -1500,6 +1500,8 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) $('').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({ + enabledIcon: "fa-circle-thin", + disabledIcon: "fa-ban", invertState: true }) @@ -1683,7 +1685,9 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) - $('').appendTo(trayFooterLeft).toggleButton({ + $('').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({ + enabledIcon: "fa-circle-thin", + disabledIcon: "fa-ban", invertState: true }) @@ -1918,6 +1922,16 @@ RED.editor = (function() { editing_config_node.label = configTypeDef.label; editing_config_node.z = scope; + if ($("#node-config-input-node-disabled").prop('checked')) { + if (editing_config_node.d !== true) { + editing_config_node.d = true; + } + } else { + if (editing_config_node.d === true) { + delete editing_config_node.d; + } + } + if (scope) { // Search for nodes that use this one that are no longer // in scope, so must be removed @@ -2072,7 +2086,7 @@ RED.editor = (function() { RED.nodes.eachConfig(function(config) { if (config.type == type && (!config.z || config.z === activeWorkspace.id)) { var label = RED.utils.getNodeLabel(config,config.id); - config.__label__ = label; + config.__label__ = label+(config.d?" ["+RED._("workspace.disabled")+"]":""); configNodes.push(config); } }); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js index c7131aa7e..86785c385 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js @@ -145,7 +145,12 @@ RED.sidebar.config = (function() { var entry = $('
  • ').appendTo(list); var nodeDiv = $('
    ').appendTo(entry); entry.data('node',node.id); - $('
    ').text(label).appendTo(nodeDiv); + var label = $('
    ').text(label).appendTo(nodeDiv); + if (node.d) { + nodeDiv.addClass("red-ui-palette-node-config-disabled"); + $('').prependTo(label); + } + if (node._def.hasUsers !== false) { var iconContainer = $('
    ',{class:"red-ui-palette-icon-container red-ui-palette-icon-container-right"}).appendTo(nodeDiv); if (node.users.length === 0) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index cdc8bd311..81453c675 100755 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -410,6 +410,8 @@ RED.view = (function() { RED.actions.add("core:zoom-in",zoomIn); RED.actions.add("core:zoom-out",zoomOut); RED.actions.add("core:zoom-reset",zoomZero); + RED.actions.add("core:enable-selected-nodes", function() { setSelectedNodeState(false)}); + RED.actions.add("core:disable-selected-nodes", function() { setSelectedNodeState(true)}); RED.actions.add("core:toggle-show-grid",function(state) { if (state === undefined) { @@ -2376,7 +2378,7 @@ RED.view = (function() { function isButtonEnabled(d) { var buttonEnabled = true; var ws = RED.nodes.workspace(RED.workspaces.active()); - if (ws && !ws.disabled) { + if (ws && !ws.disabled && !d.d) { if (d._def.button.hasOwnProperty('enabled')) { if (typeof d._def.button.enabled === "function") { buttonEnabled = d._def.button.enabled.call(d); @@ -2397,7 +2399,7 @@ RED.view = (function() { } var activeWorkspace = RED.workspaces.active(); var ws = RED.nodes.workspace(activeWorkspace); - if (ws && !ws.disabled) { + if (ws && !ws.disabled && !d.d) { if (d._def.button.toggle) { d[d._def.button.toggle] = !d[d._def.button.toggle]; d.dirty = true; @@ -3580,6 +3582,48 @@ RED.view = (function() { //TODO: subscribe/unsubscribe here redraw(); } + function setSelectedNodeState(isDisabled) { + if (mouse_mode === RED.state.SELECTING_NODE) { + return; + } + var workspaceSelection = RED.workspaces.selection(); + var changed = false; + if (workspaceSelection.length > 0) { + // TODO: toggle workspace state + } else if (moving_set.length > 0) { + var historyEvents = []; + for (var i=0;i 0) { + RED.history.push({ + t:"multi", + events: historyEvents, + dirty:RED.nodes.dirty() + }) + RED.nodes.dirty(true) + } + } + RED.view.redraw(); + + } return { init: init, diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index 3fffe2e64..db36004ab 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -201,8 +201,11 @@ RED.workspaces = (function() { } else { workspace.disabled = false; } - $("#node-input-disabled").toggleButton({invertState: true}) - + $("#node-input-disabled").toggleButton({ + enabledIcon: "fa-circle-thin", + disabledIcon: "fa-ban", + invertState: true + }) $('').prependTo(dialogForm); dialogForm.on("submit", function(e) { e.preventDefault();}); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss index 3b6d14280..8411343c5 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss @@ -224,10 +224,10 @@ $node-status-colors: ( $node-selected-color: #ff7f0e; $port-selected-color: #ff7f0e; -$link-color: #888; -$link-link-color: #ccc; +$link-color: #999; +$link-link-color: #aaa; +$link-disabled-color: #ccc; $link-link-active-color: #ff7f0e; -$link-subflow-color: #bbb; $link-unknown-color: #f00; $clipboard-textarea-background: #F3E7E7; diff --git a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss index c440ab4a8..4aae0869c 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/flow.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/flow.scss @@ -150,28 +150,36 @@ g.red-ui-flow-node-selected { } .red-ui-flow-subflow .red-ui-flow-node { - stroke-dasharray:8, 2; } + .red-ui-workspace-disabled { - .red-ui-flow-link-line { - stroke-dasharray: 10,5 !important; - stroke-width: 2 !important; - stroke: $link-subflow-color; - } .red-ui-flow-node { stroke-dasharray: 8, 3; - fill-opacity: 0.6; + fill-opacity: 0.5; + } + .red-ui-flow-link-line { + stroke-dasharray: 10,8 !important; + stroke-width: 2 !important; + stroke: $link-disabled-color; + } + .red-ui-flow-port { + fill-opacity: 1; + stroke-dasharray: none; } } .red-ui-flow-node-disabled { &.red-ui-flow-node, .red-ui-flow-node { stroke-dasharray: 8, 3; - fill-opacity: 0.6; + fill-opacity: 0.5; } &.red-ui-flow-link-line { - stroke-dasharray: 10,5 !important; + stroke-dasharray: 10,8 !important; stroke-width: 2 !important; - stroke: $link-subflow-color; + stroke: $link-disabled-color; + } + .red-ui-flow-port { + fill-opacity: 1; + stroke-dasharray: none; } } @each $current-color in red green yellow blue grey { @@ -199,7 +207,6 @@ g.red-ui-flow-node-selected { } .red-ui-flow-subflow-port { - stroke-dasharray: 5,5; fill: $node-background-placeholder; stroke: $node-border; } @@ -219,12 +226,14 @@ g.red-ui-flow-node-selected { } .red-ui-flow-link-link { stroke-width: 2; - stroke-dasharray: 10,5; stroke: $link-link-color; fill: none; - stroke-dasharray: 15,2; - // pointer-events: none; + stroke-dasharray: 25,4; } +.red-ui-flow-link-off-flow { + stroke-width: 2; +} + .red-ui-flow-link-port { fill: $node-link-port-background; stroke: $link-link-color; @@ -236,11 +245,6 @@ g.red-ui-flow-node-selected { .red-ui-flow-link-group:hover { cursor: pointer; } -.red-ui-flow-subflow-link { - stroke: $link-subflow-color; - stroke-dasharray: 10,5; - stroke-width: 2; -} .red-ui-flow-link-outline { stroke: $view-background; diff --git a/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss b/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss index 69a2ee5dd..467ce8511 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/tab-config.scss @@ -94,12 +94,20 @@ ul.red-ui-sidebar-node-config-list li.red-ui-palette-node-config-type { text-align:right; padding-right: 3px; } -.red-ui-palette-node-config-unused { +.red-ui-palette-node-config-unused,.red-ui-palette-node-config-disabled { border-color: $primary-border-color; background: $secondary-background-inactive; border-style: dashed; color: $tertiary-text-color; } +.red-ui-palette-node-config-disabled { + opacity: 0.6; + font-style: italic; + i { + color: $secondary-text-color; + margin-right: 5px; + } +} .red-ui-sidebar-node-config-filter-info { position: absolute; top: 0; diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js index d200a6684..6077f50cd 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js @@ -132,29 +132,39 @@ class Flow { id = configNodes.shift(); node = this.flow.configs[id]; if (!this.activeNodes[id]) { - var readyToCreate = true; - // This node doesn't exist. - // Check it doesn't reference another non-existent config node - for (var prop in node) { - if (node.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== '_users' && this.flow.configs[node[prop]]) { - if (!this.activeNodes[node[prop]]) { - // References a non-existent config node - // Add it to the back of the list to try again later - configNodes.push(id); - configNodeAttempts[id] = (configNodeAttempts[id]||0)+1; - if (configNodeAttempts[id] === 100) { - throw new Error("Circular config node dependency detected: "+id); + if (node.d !== true) { + var readyToCreate = true; + // This node doesn't exist. + // Check it doesn't reference another non-existent config node + for (var prop in node) { + if (node.hasOwnProperty(prop) && + prop !== 'id' && + prop !== 'wires' && + prop !== '_users' && + this.flow.configs[node[prop]] && + this.flow.configs[node[prop]].d !== true + ) { + if (!this.activeNodes[node[prop]]) { + // References a non-existent config node + // Add it to the back of the list to try again later + configNodes.push(id); + configNodeAttempts[id] = (configNodeAttempts[id]||0)+1; + if (configNodeAttempts[id] === 100) { + throw new Error("Circular config node dependency detected: "+id); + } + readyToCreate = false; + break; } - readyToCreate = false; - break; } } - } - if (readyToCreate) { - newNode = flowUtil.createNode(this,node); - if (newNode) { - this.activeNodes[id] = newNode; + if (readyToCreate) { + newNode = flowUtil.createNode(this,node); + if (newNode) { + this.activeNodes[id] = newNode; + } } + } else { + this.debug("not starting disabled config node : "+id); } } } @@ -206,6 +216,8 @@ class Flow { } } } + } else { + this.debug("not starting disabled node : "+id); } } } From f106019938bb90f61d89e409a3deb38c074921b9 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 18 Jun 2019 11:02:31 +0100 Subject: [PATCH 3/3] Add runtime test for disabled nodes --- .../runtime/lib/nodes/flows/Flow_spec.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/unit/@node-red/runtime/lib/nodes/flows/Flow_spec.js b/test/unit/@node-red/runtime/lib/nodes/flows/Flow_spec.js index 172ac11e6..e7430a6c2 100644 --- a/test/unit/@node-red/runtime/lib/nodes/flows/Flow_spec.js +++ b/test/unit/@node-red/runtime/lib/nodes/flows/Flow_spec.js @@ -319,6 +319,57 @@ describe('Flow', function() { }); }); + it("ignores disabled nodes",function(done) { + var config = flowUtils.parseConfig([ + {id:"t1",type:"tab"}, + {id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]}, + {id:"2",x:10,y:10,z:"t1",d:true,type:"test",foo:"a",wires:["3"]}, + {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]}, + {id:"4",z:"t1",type:"test",foo:"a"}, + {id:"5",z:"t1",type:"test",d:true,foo:"a"} + + ]); + var flow = Flow.create({},config,config.flows["t1"]); + flow.start(); + + Object.keys(flow.getActiveNodes()).should.have.length(3); + + flow.getNode('1').should.have.a.property('id','1'); + should.not.exist(flow.getNode('2')); + flow.getNode('3').should.have.a.property('id','3'); + flow.getNode('4').should.have.a.property('id','4'); + should.not.exist(flow.getNode('5')); + + currentNodes.should.have.a.property("1"); + currentNodes.should.not.have.a.property("2"); + currentNodes.should.have.a.property("3"); + currentNodes.should.have.a.property("4"); + + currentNodes["1"].should.have.a.property("handled",0); + currentNodes["3"].should.have.a.property("handled",0); + + currentNodes["1"].receive({payload:"test"}); + + currentNodes["1"].should.have.a.property("handled",1); + // Message doesn't reach 3 as 2 is disabled + currentNodes["3"].should.have.a.property("handled",0); + + flow.stop().then(function() { + try { + currentNodes.should.not.have.a.property("1"); + currentNodes.should.not.have.a.property("2"); + currentNodes.should.not.have.a.property("3"); + currentNodes.should.not.have.a.property("4"); + stoppedNodes.should.have.a.property("1"); + stoppedNodes.should.not.have.a.property("2"); + stoppedNodes.should.have.a.property("3"); + stoppedNodes.should.have.a.property("4"); + done(); + } catch(err) { + done(err); + } + }); + }); });