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.

" } }, { title: { "en-US": "Context Menu", - "ja": "コンテキストメニュー" + "ja": "コンテキストメニュー", + "fr": "Menu contextuel" }, image: '3.0/images/context-menu.png', description: { @@ -24,13 +27,17 @@ export default {

This makes many of the built-in actions much easier to access.

`, "ja": `

ワークスペースで右クリックすると、エディタに独自のコンテキストメニューが表示されるようになりました。

-

これによって多くの組み込み動作を、より簡単に利用できます。

` +

これによって多くの組み込み動作を、より簡単に利用できます。

`, + "fr": `

L'éditeur a maintenant son propre menu contextuel lorsque vous + faites un clic droit dans l'espace de travail.

+

Cela facilite l'accès à de nombreuses actions intégrées.

` } }, { title: { "en-US": "Wire Junctions", - "ja": "分岐点をワイヤーに追加" + "ja": "分岐点をワイヤーに追加", + "fr": "Jonctions de fils" }, image: '3.0/images/junction-slice.gif', description: { @@ -40,13 +47,18 @@ export default {

Junctions can be added to wires by holding both the Alt key and the Shift key then click and drag the mouse across the wires.

`, "ja": `

フローのワイヤーの経路をより制御しやすくするために、分岐点ノードを追加できるようになりました。

-

Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。

` +

Altキーとシフトキーを押しながらマウスをクリックし、ワイヤーを横切るようにドラッグすることで、分岐点を追加できます。

`, + "fr": `

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.

` }, }, { title: { "en-US": "Wire Junctions", - "ja": "分岐点をワイヤーに追加" + "ja": "分岐点をワイヤーに追加", + "fr": "Jonctions de fils" }, image: '3.0/images/junction-quick-add.png', description: { @@ -54,13 +66,16 @@ export default {

The dialog is opened by holding the Ctrl (or Cmd) key when clicking in the workspace.

`, "ja": `

クイック追加ダイアログを用いて、分岐点を追加することもできます。

-

本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。

` +

本ダイアログを開くには、Ctrl(またはCmd)キーを押しながら、ワークスペース上でクリックします。

`, + "fr": `

Les jonctions peuvent également être ajoutées à l'aide de la boîte de dialogue d'ajout rapide.

+

La boîte de dialogue s'ouvre en maintenant la touche Ctrl (ou Cmd) enfoncée lors d'un clic dans l'espace de travail.

` }, }, { title: { "en-US": "Debug Path Tooltip", - "ja": "デバッグパスのツールチップ" + "ja": "デバッグパスのツールチップ", + "fr": "Info-bulle du chemin de débogage" }, image: '3.0/images/debug-path-tooltip.png', description: { @@ -73,26 +88,33 @@ export default { the workspace.

`, "ja": `

デバックサイドバー内のノード名の上にマウスカーソルを乗せると、新たにツールチップが表示され、ノードの場所が分かるようになっています。

これは、サブフローを用いる時に役立つ機能であり、メッセージがどのノードから出力されたかを正確に特定することが遥かに簡単になります。

-

本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。

` +

本リスト内の要素をクリックすると、ワークスペース内にその要素が表示されます。

`, + "fr": `

Lorsque vous passez la souris sur un nom de noeud dans la barre latérale de débogage, une nouvelle info-bulle affiche l'emplacement complet du noeud.

+

C'est utile lorsque vous travaillez avec des sous-flux, ce qui facilite l'identification exacte du noeud qui a généré le message.

+

Cliquer sur n'importe quel élément de la liste le révélera dans l'espace de travail.

` }, }, { title: { "en-US": "Continuous Search", - "ja": "連続した検索" + "ja": "連続した検索", + "fr": "Recherche continue" }, image: '3.0/images/continuous-search.png', description: { "en-US": `

When searching for things in the editor, a new toolbar in the workspace provides options to quickly jump between the search results.

`, - "ja": `

ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。

` + "ja": `

ワークスペース内の新しいツールバーにあるオプションによって、エディタ内を検索する際に、検索結果の間を素早く移動できます。

`, + "fr": `

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.

` }, }, { title: { "en-US": "New wiring actions", - "ja": "新しいワイヤー操作" + "ja": "新しいワイヤー操作", + "fr": "Nouvelles actions de câblage" }, image: "3.0/images/split-wire-with-links.gif", description: { @@ -106,12 +128,18 @@ export default {
  • ワイヤーをlinkノードで分割
  • 本アクションは、メインメニュー内の動作一覧から呼び出せます。

    `, + "fr": `

    Une nouvelle action a été ajoutée pour remplacer un fil par une paire de noeuds de lien connectés :

    +
      +
    • Diviser le fil avec les noeuds de liaison
    • +
    +

    Les actions sont accessibles à partir de la liste d'actions dans le menu principal.

    ` }, }, { title: { "en-US": "Default node names", - "ja": "標準ノードの名前" + "ja": "標準ノードの名前", + "fr": "Noms de noeud par défaut" }, // image: "images/", description: { @@ -129,13 +157,22 @@ export default {
    • ノード名を生成

    本アクションは、メインメニュー内の動作一覧から呼び出せます。

    - ` + `, + "fr": `

    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.

    ` } }, { title: { "en-US": "Node Updates", - "ja": "ノードの更新" + "ja": "ノードの更新", + "fr": "Mises à jour des noeuds" }, // image: "images/", description: { @@ -148,6 +185,11 @@ export default {
  • Debugノードは、受信したメッセージの数をカウントするよう設定できるようになりました。
  • Link Callノードは、メッセージのプロパティによって、呼び出し対象のlinkを動的に指定できるようになりました。
  • HTTP Requestノードは、HTTPヘッダを事前設定できるようになりました。
  • + `, + "fr": `
      +
    • Le noeud de débogage peut être configuré pour compter les messages qu'il reçoit
    • +
    • Le noeud Link Call peut utiliser une propriété de message pour cibler dynamiquement le lien qu'il doit appeler
    • +
    • Le noeud de requête HTTP peut être préconfiguré avec des en-têtes HTTP
    ` } } diff --git a/packages/node_modules/@node-red/editor-client/src/tours/first-flow.js b/packages/node_modules/@node-red/editor-client/src/tours/first-flow.js index b26ee7d8f..7777f7952 100644 --- a/packages/node_modules/@node-red/editor-client/src/tours/first-flow.js +++ b/packages/node_modules/@node-red/editor-client/src/tours/first-flow.js @@ -3,12 +3,14 @@ export default { { title: { 'en-US': 'Create your first flow', - 'ja': 'はじめてのフローを作成' + 'ja': 'はじめてのフローを作成', + 'fr': "Créer votre premier flux" }, width: 400, description: { 'en-US': 'This tutorial will guide you through creating your first flow', - 'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。' + 'ja': '本チュートリアルでは、はじめてのフローを作成する方法について説明します。', + 'fr': "Ce didacticiel vous guidera dans la création de votre premier flux" }, nextButton: 'start' }, @@ -16,7 +18,8 @@ export default { element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add", description: { 'en-US': 'To add a new tab, click the button', - 'ja': '新しいタブを追加するため、 ボタンをクリックします。' + 'ja': '新しいタブを追加するため、 ボタンをクリックします。', + 'fr': 'Pour ajouter un nouvel onglet, cliquez sur le bouton ' }, wait: { type: "dom-event", @@ -29,7 +32,8 @@ export default { direction: 'right', description: { 'en-US': 'The palette lists all of the nodes available to use. Drag a new Inject node into the workspace.', - 'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。' + 'ja': 'パレットには、利用できる全てのノードが一覧表示されます。injectノードをワークスペースにドラッグします。', + 'fr': "La palette répertorie tous les noeuds disponibles à utiliser. Faites glisser un nouveau noeud Inject dans l'espace de travail." }, fallback: 'inset-bottom-right', wait: { @@ -52,7 +56,8 @@ export default { direction: 'right', description: { 'en-US': 'Next, drag a new Debug node into the workspace.', - 'ja': '次に、debugノードをワークスペースにドラッグします。' + 'ja': '次に、debugノードをワークスペースにドラッグします。', + 'fr': "Ensuite, faites glisser un nouveau noeud Debug dans l'espace de travail." }, fallback: 'inset-bottom-right', wait: { @@ -74,7 +79,8 @@ export default { element: function() { return $("#"+this.injectNode.id+" .red-ui-flow-port") }, description: { 'en-US': 'Add a wire from the output of the Inject node to the input of the Debug node', - 'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。' + 'ja': 'injectノードの出力から、debugノードの入力へワイヤーで接続します。', + 'fr': "Ajoutez un fil de la sortie du noeud Inject à l'entrée du noeud Debug" }, fallback: 'inset-bottom-right', wait: { @@ -89,7 +95,8 @@ export default { element: "#red-ui-header-button-deploy", description: { 'en-US': 'Deploy your changes so the flow is active in the runtime', - 'ja': 'フローをランタイムで実行させるため、変更をデプロイします。' + 'ja': 'フローをランタイムで実行させるため、変更をデプロイします。', + 'fr': "Déployez vos modifications afin que le flux soit actif dans le runtime" }, width: 200, wait: { diff --git a/packages/node_modules/@node-red/editor-client/src/tours/welcome.js b/packages/node_modules/@node-red/editor-client/src/tours/welcome.js index d6305e01b..ba9b408bb 100644 --- a/packages/node_modules/@node-red/editor-client/src/tours/welcome.js +++ b/packages/node_modules/@node-red/editor-client/src/tours/welcome.js @@ -5,17 +5,20 @@ export default { titleIcon: "fa fa-map-o", title: { "en-US": "Welcome to Node-RED 3.1 Beta 3!", - "ja": "Node-RED 3.1 ベータ3へようこそ!" + "ja": "Node-RED 3.1 ベータ3へようこそ!", + "fr": "Bienvenue dans Node-RED 3.1 Bêta 3 !" }, description: { "en-US": "

    This is the third beta release for 3.1.0. This is mostly a bug fix release, so you can skip this tour if you've tried the other betas.

    If not, stick around to see what's new in Node-RED 3.1.

    ", - "ja": "

    これは3.1.0の3回目のベータリリースです。不具合修正のリリースのため、もし他のベータ版を試したことがある場合は、このツアーを読み飛ばしてもかまいません。

    そうでない場合は、Node-RED 3.1の新機能を確認してください。

    " + "ja": "

    これは3.1.0の3回目のベータリリースです。不具合修正のリリースのため、もし他のベータ版を試したことがある場合は、このツアーを読み飛ばしてもかまいません。

    そうでない場合は、Node-RED 3.1の新機能を確認してください。

    ", + "fr": "

    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.

    `, "ja": `

    タブ内にデプロイされていない変更が存在する時は、ノードと同じスタイルで変更の印が表示されるようになりました。

    -

    これによって複数のフローを編集している時に、変更を見つけるのが簡単になりました。

    ` +

    これによって複数のフローを編集している時に、変更を見つけるのが簡単になりました。

    `, + "fr": `

    Lorsqu'un onglet contient des modifications non déployées, il affiche désormais le + même style d'icône de changement utilisé par les noeuds.

    +

    Cela facilitera grandement le suivi des modifications lorsque vous + travaillez sur plusieurs flux.

    ` } }, { title: { "en-US": "A bigger canvas to work with", - "ja": "より広くなった作業キャンバス" + "ja": "より広くなった作業キャンバス", + "fr": "Un canevas plus grand pour travailler" }, description: { "en-US": `

    The default canvas size has been increased so you can fit more @@ -60,13 +76,18 @@ export default {

    We still recommend using tools such as subflows and Link Nodes to help keep things organised, but now you have more room to work in.

    `, "ja": `

    標準のキャンバスが広くなったため、1つのフローに沢山のものを含めることができるようになりました。

    -

    引き続き、サブフローやリンクノードなどの方法を用いて整理することをお勧めしますが、作業できる場所が増えました。

    ` +

    引き続き、サブフローやリンクノードなどの方法を用いて整理することをお勧めしますが、作業できる場所が増えました。

    `, + "fr": `

    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.

    ` } }, { title: { "en-US": "Finding help", - "ja": "ヘルプを見つける" + "ja": "ヘルプを見つける", + "fr": "Trouver de l'aide" }, image: 'images/node-help.png', description: { @@ -74,23 +95,29 @@ export default { in the footer.

    Clicking it will open up the Help sidebar showing the help for that node.

    `, "ja": `

    全てのノードの編集ダイアログの下に、ノードのヘルプへのリンクが追加されました。

    -

    これをクリックすると、ノードのヘルプサイドバーが表示されます。

    ` +

    これをクリックすると、ノードのヘルプサイドバーが表示されます。

    `, + "fr": `

    Toutes les boîtes de dialogue d'édition de noeud incluent désormais un lien vers l'aide de ce noeud + dans le pied de page.

    +

    Cliquer dessus ouvrira la barre latérale d'aide affichant l'aide pour ce noeud.

    ` } }, { title: { "en-US": "And lots more...", - "ja": "そしてさらに沢山あります..." + "ja": "そしてさらに沢山あります...", + "fr": "Et plus encore..." }, description: { "en-US": `

    Of course we have everything from 3.1.0-beta.1 as well....

    `, - "ja": `

    もちろん3.1.0 ベータ1の全ての機能があります....

    ` + "ja": `

    もちろん3.1.0 ベータ1の全ての機能があります....

    `, + "fr": `

    Bien sûr, nous avons également tout ce qui concerne la version 3.1.0-beta.1...

    ` } }, { title: { "en-US": "Improved Context Menu", - "ja": "コンテキストメニューの改善" + "ja": "コンテキストメニューの改善", + "fr": "Menu contextuel amélioré" }, image: 'images/context-menu.png', description: { @@ -102,13 +129,17 @@ export default { with your flows much easier.

    `, "ja": `

    より多くの組み込み動作を利用できるように、エディタのコンテキストメニューが拡張されました。

    ノードの追加、グループの操作、その他の便利なツールをクリックするだけで実行できるようになりました。

    -

    フローのタブバーには、フローの操作をより簡単にする独自のコンテキストメニューもあります。

    ` +

    フローのタブバーには、フローの操作をより簡単にする独自のコンテキストメニューもあります。

    `, + "fr": `

    Le menu contextuel de l'éditeur a été étendu pour faire beaucoup plus d'actions intégrées disponibles.

    +

    Ajouter des noeuds, travailler avec des groupes et beaucoup d'autres outils utiles sont désormais à portée de clic.

    +

    La barre d'onglets de flux possède également son propre menu contextuel pour faciliter l'utilisation de vos flux.

    ` } }, { title: { "en-US": "Hiding Flows", - "ja": "フローを非表示" + "ja": "フローを非表示", + "fr": "Masquage de flux" }, image: 'images/hiding-flows.png', description: { @@ -116,13 +147,17 @@ export default {

    The 'hide' button in previous releases has been removed from the tabs as they were being clicked accidentally too often.

    `, "ja": `

    フローを非表示にする機能は、フローのコンテキストメニューから実行するようになりました。

    -

    これまでのリリースでタブに存在していた「非表示」ボタンは、よく誤ってクリックされていたため、削除されました。

    ` +

    これまでのリリースでタブに存在していた「非表示」ボタンは、よく誤ってクリックされていたため、削除されました。

    `, + "fr": `

    Le masquage des flux s'effectue désormais via le menu contextuel du flux.

    +

    Le bouton "Masquer" des versions précédentes a été supprimé des onglets + car il était cliqué accidentellement trop souvent.

    ` }, }, { title: { "en-US": "Locking Flows", - "ja": "フローを固定" + "ja": "フローを固定", + "fr": "Verrouillage de flux" }, image: 'images/locking-flows.png', description: { @@ -132,13 +167,18 @@ export default { as well as in the Info sidebar explorer.

    `, "ja": `

    誤ってフローに変更が加えられてしまうのを防ぐために、フローを固定できるようになりました。

    固定されている時は、ノードを修正することはできません。

    -

    フローのコンテキストメニューと、情報サイドバーのエクスプローラには、フローの固定や解除をするためのオプションが用意されています。

    ` +

    フローのコンテキストメニューと、情報サイドバーのエクスプローラには、フローの固定や解除をするためのオプションが用意されています。

    `, + "fr": `

    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.

    ` }, }, { title: { "en-US": "Adding Images to node/flow descriptions", - "ja": "ノードやフローの説明へ画像を追加" + "ja": "ノードやフローの説明へ画像を追加", + "fr": "Ajout d'images aux descriptions de noeud/flux" }, // image: 'images/debug-path-tooltip.png', description: { @@ -147,44 +187,56 @@ export default {

    When the description is shown in the Info sidebar, the image will be displayed.

    `, "ja": `

    ノードまたはフローの説明に、画像を追加できるようになりました。

    画像をテキストエディタにドラッグするだけで、行内に埋め込まれます。

    -

    情報サイドバーの説明を開くと、その画像が表示されます。

    ` +

    情報サイドバーの説明を開くと、その画像が表示されます。

    `, + "fr": `

    Vous pouvez désormais ajouter des images à la description d'un noeud ou d'un flux.

    +

    Faites simplement glisser l'image dans l'éditeur de texte et elle sera ajoutée en ligne.

    +

    Lorsque la description s'affiche dans la barre latérale d'informations, l'image s'affiche.

    ` }, }, { title: { "en-US": "Adding Mermaid Diagrams", - "ja": "Mermaid図を追加" + "ja": "Mermaid図を追加", + "fr": "Ajout de diagrammes Mermaid" }, image: 'images/mermaid.png', description: { "en-US": `

    You can also add Mermaid diagrams directly into your node or flow descriptions.

    This gives you much richer options for documenting your flows.

    `, "ja": `

    ノードやフローの説明に、Mermaid図を直接追加することもできます。

    -

    これによって、フローを説明する文書作成の選択肢がより多くなります。

    ` +

    これによって、フローを説明する文書作成の選択肢がより多くなります。

    `, + "fr": `

    Vous pouvez également ajouter des diagrammes Mermaid directement dans vos descriptions de noeud ou de flux.

    +

    Cela vous offre des options beaucoup plus riches pour documenter vos flux.

    ` }, }, { title: { "en-US": "Managing Global Environment Variables", - "ja": "グローバル環境変数の管理" + "ja": "グローバル環境変数の管理", + "fr": "Gestion des variables d'environnement globales" }, image: 'images/global-env-vars.png', description: { "en-US": `

    You can set environment variables that apply to all nodes and flows in the new 'Global Environment Variables' section of User Settings.

    `, - "ja": `

    ユーザ設定に新しく追加された「大域環境変数」のセクションで、全てのノードとフローに適用される環境変数を登録できます。

    ` + "ja": `

    ユーザ設定に新しく追加された「大域環境変数」のセクションで、全てのノードとフローに適用される環境変数を登録できます。

    `, + "fr": `

    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.

    `, - "ja": `

    コアノードにマイナーな修正、ドキュメント更新、小規模な拡張が数多く追加されています。全ての一覧は、ヘルプサイドバーの全ての更新履歴を確認してください。

    ` + "ja": `

    コアノードにマイナーな修正、ドキュメント更新、小規模な拡張が数多く追加されています。全ての一覧は、ヘルプサイドバーの全ての更新履歴を確認してください。

    `, + "fr": `

    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; }