mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add Status Node to Subflow to allow subflow-specific status
Closes #597
This commit is contained in:
parent
efe8fbbd11
commit
3bcff91328
@ -273,6 +273,7 @@
|
|||||||
"editSubflowProperties": "edit properties",
|
"editSubflowProperties": "edit properties",
|
||||||
"input": "inputs:",
|
"input": "inputs:",
|
||||||
"output": "outputs:",
|
"output": "outputs:",
|
||||||
|
"status": "status node",
|
||||||
"deleteSubflow": "delete subflow",
|
"deleteSubflow": "delete subflow",
|
||||||
"info": "Description",
|
"info": "Description",
|
||||||
"category": "Category",
|
"category": "Category",
|
||||||
|
@ -125,7 +125,8 @@ RED.history = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ev.subflow && ev.subflow.hasOwnProperty('instances')) {
|
if (ev.subflow) {
|
||||||
|
if (ev.subflow.hasOwnProperty('instances')) {
|
||||||
ev.subflow.instances.forEach(function(n) {
|
ev.subflow.instances.forEach(function(n) {
|
||||||
var node = RED.nodes.node(n.id);
|
var node = RED.nodes.node(n.id);
|
||||||
if (node) {
|
if (node) {
|
||||||
@ -134,6 +135,11 @@ RED.history = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (ev.subflow.hasOwnProperty('status')) {
|
||||||
|
subflow = RED.nodes.subflow(ev.subflow.id);
|
||||||
|
subflow.status = ev.subflow.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (subflow) {
|
if (subflow) {
|
||||||
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
RED.nodes.filterNodes({type:"subflow:"+subflow.id}).forEach(function(n) {
|
||||||
n.inputs = subflow.in.length;
|
n.inputs = subflow.in.length;
|
||||||
@ -232,6 +238,11 @@ RED.history = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (ev.subflow.hasOwnProperty('status')) {
|
||||||
|
if (ev.subflow.status) {
|
||||||
|
delete ev.node.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
RED.editor.validateNode(ev.node);
|
RED.editor.validateNode(ev.node);
|
||||||
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
RED.nodes.filterNodes({type:"subflow:"+ev.node.id}).forEach(function(n) {
|
||||||
n.inputs = ev.node.in.length;
|
n.inputs = ev.node.in.length;
|
||||||
@ -290,6 +301,7 @@ RED.history = (function() {
|
|||||||
RED.workspaces.order(ev.order);
|
RED.workspaces.order(ev.order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(modifiedTabs).forEach(function(id) {
|
Object.keys(modifiedTabs).forEach(function(id) {
|
||||||
var subflow = RED.nodes.subflow(id);
|
var subflow = RED.nodes.subflow(id);
|
||||||
if (subflow) {
|
if (subflow) {
|
||||||
@ -303,6 +315,7 @@ RED.history = (function() {
|
|||||||
RED.palette.refresh();
|
RED.palette.refresh();
|
||||||
RED.workspaces.refresh();
|
RED.workspaces.refresh();
|
||||||
RED.sidebar.config.refresh();
|
RED.sidebar.config.refresh();
|
||||||
|
RED.subflow.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -571,6 +571,18 @@ RED.nodes = (function() {
|
|||||||
node.icon = n.icon;
|
node.icon = n.icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (n.status) {
|
||||||
|
node.status = {x: n.status.x, y: n.status.y, wires:[]};
|
||||||
|
links.forEach(function(d) {
|
||||||
|
if (d.target === n.status) {
|
||||||
|
if (d.source.type != "subflow") {
|
||||||
|
node.status.wires.push({id:d.source.id, port:d.sourcePort})
|
||||||
|
} else {
|
||||||
|
node.status.wires.push({id:n.id, port:0})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -851,6 +863,12 @@ RED.nodes = (function() {
|
|||||||
output.i = i;
|
output.i = i;
|
||||||
output.id = getID();
|
output.id = getID();
|
||||||
});
|
});
|
||||||
|
if (n.status) {
|
||||||
|
n.status.type = "subflow";
|
||||||
|
n.status.direction = "status";
|
||||||
|
n.status.z = n.id;
|
||||||
|
n.status.id = getID();
|
||||||
|
}
|
||||||
new_subflows.push(n);
|
new_subflows.push(n);
|
||||||
addSubflow(n,createNewIds);
|
addSubflow(n,createNewIds);
|
||||||
}
|
}
|
||||||
@ -1189,6 +1207,19 @@ RED.nodes = (function() {
|
|||||||
});
|
});
|
||||||
delete output.wires;
|
delete output.wires;
|
||||||
});
|
});
|
||||||
|
if (n.status) {
|
||||||
|
n.status.wires.forEach(function(wire) {
|
||||||
|
var link;
|
||||||
|
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
||||||
|
link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status};
|
||||||
|
} else {
|
||||||
|
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status};
|
||||||
|
}
|
||||||
|
addLink(link);
|
||||||
|
new_links.push(link);
|
||||||
|
});
|
||||||
|
delete n.status.wires;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.workspaces.refresh();
|
RED.workspaces.refresh();
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
RED.subflow = (function() {
|
RED.subflow = (function() {
|
||||||
|
|
||||||
|
|
||||||
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow"><div class="form-row"><label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label><input type="text" id="node-input-name"></div></script>';
|
var _subflowEditTemplate = '<script type="text/x-red" data-template-name="subflow"><div class="form-row"><label for="node-input-name" data-i18n="[append]editor:common.label.name"><i class="fa fa-tag"></i> </label><input type="text" id="node-input-name"></div></script>';
|
||||||
var _subflowTemplateEditTemplate = '<script type="text/x-red" data-template-name="subflow-template">'+
|
var _subflowTemplateEditTemplate = '<script type="text/x-red" data-template-name="subflow-template">'+
|
||||||
'<div class="form-row"><i class="fa fa-tag"></i> <label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name"></div>'+
|
'<div class="form-row"><i class="fa fa-tag"></i> <label for="subflow-input-name" data-i18n="common.label.name"></label><input type="text" id="subflow-input-name"></div>'+
|
||||||
@ -24,26 +23,22 @@ RED.subflow = (function() {
|
|||||||
'<div class="form-row form-tips" id="subflow-dialog-user-count"></div>'+
|
'<div class="form-row form-tips" id="subflow-dialog-user-count"></div>'+
|
||||||
'</script>';
|
'</script>';
|
||||||
|
|
||||||
|
|
||||||
function getSubflow() {
|
|
||||||
return RED.nodes.subflow(RED.workspaces.active());
|
|
||||||
}
|
|
||||||
|
|
||||||
function findAvailableSubflowIOPosition(subflow,isInput) {
|
function findAvailableSubflowIOPosition(subflow,isInput) {
|
||||||
var pos = {x:50,y:30};
|
var pos = {x:50,y:30};
|
||||||
if (!isInput) {
|
if (!isInput) {
|
||||||
pos.x += 110;
|
pos.x += 110;
|
||||||
}
|
}
|
||||||
for (var i=0;i<subflow.out.length+subflow.in.length;i++) {
|
var ports = [].concat(subflow.out).concat(subflow.in);
|
||||||
var port;
|
if (subflow.status) {
|
||||||
if (i < subflow.out.length) {
|
ports.push(subflow.status);
|
||||||
port = subflow.out[i];
|
|
||||||
} else {
|
|
||||||
port = subflow.in[i-subflow.out.length];
|
|
||||||
}
|
}
|
||||||
|
ports.sort(function(A,B) {
|
||||||
|
return A.x-B.x;
|
||||||
|
});
|
||||||
|
for (var i=0; i<ports.length; i++) {
|
||||||
|
var port = ports[i];
|
||||||
if (port.x == pos.x && port.y == pos.y) {
|
if (port.x == pos.x && port.y == pos.y) {
|
||||||
pos.x += 55;
|
pos.x += 55;
|
||||||
i=0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pos;
|
return pos;
|
||||||
@ -191,6 +186,61 @@ RED.subflow = (function() {
|
|||||||
return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
|
return {subflowOutputs: removedSubflowOutputs, links: removedLinks}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addSubflowStatus() {
|
||||||
|
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||||
|
if (subflow.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var position = findAvailableSubflowIOPosition(subflow,false);
|
||||||
|
var statusNode = {
|
||||||
|
type:"subflow",
|
||||||
|
direction:"status",
|
||||||
|
z:subflow.id,
|
||||||
|
x:position.x,
|
||||||
|
y:position.y,
|
||||||
|
id:RED.nodes.id()
|
||||||
|
};
|
||||||
|
subflow.status = statusNode;
|
||||||
|
subflow.dirty = true;
|
||||||
|
var wasDirty = RED.nodes.dirty();
|
||||||
|
var wasChanged = subflow.changed;
|
||||||
|
subflow.changed = true;
|
||||||
|
var result = refresh(true);
|
||||||
|
var historyEvent = {
|
||||||
|
t:'edit',
|
||||||
|
node:subflow,
|
||||||
|
dirty:wasDirty,
|
||||||
|
changed:wasChanged,
|
||||||
|
subflow: { status: true }
|
||||||
|
};
|
||||||
|
RED.history.push(historyEvent);
|
||||||
|
RED.view.select();
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
RED.view.redraw();
|
||||||
|
$("#workspace-subflow-status").prop("checked",!!subflow.status);
|
||||||
|
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSubflowStatus() {
|
||||||
|
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
||||||
|
if (!subflow.status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var subflowRemovedLinks = [];
|
||||||
|
RED.nodes.eachLink(function(l) {
|
||||||
|
if (l.target.type == "subflow" && l.target.z == subflow.id && l.target.direction == "status") {
|
||||||
|
subflowRemovedLinks.push(l);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
subflowRemovedLinks.forEach(function(l) { RED.nodes.removeLink(l)});
|
||||||
|
delete subflow.status;
|
||||||
|
|
||||||
|
$("#workspace-subflow-status").prop("checked",!!subflow.status);
|
||||||
|
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!subflow.status);
|
||||||
|
|
||||||
|
return { links: subflowRemovedLinks }
|
||||||
|
}
|
||||||
|
|
||||||
function refresh(markChange) {
|
function refresh(markChange) {
|
||||||
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
var activeSubflow = RED.nodes.subflow(RED.workspaces.active());
|
||||||
refreshToolbar(activeSubflow);
|
refreshToolbar(activeSubflow);
|
||||||
@ -219,12 +269,17 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshToolbar(activeSubflow) {
|
function refreshToolbar(activeSubflow) {
|
||||||
if (activeSubflow) {
|
if (activeSubflow) {
|
||||||
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
|
$("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0);
|
||||||
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
|
$("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0);
|
||||||
|
|
||||||
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
|
$("#workspace-subflow-output .spinner-value").text(activeSubflow.out.length);
|
||||||
|
|
||||||
|
$("#workspace-subflow-status").prop("checked",!!activeSubflow.status);
|
||||||
|
$("#workspace-subflow-status").parent().parent().toggleClass("active",!!activeSubflow.status);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,22 +287,32 @@ RED.subflow = (function() {
|
|||||||
var toolbar = $("#workspace-toolbar");
|
var toolbar = $("#workspace-toolbar");
|
||||||
toolbar.empty();
|
toolbar.empty();
|
||||||
|
|
||||||
|
// Edit properties
|
||||||
$('<a class="button" id="workspace-subflow-edit" href="#" data-i18n="[append]subflow.editSubflowProperties"><i class="fa fa-pencil"></i> </a>').appendTo(toolbar);
|
$('<a class="button" id="workspace-subflow-edit" href="#" data-i18n="[append]subflow.editSubflowProperties"><i class="fa fa-pencil"></i> </a>').appendTo(toolbar);
|
||||||
|
|
||||||
|
// Inputs
|
||||||
$('<span style="margin-left: 5px;" data-i18n="subflow.input"></span> '+
|
$('<span style="margin-left: 5px;" data-i18n="subflow.input"></span> '+
|
||||||
'<div style="display: inline-block;" class="button-group">'+
|
'<div style="display: inline-block;" class="button-group">'+
|
||||||
'<a id="workspace-subflow-input-remove" class="button active" href="#">0</a>'+
|
'<a id="workspace-subflow-input-remove" class="button active" href="#">0</a>'+
|
||||||
'<a id="workspace-subflow-input-add" class="button" href="#">1</a>'+
|
'<a id="workspace-subflow-input-add" class="button" href="#">1</a>'+
|
||||||
'</div>').appendTo(toolbar);
|
'</div>').appendTo(toolbar);
|
||||||
|
|
||||||
|
// Outputs
|
||||||
$('<span style="margin-left: 5px;" data-i18n="subflow.output"></span> <div id="workspace-subflow-output" style="display: inline-block;" class="button-group spinner-group">'+
|
$('<span style="margin-left: 5px;" data-i18n="subflow.output"></span> <div id="workspace-subflow-output" style="display: inline-block;" class="button-group spinner-group">'+
|
||||||
'<a id="workspace-subflow-output-remove" class="button" href="#"><i class="fa fa-minus"></i></a>'+
|
'<a id="workspace-subflow-output-remove" class="button" href="#"><i class="fa fa-minus"></i></a>'+
|
||||||
'<div class="spinner-value">3</div>'+
|
'<div class="spinner-value">3</div>'+
|
||||||
'<a id="workspace-subflow-output-add" class="button" href="#"><i class="fa fa-plus"></i></a>'+
|
'<a id="workspace-subflow-output-add" class="button" href="#"><i class="fa fa-plus"></i></a>'+
|
||||||
'</div>').appendTo(toolbar);
|
'</div>').appendTo(toolbar);
|
||||||
|
|
||||||
|
// Status
|
||||||
|
$('<span class="button-group"><span class="button" style="padding:0"><label for="workspace-subflow-status"><input id="workspace-subflow-status" type="checkbox"> <span data-i18n="subflow.status"></span></label></span></span>').appendTo(toolbar);
|
||||||
|
|
||||||
// $('<a class="button disabled" id="workspace-subflow-add-input" href="#" data-i18n="[append]subflow.input"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
// $('<a class="button disabled" id="workspace-subflow-add-input" href="#" data-i18n="[append]subflow.input"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
||||||
// $('<a class="button" id="workspace-subflow-add-output" href="#" data-i18n="[append]subflow.output"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
// $('<a class="button" id="workspace-subflow-add-output" href="#" data-i18n="[append]subflow.output"><i class="fa fa-plus"></i> </a>').appendTo(toolbar);
|
||||||
|
|
||||||
|
// Delete
|
||||||
$('<a class="button" id="workspace-subflow-delete" href="#" data-i18n="[append]subflow.deleteSubflow"><i class="fa fa-trash"></i> </a>').appendTo(toolbar);
|
$('<a class="button" id="workspace-subflow-delete" href="#" data-i18n="[append]subflow.deleteSubflow"><i class="fa fa-trash"></i> </a>').appendTo(toolbar);
|
||||||
|
|
||||||
toolbar.i18n();
|
toolbar.i18n();
|
||||||
|
|
||||||
|
|
||||||
@ -274,6 +339,7 @@ RED.subflow = (function() {
|
|||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#workspace-subflow-output-add").click(function(event) {
|
$("#workspace-subflow-output-add").click(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
addSubflowOutput();
|
addSubflowOutput();
|
||||||
@ -283,6 +349,7 @@ RED.subflow = (function() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
addSubflowInput();
|
addSubflowInput();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#workspace-subflow-input-remove").click(function(event) {
|
$("#workspace-subflow-input-remove").click(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var wasDirty = RED.nodes.dirty();
|
var wasDirty = RED.nodes.dirty();
|
||||||
@ -307,6 +374,33 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#workspace-subflow-status").change(function(evt) {
|
||||||
|
if (this.checked) {
|
||||||
|
addSubflowStatus();
|
||||||
|
} else {
|
||||||
|
var currentStatus = activeSubflow.status;
|
||||||
|
var wasChanged = activeSubflow.changed;
|
||||||
|
var result = removeSubflowStatus();
|
||||||
|
if (result) {
|
||||||
|
activeSubflow.changed = true;
|
||||||
|
var wasDirty = RED.nodes.dirty();
|
||||||
|
RED.history.push({
|
||||||
|
t:'delete',
|
||||||
|
links:result.links,
|
||||||
|
changed: wasChanged,
|
||||||
|
dirty:wasDirty,
|
||||||
|
subflow: {
|
||||||
|
id: activeSubflow.id,
|
||||||
|
status: currentStatus
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RED.view.select();
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
RED.view.redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
$("#workspace-subflow-edit").click(function(event) {
|
$("#workspace-subflow-edit").click(function(event) {
|
||||||
RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active()));
|
RED.editor.editSubflow(RED.nodes.subflow(RED.workspaces.active()));
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -328,6 +422,7 @@ RED.subflow = (function() {
|
|||||||
$("#chart").css({"margin-top": "40px"});
|
$("#chart").css({"margin-top": "40px"});
|
||||||
$("#workspace-toolbar").show();
|
$("#workspace-toolbar").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideWorkspaceToolbar() {
|
function hideWorkspaceToolbar() {
|
||||||
$("#workspace-toolbar").hide().empty();
|
$("#workspace-toolbar").hide().empty();
|
||||||
$("#chart").css({"margin-top": "0"});
|
$("#chart").css({"margin-top": "0"});
|
||||||
@ -373,6 +468,7 @@ RED.subflow = (function() {
|
|||||||
subflows: [activeSubflow]
|
subflows: [activeSubflow]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
RED.events.on("workspace:change",function(event) {
|
RED.events.on("workspace:change",function(event) {
|
||||||
var activeSubflow = RED.nodes.subflow(event.workspace);
|
var activeSubflow = RED.nodes.subflow(event.workspace);
|
||||||
@ -436,6 +532,7 @@ RED.subflow = (function() {
|
|||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToSubflow() {
|
function convertToSubflow() {
|
||||||
var selection = RED.view.selection();
|
var selection = RED.view.selection();
|
||||||
if (!selection.nodes) {
|
if (!selection.nodes) {
|
||||||
@ -451,7 +548,6 @@ RED.subflow = (function() {
|
|||||||
var candidateOutputs = [];
|
var candidateOutputs = [];
|
||||||
var candidateInputNodes = {};
|
var candidateInputNodes = {};
|
||||||
|
|
||||||
|
|
||||||
var boundingBox = [selection.nodes[0].x,
|
var boundingBox = [selection.nodes[0].x,
|
||||||
selection.nodes[0].y,
|
selection.nodes[0].y,
|
||||||
selection.nodes[0].x,
|
selection.nodes[0].x,
|
||||||
@ -467,8 +563,8 @@ RED.subflow = (function() {
|
|||||||
Math.max(boundingBox[3],n.y)
|
Math.max(boundingBox[3],n.y)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
var offsetX = snapToGrid(boundingBox[0] - 180);
|
var offsetX = snapToGrid(boundingBox[0] - 200);
|
||||||
var offsetY = snapToGrid(boundingBox[1] - 60);
|
var offsetY = snapToGrid(boundingBox[1] - 80);
|
||||||
|
|
||||||
|
|
||||||
var center = [
|
var center = [
|
||||||
@ -643,8 +739,6 @@ RED.subflow = (function() {
|
|||||||
RED.view.redraw(true);
|
RED.view.redraw(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
createSubflow: createSubflow,
|
createSubflow: createSubflow,
|
||||||
@ -652,6 +746,7 @@ RED.subflow = (function() {
|
|||||||
removeSubflow: removeSubflow,
|
removeSubflow: removeSubflow,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
removeInput: removeSubflowInput,
|
removeInput: removeSubflowInput,
|
||||||
removeOutput: removeSubflowOutput
|
removeOutput: removeSubflowOutput,
|
||||||
|
removeStatus: removeSubflowStatus
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -1261,6 +1261,13 @@ RED.view = (function() {
|
|||||||
moving_set.push({n:n});
|
moving_set.push({n:n});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (activeSubflow.status) {
|
||||||
|
activeSubflow.status.selected = (activeSubflow.status.x > x && activeSubflow.status.x < x2 && activeSubflow.status.y > y && activeSubflow.status.y < y2);
|
||||||
|
if (activeSubflow.status.selected) {
|
||||||
|
activeSubflow.status.dirty = true;
|
||||||
|
moving_set.push({n:activeSubflow.status});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateSelection();
|
updateSelection();
|
||||||
lasso.remove();
|
lasso.remove();
|
||||||
@ -1367,6 +1374,13 @@ RED.view = (function() {
|
|||||||
moving_set.push({n:n});
|
moving_set.push({n:n});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (activeSubflow.status) {
|
||||||
|
if (!activeSubflow.status.selected) {
|
||||||
|
activeSubflow.status.selected = true;
|
||||||
|
activeSubflow.status.dirty = true;
|
||||||
|
moving_set.push({n:activeSubflow.status});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selected_link = null;
|
selected_link = null;
|
||||||
@ -1552,6 +1566,7 @@ RED.view = (function() {
|
|||||||
var removedLinks = [];
|
var removedLinks = [];
|
||||||
var removedSubflowOutputs = [];
|
var removedSubflowOutputs = [];
|
||||||
var removedSubflowInputs = [];
|
var removedSubflowInputs = [];
|
||||||
|
var removedSubflowStatus = undefined;
|
||||||
var subflowInstances = [];
|
var subflowInstances = [];
|
||||||
|
|
||||||
var startDirty = RED.nodes.dirty();
|
var startDirty = RED.nodes.dirty();
|
||||||
@ -1573,6 +1588,8 @@ RED.view = (function() {
|
|||||||
removedSubflowOutputs.push(node);
|
removedSubflowOutputs.push(node);
|
||||||
} else if (node.direction === "in") {
|
} else if (node.direction === "in") {
|
||||||
removedSubflowInputs.push(node);
|
removedSubflowInputs.push(node);
|
||||||
|
} else if (node.direction === "status") {
|
||||||
|
removedSubflowStatus = node;
|
||||||
}
|
}
|
||||||
node.dirty = true;
|
node.dirty = true;
|
||||||
}
|
}
|
||||||
@ -1590,12 +1607,19 @@ RED.view = (function() {
|
|||||||
removedLinks = removedLinks.concat(result.links);
|
removedLinks = removedLinks.concat(result.links);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (removedSubflowStatus) {
|
||||||
|
result = RED.subflow.removeStatus();
|
||||||
|
if (result) {
|
||||||
|
removedLinks = removedLinks.concat(result.links);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var instances = RED.subflow.refresh(true);
|
var instances = RED.subflow.refresh(true);
|
||||||
if (instances) {
|
if (instances) {
|
||||||
subflowInstances = instances.instances;
|
subflowInstances = instances.instances;
|
||||||
}
|
}
|
||||||
moving_set = [];
|
moving_set = [];
|
||||||
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0) {
|
if (removedNodes.length > 0 || removedSubflowOutputs.length > 0 || removedSubflowInputs.length > 0 || removedSubflowStatus) {
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1651,10 +1675,14 @@ RED.view = (function() {
|
|||||||
subflowOutputs:removedSubflowOutputs,
|
subflowOutputs:removedSubflowOutputs,
|
||||||
subflowInputs:removedSubflowInputs,
|
subflowInputs:removedSubflowInputs,
|
||||||
subflow: {
|
subflow: {
|
||||||
|
id: activeSubflow?activeSubflow.id:undefined,
|
||||||
instances: subflowInstances
|
instances: subflowInstances
|
||||||
},
|
},
|
||||||
dirty:startDirty
|
dirty:startDirty
|
||||||
};
|
};
|
||||||
|
if (removedSubflowStatus) {
|
||||||
|
historyEvent.subflow.status = removedSubflowStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
|
|
||||||
@ -2420,6 +2448,49 @@ RED.view = (function() {
|
|||||||
|
|
||||||
inGroup.append("svg:text").attr("class","port_label").attr("x",18).attr("y",20).style("font-size","10px").text("input");
|
inGroup.append("svg:text").attr("class","port_label").attr("x",18).attr("y",20).style("font-size","10px").text("input");
|
||||||
|
|
||||||
|
var subflowStatus = nodeLayer.selectAll(".subflowstatus").data(activeSubflow.status?[activeSubflow.status]:[],function(d,i){ return d.id;});
|
||||||
|
subflowStatus.exit().remove();
|
||||||
|
|
||||||
|
var statusGroup = subflowStatus.enter().insert("svg:g").attr("class","node subflowstatus").attr("transform",function(d) { return "translate("+(d.x-20)+","+(d.y-20)+")"});
|
||||||
|
statusGroup.each(function(d,i) {
|
||||||
|
d.w=40;
|
||||||
|
d.h=40;
|
||||||
|
});
|
||||||
|
statusGroup.append("rect").attr("class","subflowport").attr("rx",8).attr("ry",8).attr("width",40).attr("height",40)
|
||||||
|
// TODO: This is exactly the same set of handlers used for regular nodes - DRY
|
||||||
|
.on("mouseup",nodeMouseUp)
|
||||||
|
.on("mousedown",nodeMouseDown)
|
||||||
|
.on("touchstart",function(d) {
|
||||||
|
var obj = d3.select(this);
|
||||||
|
var touch0 = d3.event.touches.item(0);
|
||||||
|
var pos = [touch0.pageX,touch0.pageY];
|
||||||
|
startTouchCenter = [touch0.pageX,touch0.pageY];
|
||||||
|
startTouchDistance = 0;
|
||||||
|
touchStartTime = setTimeout(function() {
|
||||||
|
showTouchMenu(obj,pos);
|
||||||
|
},touchLongPressTimeout);
|
||||||
|
nodeMouseDown.call(this,d)
|
||||||
|
})
|
||||||
|
.on("touchend", function(d) {
|
||||||
|
clearTimeout(touchStartTime);
|
||||||
|
touchStartTime = null;
|
||||||
|
if (RED.touch.radialMenu.active()) {
|
||||||
|
d3.event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nodeMouseUp.call(this,d);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusGroup.append("g").attr('transform','translate(-5,15)').append("rect").attr("class","port").attr("rx",3).attr("ry",3).attr("width",10).attr("height",10)
|
||||||
|
.on("mousedown", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);} )
|
||||||
|
.on("touchstart", function(d,i){portMouseDown(d,PORT_TYPE_INPUT,0);} )
|
||||||
|
.on("mouseup", function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);})
|
||||||
|
.on("touchend",function(d,i){portMouseUp(d,PORT_TYPE_INPUT,0);} )
|
||||||
|
.on("mouseover",function(d){portMouseOver(d3.select(this),d,PORT_TYPE_INPUT,0);})
|
||||||
|
.on("mouseout",function(d){portMouseOut(d3.select(this),d,PORT_TYPE_INPUT,0);});
|
||||||
|
|
||||||
|
statusGroup.append("svg:text").attr("class","port_label").attr("x",22).attr("y",20).style("font-size","10px").text("status");
|
||||||
|
|
||||||
subflowOutputs.each(function(d,i) {
|
subflowOutputs.each(function(d,i) {
|
||||||
if (d.dirty) {
|
if (d.dirty) {
|
||||||
var output = d3.select(this);
|
var output = d3.select(this);
|
||||||
@ -2439,9 +2510,22 @@ RED.view = (function() {
|
|||||||
d.dirty = false;
|
d.dirty = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
subflowStatus.each(function(d,i) {
|
||||||
|
if (d.dirty) {
|
||||||
|
var output = d3.select(this);
|
||||||
|
output.selectAll(".subflowport").classed("node_selected",function(d) { return d.selected; })
|
||||||
|
output.selectAll(".port_index").text(function(d){ return d.i+1});
|
||||||
|
output.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; });
|
||||||
|
dirtyNodes[d.id] = d;
|
||||||
|
d.dirty = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
nodeLayer.selectAll(".subflowoutput").remove();
|
nodeLayer.selectAll(".subflowoutput").remove();
|
||||||
nodeLayer.selectAll(".subflowinput").remove();
|
nodeLayer.selectAll(".subflowinput").remove();
|
||||||
|
nodeLayer.selectAll(".subflowstatus").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = nodeLayer.selectAll(".nodegroup").data(activeNodes,function(d){return d.id});
|
var node = nodeLayer.selectAll(".nodegroup").data(activeNodes,function(d){return d.id});
|
||||||
|
@ -33,6 +33,15 @@
|
|||||||
transition: right 0.2s ease;
|
transition: right 0.2s ease;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
label {
|
||||||
|
padding: 1px 8px;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin: 0 3px 0 0 ;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.button {
|
.button {
|
||||||
@include workspace-button;
|
@include workspace-button;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
@ -265,7 +265,6 @@ class Flow {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the flow definition. This doesn't change anything that is running.
|
* Update the flow definition. This doesn't change anything that is running.
|
||||||
* This should be called after `stop` and before `start`.
|
* This should be called after `stop` and before `start`.
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
const clone = require("clone");
|
const clone = require("clone");
|
||||||
const Flow = require('./Flow').Flow;
|
const Flow = require('./Flow').Flow;
|
||||||
|
|
||||||
|
const util = require("util");
|
||||||
|
|
||||||
const redUtil = require("@node-red/util").util;
|
const redUtil = require("@node-red/util").util;
|
||||||
const flowUtil = require("./util");
|
const flowUtil = require("./util");
|
||||||
|
|
||||||
@ -104,6 +106,40 @@ class Subflow extends Flow {
|
|||||||
var self = this;
|
var self = this;
|
||||||
// Create a subflow node to accept inbound messages and route appropriately
|
// Create a subflow node to accept inbound messages and route appropriately
|
||||||
var Node = require("../Node");
|
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 = {
|
var subflowInstanceConfig = {
|
||||||
id: this.subflowInstance.id,
|
id: this.subflowInstance.id,
|
||||||
type: this.subflowInstance.type,
|
type: this.subflowInstance.type,
|
||||||
@ -168,7 +204,6 @@ class Subflow extends Flow {
|
|||||||
|
|
||||||
// Wire the subflow outputs
|
// Wire the subflow outputs
|
||||||
if (this.subflowDef.out) {
|
if (this.subflowDef.out) {
|
||||||
var modifiedNodes = {};
|
|
||||||
for (var i=0;i<this.subflowDef.out.length;i++) {
|
for (var i=0;i<this.subflowDef.out.length;i++) {
|
||||||
// i: the output index
|
// i: the output index
|
||||||
// This is what this Output is wired to
|
// This is what this Output is wired to
|
||||||
@ -180,7 +215,6 @@ class Subflow extends Flow {
|
|||||||
this.node._updateWires(subflowInstanceConfig.wires);
|
this.node._updateWires(subflowInstanceConfig.wires);
|
||||||
} else {
|
} else {
|
||||||
var node = self.node_map[wires[j].id];
|
var node = self.node_map[wires[j].id];
|
||||||
modifiedNodes[node.id] = node;
|
|
||||||
if (!node._originalWires) {
|
if (!node._originalWires) {
|
||||||
node._originalWires = clone(node.wires);
|
node._originalWires = clone(node.wires);
|
||||||
}
|
}
|
||||||
@ -189,9 +223,47 @@ 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);
|
super.start(diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* Handle a status event from a node within this flow.
|
||||||
* @param {Node} node The original node that triggered the event
|
* @param {Node} node The original node that triggered the event
|
||||||
@ -205,11 +277,15 @@ class Subflow extends Flow {
|
|||||||
handleStatus(node,statusMessage,reportingNode,muteStatus) {
|
handleStatus(node,statusMessage,reportingNode,muteStatus) {
|
||||||
let handled = super.handleStatus(node,statusMessage,reportingNode,muteStatus);
|
let handled = super.handleStatus(node,statusMessage,reportingNode,muteStatus);
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
|
if (!this.statusNode || node === this.node) {
|
||||||
// No status node on this subflow caught the status message.
|
// 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
|
// Pass up to the parent with this subflow's instance as the
|
||||||
// reporting node
|
// reporting node
|
||||||
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
|
handled = this.parent.handleStatus(node,statusMessage,this.node,true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return handled;
|
return handled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -265,7 +265,6 @@ describe('Subflow', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("instantiates a subflow inside a subflow and stops it",function(done) {
|
it("instantiates a subflow inside a subflow and stops it",function(done) {
|
||||||
var config = flowUtils.parseConfig([
|
var config = flowUtils.parseConfig([
|
||||||
{id:"t1",type:"tab"},
|
{id:"t1",type:"tab"},
|
||||||
@ -419,7 +418,6 @@ describe('Subflow', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes a status event to the subflow's parent tab status node - targetted scope",function(done) {
|
it("passes a status event to the subflow's parent tab status node - targetted scope",function(done) {
|
||||||
var config = flowUtils.parseConfig([
|
var config = flowUtils.parseConfig([
|
||||||
{id:"t1",type:"tab"},
|
{id:"t1",type:"tab"},
|
||||||
@ -457,9 +455,164 @@ describe('Subflow', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("status node", function() {
|
||||||
|
it("emits a status event when a message is passed to a subflow-status node - msg.payload as string", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||||
|
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||||
|
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||||
|
{
|
||||||
|
id:"sf1",
|
||||||
|
type:"subflow",
|
||||||
|
name:"Subflow 2",
|
||||||
|
info:"",
|
||||||
|
in:[{wires:[{id:"sf1-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf1-1",port:0}]}],
|
||||||
|
status:{wires:[{id:"sf1-1", port:0}]}
|
||||||
|
},
|
||||||
|
{id:"sf1-1",type:"test",name:"test","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||||
|
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var activeNodes = flow.getActiveNodes();
|
||||||
|
|
||||||
|
activeNodes["1"].receive({payload:"test-payload"});
|
||||||
|
|
||||||
|
currentNodes["sn"].should.have.a.property("handled",1);
|
||||||
|
var statusMessage = currentNodes["sn"].messages[0];
|
||||||
|
|
||||||
|
statusMessage.should.have.a.property("status");
|
||||||
|
statusMessage.status.should.have.a.property("text","test-payload");
|
||||||
|
statusMessage.status.should.have.a.property("source");
|
||||||
|
statusMessage.status.source.should.have.a.property("id","2");
|
||||||
|
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("emits a status event when a message is passed to a subflow-status node - msg.payload as status obj", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||||
|
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||||
|
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||||
|
{
|
||||||
|
id:"sf1",
|
||||||
|
type:"subflow",
|
||||||
|
name:"Subflow 2",
|
||||||
|
info:"",
|
||||||
|
in:[{wires:[{id:"sf1-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf1-1",port:0}]}],
|
||||||
|
status:{wires:[{id:"sf1-1", port:0}]}
|
||||||
|
},
|
||||||
|
{id:"sf1-1",type:"test",name:"test","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||||
|
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var activeNodes = flow.getActiveNodes();
|
||||||
|
|
||||||
|
activeNodes["1"].receive({payload:{text:"payload-obj"}});
|
||||||
|
|
||||||
|
currentNodes["sn"].should.have.a.property("handled",1);
|
||||||
|
var statusMessage = currentNodes["sn"].messages[0];
|
||||||
|
|
||||||
|
statusMessage.should.have.a.property("status");
|
||||||
|
statusMessage.status.should.have.a.property("text","payload-obj");
|
||||||
|
statusMessage.status.should.have.a.property("source");
|
||||||
|
statusMessage.status.source.should.have.a.property("id","2");
|
||||||
|
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("emits a status event when a message is passed to a subflow-status node - msg.status", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||||
|
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||||
|
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||||
|
{
|
||||||
|
id:"sf1",
|
||||||
|
type:"subflow",
|
||||||
|
name:"Subflow 2",
|
||||||
|
info:"",
|
||||||
|
in:[{wires:[{id:"sf1-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf1-1",port:0}]}],
|
||||||
|
status:{wires:[{id:"sf1-1", port:0}]}
|
||||||
|
},
|
||||||
|
{id:"sf1-1",type:"test",name:"test","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||||
|
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var activeNodes = flow.getActiveNodes();
|
||||||
|
|
||||||
|
activeNodes["1"].receive({status:{text:"status-obj"}});
|
||||||
|
|
||||||
|
currentNodes["sn"].should.have.a.property("handled",1);
|
||||||
|
var statusMessage = currentNodes["sn"].messages[0];
|
||||||
|
|
||||||
|
statusMessage.should.have.a.property("status");
|
||||||
|
statusMessage.status.should.have.a.property("text","status-obj");
|
||||||
|
statusMessage.status.should.have.a.property("source");
|
||||||
|
statusMessage.status.source.should.have.a.property("id","2");
|
||||||
|
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("does not emit a regular status event if it contains a subflow-status node", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||||
|
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||||
|
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||||
|
{
|
||||||
|
id:"sf1",
|
||||||
|
type:"subflow",
|
||||||
|
name:"Subflow 2",
|
||||||
|
info:"",
|
||||||
|
in:[{wires:[{id:"sf1-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf1-1",port:0}]}],
|
||||||
|
status:{wires:[]}
|
||||||
|
},
|
||||||
|
{id:"sf1-1",type:"testStatus",name:"test-status-node","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||||
|
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var activeNodes = flow.getActiveNodes();
|
||||||
|
|
||||||
|
activeNodes["1"].receive({payload:"test-payload"});
|
||||||
|
|
||||||
|
currentNodes["sn"].should.have.a.property("handled",0);
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
describe("#handleError",function() {
|
describe("#handleError",function() {
|
||||||
it("passes an error event to the subflow's parent tab catch node - all scope",function(done) {
|
it("passes an error event to the subflow's parent tab catch node - all scope",function(done) {
|
||||||
var config = flowUtils.parseConfig([
|
var config = flowUtils.parseConfig([
|
||||||
@ -493,7 +646,6 @@ describe('Subflow', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes an error event to the subflow's parent tab catch node - targetted scope",function(done) {
|
it("passes an error event to the subflow's parent tab catch node - targetted scope",function(done) {
|
||||||
var config = flowUtils.parseConfig([
|
var config = flowUtils.parseConfig([
|
||||||
{id:"t1",type:"tab"},
|
{id:"t1",type:"tab"},
|
||||||
@ -530,7 +682,6 @@ describe('Subflow', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user