mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Compare commits
26 Commits
4223-fix-h
...
wiring-twe
Author | SHA1 | Date | |
---|---|---|---|
|
56ed32e4a1 | ||
|
11f9ad8ca3 | ||
|
26fc942c79 | ||
|
2448e137c8 | ||
|
33899763ef | ||
|
ce679f90ee | ||
|
8fb379079b | ||
|
b382d048de | ||
|
4d9fcaeebf | ||
|
aa0225f59f | ||
|
20d2c11154 | ||
|
3f604e9d93 | ||
|
aafb86ef09 | ||
|
502dacd865 | ||
|
31bc99cd61 | ||
|
5435c9ebd2 | ||
|
ceb9a320ba | ||
|
ee8b2a0b58 | ||
|
8202f1b7c6 | ||
|
4808cac89d | ||
|
220a621dc6 | ||
|
876053f858 | ||
|
2f9523a586 | ||
|
0697c26dd1 | ||
|
c2812b05a4 | ||
|
2253417459 |
@@ -1033,7 +1033,7 @@ RED.view = (function() {
|
||||
})
|
||||
}
|
||||
|
||||
function generateLinkPath(origX,origY, destX, destY, sc) {
|
||||
function generateLinkPath(origX,origY, destX, destY, sc, hasStatus = false) {
|
||||
var dy = destY-origY;
|
||||
var dx = destX-origX;
|
||||
var delta = Math.sqrt(dy*dy+dx*dx);
|
||||
@@ -1050,62 +1050,110 @@ RED.view = (function() {
|
||||
} else {
|
||||
scale = 0.4-0.2*(Math.max(0,(node_width-Math.min(Math.abs(dx),Math.abs(dy)))/node_width));
|
||||
}
|
||||
function genCP(cp) {
|
||||
return ` M ${cp[0]-5} ${cp[1]} h 10 M ${cp[0]} ${cp[1]-5} v 10 `
|
||||
}
|
||||
if (dx*sc > 0) {
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+(origX+sc*(node_width*scale))+" "+(origY+scaleY*node_height)+" "+
|
||||
(destX-sc*(scale)*node_width)+" "+(destY-scaleY*node_height)+" "+
|
||||
destX+" "+destY
|
||||
let cp = [
|
||||
[(origX+sc*(node_width*scale)), (origY+scaleY*node_height)],
|
||||
[(destX-sc*(scale)*node_width), (destY-scaleY*node_height)]
|
||||
]
|
||||
return `M ${origX} ${origY} C ${cp[0][0]} ${cp[0][1]} ${cp[1][0]} ${cp[1][1]} ${destX} ${destY}`
|
||||
// + ` ${genCP(cp[0])} ${genCP(cp[1])}`
|
||||
} else {
|
||||
let topX, topY, bottomX, bottomY
|
||||
let cp
|
||||
let midX = Math.floor(destX-dx/2);
|
||||
let midY = Math.floor(destY-dy/2);
|
||||
if (Math.abs(dy) < 10) {
|
||||
bottomY = Math.max(origY, destY) + (hasStatus?35:25)
|
||||
let startCurveHeight = bottomY - origY
|
||||
let endCurveHeight = bottomY - destY
|
||||
cp = [
|
||||
[ origX + sc*15 , origY ],
|
||||
[ origX + sc*25 , origY + 5 ],
|
||||
[ origX + sc*25 , origY + startCurveHeight/2 ],
|
||||
|
||||
var midX = Math.floor(destX-dx/2);
|
||||
var midY = Math.floor(destY-dy/2);
|
||||
//
|
||||
if (dy === 0) {
|
||||
midY = destY + node_height;
|
||||
}
|
||||
var cp_height = node_height/2;
|
||||
var y1 = (destY + midY)/2
|
||||
var topX =origX + sc*node_width*scale;
|
||||
var topY = dy>0?Math.min(y1 - dy/2 , origY+cp_height):Math.max(y1 - dy/2 , origY-cp_height);
|
||||
var bottomX = destX - sc*node_width*scale;
|
||||
var bottomY = dy>0?Math.max(y1, destY-cp_height):Math.min(y1, destY+cp_height);
|
||||
var x1 = (origX+topX)/2;
|
||||
var scy = dy>0?1:-1;
|
||||
var cp = [
|
||||
// Orig -> Top
|
||||
[x1,origY],
|
||||
[topX,dy>0?Math.max(origY, topY-cp_height):Math.min(origY, topY+cp_height)],
|
||||
// Top -> Mid
|
||||
// [Mirror previous cp]
|
||||
[x1,dy>0?Math.min(midY, topY+cp_height):Math.max(midY, topY-cp_height)],
|
||||
// Mid -> Bottom
|
||||
// [Mirror previous cp]
|
||||
[bottomX,dy>0?Math.max(midY, bottomY-cp_height):Math.min(midY, bottomY+cp_height)],
|
||||
// Bottom -> Dest
|
||||
// [Mirror previous cp]
|
||||
[(destX+bottomX)/2,destY]
|
||||
];
|
||||
if (cp[2][1] === topY+scy*cp_height) {
|
||||
if (Math.abs(dy) < cp_height*10) {
|
||||
cp[1][1] = topY-scy*cp_height/2;
|
||||
cp[3][1] = bottomY-scy*cp_height/2;
|
||||
}
|
||||
cp[2][0] = topX;
|
||||
}
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+
|
||||
cp[0][0]+" "+cp[0][1]+" "+
|
||||
cp[1][0]+" "+cp[1][1]+" "+
|
||||
topX+" "+topY+
|
||||
" S "+
|
||||
cp[2][0]+" "+cp[2][1]+" "+
|
||||
midX+" "+midY+
|
||||
" S "+
|
||||
cp[3][0]+" "+cp[3][1]+" "+
|
||||
bottomX+" "+bottomY+
|
||||
" S "+
|
||||
[ origX + sc*25 , origY + startCurveHeight - 5 ],
|
||||
[ origX + sc*15 , origY + startCurveHeight ],
|
||||
[ origX , origY + startCurveHeight ],
|
||||
|
||||
[ destX - sc*15, origY + startCurveHeight ],
|
||||
[ destX - sc*25, origY + startCurveHeight - 5 ],
|
||||
[ destX - sc*25, destY + endCurveHeight/2 ],
|
||||
|
||||
[ destX - sc*25, destY + 5 ],
|
||||
[ destX - sc*15, destY ],
|
||||
[ destX, destY ],
|
||||
]
|
||||
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+
|
||||
cp[0][0]+" "+cp[0][1]+" "+
|
||||
cp[1][0]+" "+cp[1][1]+" "+
|
||||
cp[2][0]+" "+cp[2][1]+" "+
|
||||
" C " +
|
||||
cp[3][0]+" "+cp[3][1]+" "+
|
||||
cp[4][0]+" "+cp[4][1]+" "+
|
||||
destX+" "+destY
|
||||
cp[5][0]+" "+cp[5][1]+" "+
|
||||
" h "+dx+
|
||||
" C "+
|
||||
cp[6][0]+" "+cp[6][1]+" "+
|
||||
cp[7][0]+" "+cp[7][1]+" "+
|
||||
cp[8][0]+" "+cp[8][1]+" "+
|
||||
" C " +
|
||||
cp[9][0]+" "+cp[9][1]+" "+
|
||||
cp[10][0]+" "+cp[10][1]+" "+
|
||||
cp[11][0]+" "+cp[11][1]+" "
|
||||
// +genCP(cp[0])+genCP(cp[1])+genCP(cp[2])+genCP(cp[3])+genCP(cp[4])
|
||||
// +genCP(cp[5])+genCP(cp[6])+genCP(cp[7])+genCP(cp[8])+genCP(cp[9])+genCP(cp[10])
|
||||
} else {
|
||||
var cp_height = node_height/2;
|
||||
var y1 = (destY + midY)/2
|
||||
topX = origX + sc*node_width*scale;
|
||||
topY = dy>0?Math.min(y1 - dy/2 , origY+cp_height):Math.max(y1 - dy/2 , origY-cp_height);
|
||||
bottomX = destX - sc*node_width*scale;
|
||||
bottomY = dy>0?Math.max(y1, destY-cp_height):Math.min(y1, destY+cp_height);
|
||||
var x1 = (origX+topX)/2;
|
||||
var scy = dy>0?1:-1;
|
||||
cp = [
|
||||
// Orig -> Top
|
||||
[x1,origY],
|
||||
[topX,dy>0?Math.max(origY, topY-cp_height):Math.min(origY, topY+cp_height)],
|
||||
// Top -> Mid
|
||||
// [Mirror previous cp]
|
||||
[x1,dy>0?Math.min(midY, topY+cp_height):Math.max(midY, topY-cp_height)],
|
||||
// Mid -> Bottom
|
||||
// [Mirror previous cp]
|
||||
[bottomX,dy>0?Math.max(midY, bottomY-cp_height):Math.min(midY, bottomY+cp_height)],
|
||||
// Bottom -> Dest
|
||||
// [Mirror previous cp]
|
||||
[(destX+bottomX)/2,destY]
|
||||
];
|
||||
if (cp[2][1] === topY+scy*cp_height) {
|
||||
if (Math.abs(dy) < cp_height*10) {
|
||||
cp[1][1] = topY-scy*cp_height/2;
|
||||
cp[3][1] = bottomY-scy*cp_height/2;
|
||||
}
|
||||
cp[2][0] = topX;
|
||||
}
|
||||
return "M "+origX+" "+origY+
|
||||
" C "+
|
||||
cp[0][0]+" "+cp[0][1]+" "+
|
||||
cp[1][0]+" "+cp[1][1]+" "+
|
||||
topX+" "+topY+
|
||||
" S "+
|
||||
cp[2][0]+" "+cp[2][1]+" "+
|
||||
midX+" "+midY+
|
||||
" S "+
|
||||
cp[3][0]+" "+cp[3][1]+" "+
|
||||
bottomX+" "+bottomY+
|
||||
" S "+
|
||||
cp[4][0]+" "+cp[4][1]+" "+
|
||||
destX+" "+destY
|
||||
|
||||
// +genCP(cp[0])+genCP(cp[1])+genCP(cp[2])+genCP(cp[3])+genCP(cp[4])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1722,7 +1770,7 @@ RED.view = (function() {
|
||||
var portY = -((numOutputs-1)/2)*13 +13*sourcePort;
|
||||
|
||||
var sc = (drag_line.portType === PORT_TYPE_OUTPUT)?1:-1;
|
||||
drag_line.el.attr("d",generateLinkPath(drag_line.node.x+sc*drag_line.node.w/2,drag_line.node.y+portY,mousePos[0],mousePos[1],sc));
|
||||
drag_line.el.attr("d",generateLinkPath(drag_line.node.x+sc*drag_line.node.w/2,drag_line.node.y+portY,mousePos[0],mousePos[1],sc, !!drag_line.node.status));
|
||||
}
|
||||
d3.event.preventDefault();
|
||||
} else if (mouse_mode == RED.state.MOVING) {
|
||||
@@ -4112,21 +4160,27 @@ RED.view = (function() {
|
||||
nodeEl.__statusGroup__.style.display = "none";
|
||||
} else {
|
||||
nodeEl.__statusGroup__.style.display = "inline";
|
||||
let backgroundWidth = 12
|
||||
var fill = status_colours[d.status.fill]; // Only allow our colours for now
|
||||
if (d.status.shape == null && fill == null) {
|
||||
backgroundWidth = 0
|
||||
nodeEl.__statusShape__.style.display = "none";
|
||||
nodeEl.__statusBackground__.setAttribute("x", 17)
|
||||
nodeEl.__statusGroup__.setAttribute("transform","translate(-14,"+(d.h+3)+")");
|
||||
} else {
|
||||
nodeEl.__statusGroup__.setAttribute("transform","translate(3,"+(d.h+3)+")");
|
||||
var statusClass = "red-ui-flow-node-status-"+(d.status.shape||"dot")+"-"+d.status.fill;
|
||||
nodeEl.__statusShape__.style.display = "inline";
|
||||
nodeEl.__statusShape__.setAttribute("class","red-ui-flow-node-status "+statusClass);
|
||||
nodeEl.__statusBackground__.setAttribute("x", 3)
|
||||
}
|
||||
if (d.status.hasOwnProperty('text')) {
|
||||
nodeEl.__statusLabel__.textContent = d.status.text;
|
||||
} else {
|
||||
nodeEl.__statusLabel__.textContent = "";
|
||||
}
|
||||
const textSize = nodeEl.__statusLabel__.getBBox()
|
||||
nodeEl.__statusBackground__.setAttribute('width', backgroundWidth + textSize.width + 6)
|
||||
}
|
||||
delete d.dirtyStatus;
|
||||
}
|
||||
@@ -4532,17 +4586,30 @@ RED.view = (function() {
|
||||
statusEl.style.display = "none";
|
||||
node[0][0].__statusGroup__ = statusEl;
|
||||
|
||||
var statusRect = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
statusRect.setAttribute("class","red-ui-flow-node-status");
|
||||
statusRect.setAttribute("x",6);
|
||||
statusRect.setAttribute("y",1);
|
||||
statusRect.setAttribute("width",9);
|
||||
statusRect.setAttribute("height",9);
|
||||
statusRect.setAttribute("rx",2);
|
||||
statusRect.setAttribute("ry",2);
|
||||
statusRect.setAttribute("stroke-width","3");
|
||||
statusEl.appendChild(statusRect);
|
||||
node[0][0].__statusShape__ = statusRect;
|
||||
var statusBackground = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
statusBackground.setAttribute("class","red-ui-flow-node-status-background");
|
||||
statusBackground.setAttribute("x",3);
|
||||
statusBackground.setAttribute("y",-1);
|
||||
statusBackground.setAttribute("width",200);
|
||||
statusBackground.setAttribute("height",13);
|
||||
statusBackground.setAttribute("rx",1);
|
||||
statusBackground.setAttribute("ry",1);
|
||||
|
||||
statusEl.appendChild(statusBackground);
|
||||
node[0][0].__statusBackground__ = statusBackground;
|
||||
|
||||
|
||||
var statusIcon = document.createElementNS("http://www.w3.org/2000/svg","rect");
|
||||
statusIcon.setAttribute("class","red-ui-flow-node-status");
|
||||
statusIcon.setAttribute("x",6);
|
||||
statusIcon.setAttribute("y",1);
|
||||
statusIcon.setAttribute("width",9);
|
||||
statusIcon.setAttribute("height",9);
|
||||
statusIcon.setAttribute("rx",2);
|
||||
statusIcon.setAttribute("ry",2);
|
||||
statusIcon.setAttribute("stroke-width","3");
|
||||
statusEl.appendChild(statusIcon);
|
||||
node[0][0].__statusShape__ = statusIcon;
|
||||
|
||||
var statusLabel = document.createElementNS("http://www.w3.org/2000/svg","text");
|
||||
statusLabel.setAttribute("class","red-ui-flow-node-status-label");
|
||||
@@ -5067,7 +5134,7 @@ RED.view = (function() {
|
||||
// " C "+(d.x1+scale*node_width)+" "+(d.y1+scaleY*node_height)+" "+
|
||||
// (d.x2-scale*node_width)+" "+(d.y2-scaleY*node_height)+" "+
|
||||
// d.x2+" "+d.y2;
|
||||
var path = generateLinkPath(d.x1,d.y1,d.x2,d.y2,1);
|
||||
var path = generateLinkPath(d.x1,d.y1,d.x2,d.y2,1, !!(d.source.status || d.target.status));
|
||||
if (/NaN/.test(path)) {
|
||||
path = ""
|
||||
}
|
||||
|
@@ -304,7 +304,11 @@ g.red-ui-flow-node-selected {
|
||||
stroke: var(--red-ui-node-status-colors-#{"" + $current-color});
|
||||
}
|
||||
}
|
||||
|
||||
.red-ui-flow-node-status-background {
|
||||
stroke: none;
|
||||
fill: var(--red-ui-view-background);
|
||||
fill-opacity: 0.9;
|
||||
}
|
||||
.red-ui-flow-node-status-label {
|
||||
@include disable-selection;
|
||||
stroke-width: 0;
|
||||
|
@@ -281,4 +281,21 @@ declare class env {
|
||||
* ```const flowName = env.get("NR_FLOW_NAME");```
|
||||
*/
|
||||
static get(name:string) :any;
|
||||
/**
|
||||
* Get an environment variable value (asynchronous).
|
||||
*
|
||||
* Predefined node-red variables...
|
||||
* * `NR_NODE_ID` - the ID of the node
|
||||
* * `NR_NODE_NAME` - the Name of the node
|
||||
* * `NR_NODE_PATH` - the Path of the node
|
||||
* * `NR_GROUP_ID` - the ID of the containing group
|
||||
* * `NR_GROUP_NAME` - the Name of the containing group
|
||||
* * `NR_FLOW_ID` - the ID of the flow the node is on
|
||||
* * `NR_FLOW_NAME` - the Name of the flow the node is on
|
||||
* @param name Name of the environment variable to get
|
||||
* @param callback Callback function (`(err,value) => {}`)
|
||||
* @example
|
||||
* ```const flowName = env.get("NR_FLOW_NAME");```
|
||||
*/
|
||||
static get(name:string, callback: Function) :void;
|
||||
}
|
||||
|
@@ -82,6 +82,11 @@
|
||||
<input id="node-input-outputs" style="width: 60px;" value="1">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-timeout"><i class="fa fa-clock"></i> <span data-i18n="function.label.timeout"></span></label>
|
||||
<input id="node-input-timeout" style="width: 60px;" data-i18n="[placeholder]join.seconds">
|
||||
</div>
|
||||
|
||||
<div class="form-row node-input-libs-row hide" style="margin-bottom: 0px;">
|
||||
<label><i class="fa fa-cubes"></i> <span data-i18n="function.label.modules"></span></label>
|
||||
</div>
|
||||
@@ -360,6 +365,7 @@
|
||||
name: {value:"_DEFAULT_"},
|
||||
func: {value:"\nreturn msg;"},
|
||||
outputs: {value:1},
|
||||
timeout:{value:0},
|
||||
noerr: {value:0,required:true,
|
||||
validate: function(v, opt) {
|
||||
if (!v) {
|
||||
@@ -464,6 +470,26 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 4294967 is max in node.js timeout.
|
||||
$( "#node-input-timeout" ).spinner({
|
||||
min: 0,
|
||||
max: 4294967,
|
||||
change: function(event, ui) {
|
||||
var value = this.value;
|
||||
if(value == ""){
|
||||
value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = parseInt(value);
|
||||
}
|
||||
value = isNaN(value) ? 1 : value;
|
||||
value = Math.max(value, parseInt($(this).attr("aria-valuemin")));
|
||||
value = Math.min(value, parseInt($(this).attr("aria-valuemax")));
|
||||
if (value !== this.value) { $(this).spinner("value", value); }
|
||||
}
|
||||
});
|
||||
|
||||
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
|
||||
var editor = RED.editor.createEditor({
|
||||
id: id,
|
||||
@@ -503,7 +529,7 @@
|
||||
editor:this.editor, // the field name the main text body goes to
|
||||
mode:"ace/mode/nrjavascript",
|
||||
fields:[
|
||||
'name', 'outputs',
|
||||
'name', 'outputs', 'timeout',
|
||||
{
|
||||
name: 'initialize',
|
||||
get: function() {
|
||||
|
@@ -96,6 +96,13 @@ module.exports = function(RED) {
|
||||
node.name = n.name;
|
||||
node.func = n.func;
|
||||
node.outputs = n.outputs;
|
||||
node.timeout = n.timeout*1000;
|
||||
if(node.timeout>0){
|
||||
node.timeoutOptions = {
|
||||
timeout:node.timeout,
|
||||
breakOnSigint:true
|
||||
}
|
||||
}
|
||||
node.ini = n.initialize ? n.initialize.trim() : "";
|
||||
node.fin = n.finalize ? n.finalize.trim() : "";
|
||||
node.libs = n.libs || [];
|
||||
@@ -235,8 +242,8 @@ module.exports = function(RED) {
|
||||
}
|
||||
},
|
||||
env: {
|
||||
get: function(envVar) {
|
||||
return RED.util.getSetting(node, envVar);
|
||||
get: function(envVar, callback) {
|
||||
return RED.util.getSetting(node, envVar, node._flow, callback);
|
||||
}
|
||||
},
|
||||
setTimeout: function () {
|
||||
@@ -362,6 +369,10 @@ module.exports = function(RED) {
|
||||
})(__initSend__);`;
|
||||
iniOpt = createVMOpt(node, " setup");
|
||||
iniScript = new vm.Script(iniText, iniOpt);
|
||||
if(node.timeout>0){
|
||||
iniOpt.timeout = node.timeout;
|
||||
iniOpt.breakOnSigint = true;
|
||||
}
|
||||
}
|
||||
node.script = vm.createScript(functionText, createVMOpt(node, ""));
|
||||
if (node.fin && (node.fin !== "")) {
|
||||
@@ -385,6 +396,10 @@ module.exports = function(RED) {
|
||||
})();`;
|
||||
finOpt = createVMOpt(node, " cleanup");
|
||||
finScript = new vm.Script(finText, finOpt);
|
||||
if(node.timeout>0){
|
||||
finOpt.timeout = node.timeout;
|
||||
finOpt.breakOnSigint = true;
|
||||
}
|
||||
}
|
||||
var promise = Promise.resolve();
|
||||
if (iniScript) {
|
||||
@@ -396,9 +411,12 @@ module.exports = function(RED) {
|
||||
var start = process.hrtime();
|
||||
context.msg = msg;
|
||||
context.__send__ = send;
|
||||
context.__done__ = done;
|
||||
|
||||
node.script.runInContext(context);
|
||||
context.__done__ = done;
|
||||
var opts = {};
|
||||
if (node.timeout>0){
|
||||
opts = node.timeoutOptions;
|
||||
}
|
||||
node.script.runInContext(context,opts);
|
||||
context.results.then(function(results) {
|
||||
sendResults(node,send,msg._msgid,results,false);
|
||||
if (handleNodeDoneCall) {
|
||||
|
@@ -23,8 +23,6 @@ module.exports = async function(RED) {
|
||||
const { v4: uuid } = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
const URL = require("url").URL
|
||||
const http = require("http")
|
||||
const https = require("https")
|
||||
var mustache = require("mustache");
|
||||
var querystring = require("querystring");
|
||||
var cookie = require("cookie");
|
||||
@@ -67,27 +65,16 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
function HTTPRequest(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
checkNodeAgentPatch();
|
||||
const node = this;
|
||||
const nodeUrl = n.url;
|
||||
const isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
||||
const nodeMethod = n.method || "GET";
|
||||
let paytoqs = false;
|
||||
let paytobody = false;
|
||||
let redirectList = [];
|
||||
const sendErrorsToCatch = n.senderr;
|
||||
var node = this;
|
||||
var nodeUrl = n.url;
|
||||
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
|
||||
var nodeMethod = n.method || "GET";
|
||||
var paytoqs = false;
|
||||
var paytobody = false;
|
||||
var redirectList = [];
|
||||
var sendErrorsToCatch = n.senderr;
|
||||
node.headers = n.headers || [];
|
||||
const useKeepAlive = n["persist"];
|
||||
let agents = null
|
||||
if (useKeepAlive) {
|
||||
agents = {
|
||||
http: new http.Agent({ keepAlive: true }),
|
||||
https: new https.Agent({ keepAlive: true })
|
||||
}
|
||||
node.on('close', function () {
|
||||
agents.http.destroy()
|
||||
agents.https.destroy()
|
||||
})
|
||||
}
|
||||
var nodeHTTPPersistent = n["persist"];
|
||||
if (n.tls) {
|
||||
var tlsNode = RED.nodes.getNode(n.tls);
|
||||
}
|
||||
@@ -573,14 +560,12 @@ in your Node-RED user directory (${RED.settings.userDir}).
|
||||
opts.agent = {
|
||||
http: new HttpProxyAgent(proxyOptions),
|
||||
https: new HttpsProxyAgent(proxyOptions)
|
||||
}
|
||||
};
|
||||
|
||||
} else {
|
||||
node.warn("Bad proxy url: "+ prox);
|
||||
}
|
||||
}
|
||||
if (useKeepAlive && !opts.agent) {
|
||||
opts.agent = agents
|
||||
}
|
||||
if (tlsNode) {
|
||||
opts.https = {};
|
||||
tlsNode.addTLSOptions(opts.https);
|
||||
|
@@ -216,7 +216,8 @@
|
||||
"initialize": "Start",
|
||||
"finalize": "Stopp",
|
||||
"outputs": "Ausgänge",
|
||||
"modules": "Module"
|
||||
"modules": "Module",
|
||||
"timeout": "Timeout"
|
||||
},
|
||||
"text": {
|
||||
"initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n",
|
||||
|
@@ -252,7 +252,8 @@
|
||||
"initialize": "On Start",
|
||||
"finalize": "On Stop",
|
||||
"outputs": "Outputs",
|
||||
"modules": "Modules"
|
||||
"modules": "Modules",
|
||||
"timeout": "Timeout"
|
||||
},
|
||||
"text": {
|
||||
"initialize": "// Code added here will be run once\n// whenever the node is started.\n",
|
||||
|
@@ -212,7 +212,8 @@
|
||||
"function": "Функция",
|
||||
"initialize": "Настройка",
|
||||
"finalize": "Закрытие",
|
||||
"outputs": "Выходы"
|
||||
"outputs": "Выходы",
|
||||
"timeout":"Время ожидания"
|
||||
},
|
||||
"text": {
|
||||
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
|
||||
|
@@ -416,23 +416,50 @@ class Flow {
|
||||
return this.activeNodes;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get value of environment variable defined in group node.
|
||||
* @param {String} group - group node
|
||||
* @param {String} name - name of variable
|
||||
* @return {Object} object containing the value in val property or null if not defined
|
||||
|
||||
/**
|
||||
* Group callback signature
|
||||
*
|
||||
* @callback GroupEnvCallback
|
||||
* @param {Error} err The error object (or null)
|
||||
* @param {[result: {val:Any}, name: String]} result The result of the callback
|
||||
* @returns {void}
|
||||
*/
|
||||
getGroupEnvSetting(node, group, name) {
|
||||
|
||||
/**
|
||||
* @function getGroupEnvSetting
|
||||
* Get a group setting value synchronously.
|
||||
* This currently automatically defers to the parent
|
||||
* @overload
|
||||
* @param {Object} node
|
||||
* @param {Object} group
|
||||
* @param {String} name
|
||||
* @returns {Any}
|
||||
*
|
||||
* Get a group setting value asynchronously.
|
||||
* @overload
|
||||
* @param {Object} node
|
||||
* @param {Object} group
|
||||
* @param {String} name
|
||||
* @param {GroupEnvCallback} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
getGroupEnvSetting(node, group, name, callback) {
|
||||
/** @type {GroupEnvCallback} */
|
||||
const returnOrCallback = (err, [result, newName]) => {
|
||||
if (callback) {
|
||||
callback(err, [result, newName]);
|
||||
return
|
||||
}
|
||||
return [result, newName];
|
||||
}
|
||||
if (group) {
|
||||
if (name === "NR_GROUP_NAME") {
|
||||
return [{
|
||||
val: group.name
|
||||
}, null];
|
||||
return returnOrCallback(null, [{ val: group.name }, null]);
|
||||
}
|
||||
if (name === "NR_GROUP_ID") {
|
||||
return [{
|
||||
val: group.id
|
||||
}, null];
|
||||
return returnOrCallback(null, [{ val: group.id }, null]);
|
||||
}
|
||||
|
||||
if (group.credentials === undefined) {
|
||||
@@ -457,33 +484,32 @@ class Flow {
|
||||
if (env) {
|
||||
let value = env.value;
|
||||
const type = env.type;
|
||||
if ((type !== "env") ||
|
||||
(value !== name)) {
|
||||
if ((type !== "env") || (value !== name)) {
|
||||
if (type === "env") {
|
||||
value = value.replace(new RegExp("\\${"+name+"}","g"),"${$parent."+name+"}");
|
||||
}
|
||||
if (type === "bool") {
|
||||
const val
|
||||
= ((value === "true") ||
|
||||
(value === true));
|
||||
return [{
|
||||
val: val
|
||||
}, null];
|
||||
} else if (type === "bool") {
|
||||
const val = ((value === "true") || (value === true));
|
||||
return returnOrCallback(null, [{ val: val }, null])
|
||||
}
|
||||
if (type === "cred") {
|
||||
return [{
|
||||
val: value
|
||||
}, null];
|
||||
return returnOrCallback(null, [{ val: value }, null])
|
||||
}
|
||||
try {
|
||||
var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
|
||||
return [{
|
||||
val: val
|
||||
}, null];
|
||||
if (!callback) {
|
||||
var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
|
||||
return [{ val: val }, null];
|
||||
} else {
|
||||
redUtil.evaluateNodeProperty(value, type, node, null, (err, value) => {
|
||||
return returnOrCallback(err, [{ val: value }, null])
|
||||
});
|
||||
return
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e);
|
||||
return [null, null];
|
||||
if (!callback) {
|
||||
this.error(e);
|
||||
}
|
||||
return returnOrCallback(e, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,27 +520,47 @@ class Flow {
|
||||
}
|
||||
if (group.g) {
|
||||
const parent = this.getGroupNode(group.g);
|
||||
return this.getGroupEnvSetting(node, parent, name);
|
||||
const gVal = this.getGroupEnvSetting(node, parent, name, callback);
|
||||
if (callback) {
|
||||
return;
|
||||
}
|
||||
return gVal;
|
||||
}
|
||||
}
|
||||
return [null, name];
|
||||
return returnOrCallback(null, [null, name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Settings callback signature
|
||||
*
|
||||
* @callback SettingsCallback
|
||||
* @param {Error} err The error object (or null)
|
||||
* @param {Any} result The result of the callback
|
||||
* @returns {void}
|
||||
*/
|
||||
/**
|
||||
* Get a flow setting value. This currently automatically defers to the parent
|
||||
* flow which, as defined in ./index.js returns `process.env[key]`.
|
||||
* This lays the groundwork for Subflow to have instance-specific settings
|
||||
* @param {[type]} key [description]
|
||||
* @return {[type]} [description]
|
||||
* @param {String} key The settings key
|
||||
* @param {SettingsCallback} callback Optional callback function
|
||||
* @return {Any}
|
||||
*/
|
||||
getSetting(key) {
|
||||
getSetting(key, callback) {
|
||||
/** @type {SettingsCallback} */
|
||||
const returnOrCallback = (err, result) => {
|
||||
if (callback) {
|
||||
callback(err, result);
|
||||
return
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const flow = this.flow;
|
||||
if (key === "NR_FLOW_NAME") {
|
||||
return flow.label;
|
||||
return returnOrCallback(null, flow.label);
|
||||
}
|
||||
if (key === "NR_FLOW_ID") {
|
||||
return flow.id;
|
||||
return returnOrCallback(null, flow.id);
|
||||
}
|
||||
if (flow.credentials === undefined) {
|
||||
flow.credentials = credentials.get(flow.id) || {};
|
||||
@@ -544,15 +590,14 @@ class Flow {
|
||||
}
|
||||
try {
|
||||
if (type === "bool") {
|
||||
const val = ((value === "true") ||
|
||||
(value === true));
|
||||
return val;
|
||||
const val = ((value === "true") || (value === true));
|
||||
return returnOrCallback(null, val);
|
||||
}
|
||||
if (type === "cred") {
|
||||
return value;
|
||||
return returnOrCallback(null, value);
|
||||
}
|
||||
var val = redUtil.evaluateNodeProperty(value, type, null, null, null);
|
||||
return val;
|
||||
return returnOrCallback(null, val);
|
||||
}
|
||||
catch (e) {
|
||||
this.error(e);
|
||||
@@ -564,7 +609,11 @@ class Flow {
|
||||
key = key.substring(8);
|
||||
}
|
||||
}
|
||||
return this.parent.getSetting(key);
|
||||
const pVal = this.parent.getSetting(key, callback);
|
||||
if (callback) {
|
||||
return;
|
||||
}
|
||||
return pVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -780,7 +780,7 @@ const flowAPI = {
|
||||
getNode: getNode,
|
||||
handleError: () => false,
|
||||
handleStatus: () => false,
|
||||
getSetting: k => flowUtil.getEnvVar(k),
|
||||
getSetting: (k, callback) => flowUtil.getEnvVar(k, callback),
|
||||
log: m => log.log(m)
|
||||
}
|
||||
|
||||
|
@@ -308,16 +308,34 @@ module.exports = {
|
||||
runtime.settings.envVarExcludes.forEach(v => envVarExcludes[v] = true);
|
||||
}
|
||||
},
|
||||
getEnvVar: function(k) {
|
||||
if (!envVarExcludes[k]) {
|
||||
const item = getGlobalEnv(k);
|
||||
/**
|
||||
* Get the value of an environment variable
|
||||
* Call with a callback to get the value asynchronously
|
||||
* or without to get the value synchronously
|
||||
* @param {String} key The name of the environment variable
|
||||
* @param {(err: Error, val: Any)} [callback] Optional callback for asynchronous call
|
||||
* @returns {Any | void} The value of the environment variable or undefined if not found
|
||||
*/
|
||||
getEnvVar: function(key, callback) {
|
||||
const returnOrCallback = function(err, val) {
|
||||
if (callback) {
|
||||
callback(err, val);
|
||||
return;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
if (!envVarExcludes[key]) {
|
||||
const item = getGlobalEnv(key);
|
||||
if (item) {
|
||||
const val = redUtil.evaluateNodeProperty(item.value, item.type, null, null, null);
|
||||
const val = redUtil.evaluateNodeProperty(item.value, item.type, null, null, callback);
|
||||
if (callback) {
|
||||
return;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
return process.env[k];
|
||||
return returnOrCallback(null, process.env[key]);
|
||||
}
|
||||
return undefined;
|
||||
return returnOrCallback(undefined);
|
||||
},
|
||||
diffNodes: diffNodes,
|
||||
mapEnvVarProperties: mapEnvVarProperties,
|
||||
|
83
packages/node_modules/@node-red/util/lib/util.js
vendored
83
packages/node_modules/@node-red/util/lib/util.js
vendored
@@ -18,6 +18,7 @@
|
||||
/**
|
||||
* @mixin @node-red/util_util
|
||||
*/
|
||||
/** @typedef {import('../../runtime/lib/flows/Flow.js').Flow} RuntimeLibFlowsFlow */
|
||||
|
||||
const clonedeep = require("lodash.clonedeep");
|
||||
const jsonata = require("jsonata");
|
||||
@@ -526,37 +527,68 @@ function setObjectProperty(msg,prop,value,createMissing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
/**
|
||||
* Get value of environment variable.
|
||||
* @param {Node} node - accessing node
|
||||
* @param {String} name - name of variable
|
||||
* @param {RuntimeLibFlowsFlow} flow_ - (optional) flow to check for setting
|
||||
* @param {(err: Error, result: Any) => void} callback - (optional) called when the property is evaluated
|
||||
* @return {String} value of env var
|
||||
*/
|
||||
function getSetting(node, name, flow_) {
|
||||
function getSetting(node, name, flow_, callback) {
|
||||
const returnOrCallback = (err, result) => {
|
||||
if (callback) {
|
||||
callback(err, result);
|
||||
return
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (node) {
|
||||
if (name === "NR_NODE_NAME") {
|
||||
return node.name;
|
||||
return returnOrCallback(null, node.name);
|
||||
}
|
||||
if (name === "NR_NODE_ID") {
|
||||
return node.id;
|
||||
return returnOrCallback(null, node.id);
|
||||
}
|
||||
if (name === "NR_NODE_PATH") {
|
||||
return node._path;
|
||||
return returnOrCallback(null, node._path);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {RuntimeLibFlowsFlow} */
|
||||
var flow = (flow_ ? flow_ : (node ? node._flow : null));
|
||||
if (flow) {
|
||||
if (node && node.g) {
|
||||
const group = flow.getGroupNode(node.g);
|
||||
const [result, newName] = flow.getGroupEnvSetting(node, group, name);
|
||||
if (result) {
|
||||
return result.val;
|
||||
if (callback) {
|
||||
flow.getGroupEnvSetting(node, group, name, (e, [result, newName]) => {
|
||||
if (e) {
|
||||
callback(e);
|
||||
return
|
||||
}
|
||||
if (result) {
|
||||
callback(null, result.val);
|
||||
return
|
||||
}
|
||||
name = newName;
|
||||
flow.getSetting(name, callback);
|
||||
});
|
||||
return
|
||||
} else {
|
||||
const [result, newName] = flow.getGroupEnvSetting(node, group, name);
|
||||
if (result) {
|
||||
return result.val;
|
||||
}
|
||||
name = newName;
|
||||
}
|
||||
name = newName;
|
||||
}
|
||||
return flow.getSetting(name);
|
||||
const fVal = flow.getSetting(name, callback)
|
||||
if (callback) {
|
||||
return
|
||||
}
|
||||
return fVal;
|
||||
}
|
||||
return process.env[name];
|
||||
return returnOrCallback(null, process.env[name]);
|
||||
}
|
||||
|
||||
|
||||
@@ -568,19 +600,34 @@ function getSetting(node, name, flow_) {
|
||||
* will return `Hello Joe!`.
|
||||
* @param {String} value - the string to parse
|
||||
* @param {Node} node - the node evaluating the property
|
||||
* @param {(err: Error, result: Any) => void} callback - (optional) called when the property is evaluated
|
||||
* @return {String} The parsed string
|
||||
* @memberof @node-red/util_util
|
||||
*/
|
||||
function evaluateEnvProperty(value, node) {
|
||||
function evaluateEnvProperty(value, node, callback) {
|
||||
const returnOrCallback = (err, result) => {
|
||||
if (callback) {
|
||||
callback(err, result);
|
||||
return
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/** @type {RuntimeLibFlowsFlow} */
|
||||
var flow = (node && hasOwnProperty.call(node, "_flow")) ? node._flow : null;
|
||||
var result;
|
||||
if (/^\${[^}]+}$/.test(value)) {
|
||||
// ${ENV_VAR}
|
||||
var name = value.substring(2,value.length-1);
|
||||
result = getSetting(node, name, flow);
|
||||
result = getSetting(node, name, flow, callback);
|
||||
if (callback) {
|
||||
return
|
||||
}
|
||||
} else if (!/\${\S+}/.test(value)) {
|
||||
// ENV_VAR
|
||||
result = getSetting(node, value, flow);
|
||||
result = getSetting(node, value, flow, callback);
|
||||
if (callback) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// FOO${ENV_VAR}BAR
|
||||
return value.replace(/\${([^}]+)}/g, function(match, name) {
|
||||
@@ -588,8 +635,7 @@ function evaluateEnvProperty(value, node) {
|
||||
return (val === undefined)?"":val;
|
||||
});
|
||||
}
|
||||
return (result === undefined)?"":result;
|
||||
|
||||
return returnOrCallback(null, (result === undefined)?"":result);
|
||||
}
|
||||
|
||||
|
||||
@@ -677,7 +723,10 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
|
||||
return
|
||||
}
|
||||
} else if (type === 'env') {
|
||||
result = evaluateEnvProperty(value, node);
|
||||
result = evaluateEnvProperty(value, node, callback);
|
||||
if (callback) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
callback(null,result);
|
||||
|
14
packages/node_modules/node-red/red.js
vendored
14
packages/node_modules/node-red/red.js
vendored
@@ -302,7 +302,7 @@ httpsPromise.then(function(startupHttps) {
|
||||
settings.httpNodeAuth = settings.httpNodeAuth || settings.httpAuth;
|
||||
}
|
||||
|
||||
if(settings.httpStatic) {
|
||||
if (settings.httpStatic) {
|
||||
settings.httpStaticRoot = formatRoot(settings.httpStaticRoot || "/");
|
||||
const statics = Array.isArray(settings.httpStatic) ? settings.httpStatic : [settings.httpStatic];
|
||||
const sanitised = [];
|
||||
@@ -414,13 +414,7 @@ httpsPromise.then(function(startupHttps) {
|
||||
if (settings.httpNodeRoot !== false) {
|
||||
app.use(settings.httpNodeRoot,RED.httpNode);
|
||||
}
|
||||
// if (settings.httpStatic) {
|
||||
// settings.httpStaticAuth = settings.httpStaticAuth || settings.httpAuth;
|
||||
// if (settings.httpStaticAuth) {
|
||||
// app.use("/",basicAuthMiddleware(settings.httpStaticAuth.user,settings.httpStaticAuth.pass));
|
||||
// }
|
||||
// app.use("/",express.static(settings.httpStatic));
|
||||
// }
|
||||
|
||||
if (settings.httpStatic) {
|
||||
let appUseMem = {};
|
||||
for (let si = 0; si < settings.httpStatic.length; si++) {
|
||||
@@ -428,6 +422,7 @@ httpsPromise.then(function(startupHttps) {
|
||||
const filePath = sp.path;
|
||||
const thisRoot = sp.root || "/";
|
||||
const options = sp.options;
|
||||
const middleware = sp.middleware;
|
||||
if(appUseMem[filePath + "::" + thisRoot]) {
|
||||
continue;// this path and root already registered!
|
||||
}
|
||||
@@ -435,6 +430,9 @@ httpsPromise.then(function(startupHttps) {
|
||||
if (settings.httpStaticAuth) {
|
||||
app.use(thisRoot, basicAuthMiddleware(settings.httpStaticAuth.user, settings.httpStaticAuth.pass));
|
||||
}
|
||||
if (middleware) {
|
||||
app.use(thisRoot, middleware)
|
||||
}
|
||||
app.use(thisRoot, express.static(filePath, options));
|
||||
}
|
||||
}
|
||||
|
@@ -44,4 +44,30 @@ describe('unknown Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate a global environment variable that is a JSONata value', function (done) {
|
||||
const flow = [{
|
||||
id: "n1", type: "global-config", name: "XYZ",
|
||||
env: [
|
||||
{ name: "now-var", type: "jsonata", value: "$millis()" }
|
||||
]
|
||||
},
|
||||
{ id: "n2", type: "inject", topic: "t1", payload: "now-var", payloadType: "env", wires: [["n3"]], z: "flow" },
|
||||
{ id: "n3", type: "helper" }
|
||||
];
|
||||
helper.load([config, inject], flow, function () {
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
n3.on("input", (msg) => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
msg.should.have.property("payload").and.be.approximately(now, 1000);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n2.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1424,7 +1424,30 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should timeout if timeout is set', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],timeout:"0.010",func:"while(1==1){};\nreturn msg;"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "function";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var msg = logEvents[0][0];
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
should.equal(msg.msg.message, 'Script execution timed out after 10ms');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},50);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finalize function", function() {
|
||||
|
||||
|
@@ -686,7 +686,7 @@ describe('Flow', function() {
|
||||
},50);
|
||||
});
|
||||
|
||||
it.only("passes a status event to the group scoped status node",function(done) {
|
||||
it("passes a status event to the group scoped status node",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id: "g1", type: "group", g: "g3" },
|
||||
@@ -1311,33 +1311,42 @@ describe('Flow', function() {
|
||||
})
|
||||
process.env.V0 = "gv0";
|
||||
process.env.V1 = "gv1";
|
||||
process.env.V3 = "gv3";
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab",env:[
|
||||
{"name": "V0", value: "v0", type: "str"}
|
||||
{"name": "V0", value: "t1v0", type: "str"},
|
||||
{"name": "V2", value: "t1v2", type: "str"}
|
||||
]},
|
||||
{id:"g1",type:"group",z:"t1",env:[
|
||||
{"name": "V0", value: "v1", type: "str"},
|
||||
{"name": "V1", value: "v2", type: "str"}
|
||||
{"name": "V0", value: "g1v0", type: "str"},
|
||||
{"name": "V1", value: "g1v1", type: "str"}
|
||||
]},
|
||||
{id:"g2",type:"group",z:"t1",g:"g1",env:[
|
||||
{"name": "V1", value: "v3", type: "str"}
|
||||
{"name": "V1", value: "g2v1", type: "str"}
|
||||
]},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"$(V0)",wires:[]},
|
||||
{id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V0)",wires:[]},
|
||||
{id:"3",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V1)",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"$(V1)",wires:[]},
|
||||
{id:"5",x:10,y:10,z:"t1",type:"test",foo:"$(V1)",wires:[]},
|
||||
{id:"t1__V0",x:10,y:10,z:"t1",type:"test",foo:"${V0}",wires:[]}, // V0 will come from tab env V0
|
||||
{id:"t1g1V0",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${V0}",wires:[]}, // V0 will come from group 1 env V0
|
||||
{id:"t1g1V1",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${V1}",wires:[]}, // V1 will come from group 1 env V1
|
||||
{id:"t1g2V0",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${V0}",wires:[]}, // V0 will come from group 1 env V0
|
||||
{id:"t1g2V1",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${V1}",wires:[]}, // V1 will come from group 2 env V1
|
||||
{id:"t1g2V2",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${V2}",wires:[]}, // V2 will come from tab 1 env V2
|
||||
{id:"t1g2V3",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${V3}",wires:[]}, // V3 will come from process env V3
|
||||
|
||||
{id:"t1__V1",x:10,y:10,z:"t1",type:"test",foo:"${V1}",wires:[]},
|
||||
]);
|
||||
var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].foo.should.equal("v0");
|
||||
activeNodes["2"].foo.should.equal("v1");
|
||||
activeNodes["3"].foo.should.equal("v2");
|
||||
activeNodes["4"].foo.should.equal("v3");
|
||||
activeNodes["5"].foo.should.equal("gv1");
|
||||
activeNodes.t1__V0.foo.should.equal("t1v0"); // node in tab 1, get tab 1 env V0
|
||||
activeNodes.t1__V1.foo.should.equal("gv1"); // node in tab 1, get V1, (tab 1 no V1) --> parent (global has V1)
|
||||
activeNodes.t1g1V0.foo.should.equal("g1v0"); // node in group 1, get V0, (group 1 has V0)
|
||||
activeNodes.t1g1V1.foo.should.equal("g1v1"); // node in group 1, get V1, (group 1 has V1)
|
||||
activeNodes.t1g2V0.foo.should.equal("g1v0"); // node in group 2, get V0, (group 2 no V0) --> parent (group 1 has V0)
|
||||
activeNodes.t1g2V1.foo.should.equal("g2v1"); // node in group 2, get V1, (group 2 has V1)
|
||||
activeNodes.t1g2V2.foo.should.equal("t1v2"); // node in group 2, get V2, (group 2 no V2) --> parent (tab 1 has V2)
|
||||
activeNodes.t1g2V3.foo.should.equal("gv3"); // node in group 2, get V3, (group 2 no V3) --> parent (tab 1 no V2) --> parent (global has V3)
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
@@ -1347,7 +1356,6 @@ describe('Flow', function() {
|
||||
console.log(e.stack);
|
||||
done(e);
|
||||
}
|
||||
|
||||
});
|
||||
it("can access environment variable property using $parent", function (done) {
|
||||
try {
|
||||
@@ -1393,7 +1401,6 @@ describe('Flow', function() {
|
||||
console.log(e.stack);
|
||||
done(e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it("can define environment variable using JSONata", function (done) {
|
||||
@@ -1427,9 +1434,40 @@ describe('Flow', function() {
|
||||
console.log(e.stack);
|
||||
done(e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it("can access global environment variables defined as JSONata values", function (done) {
|
||||
try {
|
||||
after(function() {
|
||||
delete process.env.V0;
|
||||
})
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab",env:[
|
||||
{"name": "V0", value: "1+2", type: "jsonata"}
|
||||
]},
|
||||
{id:"g1",type:"group",z:"t1",env:[
|
||||
{"name": "V1", value: "2+3", type: "jsonata"},
|
||||
]},
|
||||
{id:"1",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V0)",wires:[]},
|
||||
{id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V1)",wires:[]},
|
||||
]);
|
||||
var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].foo.should.equal(3);
|
||||
activeNodes["2"].foo.should.equal(5);
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e.stack);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -489,7 +489,7 @@ describe('storage/localfilesystem', function() {
|
||||
var rootdir = path.win32.resolve(userDir+'/some');
|
||||
// make it into a local UNC path
|
||||
flowFile = flowFile.replace('C:\\', '\\\\localhost\\c$\\');
|
||||
localfilesystem.init({userDir:userDir, flowFile:flowFile}, mockRuntime).then(function() {
|
||||
localfilesystem.init({userDir:userDir, flowFile:flowFile, getUserSettings: () => {{}}}, mockRuntime).then(function() {
|
||||
fs.existsSync(flowFile).should.be.false();
|
||||
localfilesystem.saveFlows(testFlow).then(function() {
|
||||
fs.existsSync(flowFile).should.be.true();
|
||||
|
Reference in New Issue
Block a user