mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Merge pull request #2050 from node-red/subflow-props
Display parent subflow properties in subflow instance edit dialog
This commit is contained in:
		@@ -277,6 +277,10 @@
 | 
			
		||||
        "deleteSubflow": "delete subflow",
 | 
			
		||||
        "info": "Description",
 | 
			
		||||
        "category": "Category",
 | 
			
		||||
        "env": {
 | 
			
		||||
            "restore": "Restore to subflow default",
 | 
			
		||||
            "remove": "Remove environment variable"
 | 
			
		||||
        },
 | 
			
		||||
        "errors": {
 | 
			
		||||
            "noNodesSelected": "<strong>Cannot create subflow</strong>: no nodes selected",
 | 
			
		||||
            "multipleInputsToSelection": "<strong>Cannot create subflow</strong>: multiple inputs to selection"
 | 
			
		||||
 
 | 
			
		||||
@@ -550,54 +550,129 @@ RED.editor = (function() {
 | 
			
		||||
            .editableList({
 | 
			
		||||
                addItem: function(container, i, opt) {
 | 
			
		||||
                    var row = $('<div/>').appendTo(container);
 | 
			
		||||
                    var nameField = $('<input/>', {
 | 
			
		||||
                    if (opt.parent) {
 | 
			
		||||
                        $('<div/>', {
 | 
			
		||||
                            class:"uneditable-input",
 | 
			
		||||
                            style: "margin-left: 5px; width: calc(40% - 8px)",
 | 
			
		||||
                        }).appendTo(row).text(opt.name);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $('<input/>', {
 | 
			
		||||
                            class: "node-input-env-name",
 | 
			
		||||
                            type: "text",
 | 
			
		||||
                        style: "margin-left: 5px; width: calc(40% - 5px)",
 | 
			
		||||
                            style: "margin-left: 5px; width: calc(40% - 8px)",
 | 
			
		||||
                            placeholder: RED._("common.label.name")
 | 
			
		||||
                    }).appendTo(row);
 | 
			
		||||
                        }).appendTo(row).val(opt.name);
 | 
			
		||||
                    }
 | 
			
		||||
                    var valueField = $('<input/>',{
 | 
			
		||||
                        class: "node-input-env-value",
 | 
			
		||||
                        type: "text",
 | 
			
		||||
                        style: "margin-left: 5px; width: calc(60% - 5px)"
 | 
			
		||||
                        style: "margin-left: 5px; width: calc(60% - 8px)"
 | 
			
		||||
                    }).appendTo(row)
 | 
			
		||||
 | 
			
		||||
                    valueField.typedInput({default:'str',
 | 
			
		||||
                                           types:['str','num','bool','json','bin','re','date']
 | 
			
		||||
                                           types:['str','num','bool','json','bin','env']
 | 
			
		||||
                                          });
 | 
			
		||||
 | 
			
		||||
                    valueField.typedInput('type', opt.parent?(opt.type||opt.parent.type):opt.type);
 | 
			
		||||
                    valueField.typedInput('value', opt.parent?(opt.value||opt.parent.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);
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                    if (opt) {
 | 
			
		||||
                        nameField.val(opt.name);
 | 
			
		||||
                        valueField.typedInput('type', opt.type);
 | 
			
		||||
                        valueField.typedInput('value', opt.value);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                sortable: true,
 | 
			
		||||
                removable: true
 | 
			
		||||
                sortable: false,
 | 
			
		||||
                removable: false
 | 
			
		||||
            });
 | 
			
		||||
        var envs = node.env;
 | 
			
		||||
        if (envs) {
 | 
			
		||||
            for (var i = 0; i < envs.length; i++) {
 | 
			
		||||
                var env = envs[i];
 | 
			
		||||
                env_container.editableList('addItem', env);
 | 
			
		||||
        var parentEnv = {};
 | 
			
		||||
        var envList = [];
 | 
			
		||||
        if (/^subflow:/.test(node.type)) {
 | 
			
		||||
            var subflowDef = RED.nodes.subflow(node.type.substring(8));
 | 
			
		||||
            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;
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    function convEnv(editable_list) {
 | 
			
		||||
        if (editable_list) {
 | 
			
		||||
        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 exportEnvList(list) {
 | 
			
		||||
        if (list) {
 | 
			
		||||
            var env = [];
 | 
			
		||||
            editable_list.each(function(i) {
 | 
			
		||||
            list.each(function(i) {
 | 
			
		||||
                var entry = $(this);
 | 
			
		||||
                var nf = entry.find(".node-input-env-name");
 | 
			
		||||
                var vf = entry.find(".node-input-env-value");
 | 
			
		||||
                var name = nf.val();
 | 
			
		||||
                var value = vf.typedInput("value");
 | 
			
		||||
                var type = vf.typedInput("type");
 | 
			
		||||
                var item = entry.data('data');
 | 
			
		||||
                var name = item.parent?item.name:entry.find(".node-input-env-name").val();
 | 
			
		||||
                var valueInput = entry.find(".node-input-env-value");
 | 
			
		||||
                var value = valueInput.typedInput("value");
 | 
			
		||||
                var type = valueInput.typedInput("type");
 | 
			
		||||
                if (!item.parent || (item.parent.value !== value || item.parent.type !== type)) {
 | 
			
		||||
                    var item = {
 | 
			
		||||
                        name: name,
 | 
			
		||||
                        type: type,
 | 
			
		||||
                        value: value
 | 
			
		||||
                    };
 | 
			
		||||
                    env.push(item);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            return env;
 | 
			
		||||
        }
 | 
			
		||||
@@ -1343,7 +1418,7 @@ RED.editor = (function() {
 | 
			
		||||
 | 
			
		||||
                        if (type === "subflow") {
 | 
			
		||||
                            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)) {
 | 
			
		||||
                                editing_node.env = new_env;
 | 
			
		||||
                                changes.env = editing_node.env;
 | 
			
		||||
@@ -2070,7 +2145,7 @@ RED.editor = (function() {
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        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)) {
 | 
			
		||||
                            editing_node.env = new_env;
 | 
			
		||||
                            changes.env = editing_node.env;
 | 
			
		||||
 
 | 
			
		||||
@@ -265,7 +265,7 @@ class Subflow extends Flow {
 | 
			
		||||
        if (env && env.hasOwnProperty(name)) {
 | 
			
		||||
            var val = env[name];
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
            catch (e) {
 | 
			
		||||
 
 | 
			
		||||
@@ -256,13 +256,11 @@ describe('subflow', function() {
 | 
			
		||||
            {id:"t0", type:"tab", label:"", disabled:false, info:""},
 | 
			
		||||
            {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
 | 
			
		||||
             env: [
 | 
			
		||||
                 {name: "KS", type: "str", value: "STR"},
 | 
			
		||||
                 {name: "KN", type: "num", value: "100"},
 | 
			
		||||
                 {name: "KB", type: "bool", value: "true"},
 | 
			
		||||
                 {name: "KJ", type: "json", value: "[1,2,3]"},
 | 
			
		||||
                 {name: "Kb", type: "bin", value: "[65,65]"},
 | 
			
		||||
                 {name: "KR", type: "re", value: "[A-Z]"},
 | 
			
		||||
                 {name: "KD", type: "date", value: ""}
 | 
			
		||||
                 {name: "Ke", type: "env", value: "KS"}
 | 
			
		||||
             ],
 | 
			
		||||
             wires:[["n2"]]},
 | 
			
		||||
            {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
 | 
			
		||||
@@ -275,10 +273,13 @@ describe('subflow', function() {
 | 
			
		||||
             out:[{
 | 
			
		||||
                 x:10, y:10,
 | 
			
		||||
                 wires:[ {id:"s1-n1", port:0} ]
 | 
			
		||||
             }]
 | 
			
		||||
             }],
 | 
			
		||||
             env: [
 | 
			
		||||
                 {name: "KS", type: "str", value: "STR"}
 | 
			
		||||
             ]
 | 
			
		||||
            },
 | 
			
		||||
            {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:[]}
 | 
			
		||||
        ];
 | 
			
		||||
        helper.load(functionNode, flow, function() {
 | 
			
		||||
@@ -292,14 +293,10 @@ describe('subflow', function() {
 | 
			
		||||
                    msg.should.have.property("VJ", [1,2,3]);
 | 
			
		||||
                    msg.should.have.property("Vb");
 | 
			
		||||
                    should.ok(msg.Vb instanceof Buffer);
 | 
			
		||||
                    msg.should.have.property("VR");
 | 
			
		||||
                    should.ok(msg.VR instanceof RegExp);
 | 
			
		||||
                    msg.should.have.property("VD");
 | 
			
		||||
                    should.ok((typeof msg.VD) === "number");
 | 
			
		||||
                    msg.should.have.property("VE","STR");
 | 
			
		||||
                    done();
 | 
			
		||||
                }
 | 
			
		||||
                catch (e) {
 | 
			
		||||
                    console.log(e);
 | 
			
		||||
                    done(e);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user