mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add path property to debug messages
Fixes #2358 This property can be used to identify the full path to the node that logged a given message. If the node is inside a subflow (and maybe nested many levels deep), this path can be used to help find the node, rather than just the top-level subflow instance node. A side-effect of this change is the Debug sidebar is now able to show the message tools for a message coming from a deeply nested subflow
This commit is contained in:
parent
5e7cd79ed9
commit
95a51aafdc
@ -131,8 +131,32 @@
|
|||||||
RED.view.redraw();
|
RED.view.redraw();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
messageSourceClick: function(sourceId) {
|
messageSourceClick: function(sourceId, aliasId, path) {
|
||||||
RED.view.reveal(sourceId);
|
// Get all of the nodes that could have logged this message
|
||||||
|
var candidateNodes = [RED.nodes.node(sourceId)]
|
||||||
|
if (path) {
|
||||||
|
for (var i=2;i<path.length;i++) {
|
||||||
|
candidateNodes.push(RED.nodes.node(path[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (aliasId) {
|
||||||
|
candidateNodes.push(RED.nodes.node(aliasId));
|
||||||
|
}
|
||||||
|
if (candidateNodes.length > 1) {
|
||||||
|
// The node is in a subflow. Check to see if the active
|
||||||
|
// workspace is a subflow in the node's parentage. If
|
||||||
|
// so, reveal the relevant subflow instance node.
|
||||||
|
var ws = RED.workspaces.active();
|
||||||
|
for (var i=0;i<candidateNodes.length;i++) {
|
||||||
|
if (candidateNodes[i].z === ws) {
|
||||||
|
RED.view.reveal(candidateNodes[i].id);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The active workspace is unrelated to the node. So
|
||||||
|
// fall back to revealing the top most node
|
||||||
|
}
|
||||||
|
RED.view.reveal(candidateNodes[0].id);
|
||||||
},
|
},
|
||||||
clear: function() {
|
clear: function() {
|
||||||
RED.nodes.eachNode(function(node) {
|
RED.nodes.eachNode(function(node) {
|
||||||
@ -179,9 +203,44 @@
|
|||||||
RED.events.on("workspace:change", this.refreshMessageList);
|
RED.events.on("workspace:change", this.refreshMessageList);
|
||||||
|
|
||||||
this.handleDebugMessage = function(t,o) {
|
this.handleDebugMessage = function(t,o) {
|
||||||
var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
// console.log("->",o.id,o.z,o._alias);
|
||||||
|
//
|
||||||
|
// sourceNode should be the top-level node - one that is on a flow.
|
||||||
|
var sourceNode;
|
||||||
|
var pathParts;
|
||||||
|
if (o.path) {
|
||||||
|
// Path is a `/`-separated list of ids that identifies the
|
||||||
|
// complete parentage of the node that generated this message.
|
||||||
|
// flow-id/subflow-A-instance/subflow-A-type/subflow-B-instance/subflow-B-type/node-id
|
||||||
|
|
||||||
|
// If it has one id, that is a top level flow
|
||||||
|
// each subsequent id is the instance id of a subflow node
|
||||||
|
//
|
||||||
|
pathParts = o.path.split("/");
|
||||||
|
if (pathParts.length === 1) {
|
||||||
|
// The source node is on a flow - so can use its id to find
|
||||||
|
sourceNode = RED.nodes.node(o.id);
|
||||||
|
} else if (pathParts.length > 1) {
|
||||||
|
// Highlight the subflow instance node.
|
||||||
|
sourceNode = RED.nodes.node(pathParts[1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is probably redundant...
|
||||||
|
sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
|
||||||
|
}
|
||||||
if (sourceNode) {
|
if (sourceNode) {
|
||||||
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name,type:sourceNode.type,_alias:o._alias};
|
o._source = {
|
||||||
|
id:sourceNode.id,
|
||||||
|
z:sourceNode.z,
|
||||||
|
name:sourceNode.name,
|
||||||
|
type:sourceNode.type,
|
||||||
|
// _alias identifies the actual logging node. This is
|
||||||
|
// not necessarily the same as sourceNode, which will be
|
||||||
|
// the top-level subflow instance node.
|
||||||
|
// This means the node's name is displayed in the sidebar.
|
||||||
|
_alias:o._alias,
|
||||||
|
path: pathParts
|
||||||
|
};
|
||||||
}
|
}
|
||||||
RED.debug.handleDebugMessage(o);
|
RED.debug.handleDebugMessage(o);
|
||||||
if (subWindow) {
|
if (subWindow) {
|
||||||
@ -235,7 +294,7 @@
|
|||||||
} else if (msg.event === "mouseLeave") {
|
} else if (msg.event === "mouseLeave") {
|
||||||
options.messageMouseLeave(msg.id);
|
options.messageMouseLeave(msg.id);
|
||||||
} else if (msg.event === "mouseClick") {
|
} else if (msg.event === "mouseClick") {
|
||||||
options.messageSourceClick(msg.id);
|
options.messageSourceClick(msg.id,msg._alias,msg.path);
|
||||||
} else if (msg.event === "clear") {
|
} else if (msg.event === "clear") {
|
||||||
options.clear();
|
options.clear();
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ module.exports = function(RED) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
done(RED._("debug.invalid-exp", {error: editExpression}));
|
done(RED._("debug.invalid-exp", {error: editExpression}));
|
||||||
} else {
|
} else {
|
||||||
done(null,{id:node.id, z:node.z, name:node.name, topic:msg.topic, msg:value, _path:msg._path});
|
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:value});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -77,7 +77,7 @@ module.exports = function(RED) {
|
|||||||
output = undefined;
|
output = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done(null,{id:node.id, z:node.z, name:node.name, topic:msg.topic, property:property, msg:output, _path:msg._path});
|
done(null,{id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, property:property, msg:output});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ module.exports = function(RED) {
|
|||||||
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
|
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
|
||||||
}
|
}
|
||||||
if (this.active && this.tosidebar) {
|
if (this.active && this.tosidebar) {
|
||||||
sendDebug({id:node.id, z:node.z, name:node.name, topic:msg.topic, msg:msg, _path:msg._path});
|
sendDebug({id:node.id, z:node.z, _alias: node._alias, path:node._flow.path, name:node.name, topic:msg.topic, msg:msg});
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
|
@ -406,10 +406,16 @@ RED.debug = (function() {
|
|||||||
msg.on("mouseenter", function() {
|
msg.on("mouseenter", function() {
|
||||||
msg.addClass('red-ui-debug-msg-hover');
|
msg.addClass('red-ui-debug-msg-hover');
|
||||||
if (o._source) {
|
if (o._source) {
|
||||||
|
// highlight the top-level node (could be subflow instance)
|
||||||
config.messageMouseEnter(o._source.id);
|
config.messageMouseEnter(o._source.id);
|
||||||
if (o._source._alias) {
|
if (o._source._alias) {
|
||||||
|
// this is inside a subflow - highlight the node itself
|
||||||
config.messageMouseEnter(o._source._alias);
|
config.messageMouseEnter(o._source._alias);
|
||||||
}
|
}
|
||||||
|
// if path.length > 2, we are nested - highlight subflow instances
|
||||||
|
for (var i=2;i<o._source.path.length;i++) {
|
||||||
|
config.messageMouseEnter(o._source.path[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
msg.on("mouseleave", function() {
|
msg.on("mouseleave", function() {
|
||||||
@ -419,6 +425,9 @@ RED.debug = (function() {
|
|||||||
if (o._source._alias) {
|
if (o._source._alias) {
|
||||||
config.messageMouseLeave(o._source._alias);
|
config.messageMouseLeave(o._source._alias);
|
||||||
}
|
}
|
||||||
|
for (var i=2;i<o._source.path.length;i++) {
|
||||||
|
config.messageMouseLeave(o._source.path[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var name = sanitize(((o.name?o.name:o.id)||"").toString());
|
var name = sanitize(((o.name?o.name:o.id)||"").toString());
|
||||||
@ -452,7 +461,7 @@ RED.debug = (function() {
|
|||||||
.appendTo(metaRow)
|
.appendTo(metaRow)
|
||||||
.on("click", function(evt) {
|
.on("click", function(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
config.messageSourceClick(sourceNode.id);
|
config.messageSourceClick(sourceNode.id, sourceNode._alias, sourceNode.path);
|
||||||
});
|
});
|
||||||
} else if (name) {
|
} else if (name) {
|
||||||
$('<span class="red-ui-debug-msg-name">'+name+'</span>').appendTo(metaRow);
|
$('<span class="red-ui-debug-msg-name">'+name+'</span>').appendTo(metaRow);
|
||||||
|
@ -7,8 +7,8 @@ $(function() {
|
|||||||
messageMouseLeave: function(sourceId) {
|
messageMouseLeave: function(sourceId) {
|
||||||
window.opener.postMessage({event:"mouseLeave",id:sourceId},'*');
|
window.opener.postMessage({event:"mouseLeave",id:sourceId},'*');
|
||||||
},
|
},
|
||||||
messageSourceClick: function(sourceId) {
|
messageSourceClick: function(sourceId, aliasId, path) {
|
||||||
window.opener.postMessage({event:"mouseClick",id:sourceId},'*');
|
window.opener.postMessage({event:"mouseClick",id:sourceId, _alias: aliasId, path: path},'*');
|
||||||
},
|
},
|
||||||
clear: function() {
|
clear: function() {
|
||||||
window.opener.postMessage({event:"clear"},'*');
|
window.opener.postMessage({event:"clear"},'*');
|
||||||
|
@ -52,7 +52,7 @@ function Node(n) {
|
|||||||
// the object (such as dashboard) will not like circular refs
|
// the object (such as dashboard) will not like circular refs
|
||||||
// The value must still be writable in the case that a node does:
|
// The value must still be writable in the case that a node does:
|
||||||
// Object.assign(this,config)
|
// Object.assign(this,config)
|
||||||
// as part of its constructure - config._flow will overwrite this._flow
|
// as part of its constructor - config._flow will overwrite this._flow
|
||||||
// which we can tolerate as they are the same object.
|
// which we can tolerate as they are the same object.
|
||||||
Object.defineProperty(this,'_flow', {value: n._flow, enumerable: false, writable: true })
|
Object.defineProperty(this,'_flow', {value: n._flow, enumerable: false, writable: true })
|
||||||
this._asyncDelivery = n._flow.asyncMessageDelivery;
|
this._asyncDelivery = n._flow.asyncMessageDelivery;
|
||||||
@ -462,6 +462,9 @@ function log_helper(self, level, msg) {
|
|||||||
if (self._alias) {
|
if (self._alias) {
|
||||||
o._alias = self._alias;
|
o._alias = self._alias;
|
||||||
}
|
}
|
||||||
|
if (self._flow) {
|
||||||
|
o.path = self._flow.path;
|
||||||
|
}
|
||||||
if (self.z) {
|
if (self.z) {
|
||||||
o.z = self.z;
|
o.z = self.z;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ class Flow {
|
|||||||
this.subflowInstanceNodes = {};
|
this.subflowInstanceNodes = {};
|
||||||
this.catchNodes = [];
|
this.catchNodes = [];
|
||||||
this.statusNodes = [];
|
this.statusNodes = [];
|
||||||
|
this.path = this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,7 +121,7 @@ class Flow {
|
|||||||
* @return {[type]} [description]
|
* @return {[type]} [description]
|
||||||
*/
|
*/
|
||||||
start(diff) {
|
start(diff) {
|
||||||
this.trace("start "+this.TYPE);
|
this.trace("start "+this.TYPE+" ["+this.path+"]");
|
||||||
var node;
|
var node;
|
||||||
var newNode;
|
var newNode;
|
||||||
var id;
|
var id;
|
||||||
@ -234,7 +235,7 @@ class Flow {
|
|||||||
for (id in this.activeNodes) {
|
for (id in this.activeNodes) {
|
||||||
if (this.activeNodes.hasOwnProperty(id)) {
|
if (this.activeNodes.hasOwnProperty(id)) {
|
||||||
node = this.activeNodes[id];
|
node = this.activeNodes[id];
|
||||||
this.trace(" "+id.padEnd(16)+" | "+node.type.padEnd(12)+" | "+(node._alias||""));
|
this.trace(" "+id.padEnd(16)+" | "+node.type.padEnd(12)+" | "+(node._alias||"")+(node._zAlias?" [zAlias:"+node._zAlias+"]":""));
|
||||||
if (node.type === "catch") {
|
if (node.type === "catch") {
|
||||||
this.catchNodes.push(node);
|
this.catchNodes.push(node);
|
||||||
} else if (node.type === "status") {
|
} else if (node.type === "status") {
|
||||||
|
@ -88,7 +88,7 @@ class Subflow extends Flow {
|
|||||||
* @param {[type]} subflowInstance [description]
|
* @param {[type]} subflowInstance [description]
|
||||||
*/
|
*/
|
||||||
constructor(parent,globalFlow,subflowDef,subflowInstance) {
|
constructor(parent,globalFlow,subflowDef,subflowInstance) {
|
||||||
// console.log("CREATE SUBFLOW",subflowDef.id,subflowInstance.id);
|
// console.log("CREATE SUBFLOW",subflowDef.id,subflowInstance.id,"alias?",subflowInstance._alias);
|
||||||
// console.log("SubflowInstance\n"+JSON.stringify(subflowInstance," ",2));
|
// console.log("SubflowInstance\n"+JSON.stringify(subflowInstance," ",2));
|
||||||
// console.log("SubflowDef\n"+JSON.stringify(subflowDef," ",2));
|
// console.log("SubflowDef\n"+JSON.stringify(subflowDef," ",2));
|
||||||
var subflows = parent.flow.subflows;
|
var subflows = parent.flow.subflows;
|
||||||
@ -140,6 +140,7 @@ class Subflow extends Flow {
|
|||||||
this.subflowDef = subflowDef;
|
this.subflowDef = subflowDef;
|
||||||
this.subflowInstance = subflowInstance;
|
this.subflowInstance = subflowInstance;
|
||||||
this.node_map = node_map;
|
this.node_map = node_map;
|
||||||
|
this.path = parent.path+"/"+(subflowInstance._alias||subflowInstance.id);
|
||||||
|
|
||||||
var env = [];
|
var env = [];
|
||||||
if (this.subflowDef.env) {
|
if (this.subflowDef.env) {
|
||||||
@ -451,7 +452,7 @@ class Subflow extends Flow {
|
|||||||
function createNodeInSubflow(subflowInstanceId, def) {
|
function createNodeInSubflow(subflowInstanceId, def) {
|
||||||
let node = clone(def);
|
let node = clone(def);
|
||||||
let nid = redUtil.generateId();
|
let nid = redUtil.generateId();
|
||||||
// console.log("Create Node In subflow",node.id, "--->",nid, "(",node.type,")")
|
// console.log("Create Node In subflow",node._alias, "--->",nid, "(",node.type,")")
|
||||||
// node_map[node.id] = node;
|
// node_map[node.id] = node;
|
||||||
node._alias = node.id;
|
node._alias = node.id;
|
||||||
node.id = nid;
|
node.id = nid;
|
||||||
|
Loading…
Reference in New Issue
Block a user