1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge pull request #2050 from node-red/subflow-props

Display parent subflow properties in subflow instance edit dialog
This commit is contained in:
Nick O'Leary 2019-02-06 14:06:22 +00:00 committed by GitHub
commit 431266069e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 47 deletions

View File

@ -277,6 +277,10 @@
"deleteSubflow": "delete subflow", "deleteSubflow": "delete subflow",
"info": "Description", "info": "Description",
"category": "Category", "category": "Category",
"env": {
"restore": "Restore to subflow default",
"remove": "Remove environment variable"
},
"errors": { "errors": {
"noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected", "noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
"multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection" "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"

View File

@ -550,54 +550,129 @@ RED.editor = (function() {
.editableList({ .editableList({
addItem: function(container, i, opt) { addItem: function(container, i, opt) {
var row = $('<div/>').appendTo(container); var row = $('<div/>').appendTo(container);
var nameField = $('<input/>', { if (opt.parent) {
class: "node-input-env-name", $('<div/>', {
type: "text", class:"uneditable-input",
style: "margin-left: 5px; width: calc(40% - 5px)", style: "margin-left: 5px; width: calc(40% - 8px)",
placeholder: RED._("common.label.name") }).appendTo(row).text(opt.name);
}).appendTo(row); } else {
$('<input/>', {
class: "node-input-env-name",
type: "text",
style: "margin-left: 5px; width: calc(40% - 8px)",
placeholder: RED._("common.label.name")
}).appendTo(row).val(opt.name);
}
var valueField = $('<input/>',{ var valueField = $('<input/>',{
class: "node-input-env-value", class: "node-input-env-value",
type: "text", type: "text",
style: "margin-left: 5px; width: calc(60% - 5px)" style: "margin-left: 5px; width: calc(60% - 8px)"
}).appendTo(row) }).appendTo(row)
valueField.typedInput({default:'str', valueField.typedInput({default:'str',
types:['str','num','bool','json','bin','re','date'] types:['str','num','bool','json','bin','env']
}); });
if (opt) {
nameField.val(opt.name); valueField.typedInput('type', opt.parent?(opt.type||opt.parent.type):opt.type);
valueField.typedInput('type', opt.type); valueField.typedInput('value', opt.parent?(opt.value||opt.parent.value):opt.value);
valueField.typedInput('value', opt.value);
var actionButton = $('<a/>',{href:"#",class:"red-ui-editableList-item-remove editor-button editor-button-small"}).appendTo(container);
$('<i/>',{class:"fa "+(opt.parent?"fa-reply":"fa-remove")}).appendTo(actionButton);
container.parent().addClass("red-ui-editableList-item-removable");
if (opt.parent) {
if (opt.value && (opt.value !== opt.parent.value || opt.type !== opt.parent.type)) {
actionButton.show();
} else {
actionButton.hide();
}
var restoreTip = RED.popover.tooltip(actionButton,RED._("subflow.env.restore"));
valueField.change(function(evt) {
var newType = valueField.typedInput('type');
var newValue = valueField.typedInput('value');
if (newType === opt.parent.type && newValue === opt.parent.value) {
actionButton.hide();
} else {
actionButton.show();
}
})
actionButton.click(function(evt) {
evt.preventDefault();
restoreTip.close();
valueField.typedInput('type', opt.parent.type);
valueField.typedInput('value', opt.parent.value);
})
} else {
var removeTip = RED.popover.tooltip(actionButton,RED._("subflow.env.remove"));
actionButton.click(function(evt) {
evt.preventDefault();
removeTip.close();
container.parent().addClass("red-ui-editableList-item-deleting")
container.fadeOut(300, function() {
env_container.editableList('removeItem',opt);
});
});
} }
}, },
sortable: true, sortable: false,
removable: true removable: false
}); });
var envs = node.env; var parentEnv = {};
if (envs) { var envList = [];
for (var i = 0; i < envs.length; i++) { if (/^subflow:/.test(node.type)) {
var env = envs[i]; var subflowDef = RED.nodes.subflow(node.type.substring(8));
env_container.editableList('addItem', env); if (subflowDef.env) {
subflowDef.env.forEach(function(env) {
var item = {
name:env.name,
parent: {
type: env.type,
value: env.value
}
}
envList.push(item);
parentEnv[env.name] = item;
})
} }
} }
if (node.env) {
for (var i = 0; i < node.env.length; i++) {
var env = node.env[i];
if (parentEnv.hasOwnProperty(env.name)) {
parentEnv[env.name].type = env.type;
parentEnv[env.name].value = env.value;
} else {
envList.push({
name: env.name,
type: env.type,
value: env.value
});
}
}
}
envList.forEach(function(env) {
env_container.editableList('addItem', env);
})
} }
function convEnv(editable_list) { function exportEnvList(list) {
if (editable_list) { if (list) {
var env = []; var env = [];
editable_list.each(function(i) { list.each(function(i) {
var entry = $(this); var entry = $(this);
var nf = entry.find(".node-input-env-name"); var item = entry.data('data');
var vf = entry.find(".node-input-env-value"); var name = item.parent?item.name:entry.find(".node-input-env-name").val();
var name = nf.val(); var valueInput = entry.find(".node-input-env-value");
var value = vf.typedInput("value"); var value = valueInput.typedInput("value");
var type = vf.typedInput("type"); var type = valueInput.typedInput("type");
var item = { if (!item.parent || (item.parent.value !== value || item.parent.type !== type)) {
name: name, var item = {
type: type, name: name,
value: value type: type,
}; value: value
env.push(item); };
env.push(item);
}
}); });
return env; return env;
} }
@ -1343,7 +1418,7 @@ RED.editor = (function() {
if (type === "subflow") { if (type === "subflow") {
var old_env = editing_node.env; var old_env = editing_node.env;
var new_env = convEnv($("#node-input-env-container").editableList("items")); var new_env = exportEnvList($("#node-input-env-container").editableList("items"));
if (!isSameEnv(old_env, new_env)) { if (!isSameEnv(old_env, new_env)) {
editing_node.env = new_env; editing_node.env = new_env;
changes.env = editing_node.env; changes.env = editing_node.env;
@ -2070,7 +2145,7 @@ RED.editor = (function() {
} }
var old_env = editing_node.env; var old_env = editing_node.env;
var new_env = convEnv($("#node-input-env-container").editableList("items")); var new_env = exportEnvList($("#node-input-env-container").editableList("items"));
if (!isSameEnv(old_env, new_env)) { if (!isSameEnv(old_env, new_env)) {
editing_node.env = new_env; editing_node.env = new_env;
changes.env = editing_node.env; changes.env = editing_node.env;

View File

@ -265,7 +265,7 @@ class Subflow extends Flow {
if (env && env.hasOwnProperty(name)) { if (env && env.hasOwnProperty(name)) {
var val = env[name]; var val = env[name];
try { try {
var ret = redUtil.evaluateNodeProperty(val.value, val.type, null, null, null); var ret = redUtil.evaluateNodeProperty(val.value, val.type, this.node, null, null);
return ret; return ret;
} }
catch (e) { catch (e) {

View File

@ -166,7 +166,7 @@ describe('subflow', function() {
n1.receive({payload:"foo"}); n1.receive({payload:"foo"});
}); });
}); });
it('should access env var of subflow instance', function(done) { it('should access env var of subflow instance', function(done) {
var flow = [ var flow = [
{id:"t0", type:"tab", label:"", disabled:false, info:""}, {id:"t0", type:"tab", label:"", disabled:false, info:""},
@ -256,13 +256,11 @@ describe('subflow', function() {
{id:"t0", type:"tab", label:"", disabled:false, info:""}, {id:"t0", type:"tab", label:"", disabled:false, info:""},
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
env: [ env: [
{name: "KS", type: "str", value: "STR"},
{name: "KN", type: "num", value: "100"}, {name: "KN", type: "num", value: "100"},
{name: "KB", type: "bool", value: "true"}, {name: "KB", type: "bool", value: "true"},
{name: "KJ", type: "json", value: "[1,2,3]"}, {name: "KJ", type: "json", value: "[1,2,3]"},
{name: "Kb", type: "bin", value: "[65,65]"}, {name: "Kb", type: "bin", value: "[65,65]"},
{name: "KR", type: "re", value: "[A-Z]"}, {name: "Ke", type: "env", value: "KS"}
{name: "KD", type: "date", value: ""}
], ],
wires:[["n2"]]}, wires:[["n2"]]},
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]}, {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
@ -275,10 +273,13 @@ describe('subflow', function() {
out:[{ out:[{
x:10, y:10, x:10, y:10,
wires:[ {id:"s1-n1", port:0} ] wires:[ {id:"s1-n1", port:0} ]
}] }],
env: [
{name: "KS", type: "str", value: "STR"}
]
}, },
{id:"s1-n1", x:10, y:10, z:"s1", type:"function", {id:"s1-n1", x:10, y:10, z:"s1", type:"function",
func:"msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); msg.VR = env.get('KR'); msg.VD = env.get('KD'); return msg;", func:"msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); return msg;",
wires:[]} wires:[]}
]; ];
helper.load(functionNode, flow, function() { helper.load(functionNode, flow, function() {
@ -292,14 +293,10 @@ describe('subflow', function() {
msg.should.have.property("VJ", [1,2,3]); msg.should.have.property("VJ", [1,2,3]);
msg.should.have.property("Vb"); msg.should.have.property("Vb");
should.ok(msg.Vb instanceof Buffer); should.ok(msg.Vb instanceof Buffer);
msg.should.have.property("VR"); msg.should.have.property("VE","STR");
should.ok(msg.VR instanceof RegExp);
msg.should.have.property("VD");
should.ok((typeof msg.VD) === "number");
done(); done();
} }
catch (e) { catch (e) {
console.log(e);
done(e); done(e);
} }
}); });