mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Add support of subflow env var
This commit is contained in:
parent
4baaaa8d59
commit
a413f3cded
@ -901,6 +901,7 @@
|
|||||||
"editor-tab": {
|
"editor-tab": {
|
||||||
"properties": "Properties",
|
"properties": "Properties",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"appearance": "Appearance"
|
"appearance": "Appearance",
|
||||||
|
"env": "Env Var"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -901,6 +901,7 @@
|
|||||||
"editor-tab": {
|
"editor-tab": {
|
||||||
"properties": "プロパティ",
|
"properties": "プロパティ",
|
||||||
"description": "説明",
|
"description": "説明",
|
||||||
"appearance": "外観"
|
"appearance": "外観",
|
||||||
|
"env": "環境変数"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,10 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
subflows[sf.id] = sf;
|
subflows[sf.id] = sf;
|
||||||
RED.nodes.registerType("subflow:"+sf.id, {
|
RED.nodes.registerType("subflow:"+sf.id, {
|
||||||
defaults:{name:{value:""}},
|
defaults:{
|
||||||
|
name:{value:""},
|
||||||
|
env:{value:[]}
|
||||||
|
},
|
||||||
icon: function() { return sf.icon||"subflow.png" },
|
icon: function() { return sf.icon||"subflow.png" },
|
||||||
category: sf.category || "subflows",
|
category: sf.category || "subflows",
|
||||||
inputs: sf.in.length,
|
inputs: sf.in.length,
|
||||||
@ -535,6 +538,7 @@ RED.nodes = (function() {
|
|||||||
node.category = n.category;
|
node.category = n.category;
|
||||||
node.in = [];
|
node.in = [];
|
||||||
node.out = [];
|
node.out = [];
|
||||||
|
node.env = n.env;
|
||||||
|
|
||||||
n.in.forEach(function(p) {
|
n.in.forEach(function(p) {
|
||||||
var nIn = {x:p.x,y:p.y,wires:[]};
|
var nIn = {x:p.x,y:p.y,wires:[]};
|
||||||
@ -1018,6 +1022,7 @@ RED.nodes = (function() {
|
|||||||
node.name = n.name;
|
node.name = n.name;
|
||||||
node.outputs = subflow.out.length;
|
node.outputs = subflow.out.length;
|
||||||
node.inputs = subflow.in.length;
|
node.inputs = subflow.in.length;
|
||||||
|
node.env = n.env;
|
||||||
} else {
|
} else {
|
||||||
if (!node._def) {
|
if (!node._def) {
|
||||||
if (node.x && node.y) {
|
if (node.x && node.y) {
|
||||||
|
@ -540,7 +540,113 @@ RED.editor = (function() {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEditForm(container,formId,type,ns) {
|
function buildEnvForm(container, node) {
|
||||||
|
var env_container = $('#node-input-env-container');
|
||||||
|
env_container
|
||||||
|
.css('min-height','250px').css('min-width','450px')
|
||||||
|
.editableList({
|
||||||
|
addItem: function(container, i, opt) {
|
||||||
|
var row = $('<div/>').appendTo(container);
|
||||||
|
var nameField = $('<input/>', {
|
||||||
|
class: "node-input-env-name",
|
||||||
|
type: "text",
|
||||||
|
style: "margin-length: 5px; width: 32%;"
|
||||||
|
}).appendTo(row);
|
||||||
|
var valueField = $('<input/>',{
|
||||||
|
class: "node-input-env-value",
|
||||||
|
type: "text",
|
||||||
|
style: "margin-left: 5px; width: 65%;"
|
||||||
|
}).appendTo(row)
|
||||||
|
valueField.typedInput({default:'str',
|
||||||
|
types:['str','num','bool','json','bin','re','date']
|
||||||
|
});
|
||||||
|
if (opt) {
|
||||||
|
nameField.val(opt.name);
|
||||||
|
valueField.typedInput('type', opt.type);
|
||||||
|
valueField.typedInput('value', opt.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sortable: true,
|
||||||
|
removable: true
|
||||||
|
});
|
||||||
|
var envs = node.env;
|
||||||
|
if (envs) {
|
||||||
|
for (var i = 0; i < envs.length; i++) {
|
||||||
|
var env = envs[i];
|
||||||
|
env_container.editableList('addItem', env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convEnv(editable_list) {
|
||||||
|
if (editable_list) {
|
||||||
|
var env = [];
|
||||||
|
editable_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 info = {
|
||||||
|
name: name,
|
||||||
|
label: "",
|
||||||
|
value: value,
|
||||||
|
type: type,
|
||||||
|
target_type: "env var",
|
||||||
|
target: name
|
||||||
|
};
|
||||||
|
var item = {
|
||||||
|
name: name,
|
||||||
|
type: type,
|
||||||
|
value: value,
|
||||||
|
info: info
|
||||||
|
};
|
||||||
|
env.push(item);
|
||||||
|
});
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameEnv(env0, env1) {
|
||||||
|
function isSameInfo(info0, info1) {
|
||||||
|
if (info0 && info1 &&
|
||||||
|
(info0.name === info1.name) &&
|
||||||
|
(info0.label === info1.label) &&
|
||||||
|
(info0.value === info1.value) &&
|
||||||
|
(info0.type === info1.type) &&
|
||||||
|
(info0.target_type === info1.target_type) &&
|
||||||
|
(info0.target === info1.target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function inEnv(env, item) {
|
||||||
|
for(var i = 0; i < env.length; i++) {
|
||||||
|
var item1 = env[i];
|
||||||
|
if ((item1.name !== item.name) ||
|
||||||
|
(item1.type !== item.type) ||
|
||||||
|
(item1.value !== item.value) ||
|
||||||
|
!isSameInfo(item1.info, item.info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (env0 && env1 && (env0.length === env1.length)) {
|
||||||
|
for (var i = 0; i < env0.length; i++) {
|
||||||
|
var item0 = env0[i];
|
||||||
|
if (!inEnv(env1, item0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEditForm(container,formId,type,ns,node) {
|
||||||
var dialogForm = $('<form id="'+formId+'" class="form-horizontal" autocomplete="off"></form>').appendTo(container);
|
var dialogForm = $('<form id="'+formId+'" class="form-horizontal" autocomplete="off"></form>').appendTo(container);
|
||||||
dialogForm.html($("script[data-template-name='"+type+"']").html());
|
dialogForm.html($("script[data-template-name='"+type+"']").html());
|
||||||
ns = ns||"node-red";
|
ns = ns||"node-red";
|
||||||
@ -561,6 +667,11 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
$(this).attr("data-i18n",keys.join(";"));
|
$(this).attr("data-i18n",keys.join(";"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ((type === "subflow") || (type === "subflow-template")) {
|
||||||
|
buildEnvForm(dialogForm, node);
|
||||||
|
}
|
||||||
|
|
||||||
// Add dummy fields to prevent 'Enter' submitting the form in some
|
// Add dummy fields to prevent 'Enter' submitting the form in some
|
||||||
// cases, and also prevent browser auto-fill of password
|
// cases, and also prevent browser auto-fill of password
|
||||||
// Add in reverse order as they are prepended...
|
// Add in reverse order as they are prepended...
|
||||||
@ -1268,6 +1379,16 @@ RED.editor = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === "subflow") {
|
||||||
|
var old_env = editing_node.env;
|
||||||
|
var new_env = convEnv($("#node-input-env-container").editableList("items"));
|
||||||
|
if (!isSameEnv(old_env, new_env)) {
|
||||||
|
editing_node.env = new_env;
|
||||||
|
changes.env = editing_node.env;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
var wasChanged = editing_node.changed;
|
var wasChanged = editing_node.changed;
|
||||||
editing_node.changed = true;
|
editing_node.changed = true;
|
||||||
@ -1373,7 +1494,7 @@ RED.editor = (function() {
|
|||||||
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
||||||
iconClass: "fa fa-cog"
|
iconClass: "fa fa-cog"
|
||||||
};
|
};
|
||||||
buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns);
|
buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns,node);
|
||||||
editorTabs.addTab(nodePropertiesTab);
|
editorTabs.addTab(nodePropertiesTab);
|
||||||
|
|
||||||
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
|
||||||
@ -1986,6 +2107,14 @@ RED.editor = (function() {
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var old_env = editing_node.env;
|
||||||
|
var new_env = convEnv($("#node-input-env-container").editableList("items"));
|
||||||
|
if (!isSameEnv(old_env, new_env)) {
|
||||||
|
editing_node.env = new_env;
|
||||||
|
changes.env = editing_node.env;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
RED.palette.refresh();
|
RED.palette.refresh();
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
@ -2063,7 +2192,7 @@ RED.editor = (function() {
|
|||||||
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
content: $('<div>', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
|
||||||
iconClass: "fa fa-cog"
|
iconClass: "fa fa-cog"
|
||||||
};
|
};
|
||||||
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template");
|
buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
|
||||||
editorTabs.addTab(nodePropertiesTab);
|
editorTabs.addTab(nodePropertiesTab);
|
||||||
|
|
||||||
var descriptionTab = {
|
var descriptionTab = {
|
||||||
|
@ -17,10 +17,16 @@
|
|||||||
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>'+
|
||||||
|
'<div class="form-row"><label data-i18n="[append]editor:editor-tab.env"><i class="fa fa-th-list"></i> </label></div>'+
|
||||||
|
'<div class="form-row node-input-env-container-row"><ol id="node-input-env-container"></ol></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>'+
|
||||||
'<div class="form-row"><i class="fa fa-folder-o"></i> <label for="subflow-input-category" data-i18n="editor:subflow.category"></label><select style="width: 250px;" id="subflow-input-category"></select><input style="display:none; margin-left: 10px; width:calc(100% - 250px)" type="text" id="subflow-input-custom-category"></div>'+
|
'<div class="form-row"><i class="fa fa-folder-o"></i> <label for="subflow-input-category" data-i18n="editor:subflow.category"></label><select style="width: 250px;" id="subflow-input-category"></select><input style="display:none; margin-left: 10px; width:calc(100% - 250px)" type="text" id="subflow-input-custom-category"></div>'+
|
||||||
|
'<div class="form-row"><label data-i18n="[append]editor:editor-tab.env"><i class="fa fa-th-list"></i> </label></div>'+
|
||||||
|
'<div class="form-row node-input-env-container-row"><ol id="node-input-env-container"></ol></div>'+
|
||||||
'<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>';
|
||||||
|
|
||||||
|
@ -158,9 +158,7 @@ module.exports = function(RED) {
|
|||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
get: function(envVar) {
|
get: function(envVar) {
|
||||||
// For now, just return the env var. This will eventually
|
return node.getenv(envVar);
|
||||||
// also return project settings and subflow instance properties
|
|
||||||
return process.env[envVar]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setTimeout: function () {
|
setTimeout: function () {
|
||||||
|
@ -94,7 +94,7 @@ module.exports = function(RED) {
|
|||||||
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
|
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
|
||||||
}
|
}
|
||||||
} else if (rule.tot === 'env') {
|
} else if (rule.tot === 'env') {
|
||||||
rule.to = RED.util.evaluateNodeProperty(rule.to,'env');
|
rule.to = RED.util.evaluateNodeProperty(rule.to,'env',node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,9 @@ function Node(n) {
|
|||||||
if (n._alias) {
|
if (n._alias) {
|
||||||
this._alias = n._alias;
|
this._alias = n._alias;
|
||||||
}
|
}
|
||||||
|
if (n.env) {
|
||||||
|
this.env = n.env;
|
||||||
|
}
|
||||||
if (n._flow) {
|
if (n._flow) {
|
||||||
// Make this a non-enumerable property as it may cause
|
// Make this a non-enumerable property as it may cause
|
||||||
// circular references. Any existing code that tries to JSON serialise
|
// circular references. Any existing code that tries to JSON serialise
|
||||||
@ -236,6 +239,22 @@ Node.prototype.receive = function(msg) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Node.prototype.getenv = function(name) {
|
||||||
|
var flow = this._flow;
|
||||||
|
if (flow) {
|
||||||
|
var val = flow.getSetting(name);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
Node.prototype.setenv = function(name, val) {
|
||||||
|
var flow = this._flow;
|
||||||
|
if (flow) {
|
||||||
|
flow.setSetting(name, val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function log_helper(self, level, msg) {
|
function log_helper(self, level, msg) {
|
||||||
var o = {
|
var o = {
|
||||||
level: level,
|
level: level,
|
||||||
|
@ -461,6 +461,10 @@ class Flow {
|
|||||||
}
|
}
|
||||||
console.log("==================")
|
console.log("==================")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getenv(name) {
|
||||||
|
return process.env[name];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,35 @@ const flowUtil = require("./util");
|
|||||||
|
|
||||||
var Log;
|
var Log;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert env var definition of subflow template and instance to env var dic
|
||||||
|
* @param {Hash} env1 env var definition of template
|
||||||
|
* @param {Hash} env2 env var definition of instance
|
||||||
|
* @return {Hash} env var dic
|
||||||
|
*/
|
||||||
|
function env2Dic(env0, env1) {
|
||||||
|
var dic = {};
|
||||||
|
function add(env) {
|
||||||
|
for(var i = 0; i < env.length; i++) {
|
||||||
|
var item = env[i];
|
||||||
|
var name = item.name;
|
||||||
|
var info = Object.assign({}, item.info);
|
||||||
|
info.name = name;
|
||||||
|
dic[name] = item;
|
||||||
|
dic[name+"_type"] = { value: item.type };
|
||||||
|
dic[name+"_info"] = { value: info };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (env0) {
|
||||||
|
add(env0);
|
||||||
|
}
|
||||||
|
if (env1) {
|
||||||
|
add(env1);
|
||||||
|
}
|
||||||
|
return dic;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a subflow - which is handled as a special type of Flow
|
* This class represents a subflow - which is handled as a special type of Flow
|
||||||
*/
|
*/
|
||||||
@ -104,12 +133,14 @@ 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");
|
||||||
|
var env = env2Dic(this.subflowDef.env, this.subflowInstance.env);
|
||||||
var subflowInstanceConfig = {
|
var subflowInstanceConfig = {
|
||||||
id: this.subflowInstance.id,
|
id: this.subflowInstance.id,
|
||||||
type: this.subflowInstance.type,
|
type: this.subflowInstance.type,
|
||||||
z: this.subflowInstance.z,
|
z: this.subflowInstance.z,
|
||||||
name: this.subflowInstance.name,
|
name: this.subflowInstance.name,
|
||||||
wires: [],
|
wires: [],
|
||||||
|
env: env,
|
||||||
_flow: this
|
_flow: this
|
||||||
}
|
}
|
||||||
if (this.subflowDef.in) {
|
if (this.subflowDef.in) {
|
||||||
@ -164,7 +195,7 @@ class Subflow extends Flow {
|
|||||||
self.node._updateWires(subflowInstanceConfig.wires);
|
self.node._updateWires(subflowInstanceConfig.wires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Wire the subflow outputs
|
// Wire the subflow outputs
|
||||||
if (this.subflowDef.out) {
|
if (this.subflowDef.out) {
|
||||||
@ -172,7 +203,7 @@ class Subflow extends Flow {
|
|||||||
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
|
||||||
wires = this.subflowDef.out[i].wires;
|
var wires = this.subflowDef.out[i].wires;
|
||||||
for (var j=0;j<wires.length;j++) {
|
for (var j=0;j<wires.length;j++) {
|
||||||
if (wires[j].id === this.subflowDef.id) {
|
if (wires[j].id === this.subflowDef.id) {
|
||||||
// A subflow input wired straight to a subflow output
|
// A subflow input wired straight to a subflow output
|
||||||
@ -192,6 +223,42 @@ class Subflow extends Flow {
|
|||||||
super.start(diff);
|
super.start(diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get environment variable of subflow
|
||||||
|
* @param {String} name name of env var
|
||||||
|
* @return {Object} val value of env var
|
||||||
|
*/
|
||||||
|
getSetting(name) {
|
||||||
|
var node = this.node;
|
||||||
|
if (node) {
|
||||||
|
var env = node.env;
|
||||||
|
if (env && env.hasOwnProperty(name)) {
|
||||||
|
return env[name].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var parent = this.parent;
|
||||||
|
if (parent) {
|
||||||
|
var val = parent.getSetting(name);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set environment variable of subflow
|
||||||
|
* @param {String} name name of env var
|
||||||
|
* @param {Object} val value of env var
|
||||||
|
*/
|
||||||
|
setSetting(name, val) {
|
||||||
|
var node = this.node;
|
||||||
|
if (node) {
|
||||||
|
var env = node.env;
|
||||||
|
if (env) {
|
||||||
|
env[name] = { name: name, type: "str", value: val, info: null };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -234,7 +301,6 @@ class Subflow extends Flow {
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
38
packages/node_modules/@node-red/util/lib/util.js
vendored
38
packages/node_modules/@node-red/util/lib/util.js
vendored
@ -413,6 +413,20 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of environment variable.
|
||||||
|
* @param {Node} node - accessing node
|
||||||
|
* @param {String} name - name of variable
|
||||||
|
* @return {String} value of env var
|
||||||
|
*/
|
||||||
|
function getenv(node, name) {
|
||||||
|
if (node && node.getenv) {
|
||||||
|
return node.getenv(name);
|
||||||
|
}
|
||||||
|
return process.env[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a String contains any Environment Variable specifiers and returns
|
* Checks if a String contains any Environment Variable specifiers and returns
|
||||||
* it with their values substituted in place.
|
* it with their values substituted in place.
|
||||||
@ -420,24 +434,27 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
|||||||
* For example, if the env var `WHO` is set to `Joe`, the string `Hello ${WHO}!`
|
* For example, if the env var `WHO` is set to `Joe`, the string `Hello ${WHO}!`
|
||||||
* will return `Hello Joe!`.
|
* will return `Hello Joe!`.
|
||||||
* @param {String} value - the string to parse
|
* @param {String} value - the string to parse
|
||||||
|
* @param {Node} node - the node evaluating the property
|
||||||
* @return {String} The parsed string
|
* @return {String} The parsed string
|
||||||
* @memberof @node-red/util_util
|
* @memberof @node-red/util_util
|
||||||
*/
|
*/
|
||||||
function evaluateEnvProperty(value) {
|
function evaluateEnvProperty(value, node) {
|
||||||
if (/^\${[^}]+}$/.test(value)) {
|
if (/^\${[^}]+}$/.test(value)) {
|
||||||
// ${ENV_VAR}
|
// ${ENV_VAR}
|
||||||
value = value.substring(2,value.length-1);
|
var name = value.substring(2,value.length-1);
|
||||||
value = process.env.hasOwnProperty(value)?process.env[value]:""
|
var val = getenv(node, name);
|
||||||
|
return val ? val : "";
|
||||||
} else if (!/\${\S+}/.test(value)) {
|
} else if (!/\${\S+}/.test(value)) {
|
||||||
// ENV_VAR
|
// ENV_VAR
|
||||||
value = process.env.hasOwnProperty(value)?process.env[value]:""
|
var val = getenv(node, value);
|
||||||
|
return val ? val : "";
|
||||||
} else {
|
} else {
|
||||||
// FOO${ENV_VAR}BAR
|
// FOO${ENV_VAR}BAR
|
||||||
value = value.replace(/\${([^}]+)}/g, function(match, v) {
|
return value.replace(/\${([^}]+)}/g, function(match, name) {
|
||||||
return process.env.hasOwnProperty(v)?process.env[v]:""
|
var val = getenv(node, name);
|
||||||
|
return (val ? val : "");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -513,7 +530,7 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
|||||||
var expr = prepareJSONataExpression(value,node);
|
var expr = prepareJSONataExpression(value,node);
|
||||||
result = evaluateJSONataExpression(expr,msg);
|
result = evaluateJSONataExpression(expr,msg);
|
||||||
} else if (type === 'env') {
|
} else if (type === 'env') {
|
||||||
result = evaluateEnvProperty(value);
|
result = evaluateEnvProperty(value, node);
|
||||||
}
|
}
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(null,result);
|
callback(null,result);
|
||||||
@ -540,8 +557,9 @@ function prepareJSONataExpression(value,node) {
|
|||||||
expr.assign('globalContext',function(val) {
|
expr.assign('globalContext',function(val) {
|
||||||
return node.context().global.get(val);
|
return node.context().global.get(val);
|
||||||
});
|
});
|
||||||
expr.assign('env', function(val) {
|
expr.assign('env', function(name) {
|
||||||
return process.env[val];
|
var val = getenv(node, name);
|
||||||
|
return (val ? val : "");
|
||||||
})
|
})
|
||||||
expr.registerFunction('clone', cloneMessage, '<(oa)-:o>');
|
expr.registerFunction('clone', cloneMessage, '<(oa)-:o>');
|
||||||
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
|
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
|
||||||
|
408
test/nodes/subflow/subflow_spec.js
Normal file
408
test/nodes/subflow/subflow_spec.js
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/**
|
||||||
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
**/
|
||||||
|
|
||||||
|
var should = require("should");
|
||||||
|
var functionNode = require("nr-test-utils").require("@node-red/nodes/core/core/80-function.js");
|
||||||
|
var helper = require("node-red-node-test-helper");
|
||||||
|
|
||||||
|
// Notice:
|
||||||
|
// - nodes should have x, y, z property when defining subflow.
|
||||||
|
|
||||||
|
describe('subflow', function() {
|
||||||
|
|
||||||
|
before(function(done) {
|
||||||
|
helper.startServer(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function(done) {
|
||||||
|
helper.stopServer(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
helper.unload();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should define subflow', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t1", type:"tab"},
|
||||||
|
{id:"n1", z:"t1", type:"subflow:s1", wires:[["n2"]]},
|
||||||
|
{id:"n2", z:"t1", type:"helper", wires:[]},
|
||||||
|
// Subflow
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||||
|
in:[{wires:[ {id:"s1-n1"} ]}],
|
||||||
|
out:[{wires:[ {id:"s1-n1", port:0} ]}]},
|
||||||
|
{id:"s1-n1", z:"s1", type:"function",
|
||||||
|
func:"return msg;", wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass data to/from subflow', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"msg.payload = msg.payload+'bar'; return msg;", wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property("payload", "foobar");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass data to/from nested subflow', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow1
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n2", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||||
|
wires:[["s1-n2"]]},
|
||||||
|
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"msg.payload = msg.payload+'baz'; return msg;", wires:[]},
|
||||||
|
// Subflow2
|
||||||
|
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||||
|
func:"msg.payload=msg.payload+'bar'; return msg;", wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property("payload", "foobarbaz");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should access env var of subflow template', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "T", value: "V",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "V",
|
||||||
|
type: "T",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
|
||||||
|
wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("V", "V");
|
||||||
|
msg.should.have.property("T", "T");
|
||||||
|
msg.should.have.property("I");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should access env var of subflow instance', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "T", value: "V",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "V",
|
||||||
|
type: "T",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
|
||||||
|
wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("V", "V");
|
||||||
|
msg.should.have.property("T", "T");
|
||||||
|
msg.should.have.property("I");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should overwrite env var of subflow template by env var of subflow instance', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "T", value: "V",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "V",
|
||||||
|
type: "T",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "TT", value: "TV",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "TV",
|
||||||
|
type: "TT",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
|
||||||
|
wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("V", "V");
|
||||||
|
msg.should.have.property("T", "T");
|
||||||
|
msg.should.have.property("I");
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should access env var of parent subflow template', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow1
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "T", value: "V",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "V",
|
||||||
|
type: "T",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n2", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||||
|
wires:[["s1-n2"]]},
|
||||||
|
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"return msg;", wires:[]},
|
||||||
|
// Subflow2
|
||||||
|
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||||
|
func:"msg.V = env.get('K'); return msg;",
|
||||||
|
wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property("V", "V");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should access env var of parent subflow instance', function(done) {
|
||||||
|
var flow = [
|
||||||
|
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||||
|
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||||
|
env: [
|
||||||
|
{name: "K", type: "T", value: "V",
|
||||||
|
info: {
|
||||||
|
name: "K",
|
||||||
|
label: "",
|
||||||
|
value: "V",
|
||||||
|
type: "T",
|
||||||
|
target_type: "env var",
|
||||||
|
"target": "K"
|
||||||
|
}}
|
||||||
|
],
|
||||||
|
wires:[["n2"]]},
|
||||||
|
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||||
|
// Subflow1
|
||||||
|
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s1-n2", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||||
|
wires:[["s1-n2"]]},
|
||||||
|
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||||
|
func:"return msg;", wires:[]},
|
||||||
|
// Subflow2
|
||||||
|
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||||
|
in:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1"} ]
|
||||||
|
}],
|
||||||
|
out:[{
|
||||||
|
x:10, y:10,
|
||||||
|
wires:[ {id:"s2-n1", port:0} ]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||||
|
func:"msg.V = env.get('K'); return msg;",
|
||||||
|
wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(functionNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
msg.should.have.property("V", "V");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
n1.receive({payload:"foo"});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -67,10 +67,12 @@ describe('Subflow', function() {
|
|||||||
this.foo = n.foo;
|
this.foo = n.foo;
|
||||||
this.handled = 0;
|
this.handled = 0;
|
||||||
this.stopped = false;
|
this.stopped = false;
|
||||||
|
this.received = null;
|
||||||
currentNodes[node.id] = node;
|
currentNodes[node.id] = node;
|
||||||
this.on('input',function(msg) {
|
this.on('input',function(msg) {
|
||||||
// console.log(this.id,msg.payload);
|
// console.log(this.id,msg.payload);
|
||||||
node.handled++;
|
node.handled++;
|
||||||
|
node.received = msg.payload;
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
});
|
});
|
||||||
this.on('close',function() {
|
this.on('close',function() {
|
||||||
@ -170,6 +172,34 @@ describe('Subflow', function() {
|
|||||||
}
|
}
|
||||||
util.inherits(TestAsyncNode,Node);
|
util.inherits(TestAsyncNode,Node);
|
||||||
|
|
||||||
|
var TestEnvNode = function(n) {
|
||||||
|
Node.call(this,n);
|
||||||
|
this._index = createCount++;
|
||||||
|
this.scope = n.scope;
|
||||||
|
this.foo = n.foo;
|
||||||
|
var node = this;
|
||||||
|
this.stopped = false;
|
||||||
|
this.received = null;
|
||||||
|
currentNodes[node.id] = node;
|
||||||
|
this.on('input',function(msg) {
|
||||||
|
var val = node.getenv("__KEY__");
|
||||||
|
node.received = val;
|
||||||
|
node.send({payload: val});
|
||||||
|
});
|
||||||
|
this.on('close',function() {
|
||||||
|
node.stopped = true;
|
||||||
|
stoppedNodes[node.id] = node;
|
||||||
|
delete currentNodes[node.id];
|
||||||
|
});
|
||||||
|
this.__updateWires = this.updateWires;
|
||||||
|
this.updateWires = function(newWires) {
|
||||||
|
rewiredNodes[node.id] = node;
|
||||||
|
node.newWires = newWires;
|
||||||
|
node.__updateWires(newWires);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
util.inherits(TestEnvNode,Node);
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
getType = sinon.stub(typeRegistry,"get",function(type) {
|
getType = sinon.stub(typeRegistry,"get",function(type) {
|
||||||
if (type=="test") {
|
if (type=="test") {
|
||||||
@ -178,6 +208,8 @@ describe('Subflow', function() {
|
|||||||
return TestErrorNode;
|
return TestErrorNode;
|
||||||
} else if (type=="testStatus"){
|
} else if (type=="testStatus"){
|
||||||
return TestStatusNode;
|
return TestStatusNode;
|
||||||
|
} else if (type=="testEnv"){
|
||||||
|
return TestEnvNode;
|
||||||
} else {
|
} else {
|
||||||
return TestAsyncNode;
|
return TestAsyncNode;
|
||||||
}
|
}
|
||||||
@ -533,4 +565,128 @@ describe('Subflow', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#env var", function() {
|
||||||
|
it("can access process env var", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",wires:[]},
|
||||||
|
{id:"sf1",type:"subflow",name:"Subflow 2",info:"",
|
||||||
|
"in":[ {wires:[{id:"sf1-1"}]} ],
|
||||||
|
"out":[ {wires:[{id:"sf1-2",port:0}]} ]},
|
||||||
|
{id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
|
||||||
|
{id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1-cn",x:166,y:99,wires:[[]]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({
|
||||||
|
getSetting: k=> process.env[k],
|
||||||
|
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||||
|
},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
process.env["__KEY__"] = "__VAL__";
|
||||||
|
|
||||||
|
currentNodes["1"].receive({payload: "test"});
|
||||||
|
currentNodes["3"].should.have.a.property("received", "__VAL__");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access subflow env var", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",wires:[]},
|
||||||
|
{id:"sf1",type:"subflow",name:"Subflow 2",info:"",
|
||||||
|
"in":[ {wires:[{id:"sf1-1"}]} ],
|
||||||
|
"out":[ {wires:[{id:"sf1-2",port:0}]} ]},
|
||||||
|
{id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
|
||||||
|
{id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({
|
||||||
|
getSetting: k=> process.env[k],
|
||||||
|
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||||
|
},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var testenv_node = null;
|
||||||
|
for (var n in currentNodes) {
|
||||||
|
var node = currentNodes[n];
|
||||||
|
if (node.type === "testEnv") {
|
||||||
|
testenv_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process.env["__KEY__"] = "__VAL0__";
|
||||||
|
testenv_node.setenv("__KEY__", "__VAL1__");
|
||||||
|
|
||||||
|
currentNodes["1"].receive({payload: "test"});
|
||||||
|
currentNodes["3"].should.have.a.property("received", "__VAL1__");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can access nested subflow env var", function(done) {
|
||||||
|
var config = flowUtils.parseConfig([
|
||||||
|
{id:"t1",type:"tab"},
|
||||||
|
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",wires:[]},
|
||||||
|
{id:"sf1",type:"subflow",name:"Subflow 1",info:"",
|
||||||
|
in:[{wires:[{id:"sf1-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf1-2",port:0}]}]},
|
||||||
|
{id:"sf2",type:"subflow",name:"Subflow 2",info:"",
|
||||||
|
in:[{wires:[{id:"sf2-1"}]}],
|
||||||
|
out:[{wires:[{id:"sf2-2",port:0}]}]},
|
||||||
|
{id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
|
||||||
|
{id:"sf1-2",type:"subflow:sf2",z:"sf1",x:166,y:99,wires:[[]]},
|
||||||
|
{id:"sf2-1",type:"test",z:"sf2",foo:"sf2.1",x:166,y:99,wires:[["sf2-2"]]},
|
||||||
|
{id:"sf2-2",type:"testEnv",z:"sf2",foo:"sf2.2",x:166,y:99,wires:[[]]},
|
||||||
|
]);
|
||||||
|
var flow = Flow.create({
|
||||||
|
getSetting: k=> process.env[k],
|
||||||
|
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||||
|
},config,config.flows["t1"]);
|
||||||
|
|
||||||
|
flow.start();
|
||||||
|
|
||||||
|
var node_sf1_1 = null;
|
||||||
|
var node_sf2_1 = null;
|
||||||
|
var testenv_node = null;
|
||||||
|
for (var n in currentNodes) {
|
||||||
|
var node = currentNodes[n];
|
||||||
|
if (node.foo === "sf1.1") {
|
||||||
|
node_sf1_1 = node;
|
||||||
|
}
|
||||||
|
if (node.foo === "sf2.1") {
|
||||||
|
node_sf2_1 = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.env["__KEY__"] = "__VAL0__";
|
||||||
|
currentNodes["1"].receive({payload: "test"});
|
||||||
|
currentNodes["3"].should.have.a.property("received", "__VAL0__");
|
||||||
|
|
||||||
|
node_sf1_1.setenv("__KEY__", "__VAL1__");
|
||||||
|
currentNodes["1"].receive({payload: "test"});
|
||||||
|
currentNodes["3"].should.have.a.property("received", "__VAL1__");
|
||||||
|
|
||||||
|
node_sf2_1.setenv("__KEY__", "__VAL2__");
|
||||||
|
currentNodes["1"].receive({payload: "test"});
|
||||||
|
currentNodes["3"].should.have.a.property("received", "__VAL2__");
|
||||||
|
|
||||||
|
flow.stop().then(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user