Merge branch 'dev' into pr_2042

This commit is contained in:
Nick O'Leary
2019-02-04 14:39:00 +00:00
29 changed files with 784 additions and 129 deletions

View File

@@ -38,7 +38,11 @@ function Node(n) {
// Make this a non-enumerable property as it may cause
// circular references. Any existing code that tries to JSON serialise
// the object (such as dashboard) will not like circular refs
Object.defineProperty(this,'_flow', {value: n._flow, })
// The value must still be writable in the case that a node does:
// Object.assign(this,config)
// as part of its constructure - config._flow will overwrite this._flow
// which we can tolerate as they are the same object.
Object.defineProperty(this,'_flow', {value: n._flow, enumerable: false, writable: true })
}
this.updateWires(n.wires);
}

View File

@@ -265,7 +265,6 @@ class Flow {
return Promise.all(promises);
}
/**
* Update the flow definition. This doesn't change anything that is running.
* This should be called after `stop` and before `start`.
@@ -281,11 +280,13 @@ class Flow {
/**
* Get a node instance from this flow. If the node is not known to this
* flow, pass the request up to the parent.
* @param {[type]} id [description]
* @param {String} id [description]
* @param {Boolean} cancelBubble if true, prevents the flow from passing the request to the parent
* This stops infinite loops when the parent asked this Flow for the
* node to begin with.
* @return {[type]} [description]
*/
getNode(id) {
// console.log('getNode',id,!!this.activeNodes[id])
getNode(id, cancelBubble) {
if (!id) {
return undefined;
}
@@ -298,7 +299,10 @@ class Flow {
// TEMP: this is a subflow internal node within this flow
return this.activeNodes[id];
}
return this.parent.getNode(id);
if (!cancelBubble) {
return this.parent.getNode(id);
}
return undefined;
}
/**

View File

@@ -17,6 +17,8 @@
const clone = require("clone");
const Flow = require('./Flow').Flow;
const util = require("util");
const redUtil = require("@node-red/util").util;
const flowUtil = require("./util");
@@ -113,6 +115,40 @@ class Subflow extends Flow {
var self = this;
// Create a subflow node to accept inbound messages and route appropriately
var Node = require("../Node");
if (this.subflowDef.status) {
var subflowStatusConfig = {
id: this.subflowInstance.id+":status",
type: "subflow-status",
z: this.subflowInstance.id,
_flow: this.parent
}
this.statusNode = new Node(subflowStatusConfig);
this.statusNode.on("input", function(msg) {
if (msg.payload !== undefined) {
if (typeof msg.payload === "string") {
// if msg.payload is a String, use it as status text
self.node.status({text:msg.payload})
return;
} else if (Object.prototype.toString.call(msg.payload) === "[object Object]") {
if (msg.payload.hasOwnProperty('text') || msg.payload.hasOwnProperty('fill') || msg.payload.hasOwnProperty('shape') || Object.keys(msg.payload).length === 0) {
// msg.payload is an object that looks like a status object
self.node.status(msg.payload);
return;
}
}
// Anything else - inspect it and use as status text
var text = util.inspect(msg.payload);
if (text.length > 32) { text = text.substr(0,32) + "..."; }
self.node.status({text:text});
} else if (msg.status !== undefined) {
// if msg.status exists
self.node.status(msg.status)
}
})
}
var subflowInstanceConfig = {
id: this.subflowInstance.id,
type: this.subflowInstance.type,
@@ -177,7 +213,6 @@ class Subflow extends Flow {
// Wire the subflow outputs
if (this.subflowDef.out) {
var modifiedNodes = {};
for (var i=0;i<this.subflowDef.out.length;i++) {
// i: the output index
// This is what this Output is wired to
@@ -189,7 +224,6 @@ class Subflow extends Flow {
this.node._updateWires(subflowInstanceConfig.wires);
} else {
var node = self.node_map[wires[j].id];
modifiedNodes[node.id] = node;
if (!node._originalWires) {
node._originalWires = clone(node.wires);
}
@@ -198,6 +232,26 @@ class Subflow extends Flow {
}
}
}
if (this.subflowDef.status) {
var subflowStatusId = this.statusNode.id;
wires = this.subflowDef.status.wires;
for (var j=0;j<wires.length;j++) {
if (wires[j].id === this.subflowDef.id) {
// A subflow input wired straight to a subflow output
subflowInstanceConfig.wires[wires[j].port].push(subflowStatusId);
this.node._updateWires(subflowInstanceConfig.wires);
} else {
var node = self.node_map[wires[j].id];
if (!node._originalWires) {
node._originalWires = clone(node.wires);
}
node.wires[wires[j].port] = (node.wires[wires[j].port]||[]);
node.wires[wires[j].port].push(subflowStatusId);
}
}
}
super.start(diff);
}
@@ -227,6 +281,23 @@ class Subflow extends Flow {
return undefined;
}
/**
* Get a node instance from this subflow.
* If the subflow has a status node, check for that, otherwise use
* the super-class function
* @param {String} id [description]
* @param {Boolean} cancelBubble if true, prevents the flow from passing the request to the parent
* This stops infinite loops when the parent asked this Flow for the
* node to begin with.
* @return {[type]} [description]
*/
getNode(id, cancelBubble) {
if (this.statusNode && this.statusNode.id === id) {
return this.statusNode;
}
return super.getNode(id,cancelBubble);
}
/**
* Handle a status event from a node within this flow.
* @param {Node} node The original node that triggered the event
@@ -240,10 +311,14 @@ class Subflow extends Flow {
handleStatus(node,statusMessage,reportingNode,muteStatus) {
let handled = super.handleStatus(node,statusMessage,reportingNode,muteStatus);
if (!handled) {
// No status node on this subflow caught the status message.
// Pass up to the parent with this subflow's instance as the
// reporting node
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
if (!this.statusNode || node === this.node) {
// No status node on this subflow caught the status message.
// AND there is no Subflow Status node - so the user isn't
// wanting to manage status messages themselves
// Pass up to the parent with this subflow's instance as the
// reporting node
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
}
}
return handled;

View File

@@ -207,11 +207,11 @@ function setFlows(_config,type,muteLog,forceStart) {
function getNode(id) {
var node;
if (activeNodesToFlow[id] && activeFlows[activeNodesToFlow[id]]) {
return activeFlows[activeNodesToFlow[id]].getNode(id);
return activeFlows[activeNodesToFlow[id]].getNode(id,true);
}
for (var flowId in activeFlows) {
if (activeFlows.hasOwnProperty(flowId)) {
node = activeFlows[flowId].getNode(id);
node = activeFlows[flowId].getNode(id,true);
if (node) {
return node;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "0.20.0-beta.3",
"version": "0.20.0-beta.4",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/registry": "0.20.0-beta.3",
"@node-red/util": "0.20.0-beta.3",
"@node-red/registry": "0.20.0-beta.4",
"@node-red/util": "0.20.0-beta.4",
"clone": "2.1.2",
"express": "4.16.4",
"fs-extra": "7.0.1",