From e16d5cf83d5e99e3b42708b7d95ac634b0440084 Mon Sep 17 00:00:00 2001
From: BitCaesar
Date: Thu, 20 Apr 2023 12:28:32 +0200
Subject: [PATCH 01/20] fix: closes #4142 The issue occured because the partId
is set to "_" by default and is never overwritten in manual mode. With
concurrent messages and different processing times all parts of all messages
have the identifier "_" and are assembled following the FIFO principle.
---
.../node_modules/@node-red/nodes/core/sequence/17-split.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/node_modules/@node-red/nodes/core/sequence/17-split.js b/packages/node_modules/@node-red/nodes/core/sequence/17-split.js
index b2e11218a..10c696b76 100644
--- a/packages/node_modules/@node-red/nodes/core/sequence/17-split.js
+++ b/packages/node_modules/@node-red/nodes/core/sequence/17-split.js
@@ -629,6 +629,9 @@ module.exports = function(RED) {
joinChar = node.joiner;
if (n.count === "" && msg.hasOwnProperty('parts')) {
targetCount = msg.parts.count || 0;
+ if (msg.parts.hasOwnProperty('id')) {
+ partId = msg.parts.id;
+ }
}
if (node.build === 'object') {
propertyKey = RED.util.getMessageProperty(msg,node.key);
From 225341745994be20e057d4fd42f0b0e8f5fbfe17 Mon Sep 17 00:00:00 2001
From: Kilian Hertel
Date: Mon, 22 May 2023 10:16:37 +0200
Subject: [PATCH 02/20] adding timeout attribute to function node
- [x] New feature (non-breaking change which adds functionality)
Discussion here:
https://discourse.nodered.org/t/function-node-doesnt-have-timeout-feature/78483
## Proposed changes
Adding a timeout attribute to the function node, so an endless funciton doesnt break the node red server.
## Checklist
- [x] I have read the [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
- [x] For non-bugfix PRs, I have discussed this change on the forum/slack team.
- [x] I have run `grunt` to verify the unit tests pass
- [x] I have added suitable unit tests to cover the new/changed functionality
---
.../nodes/core/function/10-function.html | 28 ++++++++++++++++++-
.../nodes/core/function/10-function.js | 24 ++++++++++++++--
.../@node-red/nodes/locales/de/messages.json | 3 +-
.../nodes/locales/en-US/messages.json | 3 +-
.../@node-red/nodes/locales/ru/messages.json | 3 +-
test/nodes/core/function/10-function_spec.js | 25 ++++++++++++++++-
6 files changed, 78 insertions(+), 8 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.html b/packages/node_modules/@node-red/nodes/core/function/10-function.html
index e17f58aca..8130be2ad 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.html
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.html
@@ -82,6 +82,11 @@
+
+
+
+
+
@@ -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 @@
}
});
+ // 4294967295 is max in node.js timeout.
+ $( "#node-input-timeout" ).spinner({
+ min: 0,
+ max: 4294967294,
+ 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() {
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.js b/packages/node_modules/@node-red/nodes/core/function/10-function.js
index b84ee8571..3ada08943 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.js
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.js
@@ -96,6 +96,13 @@ module.exports = function(RED) {
node.name = n.name;
node.func = n.func;
node.outputs = n.outputs;
+ node.timeout = n.timeout*1;
+ 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 || [];
@@ -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) {
diff --git a/packages/node_modules/@node-red/nodes/locales/de/messages.json b/packages/node_modules/@node-red/nodes/locales/de/messages.json
index 65f251e98..2efd2b86d 100644
--- a/packages/node_modules/@node-red/nodes/locales/de/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json
@@ -214,7 +214,8 @@
"initialize": "Start",
"finalize": "Stopp",
"outputs": "Ausgänge",
- "modules": "Module"
+ "modules": "Module",
+ "timeout": "Timeout (ms)"
},
"text": {
"initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 9c055d47b..7fc5912bb 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -248,7 +248,8 @@
"initialize": "On Start",
"finalize": "On Stop",
"outputs": "Outputs",
- "modules": "Modules"
+ "modules": "Modules",
+ "timeout": "Timeout (ms)"
},
"text": {
"initialize": "// Code added here will be run once\n// whenever the node is started.\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/ru/messages.json b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
index 32364b458..0fac5118e 100644
--- a/packages/node_modules/@node-red/nodes/locales/ru/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
@@ -212,7 +212,8 @@
"function": "Функция",
"initialize": "Настройка",
"finalize": "Закрытие",
- "outputs": "Выходы"
+ "outputs": "Выходы",
+ "timeout":"Время ожидания (мс)"
},
"text": {
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
diff --git a/test/nodes/core/function/10-function_spec.js b/test/nodes/core/function/10-function_spec.js
index 4f7f0b806..e5b689136 100644
--- a/test/nodes/core/function/10-function_spec.js
+++ b/test/nodes/core/function/10-function_spec.js
@@ -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:"10",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() {
From 58e045f25d2d40a2c5b3d397bb70fd9022709bbd Mon Sep 17 00:00:00 2001
From: GogoVega
Date: Fri, 26 May 2023 20:52:25 +0200
Subject: [PATCH 03/20] French translation of changes from v3.1.0-beta.3
---
.../node_modules/@node-red/editor-client/locales/fr/editor.json | 1 +
packages/node_modules/@node-red/nodes/locales/fr/messages.json | 1 +
2 files changed, 2 insertions(+)
diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
index a80c9160e..46d85daa5 100644
--- a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json
@@ -504,6 +504,7 @@
"unassigned": "Non attribué",
"global": "global",
"workspace": "espace de travail",
+ "editor": "boîte de dialogue d'édition",
"selectAll": "Tout sélectionner",
"selectNone": "Ne rien sélectionner",
"selectAllConnected": "Sélectionner tous les éléments connectés",
diff --git a/packages/node_modules/@node-red/nodes/locales/fr/messages.json b/packages/node_modules/@node-red/nodes/locales/fr/messages.json
index 0141b010e..e46ef9592 100644
--- a/packages/node_modules/@node-red/nodes/locales/fr/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/fr/messages.json
@@ -414,6 +414,7 @@
"port": "Port",
"keepalive": "Rester en vie",
"cleansession": "Utiliser une session propre",
+ "autoUnsubscribe": "Se désabonner automatiquement lors de la déconnexion",
"cleanstart": "Utiliser un démarrage propre",
"use-tls": "Utiliser TLS",
"tls-config": "Configuration TLS",
From 4cb2624a5db2438b4047ca382aa9f8ac2bfc9507 Mon Sep 17 00:00:00 2001
From: GogoVega
Date: Fri, 26 May 2023 20:58:50 +0200
Subject: [PATCH 04/20] French translation of Welcome Tours
---
.../editor-client/src/tours/3.0/welcome.js | 74 +++++++++---
.../editor-client/src/tours/first-flow.js | 21 ++--
.../editor-client/src/tours/welcome.js | 108 +++++++++++++-----
3 files changed, 152 insertions(+), 51 deletions(-)
diff --git a/packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js b/packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js
index 80f1a6f9c..4ec95c693 100644
--- a/packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js
+++ b/packages/node_modules/@node-red/editor-client/src/tours/3.0/welcome.js
@@ -5,17 +5,20 @@ export default {
titleIcon: "fa fa-map-o",
title: {
"en-US": "Welcome to Node-RED 3.0!",
- "ja": "Node-RED 3.0へようこそ!"
+ "ja": "Node-RED 3.0へようこそ!",
+ "fr": "Bienvenue dans Node-RED 3.0 !"
},
description: {
"en-US": "
Let's take a moment to discover the new features in this release.
",
- "ja": "
本リリースの新機能を見つけてみましょう。
"
+ "ja": "
本リリースの新機能を見つけてみましょう。
",
+ "fr": "
Prenons un moment pour découvrir les nouvelles fonctionnalités de cette version.
Pour faciliter le routage des câbles autour de vos flux, il est désormais possible d'ajouter des noeuds
+ de jonction qui vous donnent plus de contrôle.
+
Les jonctions peuvent être ajoutées aux fils en maintenant les touches Alt et Maj enfoncées, puis en cliquant
+ et en faisant glisser la souris sur les fils.
Lorsque vous recherchez des éléments dans l'éditeur, une nouvelle barre d'outils dans l'espace de travail fournit des options pour passer
+ rapidement d'un résultat de recherche à l'autre.
Certains noeuds ont été mis à jour pour générer un nom unique lorsque
+ de nouvelles instances sont ajoutées à l'espace de travail. Ceci s'applique aux
+ noeuds Debug, Function et Link.
+
Une nouvelle action a également été ajoutée pour générer des noms par défaut pour les noeuds sélectionnés :
+
+
Générer des noms de noeud
+
+
Les actions sont accessibles à partir de la liste d'actions dans le menu principal.
Il s'agit de la troisième bêta de la version 3.1.0. Cette version apporte principalement la correction de bugs, vous pouvez donc ignorer cette visite guidée si vous avez essayé les autres versions bêta.
Si ce n'est pas le cas, restez dans les parages pour voir les nouveautés de Node-RED 3.1.
"
}
},
{
title: {
"en-US": "New ways to work with groups",
- "ja": "グループの新たな操作方法"
+ "ja": "グループの新たな操作方法",
+ "fr": "De nouvelles façons de travailler avec les groupes"
},
description: {
"en-US": `
We have changed how you interact with groups in the editor.
@@ -31,28 +34,41 @@ export default {
「前面へ移動」と「背面へ移動」の動作を用いて、複数のグループの表示順序を変えることができます。
グループ内へ一度に複数のノードをドラッグできるようになりました。
Alt を押したまま、グループ内のノードをドラッグすると、そのグループから *除く* ことができます。
+ `,
+ "fr": `
Nous avons modifié la façon dont vous interagissez avec les groupes dans l'éditeur.
+
+
Ils ne gênent plus lorsque vous cliquez sur un noeud
+
Ils peuvent être réorganisés à l'aide des actions Avancer et Reculer
+
Plusieurs noeuds peuvent être glissés dans un groupe en une seule fois
+
Maintenir Alt lors du déplacement d'un noeud le *supprimera* de son groupe
`
}
},
{
title: {
"en-US": "Change notification on tabs",
- "ja": "タブ上の変更通知"
+ "ja": "タブ上の変更通知",
+ "fr": "Notification de changement sur les onglets"
},
image: 'images/tab-changes.png',
description: {
"en-US": `
When a tab contains undeployed changes it now shows the
- same style of change icon used by nodes.
-
This will make it much easier to track down changes when you're
- working across multiple flows.
`,
+ same style of change icon used by nodes.
+
This will make it much easier to track down changes when you're
+ working across multiple flows.
La taille par défaut du canevas a été augmentée pour que vous puissiez en mettre plus
+ sur un seul flux.
+
Nous recommandons toujours d'utiliser des outils tels que les sous-flux et les noeuds de lien pour vous aider
+ à garder les choses organisées, mais vous avez maintenant plus d'espace pour travailler.
Les flux peuvent désormais être verrouillés pour éviter toute modification accidentelle.
+
Lorsqu'il est verrouillé, vous ne pouvez en aucun cas modifier les noeuds.
+
Le menu contextuel du flux fournit les options pour verrouiller et déverrouiller les flux,
+ ainsi que dans l'explorateur de la barre latérale d'informations.
Vous pouvez définir des variables d'environnement qui s'appliquent à tous les noeuds et flux dans la nouvelle
+ section "Global Environment Variables" des paramètres utilisateur.
`
},
},
{
title: {
"en-US": "Node Updates",
- "ja": "ノードの更新"
+ "ja": "ノードの更新",
+ "fr": "Mises à jour des noeuds"
},
// image: "images/",
description: {
"en-US": `
The core nodes have received lots of minor fixes, documentation updates and
small enhancements. Check the full changelog in the Help sidebar for a full list.
Les noeuds principaux ont reçu de nombreux correctifs mineurs, mises à jour de la documentation et
+ petites améliorations. Consulter le journal des modifications complet dans la barre latérale d'aide.
`
}
}
]
From 5e4fce1e12e8383ca9260ab83a58d4fe0667b651 Mon Sep 17 00:00:00 2001
From: Dave Conway-Jones
Date: Sat, 27 May 2023 17:51:21 +0100
Subject: [PATCH 05/20] Fix delay node flush issue
to close #4202
---
packages/node_modules/@node-red/nodes/core/function/89-delay.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/node_modules/@node-red/nodes/core/function/89-delay.js b/packages/node_modules/@node-red/nodes/core/function/89-delay.js
index 6d4843caf..0b9ca412f 100644
--- a/packages/node_modules/@node-red/nodes/core/function/89-delay.js
+++ b/packages/node_modules/@node-red/nodes/core/function/89-delay.js
@@ -229,6 +229,7 @@ module.exports = function(RED) {
node.on("input", function(msg, send, done) {
if (!node.drop) {
var m = RED.util.cloneMessage(msg);
+ delete m.flush;
if (Object.keys(m).length > 1) {
if (node.intervalID !== -1) {
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate)) && node.rate !== m.rate) {
From a78da0db1e61ae64ebd432b2ca6cce7ecdd288ee Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Mon, 29 May 2023 22:47:29 +0100
Subject: [PATCH 06/20] Update status and catch node labels in group mode
---
.../@node-red/nodes/core/common/25-catch.html | 4 +++-
.../@node-red/nodes/core/common/25-status.html | 10 +++++++++-
.../@node-red/nodes/locales/en-US/messages.json | 2 ++
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/common/25-catch.html b/packages/node_modules/@node-red/nodes/core/common/25-catch.html
index fe68b46db..4b92c9758 100644
--- a/packages/node_modules/@node-red/nodes/core/common/25-catch.html
+++ b/packages/node_modules/@node-red/nodes/core/common/25-catch.html
@@ -41,7 +41,9 @@
if (this.name) {
return this.name;
}
- if (this.scope) {
+ if (this.scope === "group") {
+ return this._("catch.catchGroup");
+ } else if (Array.isArray(this.scope)) {
return this._("catch.catchNodes",{number:this.scope.length});
}
return this.uncaught?this._("catch.catchUncaught"):this._("catch.catch")
diff --git a/packages/node_modules/@node-red/nodes/core/common/25-status.html b/packages/node_modules/@node-red/nodes/core/common/25-status.html
index 0efdede33..b5efadeac 100644
--- a/packages/node_modules/@node-red/nodes/core/common/25-status.html
+++ b/packages/node_modules/@node-red/nodes/core/common/25-status.html
@@ -33,7 +33,15 @@
outputs:1,
icon: "status.svg",
label: function() {
- return this.name||(this.scope?this._("status.statusNodes",{number:this.scope.length}):this._("status.status"));
+ if (this.name) {
+ return this.name;
+ }
+ if (this.scope === "group") {
+ return this._("status.statusGroup");
+ } else if (Array.isArray(this.scope)) {
+ return this._("status.statusNodes",{number:this.scope.length});
+ }
+ return this._("status.status")
},
labelStyle: function() {
return this.name?"node_label_italic":"";
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 52fd1455d..673440b8f 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -94,6 +94,7 @@
},
"catch": {
"catch": "catch: all",
+ "catchGroup": "catch: in same group",
"catchNodes": "catch: __number__",
"catchUncaught": "catch: uncaught",
"label": {
@@ -109,6 +110,7 @@
},
"status": {
"status": "status: all",
+ "statusGroup": "status: in same group",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",
From 613a345771172871bdfbfff438978d06828a4acd Mon Sep 17 00:00:00 2001
From: HiroyasuNishiyama
Date: Tue, 30 May 2023 20:58:17 +0900
Subject: [PATCH 07/20] add additional Japanese translation for status and
catch node
---
packages/node_modules/@node-red/nodes/locales/ja/messages.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/node_modules/@node-red/nodes/locales/ja/messages.json b/packages/node_modules/@node-red/nodes/locales/ja/messages.json
index a5736c60e..2e0865011 100644
--- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json
@@ -103,6 +103,7 @@
},
"scope": {
"all": "全てのノード",
+ "group": "同一グループ内",
"selected": "選択したノード"
}
},
@@ -115,6 +116,7 @@
},
"scope": {
"all": "全てのノード",
+ "group": "同一グループ内",
"selected": "選択したノード"
}
},
From 9714ef19dea573626b6959477ee6af397766e8f5 Mon Sep 17 00:00:00 2001
From: GogoVega
Date: Tue, 30 May 2023 14:19:39 +0200
Subject: [PATCH 08/20] Missing french translation of beta 3 changes
---
packages/node_modules/@node-red/nodes/locales/fr/messages.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/node_modules/@node-red/nodes/locales/fr/messages.json b/packages/node_modules/@node-red/nodes/locales/fr/messages.json
index e46ef9592..7890ce9a2 100644
--- a/packages/node_modules/@node-red/nodes/locales/fr/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/fr/messages.json
@@ -103,6 +103,7 @@
},
"scope": {
"all": "tous les noeuds",
+ "group": "dans le même groupe",
"selected": "noeuds sélectionnés"
}
},
@@ -115,6 +116,7 @@
},
"scope": {
"all": "tous les noeuds",
+ "group": "dans le même groupe",
"selected": "noeuds sélectionnés"
}
},
From 5eee38e7de4e49409e1b07c4ce37d4f56449438f Mon Sep 17 00:00:00 2001
From: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
Date: Wed, 31 May 2023 14:10:59 +0100
Subject: [PATCH 09/20] Update
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary
---
.../node_modules/@node-red/nodes/locales/en-US/messages.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 673440b8f..235a9d07c 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -94,7 +94,7 @@
},
"catch": {
"catch": "catch: all",
- "catchGroup": "catch: in same group",
+ "catchGroup": "catch: group",
"catchNodes": "catch: __number__",
"catchUncaught": "catch: uncaught",
"label": {
From f8175fc3254966252b824475335e296a608071d5 Mon Sep 17 00:00:00 2001
From: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com>
Date: Wed, 31 May 2023 14:11:06 +0100
Subject: [PATCH 10/20] Update
packages/node_modules/@node-red/nodes/locales/en-US/messages.json
Co-authored-by: Nick O'Leary
---
.../node_modules/@node-red/nodes/locales/en-US/messages.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 235a9d07c..2f282036c 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -110,7 +110,7 @@
},
"status": {
"status": "status: all",
- "statusGroup": "status: in same group",
+ "statusGroup": "status: group",
"statusNodes": "status: __number__",
"label": {
"source": "Report status from",
From 4808cac89dbe901663be64106b1d7599739a6e63 Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 21:14:56 +0100
Subject: [PATCH 11/20] Add async to all paths that JSONata env var calls
---
.../@node-red/runtime/lib/flows/Flow.js | 139 ++++++++++++------
.../@node-red/runtime/lib/flows/index.js | 2 +-
.../@node-red/runtime/lib/flows/util.js | 30 +++-
.../node_modules/@node-red/util/lib/util.js | 82 ++++++++---
4 files changed, 184 insertions(+), 69 deletions(-)
diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js
index 489ec42cb..2e1e97c4b 100644
--- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js
+++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js
@@ -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;
}
/**
diff --git a/packages/node_modules/@node-red/runtime/lib/flows/index.js b/packages/node_modules/@node-red/runtime/lib/flows/index.js
index e18861f17..9c6133ea5 100644
--- a/packages/node_modules/@node-red/runtime/lib/flows/index.js
+++ b/packages/node_modules/@node-red/runtime/lib/flows/index.js
@@ -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)
}
diff --git a/packages/node_modules/@node-red/runtime/lib/flows/util.js b/packages/node_modules/@node-red/runtime/lib/flows/util.js
index 868657c7b..39ff820b4 100644
--- a/packages/node_modules/@node-red/runtime/lib/flows/util.js
+++ b/packages/node_modules/@node-red/runtime/lib/flows/util.js
@@ -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,
diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js
index ad05d45f1..8511376d7 100644
--- a/packages/node_modules/@node-red/util/lib/util.js
+++ b/packages/node_modules/@node-red/util/lib/util.js
@@ -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,67 @@ 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);
+ }
+ 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 +599,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 +634,7 @@ function evaluateEnvProperty(value, node) {
return (val === undefined)?"":val;
});
}
- return (result === undefined)?"":result;
-
+ return returnOrCallback(null, (result === undefined)?"":result);
}
@@ -677,7 +722,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);
From 8202f1b7c6c5e7f53eb9844bfb7482988eed038b Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 21:54:32 +0100
Subject: [PATCH 12/20] Add env var is JSONata expr test
---
.../core/common/91-global-config_spec.js | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/test/nodes/core/common/91-global-config_spec.js b/test/nodes/core/common/91-global-config_spec.js
index 8cc5658cf..cf711dba9 100644
--- a/test/nodes/core/common/91-global-config_spec.js
+++ b/test/nodes/core/common/91-global-config_spec.js
@@ -44,4 +44,30 @@ describe('unknown Node', function() {
});
});
+ it.only('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({});
+ });
+ });
+
});
From ee8b2a0b5811c13a9c05adb6ea8fcfaa8e5ca0bc Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 22:03:59 +0100
Subject: [PATCH 13/20] Delete stray it.only
---
test/unit/@node-red/runtime/lib/flows/Flow_spec.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
index 6d53747ef..c376f839a 100644
--- a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
+++ b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
@@ -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" },
From ceb9a320baef060dab40612ae11c940ce683eaea Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 22:11:02 +0100
Subject: [PATCH 14/20] expand existing env var test for all scenarios
---
.../@node-red/runtime/lib/flows/Flow_spec.js | 72 ++++++++++++++-----
1 file changed, 55 insertions(+), 17 deletions(-)
diff --git a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
index c376f839a..9f99830b0 100644
--- a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
+++ b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
@@ -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);
+ }
+ });
});
});
From 5435c9ebd2d32a2058432114a08f6f75493355c9 Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 22:12:09 +0100
Subject: [PATCH 15/20] =?UTF-8?q?fix=20test=20(missing=20getUserSettings?=
=?UTF-8?q?=20stub=20=F0=9F=A4=B7=E2=80=8D=E2=99=82=EF=B8=8F)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../@node-red/runtime/lib/storage/localfilesystem/index_spec.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js
index 65826c9f4..00fab11cf 100644
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js
+++ b/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js
@@ -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();
From 31bc99cd611a4b2a5118408fe5e3025195f2617a Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 22:29:39 +0100
Subject: [PATCH 16/20] remove .only
---
test/nodes/core/common/91-global-config_spec.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/nodes/core/common/91-global-config_spec.js b/test/nodes/core/common/91-global-config_spec.js
index cf711dba9..29dd905ae 100644
--- a/test/nodes/core/common/91-global-config_spec.js
+++ b/test/nodes/core/common/91-global-config_spec.js
@@ -44,7 +44,7 @@ describe('unknown Node', function() {
});
});
- it.only('should evaluate a global environment variable that is a JSONata value', function (done) {
+ it('should evaluate a global environment variable that is a JSONata value', function (done) {
const flow = [{
id: "n1", type: "global-config", name: "XYZ",
env: [
From 502dacd865e791e53ab16c1eb7cc314183e7fffe Mon Sep 17 00:00:00 2001
From: Steve-Mcl
Date: Sat, 17 Jun 2023 22:44:55 +0100
Subject: [PATCH 17/20] fix failure to return after calling callback
---
packages/node_modules/@node-red/util/lib/util.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/node_modules/@node-red/util/lib/util.js b/packages/node_modules/@node-red/util/lib/util.js
index 8511376d7..9f711f4fa 100644
--- a/packages/node_modules/@node-red/util/lib/util.js
+++ b/packages/node_modules/@node-red/util/lib/util.js
@@ -568,6 +568,7 @@ function getSetting(node, name, flow_, callback) {
}
if (result) {
callback(null, result.val);
+ return
}
name = newName;
flow.getSetting(name, callback);
From 3f604e9d93d8c0e08580d728a8761268360d5e8f Mon Sep 17 00:00:00 2001
From: Nick O'Leary
Date: Wed, 21 Jun 2023 14:20:23 +0100
Subject: [PATCH 18/20] Adds optional callback to env.get in function node
---
.../node_modules/@node-red/nodes/core/function/10-function.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.js b/packages/node_modules/@node-red/nodes/core/function/10-function.js
index b84ee8571..b69f6eeed 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.js
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.js
@@ -235,8 +235,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 () {
From aa0225f59fcc294984322dcd05e7f62b7fafa0ac Mon Sep 17 00:00:00 2001
From: Nick O'Leary
Date: Wed, 21 Jun 2023 14:27:32 +0100
Subject: [PATCH 19/20] Apply suggestions from code review
---
.../@node-red/nodes/core/function/10-function.html | 6 +++---
.../@node-red/nodes/core/function/10-function.js | 2 +-
.../node_modules/@node-red/nodes/locales/de/messages.json | 2 +-
.../@node-red/nodes/locales/en-US/messages.json | 2 +-
.../node_modules/@node-red/nodes/locales/ru/messages.json | 2 +-
test/nodes/core/function/10-function_spec.js | 2 +-
6 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.html b/packages/node_modules/@node-red/nodes/core/function/10-function.html
index 8130be2ad..581c58c73 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.html
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.html
@@ -84,7 +84,7 @@
-
+
@@ -470,10 +470,10 @@
}
});
- // 4294967295 is max in node.js timeout.
+ // 4294967 is max in node.js timeout.
$( "#node-input-timeout" ).spinner({
min: 0,
- max: 4294967294,
+ max: 4294967,
change: function(event, ui) {
var value = this.value;
if(value == ""){
diff --git a/packages/node_modules/@node-red/nodes/core/function/10-function.js b/packages/node_modules/@node-red/nodes/core/function/10-function.js
index 3ada08943..662b7fa47 100644
--- a/packages/node_modules/@node-red/nodes/core/function/10-function.js
+++ b/packages/node_modules/@node-red/nodes/core/function/10-function.js
@@ -96,7 +96,7 @@ module.exports = function(RED) {
node.name = n.name;
node.func = n.func;
node.outputs = n.outputs;
- node.timeout = n.timeout*1;
+ node.timeout = n.timeout*1000;
if(node.timeout>0){
node.timeoutOptions = {
timeout:node.timeout,
diff --git a/packages/node_modules/@node-red/nodes/locales/de/messages.json b/packages/node_modules/@node-red/nodes/locales/de/messages.json
index 0b98bd927..bc706e1f1 100644
--- a/packages/node_modules/@node-red/nodes/locales/de/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json
@@ -217,7 +217,7 @@
"finalize": "Stopp",
"outputs": "Ausgänge",
"modules": "Module",
- "timeout": "Timeout (ms)"
+ "timeout": "Timeout"
},
"text": {
"initialize": "// Der Code hier wird ausgeführt,\n// wenn der Node gestartet wird\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index 5e47a7960..a7b583878 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -253,7 +253,7 @@
"finalize": "On Stop",
"outputs": "Outputs",
"modules": "Modules",
- "timeout": "Timeout (ms)"
+ "timeout": "Timeout"
},
"text": {
"initialize": "// Code added here will be run once\n// whenever the node is started.\n",
diff --git a/packages/node_modules/@node-red/nodes/locales/ru/messages.json b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
index 0fac5118e..58ccf90fe 100644
--- a/packages/node_modules/@node-red/nodes/locales/ru/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/ru/messages.json
@@ -213,7 +213,7 @@
"initialize": "Настройка",
"finalize": "Закрытие",
"outputs": "Выходы",
- "timeout":"Время ожидания (мс)"
+ "timeout":"Время ожидания"
},
"text": {
"initialize": "// Добавленный здесь код будет исполняться\n// однократно при развертывании узла.\n",
diff --git a/test/nodes/core/function/10-function_spec.js b/test/nodes/core/function/10-function_spec.js
index e5b689136..99557f0b3 100644
--- a/test/nodes/core/function/10-function_spec.js
+++ b/test/nodes/core/function/10-function_spec.js
@@ -1425,7 +1425,7 @@ describe('function node', function() {
});
it('should timeout if timeout is set', function(done) {
- var flow = [{id:"n1",type:"function",wires:[["n2"]],timeout:"10",func:"while(1==1){};\nreturn msg;"}];
+ 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"});
From 4d9fcaeebfb3fb3e8e60f1feea7b7e042c2323e1 Mon Sep 17 00:00:00 2001
From: Nick O'Leary
Date: Wed, 21 Jun 2023 15:00:27 +0100
Subject: [PATCH 20/20] Update env.get type hint
---
.../editor-client/src/types/node-red/func.d.ts | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/packages/node_modules/@node-red/editor-client/src/types/node-red/func.d.ts b/packages/node_modules/@node-red/editor-client/src/types/node-red/func.d.ts
index 59f8a8bd7..8544439d9 100644
--- a/packages/node_modules/@node-red/editor-client/src/types/node-red/func.d.ts
+++ b/packages/node_modules/@node-red/editor-client/src/types/node-red/func.d.ts
@@ -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;
}