From 53e092e4840ae03ef53ea0cc461096d3dc553cb5 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:06:58 +0200 Subject: [PATCH 01/87] Add config node to history + handling `changed` prop --- .../editor-client/src/js/ui/editor.js | 231 ++++++++++-------- 1 file changed, 134 insertions(+), 97 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 46dc60fe2..c6a448dd3 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -1475,134 +1475,171 @@ RED.editor = (function() { }, { id: "node-config-dialog-ok", - text: adding?RED._("editor.configAdd"):RED._("editor.configUpdate"), + text: adding ? RED._("editor.configAdd") : RED._("editor.configUpdate"), class: "primary", click: function() { - var editState = { + // TODO: Already defined + const configProperty = name; + const configType = type; + const configTypeDef = RED.nodes.getType(configType); + + const wasChanged = editing_config_node.changed; + const editState = { changes: {}, changed: false, outputMap: null }; - var configProperty = name; - var configId = editing_config_node.id; - var configType = type; - var configAdding = adding; - var configTypeDef = RED.nodes.getType(configType); - var d; - var input; + + // Call `oneditsave` and search for changes + handleEditSave(editing_config_node, editState); - if (configTypeDef.oneditsave) { - try { - configTypeDef.oneditsave.call(editing_config_node); - } catch(err) { - console.warn("oneditsave",editing_config_node.id,editing_config_node.type,err.toString()); - } - } - - for (d in configTypeDef.defaults) { - if (configTypeDef.defaults.hasOwnProperty(d)) { - var newValue; - input = $("#node-config-input-"+d); - if (input.attr('type') === "checkbox") { - newValue = input.prop('checked'); - } else if ("format" in configTypeDef.defaults[d] && configTypeDef.defaults[d].format !== "" && input[0].nodeName === "DIV") { - newValue = input.text(); - } else { - newValue = input.val(); - } - if (newValue != null && newValue !== editing_config_node[d]) { - if (editing_config_node._def.defaults[d].type) { - if (newValue == "_ADD_") { - newValue = ""; - } - // Change to a related config node - var configNode = RED.nodes.node(editing_config_node[d]); - if (configNode) { - var users = configNode.users; - users.splice(users.indexOf(editing_config_node),1); - RED.events.emit("nodes:change",configNode); - } - configNode = RED.nodes.node(newValue); - if (configNode) { - configNode.users.push(editing_config_node); - RED.events.emit("nodes:change",configNode); - } - } - editing_config_node[d] = newValue; - } - } - } - - activeEditPanes.forEach(function(pane) { + // Search for changes in the edit box (panes) + activeEditPanes.forEach(function (pane) { if (pane.apply) { pane.apply.call(pane, editState); } - }) + }); - editing_config_node.label = configTypeDef.label; - - var scope = $("#red-ui-editor-config-scope").val(); - editing_config_node.z = scope; + // TODO: Why? + editing_config_node.label = configTypeDef.label + // Check if disabled has changed if ($("#node-config-input-node-disabled").prop('checked')) { if (editing_config_node.d !== true) { + editState.changes.d = editing_config_node.d; + editState.changed = true; editing_config_node.d = true; } } else { if (editing_config_node.d === true) { + editState.changes.d = editing_config_node.d; + editState.changed = true; delete editing_config_node.d; } } + // NOTE: must be undefined if no scope used + const scope = $("#red-ui-editor-config-scope").val() || undefined; + + // Check if the scope has changed + if (editing_config_node.z !== scope) { + editState.changes.z = editing_config_node.z; + editState.changed = true; + editing_config_node.z = scope; + } + + // Search for nodes that use this config node that are no longer + // in scope, so must be removed + const historyEvents = []; if (scope) { - // Search for nodes that use this one that are no longer - // in scope, so must be removed - editing_config_node.users = editing_config_node.users.filter(function(n) { - var keep = true; - for (var d in n._def.defaults) { - if (n._def.defaults.hasOwnProperty(d)) { - if (n._def.defaults[d].type === editing_config_node.type && - n[d] === editing_config_node.id && - n.z !== scope) { - keep = false; - // Remove the reference to this node - // and revalidate - n[d] = null; - n.dirty = true; - n.changed = true; - validateNode(n); + const newUsers = editing_config_node.users.filter(function (node) { + let keepNode = false; + + for (const d in node._def.defaults) { + if (node._def.defaults.hasOwnProperty(d)) { + if (node._def.defaults[d].type === editing_config_node.type) { + if (node[d] === editing_config_node.id) { + if (node.z === editing_config_node.z) { + // The node is kept only if at least one property uses + // this config node in the correct scope. + keepNode = true; + } else { + historyEvents.push({ + t: "edit", + node: node, + changes: { [d]: node[d] }, + changed: node.changed, + dirty: node.dirty + }); + + // Remove the reference to the config + node[d] = ""; + } + } } } } - return keep; - }); - } - if (configAdding) { - RED.nodes.add(editing_config_node); - } - - validateNode(editing_config_node); - var validatedNodes = {}; - validatedNodes[editing_config_node.id] = true; - - var userStack = editing_config_node.users.slice(); - while(userStack.length > 0) { - var user = userStack.pop(); - if (!validatedNodes[user.id]) { - validatedNodes[user.id] = true; - if (user.users) { - userStack = userStack.concat(user.users); + // Mark as changed and revalidate this node + if (!keepNode) { + node.changed = true; + node.dirty = true; + validateNode(node); + RED.events.emit("nodes:change", node); } - validateNode(user); + + return keepNode; + }); + + // Check if users are changed + if (editing_config_node.users.length !== newUsers.length) { + editState.changes.users = editing_config_node.users; + editState.changed = true; + editing_config_node.users = newUsers; } } - RED.nodes.dirty(true); - RED.view.redraw(true); - if (!configAdding) { - RED.events.emit("editor:save",editing_config_node); - RED.events.emit("nodes:change",editing_config_node); + + if (editState.changed) { + // Set the congig node as changed + editing_config_node.changed = true; } + + // Now, validate the config node + validateNode(editing_config_node); + + // And validate nodes using this config node too + const validatedNodes = new Set(); + const userStack = editing_config_node.users.slice(); + + validatedNodes.add(editing_config_node.id); + while (userStack.length) { + const node = userStack.pop(); + if (!validatedNodes.has(node.id)) { + validatedNodes.add(node.id); + if (node.users) { + userStack.push(...node.users); + } + validateNode(node); + } + } + + let historyEvent = { + t: "edit", + node: editing_config_node, + changes: editState.changes, + changed: wasChanged, + dirty: RED.nodes.dirty() + }; + + if (historyEvents.length) { + // Need a multi events + historyEvent = { + t: "multi", + events: [historyEvent].concat(historyEvents), + dirty: historyEvent.dirty + }; + } + + if (!adding) { + // This event is triggered when the edit box is saved, + // regardless of whether there are any modifications. + RED.events.emit("editor:save", editing_config_node); + } + + if (editState.changed) { + if (adding) { + RED.history.push({ t: "add", nodes: [editing_config_node.id], dirty: RED.nodes.dirty() }); + // Add the new config node and trigger the `nodes:add` event + RED.nodes.add(editing_config_node); + } else { + RED.history.push(historyEvent); + RED.events.emit("nodes:change", editing_config_node); + } + + RED.nodes.dirty(true); + RED.view.redraw(true); + } + RED.tray.close(function() { var filter = null; // when editing a config via subflow edit panel, the `configProperty` will not From ed4b98b5982720ea005bc1fcf433d01ccb2bddc6 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Wed, 26 Jun 2024 09:22:01 +0200 Subject: [PATCH 02/87] Fix adding users to history if multiple props modified --- .../editor-client/src/js/ui/editor.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index c6a448dd3..1bdd134fb 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -1534,6 +1534,7 @@ RED.editor = (function() { if (scope) { const newUsers = editing_config_node.users.filter(function (node) { let keepNode = false; + let nodeModified = null; for (const d in node._def.defaults) { if (node._def.defaults.hasOwnProperty(d)) { @@ -1544,15 +1545,19 @@ RED.editor = (function() { // this config node in the correct scope. keepNode = true; } else { - historyEvents.push({ - t: "edit", - node: node, - changes: { [d]: node[d] }, - changed: node.changed, - dirty: node.dirty - }); + if (!nodeModified) { + nodeModified = { + t: "edit", + node: node, + changes: { [d]: node[d] }, + changed: node.changed, + dirty: node.dirty + }; + } else { + nodeModified.changes[d] = node[d]; + } - // Remove the reference to the config + // Remove the reference to the config node node[d] = ""; } } @@ -1560,6 +1565,11 @@ RED.editor = (function() { } } + // Add the node modified to the history + if (nodeModified) { + historyEvents.push(nodeModified); + } + // Mark as changed and revalidate this node if (!keepNode) { node.changed = true; From 7950ee124150652f58a643dd675007738456a379 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:16:59 +0200 Subject: [PATCH 03/87] Fix updating the subflow name during a copy --- .../@node-red/editor-client/src/js/nodes.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 2a7b440f2..2874a024e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1032,23 +1032,31 @@ RED.nodes = (function() { return {nodes:removedNodes,links:removedLinks, groups: removedGroups, junctions: removedJunctions}; } + /** + * Add a Subflow to the Workspace + * + * @param {object} sf The Subflow to add. + * @param {boolean|undefined} createNewIds Whether to update the name. + */ function addSubflow(sf, createNewIds) { if (createNewIds) { - var subflowNames = Object.keys(subflows).map(function(sfid) { - return subflows[sfid].name; - }); + // Update the Subflow name to highlight that this is a copy + const subflowNames = Object.keys(subflows).map(function (sfid) { + return subflows[sfid].name || ""; + }).sort(); - subflowNames.sort(); - var copyNumber = 1; - var subflowName = sf.name; + let copyNumber = 1; + let subflowName = sf.name; subflowNames.forEach(function(name) { if (subflowName == name) { + subflowName = sf.name + " (" + copyNumber + ")"; copyNumber++; - subflowName = sf.name+" ("+copyNumber+")"; } }); + sf.name = subflowName; } + subflows[sf.id] = sf; allNodes.addTab(sf.id); linkTabMap[sf.id] = []; @@ -2023,6 +2031,8 @@ RED.nodes = (function() { if (matchingSubflow) { subflow_denylist[n.id] = matchingSubflow; } else { + const oldId = n.id; + subflow_map[n.id] = n; if (createNewIds || options.importMap[n.id] === "copy") { nid = getID(); @@ -2050,7 +2060,7 @@ RED.nodes = (function() { n.status.id = getID(); } new_subflows.push(n); - addSubflow(n,createNewIds || options.importMap[n.id] === "copy"); + addSubflow(n,createNewIds || options.importMap[oldId] === "copy"); } } } From bea08706cc10558012874d45120fc44bb0fe13c6 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Wed, 26 Jun 2024 22:51:08 +0200 Subject: [PATCH 04/87] Handle the import of an incomplete Subflow --- .../@node-red/editor-client/src/js/nodes.js | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 2a7b440f2..6b839714f 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1049,6 +1049,9 @@ RED.nodes = (function() { }); sf.name = subflowName; } + + sf.instances = []; + subflows[sf.id] = sf; allNodes.addTab(sf.id); linkTabMap[sf.id] = []; @@ -1101,7 +1104,7 @@ RED.nodes = (function() { module: "node-red" } }); - sf.instances = []; + sf._def = RED.nodes.getType("subflow:"+sf.id); RED.events.emit("subflows:add",sf); } @@ -1743,7 +1746,8 @@ RED.nodes = (function() { // Remove the old subflow definition - but leave the instances in place var removalResult = RED.subflow.removeSubflow(n.id, true); // Create the list of nodes for the new subflow def - var subflowNodes = [n].concat(zMap[n.id]); + // Need to sort the list in order to remove missing nodes + var subflowNodes = [n].concat(zMap[n.id]).filter((s) => !!s); // Import the new subflow - no clashes should occur as we've removed // the old version var result = importNodes(subflowNodes); @@ -2170,7 +2174,7 @@ RED.nodes = (function() { x:parseFloat(n.x || 0), y:parseFloat(n.y || 0), z:n.z, - type:0, + type: n.type, info: n.info, changed:false, _config:{} @@ -2261,6 +2265,15 @@ RED.nodes = (function() { outputs: n.outputs|| (n.wires && n.wires.length) || 0, set: registry.getNodeSet("node-red/unknown") } + var orig = {}; + for (var p in n) { + if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") { + orig[p] = n[p]; + } + } + node._orig = orig; + node.name = n.type; + node.type = "unknown"; } else { if (subflow_denylist[parentId] || createNewIds || options.importMap[n.id] === "copy") { parentId = subflow.id; @@ -2441,9 +2454,11 @@ RED.nodes = (function() { n = new_subflows[i]; n.in.forEach(function(input) { input.wires.forEach(function(wire) { - var link = {source:input, sourcePort:0, target:node_map[wire.id]}; - addLink(link); - new_links.push(link); + if (node_map.hasOwnProperty(wire.id)) { + var link = {source:input, sourcePort:0, target:node_map[wire.id]}; + addLink(link); + new_links.push(link); + } }); delete input.wires; }); @@ -2452,11 +2467,13 @@ RED.nodes = (function() { var link; if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) { link = {source:n.in[wire.port], sourcePort:wire.port,target:output}; - } else { + } else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) { link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:output}; } - addLink(link); - new_links.push(link); + if (link) { + addLink(link); + new_links.push(link); + } }); delete output.wires; }); @@ -2465,11 +2482,13 @@ RED.nodes = (function() { var link; if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) { link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status}; - } else { + } else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) { link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status}; } - addLink(link); - new_links.push(link); + if (link) { + addLink(link); + new_links.push(link); + } }); delete n.status.wires; } From 375fa9da647307c781f76019ff3b464174525857 Mon Sep 17 00:00:00 2001 From: Mauricio Bonani Date: Fri, 28 Jun 2024 09:51:23 -0400 Subject: [PATCH 05/87] Use a more subtle border on the header --- .../node_modules/@node-red/editor-client/src/sass/colors.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss index f0a69e00a..869211cc6 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss @@ -259,7 +259,7 @@ $deploy-button-background-disabled-hover: #555; $header-background: #000; $header-button-background-active: #121212; -$header-accent: #d41313; +$header-accent: #8c101c; $header-menu-color: #eee; $header-menu-color-disabled: #666; $header-menu-heading-color: #fff; From 6503498f0a97fbdc417735163c8f5057dd354cf8 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Sat, 29 Jun 2024 18:14:54 +0100 Subject: [PATCH 06/87] Clean up orphaned editors closes #4820 --- .../src/js/ui/editors/code-editors/monaco.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js index cbeecd512..b9f586944 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editors/monaco.js @@ -165,7 +165,13 @@ RED.editor.codeEditor.monaco = (function() { //Handles orphaned models //ensure loaded models that are not explicitly destroyed by a call to .destroy() are disposed RED.events.on("editor:close",function() { - let models = window.monaco ? monaco.editor.getModels() : null; + if (!window.monaco) { return; } + const editors = window.monaco.editor.getEditors() + const orphanEditors = editors.filter(editor => editor && !document.body.contains(editor.getDomNode())) + orphanEditors.forEach(editor => { + editor.dispose(); + }); + let models = monaco.editor.getModels() if(models && models.length) { console.warn("Cleaning up monaco models left behind. Any node that calls createEditor() should call .destroy().") for (let index = 0; index < models.length; index++) { @@ -1124,6 +1130,7 @@ RED.editor.codeEditor.monaco = (function() { $(el).remove(); $(toolbarRow).remove(); + ed.dispose(); } ed.resize = function resize() { From 8085eda431925de5c362b51d1942be48e7a5579f Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 30 Jun 2024 22:27:38 +0200 Subject: [PATCH 07/87] Add missing French translations from v4 --- .../@node-red/editor-client/locales/fr/editor.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 bacd5b70f..3e5889442 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 @@ -27,7 +27,8 @@ "lock": "Verrouiller", "unlock": "Déverrouiller", "locked": "Verrouillé", - "unlocked": "Déverrouillé" + "unlocked": "Déverrouillé", + "format": "Format" }, "type": { "string": "chaîne de caractères", @@ -372,6 +373,7 @@ "deleted": "supprimé", "flowDeleted": "flux supprimé", "flowAdded": "flux ajouté", + "moved": "déplacé", "movedTo": "déplacé vers __id__", "movedFrom": "déplacé depuis __id__" }, From 16570410a5a557f32c319f8821f1086079624032 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 1 Jul 2024 09:43:42 +0200 Subject: [PATCH 08/87] Improve French translations --- .../editor-client/locales/fr/editor.json | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) 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 3e5889442..950266007 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 @@ -55,10 +55,10 @@ "workspace": { "defaultName": "Flux __number__", "editFlow": "Modifier le flux : __name__", - "confirmDelete": "Confirmation de la suppression", - "delete": "Etes-vous sûr de vouloir supprimer '__label__'?", - "dropFlowHere": "Déposer le flux ici", - "dropImageHere": "Déposer l'image ici", + "confirmDelete": "Confirmer la suppression", + "delete": "Êtes-vous sûr de vouloir supprimer '__label__' ?", + "dropFlowHere": "Lâchez le flux ici", + "dropImageHere": "Lâchez l'image ici", "addFlow": "Ajouter un flux", "addFlowToRight": "Ajouter un flux à droite", "closeFlow": "Fermer le flux", @@ -75,7 +75,7 @@ "enabled": "Activé", "disabled": "Désactivé", "info": "Description", - "selectNodes": "Cliquer sur les noeuds pour sélectionner", + "selectNodes": "Cliquer pour sélectionner", "enableFlow": "Activer le flux", "disableFlow": "Désactiver le flux", "lockFlow": "Verrouiller le flux", @@ -99,7 +99,7 @@ "rtl": "De droite à gauche", "auto": "Contextuel", "language": "Langue", - "browserDefault": "Navigateur par défaut" + "browserDefault": "Par défaut du Navigateur" }, "sidebar": { "show": "Afficher la barre latérale" @@ -135,7 +135,7 @@ "disableSelectedNodes": "Désactiver les noeuds sélectionnés", "showSelectedNodeLabels": "Afficher les étiquettes des noeuds sélectionnés", "hideSelectedNodeLabels": "Masquer les étiquettes des noeuds sélectionnés", - "showWelcomeTours": "Afficher les visites guidées pour les nouvelles versions", + "showWelcomeTours": "Afficher les visites guidées des nouvelles versions", "help": "Site web de Node-RED", "projects": "Projets", "projects-new": "Nouveau projet", @@ -144,7 +144,7 @@ "showNodeLabelDefault": "Afficher l'étiquette des noeuds nouvellement ajoutés", "codeEditor": "Éditeur de code", "groups": "Groupes", - "groupSelection": "Grouper cette sélection", + "groupSelection": "Grouper la sélection", "ungroupSelection": "Dégrouper la sélection", "groupMergeSelection": "Fusionner la sélection", "groupRemoveSelection": "Supprimer du groupe", @@ -156,7 +156,7 @@ "alignMiddle": "Aligner au milieu", "alignBottom": "Aligner en bas", "distributeHorizontally": "Répartir horizontalement", - "distributeVertically": "Distribuer verticalement", + "distributeVertically": "Répartir verticalement", "moveToBack": "Déplacer vers l'arrière", "moveToFront": "Déplacer vers l'avant", "moveBackwards": "Reculer", @@ -164,21 +164,21 @@ } }, "actions": { - "toggle-navigator": "Basculer de navigateur", - "zoom-out": "Dézoomer", - "zoom-reset": "Réinitialiser le zoom", + "toggle-navigator": "Basculer l'affichage du navigateur", + "zoom-out": "Réduire", + "zoom-reset": "Réinitialiser", "zoom-in": "Agrandir", "search-flows": "Rechercher le flux", "search-prev": "Précédent", "search-next": "Suivant", - "search-counter": "\"__term__\" __result__ de __count__" + "search-counter": "\"__term__\" __result__ sur __count__" }, "user": { "loggedInAs": "Connecté en tant que __name__", "username": "Nom d'utilisateur", "password": "Mot de passe", - "login": "Connexion", - "loginFailed": "Échec de la connexion", + "login": "Se connecter", + "loginFailed": "Échec de connexion", "notAuthorized": "Pas autorisé", "errors": { "settings": "Vous devez être connecté pour accéder aux paramètres", @@ -194,16 +194,16 @@ "warning": "Attention : __message__", "warnings": { "undeployedChanges": "Le noeud a des modifications non déployées", - "nodeActionDisabled": "Actions de noeud désactivées", - "nodeActionDisabledSubflow": "Actions de noeud désactivées dans le sous-flux", + "nodeActionDisabled": "Les actions du noeud sont désactivées", + "nodeActionDisabledSubflow": "Les actions de noeud sont désactivées à l'intérieur du sous-flux", "missing-types": "

Flux arrêtés en raison de types de noeuds manquants.

", "missing-modules": "

Flux arrêtés en raison de modules manquants.

", - "safe-mode": "

Flux arrêtés en mode sans échec.

Vous pouvez modifier vos flux et déployer les changements pour redémarrer.

", + "safe-mode": "

Flux arrêtés en mode sans échec.

Vous pouvez modifier vos flux et déployer ensuite les changements afin de démarrer vos flux.

", "restartRequired": "Node-RED doit être redémarré pour mettre à jour les modules", - "credentials_load_failed": "

Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

", - "credentials_load_failed_reset": "

Les informations d'identification n'ont pas pu être déchiffrées

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification de flux existantes seront perdues.

", + "credentials_load_failed": "

Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.

Le fichier d'informations d'identification du flux est chiffré mais la clé de chiffrement du projet est manquante ou invalide.

", + "credentials_load_failed_reset": "

Les informations d'identification n'ont pas pu être déchiffrées

Le fichier d'informations d'identification du flux est chiffré mais la clé de chiffrement du projet est manquante ou invalide.

Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification des flux existants seront perdues.

", "missing_flow_file": "

Fichier contenant les flux introuvable.

Le projet n'est pas configuré avec un fichier de flux.

", - "missing_package_file": "

Fichier de paquetage du projet introuvable.

Il manque au projet un fichier package.json.

", + "missing_package_file": "

Fichier de paquetage du projet introuvable.

Il manque au projet le fichier package.json.

", "project_empty": "

Le projet est vide.

Voulez-vous créer un ensemble de fichiers de projet par défaut ?
Sinon, vous devrez ajouter manuellement des fichiers au projet (en dehors de l'éditeur).

", "project_not_found": "

Le projet '__project__' est introuvable.

", "git_merge_conflict": "

La fusion automatique des modifications a échoué.

Corriger les conflits non fusionnés, puis valider le résultat.

" @@ -220,7 +220,7 @@ }, "project": { "change-branch": "Changer pour une branche locale '__project__'", - "merge-abort": "Git fusion abandonnée", + "merge-abort": "Fusion Git abandonnée", "loaded": "Projet '__project__' chargé", "updated": "Projet '__project__' mis à jour", "pull": "Projet '__project__' rechargé", @@ -353,7 +353,7 @@ "backgroundUpdate": "Les flux sur le serveur ont été mis à jour.", "conflictChecking": "Vérifier si les modifications peuvent être fusionnées automatiquement", "conflictAutoMerge": "Les modifications n'incluent aucun conflit et peuvent être fusionnées automatiquement.", - "conflictManualMerge": "Les changements incluent des conflits qui doivent être résolus avant de pouvoir être déployés.", + "conflictManualMerge": "Les modifications incluent des conflits qui doivent être résolus avant de pouvoir être déployées.", "plusNMore": "+ __count__ en plus" } }, @@ -380,10 +380,10 @@ "nodeCount": "__count__ noeud", "nodeCount_plural": "__count__ noeuds", "local": "Changements locaux", - "remote": "Modifications à distance", + "remote": "Changements distants", "reviewChanges": "Examiner les modifications", "noBinaryFileShowed": "Impossible d'afficher le contenu du fichier binaire", - "viewCommitDiff": "Afficher les modifications de validation", + "viewCommitDiff": "Afficher les modifications de la validation", "compareChanges": "Comparer les modifications", "saveConflict": "Enregistrer la résolution des conflits", "conflictHeader": "__resolved__ sur __unresolved__ conflit(s) résolu(s)", @@ -397,9 +397,9 @@ "edit": "Modifier le modèle du sous-flux", "subflowInstances": "Il existe __count__ instance de ce modèle de sous-flux", "subflowInstances_plural": "Il existe __count__ instances de ce modèle de sous-flux", - "editSubflowProperties": "modifier les propriétés", - "input": "Entrées:", - "output": "Sorties:", + "editSubflowProperties": "Modifier les propriétés", + "input": "Entrées :", + "output": "Sorties :", "status": "Statut du noeud", "deleteSubflow": "Supprimer le sous-flux", "confirmDelete": "Voulez-vous vraiment supprimer ce sous-flux ?", @@ -413,7 +413,7 @@ "version": "Version", "versionPlaceholder": "x.y.z", "keys": "Mots clés", - "keysPlaceholder": "Mots clés séparés par des virgules", + "keysPlaceholder": "Mots clés séparés par une virgule", "author": "Auteur", "authorPlaceholder": "Votre nom ", "desc": "Description", @@ -470,7 +470,7 @@ "select": "sélection", "checkbox": "case à cocher", "spinner": "valeurs à défiler", - "none": "aucune", + "none": "aucun", "hidden": "masquer la propriété" }, "types": { @@ -498,7 +498,7 @@ "max": "Maximum" }, "errors": { - "scopeChange": "La modification de la portée la rendra indisponible pour les noeuds d'autres flux qui l'utilisent", + "scopeChange": "La modification de la portée rendra indisponible ce noeud de configuration aux noeuds d'autres flux qui l'utilisent", "invalidProperties": "Propriétés invalides :", "credentialLoadFailed": "Échec du chargement des identifiants du noeud" } @@ -512,7 +512,7 @@ "unassigned": "Non attribué", "global": "Global", "workspace": "Espace de travail", - "editor": "Boîte de dialogue d'édition", + "editor": "Boîte d'édition", "selectAll": "Tout sélectionner", "selectNone": "Ne rien sélectionner", "selectAllConnected": "Sélectionner tous les éléments connectés", @@ -543,7 +543,7 @@ "openLibrary": "Ouvrir la bibliothèque...", "saveToLibrary": "Enregistrer dans la bibliothèque...", "typeLibrary": "__type__ bibliothèque", - "unnamedType": "Innomé __type__", + "unnamedType": "Sans nom __type__", "exportedToLibrary": "Noeuds exportés vers la bibliothèque", "dialogSaveOverwrite": "Une __libraryType__ appelée __libraryName__ existe déjà. Écraser ?", "invalidFilename": "Nom de fichier non valide", @@ -560,7 +560,7 @@ "noInfo": "Pas d'information disponible", "filter": "Rechercher le noeud", "search": "Rechercher les modules", - "addCategory": "Ajouter un nouveau...", + "addCategory": "Ajouter une nouvelle...", "label": { "subflows": "Sous-flux", "network": "Réseau", @@ -640,7 +640,7 @@ "sortAZ": "A-Z", "sortRecent": "Récent", "more": "+ __count__ en plus", - "upload": "Charger le fichier tgz du module", + "upload": "Charger le fichier .tgz du module", "refresh": "Actualiser la liste des modules", "errors": { "catalogLoadFailed": "

Échec du chargement du catalogue de noeuds.

Vérifier la console du navigateur pour plus d'informations

", @@ -653,7 +653,7 @@ }, "confirm": { "install": { - "body": "

Installation de '__module__'

Avant l'installation, veuiller lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.

", + "body": "

Installation de '__module__'

Avant l'installation, veuillez lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.

", "title": "Installer les noeuds" }, "remove": { @@ -668,7 +668,7 @@ "title": "Mettre à jour les noeuds" }, "cannotUpdate": { - "body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.

Veuiller vous référer à la documentation pour savoir comment mettre à jour ce noeud." + "body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.

Veuillez vous référer à la documentation pour savoir comment mettre à jour ce noeud." }, "button": { "review": "Ouvrir la documentation", @@ -710,8 +710,8 @@ "nodeHelp": "Aide sur les noeuds", "none": "Aucun", "arrayItems": "__count__ éléments", - "showTips": "Vous pouvez ouvrir les astuces à partir du panneau des paramètres", - "outline": "Plan", + "showTips": "Vous pouvez afficher les astuces à partir du panneau des paramètres", + "outline": "Contour", "empty": "Vide", "globalConfig": "Noeuds de configuration globale", "triggerAction": "Déclencher une action", @@ -724,7 +724,7 @@ "help": { "name": "Aide", "label": "Aide", - "search": "Aide à la recherche", + "search": "Rechercher l'aide", "nodeHelp": "Aide sur les noeuds", "showHelp": "Afficher l'aide", "showInOutline": "Afficher dans les grandes lignes", @@ -803,7 +803,7 @@ "branches": "Branches", "noBranches": "Pas de branche", "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la branche locale '__name__' ? Ça ne peut pas être annulé.", - "unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Etes-vous sûr de vouloir la supprimer?", + "unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Êtes-vous sûr de vouloir la supprimer?", "deleteUnmergedBranch": "Supprimer la branche non fusionnée", "gitRemotes": "Git distant", "addRemote": "Ajout distant", @@ -847,17 +847,17 @@ "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la clé SSH __name__ ? Ça ne peut pas être annulé." }, "versionControl": { - "unstagedChanges": "Abandon des changements", - "stagedChanges": "Changement mis en place", - "unstageChange": "Ne pas mettre en place le changement", - "stageChange": "Mettre en place le changement", - "unstageAllChange": "Ne pas mettre en place tous les changements", - "stageAllChange": "Mettre en place tous les changements", + "unstagedChanges": "Changements non indexés", + "stagedChanges": "Changements indexés", + "unstageChange": "Annuler l'indexation des changements", + "stageChange": "Indexer les changements", + "unstageAllChange": "Annuler l'indexation de tous les changements", + "stageAllChange": "Indexer tous les changements", "commitChanges": "Valider les changements", "resolveConflicts": "Résoudre les conflits", "head": "En-tête", - "staged": "Mis en place", - "unstaged": "Non mis en place", + "staged": "Indexé", + "unstaged": "Non indexé", "local": "Local", "remote": "Distant", "revert": "Voulez-vous vraiment annuler les modifications apportées à '__file__' ? Ça ne peut pas être annulé.", @@ -891,11 +891,11 @@ "pushFailed": "L'envoi a échoué car la branche a des validations plus récentes. Tirer et fusionner d'abord, puis envoyer à nouveau.", "push": "Envoyer", "pull": "Tirer", - "unablePull": "

Impossible d'extraire les modifications à distance ; vos modifications locales non mises en place seraient écrasées.

Valider vos modifications et réessayer.

", - "showUnstagedChanges": "Afficher les modifications non mise en place", + "unablePull": "

Impossible d'extraire les modifications à distance; vos modifications locales non mises en place seraient écrasées.

Valider vos modifications et réessayer.

", + "showUnstagedChanges": "Afficher les modifications non indexées", "connectionFailed": "Impossible de se connecter au référentiel distant: ", "pullUnrelatedHistory": "

Le réferentiel distant a un historique de validations sans rapport.

Êtes-vous sûr de vouloir extraire les modifications dans votre référentiel local ?

", - "pullChanges": "Tirer les changements", + "pullChanges": "Tirer les changements distants", "history": "Historique", "projectHistory": "Historique du projet", "daysAgo": "il y a __count__ jour", @@ -976,7 +976,7 @@ "result": "Résultat", "format": "Format", "compatMode": "Mode de compatibilité activé", - "compatModeDesc": "

Mode de compatibilité JSONata

L'expression actuelle semble toujours faire référence à msg et sera donc évaluée en mode de compatibilité. Veuiller mettre à jour l'expression pour ne pas utiliser msg car ce mode sera supprimé à l'avenir.

Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet msg. Par exemple, msg.payload serait utilisé pour accéder à la charge utile.

Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement charge utile.

", + "compatModeDesc": "

Mode de compatibilité JSONata

L'expression actuelle semble toujours faire référence à msg et sera donc évaluée en mode de compatibilité. Veuillez mettre à jour l'expression pour ne pas utiliser msg car ce mode sera supprimé à l'avenir.

Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet msg. Par exemple, msg.payload serait utilisé pour accéder à la charge utile.

Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement charge utile.

", "noMatch": "Aucun résultat correspondant", "errors": { "invalid-expr": "Expression JSONata non valide :\n __message__", @@ -999,7 +999,7 @@ }, "jsonEditor": { "title": "Éditeur JSON", - "format": "Format JSON", + "format": "Formatter JSON", "rawMode": "Modifier JSON", "uiMode": "Afficher l'éditeur", "rawMode-readonly": "JSON", @@ -1018,7 +1018,7 @@ "markdownEditor": { "title": "Éditeur Markdown", "expand": "Développer", - "format": "Formaté avec Markdown", + "format": "Formatter avec Markdown", "heading1": "Rubrique 1", "heading2": "Rubrique 2", "heading3": "Rubrique 3", @@ -1092,7 +1092,7 @@ "credential-key": "Clé de chiffrement des identifiants", "cant-get-ssh-key": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", "already-exists2": "Existe déjà", - "git-error": "Erreur git", + "git-error": "Erreur Git", "connection-failed": "La connexion a échoué", "not-git-repo": "Ce n'est pas un dépôt Git", "repo-not-found": "Référentiel introuvable" @@ -1106,7 +1106,7 @@ "credentials-file": "Fichier d'identifiants" }, "encryption-config": { - "setup": "Configuration du chiffrage de votre fichier d'informations d'identification", + "setup": "Configuration du chiffrement de votre fichier d'informations d'identification", "desc0": "Votre fichier d'informations d'identification de flux peut être chiffré pour sécuriser son contenu.", "desc1": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.", "desc2": "Votre fichier d'identifiants de flux n'est actuellement pas chiffré.", @@ -1163,9 +1163,9 @@ "add-ssh-key": "Ajouter une clé ssh", "credentials-encryption-key": "Clé de chiffrement des identifiants", "already-exists-2": "Existe déjà", - "git-error": "Erreur git", + "git-error": "Erreur Git", "con-failed": "La connexion a échoué", - "not-git": "Ce n'est pas un dépôt git", + "not-git": "Ce n'est pas un dépôt Git", "no-resource": "Référentiel introuvable", "cant-get-ssh-key-path": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", "unexpected_error": "Erreur inattendue", @@ -1203,7 +1203,7 @@ }, "errors": { "no-username-email": "Votre client Git n'est pas configuré avec un nom d'utilisateur/e-mail.", - "unexpected": "Une erreur inattendue est apparue", + "unexpected": "Une erreur inattendue est survenue", "code": "Code" } }, @@ -1272,7 +1272,7 @@ "list-modified-nodes": "Afficher les flux modifiés", "list-hidden-flows": "Afficher les flux cachés", "list-flows": "Lister les flux", - "list-subflows": "Liste les sous-flux", + "list-subflows": "Lister les sous-flux", "go-to-previous-location": "Aller à l'emplacement précédent", "go-to-next-location": "Aller à l'emplacement suivant", "copy-selection-to-internal-clipboard": "Copier la sélection dans le presse-papiers", @@ -1332,8 +1332,8 @@ "align-selection-to-bottom": "Aligner la sélection vers le bas", "align-selection-to-middle": "Aligner la sélection au centre verticalement", "align-selection-to-center": "Aligner la sélection au centre horizontalement", - "distribute-selection-horizontally": "Distribuer la sélection horizontalement", - "distribute-selection-vertical": "Distribuer la sélection verticalement", + "distribute-selection-horizontally": "Répartir la sélection horizontalement", + "distribute-selection-vertical": "Répartir la sélection verticalement", "wire-series-of-nodes": "Connecter les noeuds en série", "wire-node-to-multiple": "Connecter les noeuds à plusieurs", "wire-multiple-to-node": "Connecter plusieurs au noeud", From c113b3de13e14e1e0bfea631a028e930bd76de3b Mon Sep 17 00:00:00 2001 From: Mauricio Bonani Date: Mon, 1 Jul 2024 06:18:17 -0400 Subject: [PATCH 09/87] Use a not-so-dark color for the header border --- .../node_modules/@node-red/editor-client/src/sass/colors.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss index 869211cc6..8e03b7f0d 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss @@ -259,7 +259,7 @@ $deploy-button-background-disabled-hover: #555; $header-background: #000; $header-button-background-active: #121212; -$header-accent: #8c101c; +$header-accent: #C02020; $header-menu-color: #eee; $header-menu-color-disabled: #666; $header-menu-heading-color: #fff; From c0f15813700af5b44d34530548912f0e2aeb4cab Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 1 Jul 2024 16:38:28 +0100 Subject: [PATCH 10/87] Bump for 4.0.2 --- CHANGELOG.md | 15 +++++++++++++++ package.json | 2 +- .../@node-red/editor-api/package.json | 6 +++--- .../@node-red/editor-client/package.json | 2 +- .../node_modules/@node-red/nodes/package.json | 2 +- .../node_modules/@node-red/registry/package.json | 4 ++-- .../node_modules/@node-red/runtime/package.json | 6 +++--- packages/node_modules/@node-red/util/package.json | 2 +- packages/node_modules/node-red/package.json | 10 +++++----- 9 files changed, 32 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15e35cd8b..e4ebd3087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +#### 4.0.2: Maintenance Release + +Editor + + - Use a more subtle border on the header (#4818) @bonanitech + - Improve the editor's French translations (#4824) @GogoVega + - Clean up orphaned editors (#4821) @Steve-Mcl + - Fix node validation if the property is not required (#4812) @GogoVega + - Ensure mermaid.min.js is cached properly between loads of the editor (#4817) @knolleary + +Runtime + + - Allow auth cookie name to be customised (#4815) @knolleary + - Guard against undefined sessions in multiplayer (#4816) @knolleary + #### 4.0.1: Maintenance Release Editor diff --git a/package.json b/package.json index e7e988f75..f705e0752 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.1", + "version": "4.0.2", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 02c261e22..792b5b67f 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/util": "4.0.1", - "@node-red/editor-client": "4.0.1", + "@node-red/util": "4.0.2", + "@node-red/editor-client": "4.0.2", "bcryptjs": "2.4.3", "body-parser": "1.20.2", "clone": "2.1.2", diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index d540bbe51..932afb7ac 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index 0d2372866..e8e384948 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/nodes", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 821e50d69..1d54f76d8 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/registry", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,7 +16,7 @@ } ], "dependencies": { - "@node-red/util": "4.0.1", + "@node-red/util": "4.0.2", "clone": "2.1.2", "fs-extra": "11.2.0", "semver": "7.5.4", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 68f0cef52..d6a7a0009 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/runtime", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/registry": "4.0.1", - "@node-red/util": "4.0.1", + "@node-red/registry": "4.0.2", + "@node-red/util": "4.0.2", "async-mutex": "0.5.0", "clone": "2.1.2", "express": "4.19.2", diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 34a4765c5..1f25923bb 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/util", - "version": "4.0.1", + "version": "4.0.2", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index 9cf0615f6..93c90f807 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.1", + "version": "4.0.2", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "flow" ], "dependencies": { - "@node-red/editor-api": "4.0.1", - "@node-red/runtime": "4.0.1", - "@node-red/util": "4.0.1", - "@node-red/nodes": "4.0.1", + "@node-red/editor-api": "4.0.2", + "@node-red/runtime": "4.0.2", + "@node-red/util": "4.0.2", + "@node-red/nodes": "4.0.2", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", From bda9f249bc2243de7eed14aef8b4f22b82a4ff7f Mon Sep 17 00:00:00 2001 From: Gauthier Dandele <92022724+GogoVega@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:43:39 +0200 Subject: [PATCH 11/87] Update packages/node_modules/@node-red/editor-client/src/js/nodes.js Co-authored-by: Nick O'Leary --- packages/node_modules/@node-red/editor-client/src/js/nodes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 2874a024e..b940bfc32 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1043,7 +1043,8 @@ RED.nodes = (function() { // Update the Subflow name to highlight that this is a copy const subflowNames = Object.keys(subflows).map(function (sfid) { return subflows[sfid].name || ""; - }).sort(); + }) + subflowNames.sort() let copyNumber = 1; let subflowName = sf.name; From 8aec038c2453411fb730debc4a8c9c8adade59a3 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:59:28 +0200 Subject: [PATCH 12/87] Remove duplicate type definition --- packages/node_modules/@node-red/editor-client/src/js/nodes.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 6b839714f..c24da629e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2235,7 +2235,6 @@ RED.nodes = (function() { } } } - node.type = n.type; node._def = def; if (node.type === "group") { node._def = RED.group.def; From 14ac309b6e0c2f38911a182710d6525677cd56b6 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:38:56 +0200 Subject: [PATCH 13/87] Fix menu to enable/disable selection when it's a group --- .../editor-client/src/js/ui/contextMenu.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index dae3f6fa6..60615671e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -32,24 +32,28 @@ RED.contextMenu = (function () { const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g let hasGroup, isAllGroups = true, hasDisabledNode, hasEnabledNode, hasLabeledNode, hasUnlabeledNode; if (hasSelection) { - selection.nodes.forEach(n => { + const nodes = selection.nodes.slice(); + while (nodes.length) { + const n = nodes.shift(); if (n.type === 'group') { hasGroup = true; + nodes.push(...n.nodes); } else { isAllGroups = false; - } - if (n.d) { - hasDisabledNode = true; - } else { - hasEnabledNode = true; + if (n.d) { + hasDisabledNode = true; + } else { + hasEnabledNode = true; + } } if (n.l === undefined || n.l) { hasLabeledNode = true; } else { hasUnlabeledNode = true; } - }); + } } + const offset = $("#red-ui-workspace-chart").offset() let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() From 05c924a9df670843654f43787b1a5af36460b3f2 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 4 Jul 2024 15:09:55 +0100 Subject: [PATCH 14/87] Let batch node terminate "early" if msg.parts set to end of sequence (ie index = count -1). Useful to close at end of files etc. --- .../nodes/core/sequence/19-batch.html | 7 ++++- .../@node-red/nodes/core/sequence/19-batch.js | 8 +++++- .../nodes/locales/en-US/messages.json | 1 + test/nodes/core/sequence/19-batch_spec.js | 27 ++++++++++++++++--- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/sequence/19-batch.html b/packages/node_modules/@node-red/nodes/core/sequence/19-batch.html index 9afb84205..91e6567c5 100644 --- a/packages/node_modules/@node-red/nodes/core/sequence/19-batch.html +++ b/packages/node_modules/@node-red/nodes/core/sequence/19-batch.html @@ -36,6 +36,10 @@ +
+ + +
@@ -45,7 +49,7 @@
- +
@@ -101,6 +105,7 @@ } }, allowEmptySequence: {value:false}, + honourParts: {value:false}, topics: {value:[{topic:""}]} }, inputs:1, diff --git a/packages/node_modules/@node-red/nodes/core/sequence/19-batch.js b/packages/node_modules/@node-red/nodes/core/sequence/19-batch.js index f3f29df6a..5cc97e6a9 100644 --- a/packages/node_modules/@node-red/nodes/core/sequence/19-batch.js +++ b/packages/node_modules/@node-red/nodes/core/sequence/19-batch.js @@ -181,6 +181,8 @@ module.exports = function(RED) { RED.nodes.createNode(this,n); var node = this; var mode = n.mode || "count"; + var eof = false; + node.honourParts = n.honourParts || false; node.pending_count = 0; if (mode === "count") { @@ -201,9 +203,12 @@ module.exports = function(RED) { return; } var queue = node.pending; + if (node.honourParts && msg.hasOwnProperty("parts")) { + if (msg.parts.index + 1 === msg.parts.count) { eof = true; } + } queue.push({msg, send, done}); node.pending_count++; - if (queue.length === count) { + if (queue.length === count || eof === true) { send_msgs(node, queue, is_overlap); for (let i = 0; i < queue.length-overlap; i++) { queue[i].done(); @@ -211,6 +216,7 @@ module.exports = function(RED) { node.pending = (overlap === 0) ? [] : queue.slice(-overlap); node.pending_count = 0; + eof = false; } var max_msgs = max_kept_msgs_count(node); if ((max_msgs > 0) && (node.pending_count > max_msgs)) { 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 560d192c1..37a249567 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 @@ -1112,6 +1112,7 @@ "too-many": "too many pending messages in batch node", "unexpected": "unexpected mode", "no-parts": "no parts property in message", + "honourParts": "Allow msg.parts to also complete batch operation.", "error": { "invalid-count": "Invalid count", "invalid-overlap": "Invalid overlap", diff --git a/test/nodes/core/sequence/19-batch_spec.js b/test/nodes/core/sequence/19-batch_spec.js index 2ebcb8d4d..b4025a3f8 100644 --- a/test/nodes/core/sequence/19-batch_spec.js +++ b/test/nodes/core/sequence/19-batch_spec.js @@ -98,7 +98,7 @@ describe('BATCH node', function() { var n2 = helper.getNode("n2"); check_data(n1, n2, results, done); for(var i = 0; i < 6; i++) { - n1.receive({payload: i}); + n1.receive({payload: i, parts: { count:6, index:i }}); } }); } @@ -168,6 +168,25 @@ describe('BATCH node', function() { check_count(flow, results, done); }); + it('should create seq. with count (more sent than count)', function(done) { + var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 4, overlap: 0, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]}, + {id:"n2", type:"helper"}]; + var results = [ + [0, 1, 2, 3] + ]; + check_count(flow, results, done); + }); + + it('should create seq. with count and terminate early if parts honoured', function(done) { + var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 4, overlap: 0, interval: 10, allowEmptySequence:false, honourParts:true, topics: [], wires:[["n2"]]}, + {id:"n2", type:"helper"}]; + var results = [ + [0, 1, 2, 3], + [4, 5] + ]; + check_count(flow, results, done); + }); + it('should create seq. with count and overlap', function(done) { var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 3, overlap: 2, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]}, {id:"n2", type:"helper"}]; @@ -455,7 +474,7 @@ describe('BATCH node', function() { function mapiDoneTestHelper(done, mode, count, overlap, interval, allowEmptySequence, msgAndTimings) { const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js"); const catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js"); - const flow = [{id:"batchNode1", type:"batch", name: "BatchNode", mode, count, overlap, interval, + const flow = [{id:"batchNode1", type:"batch", name: "BatchNode", mode, count, overlap, interval, allowEmptySequence, topics: [{topic: "TA"}], wires:[[]]}, {id:"completeNode1",type:"complete",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]}, {id:"catchNode1", type:"catch",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]}, @@ -482,13 +501,13 @@ describe('BATCH node', function() { } it('should call done() when message is sent (mode: count)', function(done) { - mapiDoneTestHelper(done, "count", 2, 0, 2, false, [ + mapiDoneTestHelper(done, "count", 2, 0, 2, false, [ { msg: {payload: 0}, delay: 0, avr: 0, var: 100}, { msg: {payload: 1}, delay: 0, avr: 0, var: 100} ]); }); it('should call done() when reset (mode: count)', function(done) { - mapiDoneTestHelper(done, "count", 2, 0, 2, false, [ + mapiDoneTestHelper(done, "count", 2, 0, 2, false, [ { msg: {payload: 0}, delay: 0, avr: 200, var: 100}, { msg: {payload: 1, reset:true}, delay: 200, avr: 200, var: 100} ]); From ff35c46d5d6907abec79f8db8da3c800d561dc38 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Tue, 16 Jul 2024 14:37:16 +0100 Subject: [PATCH 15/87] Fix unintentianal Capitalisation in Split node to close #4832 --- .../nodes/core/sequence/17-split.html | 2 +- .../@node-red/nodes/locales/de/messages.json | 1 + .../nodes/locales/en-US/messages.json | 3 ++- .../@node-red/nodes/locales/ja/messages.json | 1 + .../nodes/locales/pt-BR/messages.json | 23 ++++++++++--------- .../@node-red/nodes/locales/ru/messages.json | 1 + .../nodes/locales/zh-CN/messages.json | 1 + .../nodes/locales/zh-TW/messages.json | 1 + 8 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/sequence/17-split.html b/packages/node_modules/@node-red/nodes/core/sequence/17-split.html index d19be77f5..f1237231f 100644 --- a/packages/node_modules/@node-red/nodes/core/sequence/17-split.html +++ b/packages/node_modules/@node-red/nodes/core/sequence/17-split.html @@ -21,7 +21,7 @@
- +
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 051d65f47..a51e504cf 100644 --- a/packages/node_modules/@node-red/nodes/locales/de/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json @@ -912,6 +912,7 @@ "objectSend": "Sende eine Nachricht für jedes Schlüssel/Wert-Paar", "strBuff": "string / buffer", "array": "array", + "splitThe": "Split", "splitUsing": "Aufteilung", "splitLength": "feste Längen von", "stream": "Als Nachrichtenstrom behandeln (Streaming-Modus)", 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 1c0ec6090..598e3536a 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 @@ -1011,12 +1011,13 @@ "tip": "Tip: The filename should be an absolute path, otherwise it will be relative to the working directory of the Node-RED process." }, "split": { - "split": "Split", + "split": "split", "intro": "Split msg.payload based on type:", "object": "Object", "objectSend": "Send a message for each key/value pair", "strBuff": "String / Buffer", "array": "Array", + "splitThe": "Split the", "splitUsing": "Split using", "splitLength": "Fixed length of", "stream": "Handle as a stream of messages", 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 fe81a80ad..8d38ac077 100644 --- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json @@ -1017,6 +1017,7 @@ "objectSend": "各key/valueペアのメッセージを送信", "strBuff": "文字列 / バッファ", "array": "配列", + "splitThe": "に基づく", "splitUsing": "分割", "splitLength": "固定長", "stream": "メッセージのストリームとして処理", diff --git a/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json b/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json index 274053bc6..51e1fd897 100644 --- a/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/pt-BR/messages.json @@ -44,7 +44,7 @@ "global": "contexto global", "str": "Cadeia de caracteres", "num": "número", - "bool": "booliano", + "bool": "booliano", "json": "objeto", "bin": "Armazenamento temporário", "date": "Carimbo de data/hora", @@ -352,8 +352,8 @@ } }, "trigger": { - "send": "Enviar", - "then": "então", + "send": "Enviar", + "then": "então", "then-send": "então enviem", "output": { "string": "a cadeia de caracteres", @@ -446,7 +446,7 @@ "staticTopic": "Assinar um tópico único", "dynamicTopic": "Assinatura dinâmica", "auto-connect": "Conectar automaticamente", - "auto-mode-depreciated": "Esta opção está deprecada. Favor utilizar o novo modo de auto-detecção." + "auto-mode-depreciated": "Esta opção está deprecada. Favor utilizar o novo modo de auto-detecção." }, "sections-label": { "birth-message": "Mensagem enviada na conexão (mensagem de nascimento)", @@ -466,8 +466,8 @@ "close-topic": "Deixe em branco para desativar a mensagem de fechamento" }, "state": { - "connected": "Conectado ao negociante: _ broker _", - "disconnected": "Desconectado do negociante: _ broker _", + "connected": "Conectado ao negociante: _ broker _", + "disconnected": "Desconectado do negociante: _ broker _", "connect-failed": "Falha na conexão com o negociante: __broker__", "broker-disconnected": "Cliente de negociante __broker__ desconectado: __reasonCode__ __reasonString__" }, @@ -898,7 +898,7 @@ "o2j": "Objeto para opções JSON", "pretty": "Formatar cadeia de caracteres JSON", "action": "Ação", - "property": "Propriedade", + "property": "Propriedade", "actions": { "toggle": "Converter entre cadeia de caracteres JSON e Objeto", "str": "Sempre converter em cadeia de caracteres JSON", @@ -929,7 +929,7 @@ "write": "escrever arquivo", "read": "ler arquivo", "filename": "Nome do arquivo", - "path": "caminho", + "path": "caminho", "action": "Ação", "addnewline": "Adicionar nova linha (\\n) a cada carga útil?", "createdir": "Criar diretório se não existir?", @@ -994,6 +994,7 @@ "objectSend": "Envia uma mensagem para cada par chave/valor", "strBuff": "Cadeia de caracteres / Armazenamento Temporário", "array": "Matriz", + "splitThe": "Dividir", "splitUsing": "Dividir usando", "splitLength": "Comprimento fixo de", "stream": "Tratar como uma transmissão de mensagens", @@ -1066,9 +1067,9 @@ "batch" : { "batch": "lote", "mode": { - "label": "Modo", - "num-msgs": "Agrupar por número de mensagens", - "interval": "Agrupar por intervalo de tempo", + "label": "Modo", + "num-msgs": "Agrupar por número de mensagens", + "interval": "Agrupar por intervalo de tempo", "concat": "Concatenar sequências" }, "count": { 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 d2bb5777e..2694ac6a5 100644 --- a/packages/node_modules/@node-red/nodes/locales/ru/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/ru/messages.json @@ -874,6 +874,7 @@ "objectSend":"Отправлять сообщение для каждой пары ключ/значение", "strBuff":"Строка / Буфер", "array":"Массив", + "splitThe": "Pазделить", "splitUsing":"С помощью", "splitLength":"Фикс. длина", "stream":"Обрабатывать как поток сообщений", diff --git a/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json b/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json index 7a0ea4ae4..7d5616a8f 100644 --- a/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/zh-CN/messages.json @@ -997,6 +997,7 @@ "objectSend": "每个键值对作为单个消息发送", "strBuff": "字符串 / Buffer", "array": "数组", + "splitThe": "Split", "splitUsing": "拆分使用", "splitLength": "固定长度", "stream": "作为消息流处理", diff --git a/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json b/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json index f43531fb1..7d16c5817 100644 --- a/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/zh-TW/messages.json @@ -866,6 +866,7 @@ "objectSend": "每個鍵值對作為單個消息發送", "strBuff": "字串 / Buffer", "array": "陣列", + "splitThe": "Split", "splitUsing": "拆分使用", "splitLength": "固定長度", "stream": "作為消息流處理", From 97ee6c67457ac3efd9184fc9a1e5e8d8685be384 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 18 Jul 2024 17:17:50 +0100 Subject: [PATCH 16/87] Back off node 22.5 --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 70d36deb1..cf871716a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18, 20, 22] + node-version: [18, 20, 22.4.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} From af42664d7355f638de80df581da56c37bb06df03 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Sat, 20 Jul 2024 13:36:37 +0900 Subject: [PATCH 17/87] Refresh page title after changing tab name --- .../@node-red/editor-client/src/js/ui/workspaces.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index 0d7b1da54..365d827f7 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -904,6 +904,13 @@ RED.workspaces = (function() { } }, refresh: function() { + var workspace = RED.nodes.workspace(RED.workspaces.active()); + if (workspace) { + document.title = `${documentTitle} : ${workspace.label}`; + } else { + var subflow = RED.nodes.subflow(RED.workspaces.active()); + document.title = `${documentTitle} : ${subflow.name}`; + } RED.nodes.eachWorkspace(function(ws) { workspace_tabs.renameTab(ws.id,ws.label); $("#red-ui-tab-"+(ws.id.replace(".","-"))).attr("flowname",ws.label) From 7b95e64a60ec83bdec2cf9162459991dba2c9257 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Mon, 22 Jul 2024 14:13:09 +0200 Subject: [PATCH 18/87] fix: modulesInUse might be undefined --- .../editor-client/src/js/ui/projects/projectSettings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js index c5dbfbdbf..218335249 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js @@ -308,7 +308,7 @@ RED.projects.settings = (function() { if (activeProject.dependencies) { for (var m in activeProject.dependencies) { if (activeProject.dependencies.hasOwnProperty(m)) { - var installed = !!RED.nodes.registry.getModule(m) && activeProject.dependencies[m] === modulesInUse[m].version; + var installed = !!RED.nodes.registry.getModule(m) && activeProject.dependencies[m] === modulesInUse[m]?.version; depsList.editableList('addItem',{ id: m, version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version, From 886fb45ad213dbe218f68d8c9b499dab23e26786 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Sun, 4 Aug 2024 11:30:48 +0100 Subject: [PATCH 19/87] Adjust type search dialog position to prevent x-overflow fixes #4843 --- .../@node-red/editor-client/src/js/ui/typeSearch.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js index 3d05fd1c8..2d6c62b04 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js @@ -279,6 +279,11 @@ RED.typeSearch = (function() { if ($("#red-ui-main-container").height() - opts.y - 195 < 0) { opts.y = opts.y - 275; } + const dialogWidth = dialog.width() || 300 // default is 300 (defined in class .red-ui-search) + const mainWidth = $("#red-ui-main-container").width() + if (mainWidth > dialogWidth && mainWidth - opts.x - dialogWidth < 0) { + opts.x = opts.x - (dialogWidth - RED.view.node_width) + } dialog.css({left:opts.x+"px",top:opts.y+"px"}).show(); searchResultsDiv.slideDown(300); setTimeout(function() { From b62c17f94bab934596ffc63e7435385320013394 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Sun, 4 Aug 2024 11:34:29 +0100 Subject: [PATCH 20/87] use workspace width to contain the search box --- .../@node-red/editor-client/src/js/ui/typeSearch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js index 2d6c62b04..703b57309 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js @@ -280,8 +280,8 @@ RED.typeSearch = (function() { opts.y = opts.y - 275; } const dialogWidth = dialog.width() || 300 // default is 300 (defined in class .red-ui-search) - const mainWidth = $("#red-ui-main-container").width() - if (mainWidth > dialogWidth && mainWidth - opts.x - dialogWidth < 0) { + const workspaceWidth = $('#red-ui-workspace').width() + if (workspaceWidth > dialogWidth && workspaceWidth - opts.x - dialogWidth < 0) { opts.x = opts.x - (dialogWidth - RED.view.node_width) } dialog.css({left:opts.x+"px",top:opts.y+"px"}).show(); From 964271f9c771318f4b1b7e65926044379218d95c Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 5 Aug 2024 16:18:05 +0100 Subject: [PATCH 21/87] Multiplayer: add real-time cursor tracking --- .../editor-client/src/js/multiplayer.js | 195 ++++++++++++------ .../runtime/lib/multiplayer/index.js | 3 +- 2 files changed, 135 insertions(+), 63 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/multiplayer.js b/packages/node_modules/@node-red/editor-client/src/js/multiplayer.js index ea836eaf4..b37d90fcb 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/multiplayer.js +++ b/packages/node_modules/@node-red/editor-client/src/js/multiplayer.js @@ -100,16 +100,36 @@ RED.multiplayer = (function () { break } } + if (isInWorkspace) { + const chart = $('#red-ui-workspace-chart') + const chartOffset = chart.offset() + const scaleFactor = RED.view.scale() + location.cursor = { + x: (lastPosition[0] - chartOffset.left + chart.scrollLeft()) / scaleFactor, + y: (lastPosition[1] - chartOffset.top + chart.scrollTop()) / scaleFactor + } + } return location } + + let publishLocationTimeout + let lastPosition = [0,0] + let isInWorkspace = false + function publishLocation () { - const location = getLocation() - if (location.workspace !== 0) { - log('send', 'multiplayer/location', location) - RED.comms.send('multiplayer/location', location) + if (!publishLocationTimeout) { + publishLocationTimeout = setTimeout(() => { + const location = getLocation() + if (location.workspace !== 0) { + log('send', 'multiplayer/location', location) + RED.comms.send('multiplayer/location', location) + } + publishLocationTimeout = null + }, 100) } } + function revealUser(location, skipWorkspace) { if (location.node) { // Need to check if this is a known node, so we can fall back to revealing @@ -271,7 +291,16 @@ RED.multiplayer = (function () { function removeUserLocation (sessionId) { updateUserLocation(sessionId, {}) + removeUserCursor(sessionId) } + function removeUserCursor (sessionId) { + // return + if (sessions[sessionId]?.cursor) { + sessions[sessionId].cursor.parentNode.removeChild(sessions[sessionId].cursor) + delete sessions[sessionId].cursor + } + } + function updateUserLocation (sessionId, location) { let viewTouched = false const oldLocation = sessions[sessionId].location @@ -291,6 +320,28 @@ RED.multiplayer = (function () { // console.log(`updateUserLocation sessionId:${sessionId} oldWS:${oldLocation?.workspace} newWS:${location.workspace}`) if (location.workspace) { getWorkspaceTray(location.workspace).addUser(sessionId) + if (location.cursor && location.workspace === RED.workspaces.active()) { + if (!sessions[sessionId].cursor) { + const user = sessions[sessionId].user + const cursorIcon = document.createElementNS("http://www.w3.org/2000/svg","g"); + cursorIcon.setAttribute("class", "red-ui-multiplayer-annotation") + cursorIcon.appendChild(createAnnotationUser(user, true)) + $(cursorIcon).css({ + transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)`, + transition: 'transform 0.1s linear' + }) + $("#red-ui-workspace-chart svg").append(cursorIcon) + sessions[sessionId].cursor = cursorIcon + } else { + const cursorIcon = sessions[sessionId].cursor + $(cursorIcon).css({ + transform: `translate( ${location.cursor.x}px, ${location.cursor.y}px)` + }) + + } + } else if (sessions[sessionId].cursor) { + removeUserCursor(sessionId) + } } if (location.node) { addUserToNode(sessionId, location.node) @@ -309,67 +360,69 @@ RED.multiplayer = (function () { // } // } + + function createAnnotationUser(user, pointer = false) { + const radius = 20 + const halfRadius = radius/2 + const group = document.createElementNS("http://www.w3.org/2000/svg","g"); + const badge = document.createElementNS("http://www.w3.org/2000/svg","path"); + let shapePath + if (!pointer) { + shapePath = `M 0 ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 ${radius} 0 a ${halfRadius} ${halfRadius} 0 1 1 -${radius} 0 z` + } else { + shapePath = `M 0 0 h ${halfRadius} a ${halfRadius} ${halfRadius} 0 1 1 -${halfRadius} ${halfRadius} z` + } + badge.setAttribute('d', shapePath) + badge.setAttribute("class", "red-ui-multiplayer-annotation-background") + group.appendChild(badge) + if (user && user.profileColor !== undefined) { + badge.setAttribute("class", "red-ui-multiplayer-annotation-background red-ui-user-profile-color-" + user.profileColor) + } + if (user && user.image) { + const image = document.createElementNS("http://www.w3.org/2000/svg","image"); + image.setAttribute("width", radius) + image.setAttribute("height", radius) + image.setAttribute("href", user.image) + image.setAttribute("clip-path", "circle("+Math.floor(radius/2)+")") + group.appendChild(image) + } else if (user && user.anonymous) { + const anonIconHead = document.createElementNS("http://www.w3.org/2000/svg","circle"); + anonIconHead.setAttribute("cx", radius/2) + anonIconHead.setAttribute("cy", radius/2 - 2) + anonIconHead.setAttribute("r", 2.4) + anonIconHead.setAttribute("class","red-ui-multiplayer-annotation-anon-label"); + group.appendChild(anonIconHead) + const anonIconBody = document.createElementNS("http://www.w3.org/2000/svg","path"); + anonIconBody.setAttribute("class","red-ui-multiplayer-annotation-anon-label"); + // anonIconBody.setAttribute("d",`M ${radius/2 - 4} ${radius/2 + 1} h 8 v4 h -8 z`); + anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`); + group.appendChild(anonIconBody) + } else { + const labelText = user.username ? user.username.substring(0,2) : user + const label = document.createElementNS("http://www.w3.org/2000/svg","text"); + if (user.username) { + label.setAttribute("class","red-ui-multiplayer-annotation-label"); + label.textContent = user.username.substring(0,2) + } else { + label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count") + label.textContent = user + } + label.setAttribute("text-anchor", "middle") + label.setAttribute("x",radius/2); + label.setAttribute("y",radius/2 + 3); + group.appendChild(label) + } + const border = document.createElementNS("http://www.w3.org/2000/svg","path"); + border.setAttribute('d', shapePath) + border.setAttribute("class", "red-ui-multiplayer-annotation-border") + group.appendChild(border) + return group + } + return { init: function () { - function createAnnotationUser(user) { - - const group = document.createElementNS("http://www.w3.org/2000/svg","g"); - const badge = document.createElementNS("http://www.w3.org/2000/svg","circle"); - const radius = 20 - badge.setAttribute("cx",radius/2); - badge.setAttribute("cy",radius/2); - badge.setAttribute("r",radius/2); - badge.setAttribute("class", "red-ui-multiplayer-annotation-background") - group.appendChild(badge) - if (user && user.profileColor !== undefined) { - badge.setAttribute("class", "red-ui-multiplayer-annotation-background red-ui-user-profile-color-" + user.profileColor) - } - if (user && user.image) { - const image = document.createElementNS("http://www.w3.org/2000/svg","image"); - image.setAttribute("width", radius) - image.setAttribute("height", radius) - image.setAttribute("href", user.image) - image.setAttribute("clip-path", "circle("+Math.floor(radius/2)+")") - group.appendChild(image) - } else if (user && user.anonymous) { - const anonIconHead = document.createElementNS("http://www.w3.org/2000/svg","circle"); - anonIconHead.setAttribute("cx", radius/2) - anonIconHead.setAttribute("cy", radius/2 - 2) - anonIconHead.setAttribute("r", 2.4) - anonIconHead.setAttribute("class","red-ui-multiplayer-annotation-anon-label"); - group.appendChild(anonIconHead) - const anonIconBody = document.createElementNS("http://www.w3.org/2000/svg","path"); - anonIconBody.setAttribute("class","red-ui-multiplayer-annotation-anon-label"); - // anonIconBody.setAttribute("d",`M ${radius/2 - 4} ${radius/2 + 1} h 8 v4 h -8 z`); - anonIconBody.setAttribute("d",`M ${radius/2} ${radius/2 + 5} h -2.5 c -2 1 -2 -5 0.5 -4.5 c 2 1 2 1 4 0 c 2.5 -0.5 2.5 5.5 0 4.5 z`); - group.appendChild(anonIconBody) - } else { - const labelText = user.username ? user.username.substring(0,2) : user - const label = document.createElementNS("http://www.w3.org/2000/svg","text"); - if (user.username) { - label.setAttribute("class","red-ui-multiplayer-annotation-label"); - label.textContent = user.username.substring(0,2) - } else { - label.setAttribute("class","red-ui-multiplayer-annotation-label red-ui-multiplayer-user-count") - label.textContent = user - } - label.setAttribute("text-anchor", "middle") - label.setAttribute("x",radius/2); - label.setAttribute("y",radius/2 + 3); - group.appendChild(label) - } - const border = document.createElementNS("http://www.w3.org/2000/svg","circle"); - border.setAttribute("cx",radius/2); - border.setAttribute("cy",radius/2); - border.setAttribute("r",radius/2); - border.setAttribute("class", "red-ui-multiplayer-annotation-border") - group.appendChild(border) - - - - return group - } + RED.view.annotations.register("red-ui-multiplayer",{ type: 'badge', @@ -479,6 +532,24 @@ RED.multiplayer = (function () { RED.comms.send('multiplayer/disconnect', disconnectInfo) RED.settings.removeLocal('multiplayer:sessionId') }) + + const chart = $('#red-ui-workspace-chart') + chart.on('mousemove', function (evt) { + lastPosition[0] = evt.clientX + lastPosition[1] = evt.clientY + publishLocation() + }) + chart.on('scroll', function (evt) { + publishLocation() + }) + chart.on('mouseenter', function () { + isInWorkspace = true + publishLocation() + }) + chart.on('mouseleave', function () { + isInWorkspace = false + publishLocation() + }) } } diff --git a/packages/node_modules/@node-red/runtime/lib/multiplayer/index.js b/packages/node_modules/@node-red/runtime/lib/multiplayer/index.js index 08cb0d5a1..85a90e977 100644 --- a/packages/node_modules/@node-red/runtime/lib/multiplayer/index.js +++ b/packages/node_modules/@node-red/runtime/lib/multiplayer/index.js @@ -110,7 +110,8 @@ module.exports = { const payload = { session: sessionId, workspace: opts.data.workspace, - node: opts.data.node + node: opts.data.node, + cursor: opts.data.cursor } runtime.events.emit('comms', { topic: 'multiplayer/location', From d11934beeb6b56dc5f8178bb91cb4506f6d862ed Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Mon, 12 Aug 2024 00:14:28 +0900 Subject: [PATCH 22/87] Add Japanese translations for batch and join nodes --- 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 8d38ac077..1693f879e 100644 --- a/packages/node_modules/@node-red/nodes/locales/ja/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/ja/messages.json @@ -1047,6 +1047,7 @@ "joinedUsing": "連結文字", "send": "メッセージ送信:", "afterCount": "指定数のメッセージパーツを受信後", + "useparts": "既存のmsg.partsプロパティを使用", "count": "合計値", "subsequent": "後続のメッセージ毎", "afterTimeout": "最初のメッセージ受信からのタイムアウト後", @@ -1113,6 +1114,7 @@ "too-many": "batchノード内で保持しているメッセージが多すぎます", "unexpected": "想定外のモード", "no-parts": "メッセージにpartsプロパティがありません", + "honourParts": "msg.partsを用いたbatch操作を許可", "error": { "invalid-count": "メッセージ数が不正", "invalid-overlap": "オーバラップが不正", From e0059943dfab55fb31253af9e8ac1a3e1d7997d0 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Mon, 12 Aug 2024 00:19:21 +0900 Subject: [PATCH 23/87] Add Japanese translations for project feature --- .../editor-client/locales/en-US/editor.json | 11 ++++++++++- .../editor-client/locales/ja/editor.json | 11 ++++++++++- .../@node-red/editor-client/src/js/ui/diff.js | 15 +++++++-------- .../src/js/ui/projects/projectSettings.js | 2 +- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json index a88890125..3f6617752 100644 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -375,7 +375,10 @@ "flowAdded": "flow added", "moved": "moved", "movedTo": "moved to __id__", - "movedFrom": "moved from __id__" + "movedFrom": "moved from __id__", + "none": "none", + "position": "position", + "wires": "wires" }, "nodeCount": "__count__ node", "nodeCount_plural": "__count__ nodes", @@ -384,9 +387,14 @@ "reviewChanges": "Review Changes", "noBinaryFileShowed": "Cannot show binary file contents", "viewCommitDiff": "View Commit Changes", + "commit": "Commit", "compareChanges": "Compare Changes", "saveConflict": "Save conflict resolution", "conflictHeader": "__resolved__ of __unresolved__ conflicts resolved", + "localChanges": "Local Changes", + "remoteChanges": "Remote Changes", + "useLocalChanges": "use local changes", + "useRemoteChanges": "use remote changes", "commonVersionError": "Common Version doesn't contain valid JSON:", "oldVersionError": "Old Version doesn't contain valid JSON:", "newVersionError": "New Version doesn't contain valid JSON:" @@ -803,6 +811,7 @@ "branches": "Branches", "noBranches": "No branches", "deleteConfirm": "Are you sure you want to delete the local branch '__name__'? This cannot be undone.", + "deleteBranch": "Delete branch", "unmergedConfirm": "The local branch '__name__' has unmerged changes that will be lost. Are you sure you want to delete it?", "deleteUnmergedBranch": "Delete unmerged branch", "gitRemotes": "Git remotes", diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json index ab19d459e..5b11e24c4 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -375,7 +375,10 @@ "flowAdded": "追加されたフロー", "moved": "移動", "movedTo": "__id__ へ移動", - "movedFrom": "__id__ から移動" + "movedFrom": "__id__ から移動", + "none": "なし", + "position": "位置", + "wires": "ワイヤー" }, "nodeCount": "__count__ 個のノード", "nodeCount_plural": "__count__ 個のノード", @@ -384,9 +387,14 @@ "reviewChanges": "変更を表示", "noBinaryFileShowed": "バイナリファイルの中身は表示することができません", "viewCommitDiff": "コミットの内容を表示", + "commit": "コミット", "compareChanges": "変更を比較", "saveConflict": "解決して保存", "conflictHeader": "__unresolved__ 個中 __resolved__ 個のコンフリクトを解決", + "localChanges": "ローカルの変更", + "remoteChanges": "リモートの変更", + "useLocalChanges": "ローカルの変更を使用", + "useRemoteChanges": "リモートの変更を使用", "commonVersionError": "共通バージョンは正しいJSON形式ではありません:", "oldVersionError": "古いバージョンは正しいJSON形式ではありません:", "newVersionError": "新しいバージョンは正しいJSON形式ではありません:" @@ -803,6 +811,7 @@ "branches": "ブランチ", "noBranches": "ブランチなし", "deleteConfirm": "本当にローカルブランチ'__name__'を削除しますか?削除すると元に戻すことはできません。", + "deleteBranch": "ブランチを削除", "unmergedConfirm": "ローカルブランチ'__name__'にはマージされていない変更があります。この変更は削除されます。本当に削除しますか?", "deleteUnmergedBranch": "マージされていないブランチを削除", "gitRemotes": "Gitリモート", diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js index ebdf683e3..26cdceb7e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/diff.js @@ -497,7 +497,7 @@ RED.diff = (function() { } }) if (c === 0) { - result.text("none"); + result.text(RED._("diff.type.none")); } else { list.appendTo(result); } @@ -821,7 +821,7 @@ RED.diff = (function() { conflict = true; } row = $("").appendTo(nodePropertiesTableBody); - $("",{class:"red-ui-diff-list-cell-label"}).text("position").appendTo(row); + $("",{class:"red-ui-diff-list-cell-label"}).text(RED._("diff.type.position")).appendTo(row); localCell = $("",{class:"red-ui-diff-list-cell red-ui-diff-list-node-local"}).appendTo(row); if (localNode) { localCell.addClass("red-ui-diff-status-"+(localChanged?"moved":"unchanged")); @@ -899,7 +899,7 @@ RED.diff = (function() { conflict = true; } row = $("").appendTo(nodePropertiesTableBody); - $("",{class:"red-ui-diff-list-cell-label"}).text("wires").appendTo(row); + $("",{class:"red-ui-diff-list-cell-label"}).text(RED._("diff.type.wires")).appendTo(row); localCell = $("",{class:"red-ui-diff-list-cell red-ui-diff-list-node-local"}).appendTo(row); if (localNode) { if (!conflict) { @@ -2029,15 +2029,14 @@ RED.diff = (function() { if (!isSeparator) { var isOurs = /^..<<<<<<').text("<<<<<<< Local Changes").appendTo(line); + $('').text("<<<<<<< " + RED._("diff.localChanges")).appendTo(line); hunk.localChangeStart = actualLineNumber; } else { hunk.remoteChangeEnd = actualLineNumber; - $('').text(">>>>>>> Remote Changes").appendTo(line); - + $('').text(">>>>>>> " + RED._("diff.remoteChanges")).appendTo(line); } diffRow.addClass("mergeHeader-"+(isOurs?"ours":"theirs")); - $('') + $('') .appendTo(line) .on("click", function(evt) { evt.preventDefault(); @@ -2119,7 +2118,7 @@ RED.diff = (function() { $("

").text(commit.title).appendTo(content); $('
').text(commit.comment).appendTo(content); var summary = $('
').appendTo(content); - $('
').text("Commit "+commit.sha).appendTo(summary); + $('
').text(RED._('diff.commit')+" "+commit.sha).appendTo(summary); $('
').text((commit.authorName||commit.author)+" - "+options.date).appendTo(summary); if (commit.files) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js index c5dbfbdbf..2f782e011 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js @@ -1256,7 +1256,7 @@ RED.projects.settings = (function() { notification.close(); } },{ - text: 'Delete branch', + text: RED._("sidebar.project.projectSettings.deleteBranch"), click: function() { notification.close(); var url = "projects/"+activeProject.name+"/branches/"+entry.name; From 509d6090202e529e2f396cd348979f5fc84a947f Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 12 Aug 2024 16:53:23 +0100 Subject: [PATCH 24/87] Fix moving link wires --- .../@node-red/editor-client/src/js/ui/view.js | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index e97e2e36e..fd1205a30 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -3189,27 +3189,59 @@ RED.view = (function() { for (i=0;i id !== oldDst.id) + dst.links = dst.links.filter(id => id !== oldDst.id) + var oldOldDstLinks = [...oldDst.links] + oldDst.links = oldDst.links.filter(id => id !== oldSrc.id) + oldDst.dirty = true; + modifiedNodes.push(oldDst); + linkEditEvents.push({ + t:'edit', + node: oldDst, + dirty: RED.nodes.dirty(), + changed: oldDst.changed, + changes: { + links:oldOldDstLinks + } + }); + oldDst.changed = true; + } + src.dirty = true; dst.dirty = true; + modifiedNodes.push(src); modifiedNodes.push(dst); @@ -3237,6 +3269,7 @@ RED.view = (function() { links:oldDstLinks } }); + src.changed = true; dst.changed = true; } From b5785dab9c9fe635f9de80972790642c23f9a232 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Tue, 13 Aug 2024 23:48:28 +0900 Subject: [PATCH 25/87] Add Japanese translations for v4.0.2 (again) --- .../@node-red/editor-client/locales/en-US/editor.json | 4 +++- .../@node-red/editor-client/locales/ja/editor.json | 4 +++- .../node_modules/@node-red/editor-client/src/js/ui/library.js | 4 ++-- .../@node-red/editor-client/src/js/ui/tab-info.js | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json index 3f6617752..9bdd55155 100644 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -562,7 +562,9 @@ "types": { "local": "Local", "examples": "Examples" - } + }, + "type": "Type", + "name": "Name" }, "palette": { "noInfo": "no information available", diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json index 5b11e24c4..c0296f457 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -562,7 +562,9 @@ "types": { "local": "ローカル", "examples": "サンプル" - } + }, + "type": "型", + "name": "名前" }, "palette": { "noInfo": "情報がありません", diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/library.js b/packages/node_modules/@node-red/editor-client/src/js/ui/library.js index d276b1572..0098bc947 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/library.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/library.js @@ -839,10 +839,10 @@ RED.library = (function() { if (file && file.label && !file.children) { $.get("library/"+file.library+"/"+file.type+"/"+file.path, function(data) { //TODO: nls + sanitize - var propRow = $('Type').appendTo(table); + var propRow = $(''+RED._("library.type")+'').appendTo(table); $(propRow.children()[1]).text(activeLibrary.type); if (file.props.hasOwnProperty('name')) { - propRow = $('Name'+file.props.name+'').appendTo(table); + propRow = $(''+RED._("library.name")+''+file.props.name+'').appendTo(table); $(propRow.children()[1]).text(file.props.name); } for (var p in file.props) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js index f72a7b3f2..fa9b98322 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js @@ -204,7 +204,7 @@ RED.sidebar.info = (function() { propertiesPanelHeaderIcon.empty(); RED.utils.createNodeIcon({type:"_selection_"}).appendTo(propertiesPanelHeaderIcon); - propertiesPanelHeaderLabel.text("Selection"); + propertiesPanelHeaderLabel.text(RED._("sidebar.info.selection")); propertiesPanelHeaderReveal.hide(); propertiesPanelHeaderHelp.hide(); propertiesPanelHeaderCopyLink.hide(); From b4d29d4d4a2eb16f6daa9fd2abee7e973909cfba Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Wed, 14 Aug 2024 00:25:59 +0900 Subject: [PATCH 26/87] Fix typo in flow example name --- ... Join extracted sequence of HTML element using join node.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/node_modules/@node-red/nodes/examples/parser/html/{04 - Join extracedt sequence of HTML element using join node.json => 04 - Join extracted sequence of HTML element using join node.json} (100%) diff --git a/packages/node_modules/@node-red/nodes/examples/parser/html/04 - Join extracedt sequence of HTML element using join node.json b/packages/node_modules/@node-red/nodes/examples/parser/html/04 - Join extracted sequence of HTML element using join node.json similarity index 100% rename from packages/node_modules/@node-red/nodes/examples/parser/html/04 - Join extracedt sequence of HTML element using join node.json rename to packages/node_modules/@node-red/nodes/examples/parser/html/04 - Join extracted sequence of HTML element using join node.json From edc01552f9f2f7542dfe60a3e2ed7cd2c9e298a3 Mon Sep 17 00:00:00 2001 From: Kazuhito Yokoi Date: Thu, 15 Aug 2024 03:42:07 +0900 Subject: [PATCH 27/87] Fix invalid property error in range node example (#4855) --- .../nodes/examples/function/range/01 - Scale input value.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/nodes/examples/function/range/01 - Scale input value.json b/packages/node_modules/@node-red/nodes/examples/function/range/01 - Scale input value.json index 39bc40c4a..851634d0c 100644 --- a/packages/node_modules/@node-red/nodes/examples/function/range/01 - Scale input value.json +++ b/packages/node_modules/@node-red/nodes/examples/function/range/01 - Scale input value.json @@ -1 +1 @@ -[{"id":"827a48c0.912d88","type":"comment","z":"ff17dfa9.8fa6d","name":"Map property between different numeric ranges","info":"Range node can scale a number from one numeric range to another.\n\nSee Node-RED cookbook [item](https://cookbook.nodered.org/basic/map-between-different-number-ranges).","x":240,"y":60,"wires":[]},{"id":"bb23bd77.ce725","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"0","payloadType":"num","x":170,"y":120,"wires":[["42ed281c.790b38"]]},{"id":"42ed281c.790b38","type":"range","z":"ff17dfa9.8fa6d","minin":"0","maxin":"1023","minout":"0","maxout":"5","action":"clamp","round":false,"name":"","x":390,"y":160,"wires":[["56e6dd0f.436c24"]]},{"id":"54659d5c.0283e4","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"512","payloadType":"num","x":170,"y":160,"wires":[["42ed281c.790b38"]]},{"id":"85ce0127.07b06","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"1023","payloadType":"num","x":170,"y":200,"wires":[["42ed281c.790b38"]]},{"id":"56e6dd0f.436c24","type":"debug","z":"ff17dfa9.8fa6d","name":"","active":true,"console":"false","complete":"false","x":590,"y":160,"wires":[]}] \ No newline at end of file +[{"id":"827a48c0.912d88","type":"comment","z":"ff17dfa9.8fa6d","name":"Map property between different numeric ranges","info":"Range node can scale a number from one numeric range to another.\n\nSee Node-RED cookbook [item](https://cookbook.nodered.org/basic/map-between-different-number-ranges).","x":240,"y":60,"wires":[]},{"id":"bb23bd77.ce725","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"0","payloadType":"num","x":170,"y":120,"wires":[["42ed281c.790b38"]]},{"id":"42ed281c.790b38","type":"range","z":"ff17dfa9.8fa6d","minin":"0","maxin":"1023","minout":"0","maxout":"5","action":"clamp","round":false,"property":"payload","name":"","x":390,"y":160,"wires":[["56e6dd0f.436c24"]]},{"id":"54659d5c.0283e4","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"512","payloadType":"num","x":170,"y":160,"wires":[["42ed281c.790b38"]]},{"id":"85ce0127.07b06","type":"inject","z":"ff17dfa9.8fa6d","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"1023","payloadType":"num","x":170,"y":200,"wires":[["42ed281c.790b38"]]},{"id":"56e6dd0f.436c24","type":"debug","z":"ff17dfa9.8fa6d","name":"","active":true,"console":"false","complete":"false","x":590,"y":160,"wires":[]}] \ No newline at end of file From e6ca3af1edff1f48b5709ea9ffdf254146478bed Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:53:55 +0200 Subject: [PATCH 28/87] Add French translations for Project feature --- .../@node-red/editor-client/locales/fr/editor.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 950266007..05a36c109 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 @@ -375,7 +375,10 @@ "flowAdded": "flux ajouté", "moved": "déplacé", "movedTo": "déplacé vers __id__", - "movedFrom": "déplacé depuis __id__" + "movedFrom": "déplacé depuis __id__", + "none": "aucun", + "position": "position", + "wires": "câbles" }, "nodeCount": "__count__ noeud", "nodeCount_plural": "__count__ noeuds", @@ -384,9 +387,14 @@ "reviewChanges": "Examiner les modifications", "noBinaryFileShowed": "Impossible d'afficher le contenu du fichier binaire", "viewCommitDiff": "Afficher les modifications de la validation", + "commit": "Validation", "compareChanges": "Comparer les modifications", "saveConflict": "Enregistrer la résolution des conflits", "conflictHeader": "__resolved__ sur __unresolved__ conflit(s) résolu(s)", + "localChanges": "Modifications locales", + "remoteChanges": "Modifications distantes", + "useLocalChanges": "utiliser les modifications locales", + "useRemoteChanges": "utiliser les modifications distantes", "commonVersionError": "La version commune ne contient pas de JSON valide :", "oldVersionError": "L'ancienne version ne contient pas de JSON valide :", "newVersionError": "La nouvelle version ne contient pas de JSON valide :" @@ -803,6 +811,7 @@ "branches": "Branches", "noBranches": "Pas de branche", "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la branche locale '__name__' ? Ça ne peut pas être annulé.", + "deleteBranch": "Supprimer la branche", "unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Êtes-vous sûr de vouloir la supprimer?", "deleteUnmergedBranch": "Supprimer la branche non fusionnée", "gitRemotes": "Git distant", From aed9a868abf1267065697ed001891e3537b7e499 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:55:28 +0200 Subject: [PATCH 29/87] Add French translations for batch and join nodes --- packages/node_modules/@node-red/nodes/locales/fr/messages.json | 3 +++ 1 file changed, 3 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 99002f48f..238763e3b 100644 --- a/packages/node_modules/@node-red/nodes/locales/fr/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/fr/messages.json @@ -1017,6 +1017,7 @@ "objectSend": "Envoie un message pour chaque paire clé/valeur", "strBuff": "Chaîne / Tampon", "array": "Tableau", + "splitThe": "Diviser le", "splitUsing": "Diviser en utilisant", "splitLength": "Longueur fixe de", "stream": "Gérer comme un flux de messages", @@ -1046,6 +1047,7 @@ "joinedUsing": "joint en utilisant", "send": "Envoyer le message :", "afterCount": "Après un nombre de parties du message", + "useparts": "Utiliser la propriété msg.parts existante", "count": "nombre", "subsequent": "Et tous les messages suivants.", "afterTimeout": "Après un délai d'attente après le premier message", @@ -1112,6 +1114,7 @@ "too-many": "Trop de messages en attente dans le noeud batch", "unexpected": "Mode inattendu", "no-parts": "Aucune propriété de pièces dans le message", + "honourParts": "Autoriser msg.parts à compléter les opération par lots", "error": { "invalid-count": "Compte invalide", "invalid-overlap": "Recouvrement invalide", From 1ebb66f6ca2a7578639856b35acff05493649d4f Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 18 Aug 2024 13:11:56 +0200 Subject: [PATCH 30/87] Add French translations for properties in info sidebar --- .../@node-red/editor-client/locales/fr/editor.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 05a36c109..fbd6f2849 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 @@ -562,7 +562,9 @@ "types": { "local": "Local", "examples": "Exemples" - } + }, + "type": "Type", + "name": "Nom" }, "palette": { "noInfo": "Pas d'information disponible", From 2c4dc3334d753d68cd2cfbe4ba839f08628c7b0c Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:46:48 +0200 Subject: [PATCH 31/87] Fix subflow outbound-link filter --- .../@node-red/editor-client/src/js/nodes.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 2a7b440f2..84a290b59 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2406,12 +2406,15 @@ RED.nodes = (function() { } else { delete n.g } - // If importing into a subflow, ensure an outbound-link doesn't get added - if (activeSubflow && /^link /.test(n.type) && n.links) { - n.links = n.links.filter(function(id) { - const otherNode = node_map[id] || RED.nodes.node(id); - return (otherNode && otherNode.z === activeWorkspace); - }); + // If importing a subflow, ensure an outbound-link doesn't get added + if (/^link /.test(n.type) && n.links) { + const isSubflow = !!getSubflow(n.z); + if (isSubflow) { + n.links = n.links.filter(function(id) { + const otherNode = node_map[id] || RED.nodes.node(id); + return (otherNode && otherNode.z === n.z); + }); + } } for (var d3 in n._def.defaults) { if (n._def.defaults.hasOwnProperty(d3)) { From 27604fef232eeb4df73abd59c7b46d3ef56ded92 Mon Sep 17 00:00:00 2001 From: Luis Antonio Obis Aparicio Date: Sat, 31 Aug 2024 04:32:01 +0200 Subject: [PATCH 32/87] add citation file --- CITATION.cff | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 CITATION.cff diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..9372ad005 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,7 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +title: "Node-RED" +authors: + - family-names: "OpenJS Foundation" + - family-names: "Contributors" +url: "https://nodered.org" From 8c53d95610ce834ac7faf820a5f160ae3d49921c Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 9 Sep 2024 16:49:17 +0100 Subject: [PATCH 33/87] Hide add-flow options when disabled via editorTheme --- .../editor-client/src/js/ui/workspaces.js | 101 ++++++++++-------- .../editor-client/src/sass/tabs.scss | 10 +- 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index 0d7b1da54..c551ff92e 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -183,25 +183,29 @@ RED.workspaces = (function() { }, null) } - menuItems.push( - { - id:"red-ui-tabs-menu-option-add-flow", - label: RED._("workspace.addFlow"), - onselect: "core:add-flow" - } - ) - if (isMenuButton || !!tab) { + if (RED.settings.theme("menu.menu-item-workspace-add", true)) { menuItems.push( { - id:"red-ui-tabs-menu-option-add-flow-right", - label: RED._("workspace.addFlowToRight"), - shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"), - onselect: function() { - RED.actions.invoke("core:add-flow-to-right", tab) - } - }, - null + id:"red-ui-tabs-menu-option-add-flow", + label: RED._("workspace.addFlow"), + onselect: "core:add-flow" + } ) + } + if (isMenuButton || !!tab) { + if (RED.settings.theme("menu.menu-item-workspace-add", true)) { + menuItems.push( + { + id:"red-ui-tabs-menu-option-add-flow-right", + label: RED._("workspace.addFlowToRight"), + shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"), + onselect: function() { + RED.actions.invoke("core:add-flow-to-right", tab) + } + }, + null + ) + } if (activeWorkspace && activeWorkspace.type === 'tab') { menuItems.push( isFlowDisabled ? { @@ -255,7 +259,9 @@ RED.workspaces = (function() { } ) } - menuItems.push(null) + if (menuItems.length > 0) { + menuItems.push(null) + } if (isMenuButton || !!tab) { menuItems.push( { @@ -299,19 +305,24 @@ RED.workspaces = (function() { } ) if (tab) { + menuItems.push(null) + + if (RED.settings.theme("menu.menu-item-workspace-delete", true)) { + menuItems.push( + { + label: RED._("common.label.delete"), + onselect: function() { + if (tab.type === 'tab') { + RED.workspaces.delete(tab) + } else if (tab.type === 'subflow') { + RED.subflow.delete(tab.id) + } + }, + disabled: isCurrentLocked || (workspaceTabCount === 1) + } + ) + } menuItems.push( - null, - { - label: RED._("common.label.delete"), - onselect: function() { - if (tab.type === 'tab') { - RED.workspaces.delete(tab) - } else if (tab.type === 'subflow') { - RED.subflow.delete(tab.id) - } - }, - disabled: isCurrentLocked || (workspaceTabCount === 1) - }, { label: RED._("menu.label.export"), shortcut: RED.keyboard.getShortcut("core:show-export-dialog"), @@ -469,6 +480,7 @@ RED.workspaces = (function() { minimumActiveTabWidth: 150, scrollable: true, addButton: "core:add-flow", + addButton: RED.settings.theme("menu.menu-item-workspace-add", true) ? "core:add-flow" : undefined, addButtonCaption: RED._("workspace.addFlow"), menu: function() { return getMenuItems(true) }, contextmenu: function(tab) { return getMenuItems(false, tab) } @@ -525,19 +537,24 @@ RED.workspaces = (function() { $(window).on("resize", function() { workspace_tabs.resize(); }); - - RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)}); - RED.actions.add("core:add-flow-to-right",function(workspace) { - let index - if (workspace) { - index = workspace_tabs.getTabIndex(workspace.id)+1 - } else { - index = workspace_tabs.activeIndex()+1 - } - addWorkspace(undefined,undefined,index) - }); - RED.actions.add("core:edit-flow",editWorkspace); - RED.actions.add("core:remove-flow",removeWorkspace); + if (RED.settings.theme("menu.menu-item-workspace-add", true)) { + RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)}); + RED.actions.add("core:add-flow-to-right",function(workspace) { + let index + if (workspace) { + index = workspace_tabs.getTabIndex(workspace.id)+1 + } else { + index = workspace_tabs.activeIndex()+1 + } + addWorkspace(undefined,undefined,index) + }); + } + if (RED.settings.theme("menu.menu-item-workspace-edit", true)) { + RED.actions.add("core:edit-flow",editWorkspace); + } + if (RED.settings.theme("menu.menu-item-workspace-delete", true)) { + RED.actions.add("core:remove-flow",removeWorkspace); + } RED.actions.add("core:enable-flow",enableWorkspace); RED.actions.add("core:disable-flow",disableWorkspace); RED.actions.add("core:lock-flow",lockWorkspace); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss b/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss index 595423888..f2cb882b7 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss @@ -151,8 +151,9 @@ &.red-ui-tabs-add { padding-right: 29px; } - &.red-ui-tabs-add.red-ui-tabs-scrollable { - padding-right: 53px; + &.red-ui-tabs-add.red-ui-tabs-scrollable, + &.red-ui-tabs-menu.red-ui-tabs-scrollable { + padding-right: 53px; } &.red-ui-tabs-add.red-ui-tabs-menu.red-ui-tabs-scrollable, &.red-ui-tabs-add.red-ui-tabs-search.red-ui-tabs-scrollable { @@ -310,8 +311,9 @@ } } -.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right { - right: 32px; +.red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right, +.red-ui-tabs.red-ui-tabs-menu .red-ui-tab-scroll-right { + right: 32px; } .red-ui-tabs.red-ui-tabs-add.red-ui-tabs-menu .red-ui-tab-scroll-right, From 9745904c5b64c0514fcc76e8b77d6220d5ab2fa3 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 9 Sep 2024 16:52:45 +0100 Subject: [PATCH 34/87] Remove duplicate key --- .../node_modules/@node-red/editor-client/src/js/ui/workspaces.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index c551ff92e..06a11f38b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -479,7 +479,6 @@ RED.workspaces = (function() { }, minimumActiveTabWidth: 150, scrollable: true, - addButton: "core:add-flow", addButton: RED.settings.theme("menu.menu-item-workspace-add", true) ? "core:add-flow" : undefined, addButtonCaption: RED._("workspace.addFlow"), menu: function() { return getMenuItems(true) }, From 593726ecb8abb4589b1351f07ad6432a644da174 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 10:41:23 +0100 Subject: [PATCH 35/87] Hide actionList in context menu if disabled --- .../@node-red/editor-client/src/js/ui/actionList.js | 4 +++- .../@node-red/editor-client/src/js/ui/contextMenu.js | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js index d949899ca..d47a20f5d 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/actionList.js @@ -205,7 +205,9 @@ RED.actionList = (function() { } function init() { - RED.actions.add("core:show-action-list",show); + if (RED.settings.theme("menu.menu-item-action-list", true)) { + RED.actions.add("core:show-action-list",show); + } RED.events.on("editor:open",function() { disabled = true; }); RED.events.on("editor:close",function() { disabled = false; }); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index 60615671e..698842dbd 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -65,10 +65,11 @@ RED.contextMenu = (function () { addY = gridSize * Math.floor(addY / gridSize) } - menuItems.push( - { onselect: 'core:show-action-list', label: RED._("contextMenu.showActionList"), onpostselect: function () { } } - ) - + if (RED.settings.theme("menu.menu-item-action-list", true)) { + menuItems.push( + { onselect: 'core:show-action-list', label: RED._("contextMenu.showActionList"), onpostselect: function () { } } + ) + } const insertOptions = [] menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions }) insertOptions.push( From 2e5a3f4949c2bd5debccedd6022a5385f678e012 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 11:28:42 +0100 Subject: [PATCH 36/87] Fix env-var config select when multiple defined --- .../node_modules/@node-red/editor-client/src/js/ui/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 30c329c41..8d515e7c8 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -899,7 +899,7 @@ RED.editor = (function() { const labelText = RED.editor.envVarList.lookupLabel(labels, labels["en-US"] || tenv.name, locale) const config = { env: tenv, - id: '${' + parentEnv[0].name + '}', + id: '${' + tenv.name + '}', type: type, label: labelText, __label__: `[env] ${labelText}` From 7f77a414ec44715a1773e25d930a45805b1ccf7a Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 12:10:37 +0100 Subject: [PATCH 37/87] Ensure will payload is a string --- .../@node-red/nodes/core/network/10-mqtt.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index 7be0263d6..9e707fa68 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -673,6 +673,8 @@ module.exports = function(RED) { delete node.options.protocolId; //V4+ default delete node.options.protocolVersion; //V4 default delete node.options.properties;//V5 only + + if (node.compatmode == "true" || node.compatmode === true || node.protocolVersion == 3) { node.options.protocolId = 'MQIsdp';//V3 compat only node.options.protocolVersion = 3; @@ -691,6 +693,21 @@ module.exports = function(RED) { setIntProp(node,node.options.properties,"sessionExpiryInterval"); } } + // Ensure will payload, if set, is a string + if (node.options.will && Object.hasOwn(node.options.will, 'payload')) { + let payload = node.options.will.payload + if (payload === null || payload === undefined) { + payload = ""; + } else if (!Buffer.isBuffer(payload)) { + if (typeof payload === "object") { + payload = JSON.stringify(payload); + } else if (typeof payload !== "string") { + payload = "" + payload; + } + } + node.options.will.payload = payload + } + if (node.usetls && n.tls) { var tlsNode = RED.nodes.getNode(n.tls); if (tlsNode) { From 20ae4a7272f183a1b19593a01756ee7355b2b9b7 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 13:58:16 +0100 Subject: [PATCH 38/87] Update dependencies --- package.json | 12 ++++++------ .../node_modules/@node-red/editor-api/package.json | 4 ++-- packages/node_modules/@node-red/nodes/package.json | 8 ++++---- packages/node_modules/@node-red/runtime/package.json | 2 +- packages/node_modules/node-red/package.json | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index f705e0752..06161a639 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ } ], "dependencies": { - "acorn": "8.11.3", - "acorn-walk": "8.3.2", - "ajv": "8.14.0", + "acorn": "8.12.1", + "acorn-walk": "8.3.4", + "ajv": "8.17.1", "async-mutex": "0.5.0", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "cheerio": "1.0.0-rc.10", "clone": "2.1.2", "content-type": "1.0.5", @@ -41,7 +41,7 @@ "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", - "express": "4.19.2", + "express": "4.20.0", "express-session": "1.18.0", "form-data": "4.0.0", "fs-extra": "11.2.0", @@ -64,7 +64,7 @@ "mqtt": "5.7.0", "multer": "1.4.5-lts.1", "mustache": "4.2.0", - "node-red-admin": "^4.0.0", + "node-red-admin": "^4.0.1", "node-watch": "0.7.4", "nopt": "5.0.0", "oauth2orize": "1.12.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 792b5b67f..f46a31a02 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -19,11 +19,11 @@ "@node-red/util": "4.0.2", "@node-red/editor-client": "4.0.2", "bcryptjs": "2.4.3", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "clone": "2.1.2", "cors": "2.8.5", "express-session": "1.18.0", - "express": "4.19.2", + "express": "4.20.0", "memorystore": "1.6.7", "mime": "3.0.0", "multer": "1.4.5-lts.1", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index e8e384948..45f0de327 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -15,10 +15,10 @@ } ], "dependencies": { - "acorn": "8.11.3", - "acorn-walk": "8.3.2", - "ajv": "8.14.0", - "body-parser": "1.20.2", + "acorn": "8.12.1", + "acorn-walk": "8.3.4", + "ajv": "8.17.1", + "body-parser": "1.20.3", "cheerio": "1.0.0-rc.10", "content-type": "1.0.5", "cookie-parser": "1.4.6", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index d6a7a0009..a6ae8d8dc 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -20,7 +20,7 @@ "@node-red/util": "4.0.2", "async-mutex": "0.5.0", "clone": "2.1.2", - "express": "4.19.2", + "express": "4.20.0", "fs-extra": "11.2.0", "json-stringify-safe": "5.0.1", "rfdc": "^1.3.1" diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index 93c90f807..a7de8cd80 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -38,9 +38,9 @@ "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", - "express": "4.19.2", + "express": "4.20.0", "fs-extra": "11.2.0", - "node-red-admin": "^4.0.0", + "node-red-admin": "^4.0.1", "nopt": "5.0.0", "semver": "7.5.4" }, From de0546b251b2cf707cdcfdfb55ff8d58bef0b1a0 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 15:23:03 +0100 Subject: [PATCH 39/87] Update packages/node_modules/@node-red/nodes/core/network/10-mqtt.js Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com> --- packages/node_modules/@node-red/nodes/core/network/10-mqtt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index 9e707fa68..f91a7c7d7 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -696,7 +696,7 @@ module.exports = function(RED) { // Ensure will payload, if set, is a string if (node.options.will && Object.hasOwn(node.options.will, 'payload')) { let payload = node.options.will.payload - if (payload === null || payload === undefined) { + if (payload === null || typeof payload === 'undefined') { payload = ""; } else if (!Buffer.isBuffer(payload)) { if (typeof payload === "object") { From 912a30b28de344876f687324d26ce442962b837d Mon Sep 17 00:00:00 2001 From: Gauthier Dandele <92022724+GogoVega@users.noreply.github.com> Date: Wed, 11 Sep 2024 17:02:18 +0200 Subject: [PATCH 40/87] Improve the filter to handle all cases + comments Co-authored-by: Nick O'Leary --- .../@node-red/editor-client/src/js/nodes.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 84a290b59..dacd6eeae 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2406,15 +2406,25 @@ RED.nodes = (function() { } else { delete n.g } - // If importing a subflow, ensure an outbound-link doesn't get added + // If importing a link node, ensure both ends of each link are either: + // - not in a subflow + // - both in the same subflow if (/^link /.test(n.type) && n.links) { - const isSubflow = !!getSubflow(n.z); - if (isSubflow) { - n.links = n.links.filter(function(id) { - const otherNode = node_map[id] || RED.nodes.node(id); - return (otherNode && otherNode.z === n.z); - }); - } + n.links = n.links.filter(function(id) { + const otherNode = node_map[id] || RED.nodes.node(id); + if (!otherNode) { + // Cannot find other end - remove the link + return false + } + if (otherNode.z === n.z) { + // Both ends in the same flow/subflow + return true + } else if (!!getSubflow(n.z) || !!getSubflow(otherNode.z)) { + // One end is in a subflow - remove the link + return false + } + return true + }); } for (var d3 in n._def.defaults) { if (n._def.defaults.hasOwnProperty(d3)) { From 92911f6714d0d1f8063368fbc6fc117b3a1f3856 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 17:37:50 +0100 Subject: [PATCH 41/87] Update tough-cookie --- package.json | 2 +- packages/node_modules/@node-red/nodes/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 06161a639..b0b5b1e8b 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "rfdc": "^1.3.1", "semver": "7.5.4", "tar": "7.2.0", - "tough-cookie": "4.1.4", + "tough-cookie": "^5.0.0", "uglify-js": "3.17.4", "uuid": "9.0.1", "ws": "7.5.10", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index 45f0de327..b5cbc16b9 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -41,7 +41,7 @@ "node-watch": "0.7.4", "on-headers": "1.0.2", "raw-body": "2.5.2", - "tough-cookie": "4.1.4", + "tough-cookie": "^5.0.0", "uuid": "9.0.1", "ws": "7.5.10", "xml2js": "0.6.2", From d76b0d39cd18cea065c93ed3637b47bbdbda9e04 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 17:47:26 +0100 Subject: [PATCH 42/87] Remove use of util.log --- .../node_modules/@node-red/util/lib/log.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/node_modules/@node-red/util/lib/log.js b/packages/node_modules/@node-red/util/lib/log.js index 341019080..7b7e9b2dc 100644 --- a/packages/node_modules/@node-red/util/lib/log.js +++ b/packages/node_modules/@node-red/util/lib/log.js @@ -75,12 +75,28 @@ LogHandler.prototype.shouldReportMessage = function(msglevel) { msglevel <= this.logLevel; } + +// Older versions of Node-RED used the deprecated util.log function. +// With Node.js 22, use of that function causes warnings. So here we +// are replicating the same format output to ensure we don't break any +// log parsing that happens in the real world. +const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +const utilLog = function (msg) { + const d = new Date(); + const time = [ + d.getHours().toString().padStart(2, '0'), + d.getMinutes().toString().padStart(2, '0'), + d.getSeconds().toString().padStart(2, '0') + ].join(':'); + console.log(`${d.getDate()} ${months[d.getMonth()]} ${time} - ${msg}`) +} + var consoleLogger = function(msg) { if (msg.level == log.METRIC || msg.level == log.AUDIT) { - util.log("["+levelNames[msg.level]+"] "+JSON.stringify(msg)); + utilLog("["+levelNames[msg.level]+"] "+JSON.stringify(msg)); } else { if (verbose && msg.msg && msg.msg.stack) { - util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+msg.msg.stack); + utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+msg.msg.stack); } else { var message = msg.msg; try { @@ -91,7 +107,7 @@ var consoleLogger = function(msg) { message = 'Exception trying to log: '+util.inspect(message); } - util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message); + utilLog("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message); } } } From d4b001a74e4c88c9d3edc8d0a7b2cdda23bb0830 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 11 Sep 2024 18:28:35 +0100 Subject: [PATCH 43/87] Fix tests for util.log removal --- test/unit/@node-red/util/lib/log_spec.js | 79 ++++++++++++------------ 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/test/unit/@node-red/util/lib/log_spec.js b/test/unit/@node-red/util/lib/log_spec.js index 056f37672..8fe09b3bf 100644 --- a/test/unit/@node-red/util/lib/log_spec.js +++ b/test/unit/@node-red/util/lib/log_spec.js @@ -24,38 +24,38 @@ var log = NR_TEST_UTILS.require("@node-red/util").log; describe("@node-red/util/log", function() { beforeEach(function () { - var spy = sinon.stub(util, 'log').callsFake(function(arg){}); + var spy = sinon.stub(console, 'log').callsFake(function(arg){}); var settings = {logging: { console: { level: 'metric', metrics: true } } }; log.init(settings); }); afterEach(function() { - util.log.restore(); + console.log.restore(); }); it('it can raise an error', function() { var ret = log.error("This is an error"); - sinon.assert.calledWithMatch(util.log,"[error] This is an error"); + sinon.assert.calledWithMatch(console.log,"[error] This is an error"); }); it('it can raise a trace', function() { var ret = log.trace("This is a trace"); - sinon.assert.calledWithMatch(util.log,"[trace] This is a trace"); + sinon.assert.calledWithMatch(console.log,"[trace] This is a trace"); }); it('it can raise a debug', function() { var ret = log.debug("This is a debug"); - sinon.assert.calledWithMatch(util.log,"[debug] This is a debug"); + sinon.assert.calledWithMatch(console.log,"[debug] This is a debug"); }); it('it can raise a info', function() { var ret = log.info("This is an info"); - sinon.assert.calledWithMatch(util.log,"[info] This is an info"); + sinon.assert.calledWithMatch(console.log,"[info] This is an info"); }); it('it can raise a warn', function() { var ret = log.warn("This is a warn"); - sinon.assert.calledWithMatch(util.log,"[warn] This is a warn"); + sinon.assert.calledWithMatch(console.log,"[warn] This is a warn"); }); it('it can raise a metric', function() { @@ -66,9 +66,10 @@ describe("@node-red/util/log", function() { metrics.msgid = "12345"; metrics.value = "the metric payload"; var ret = log.log(metrics); - util.log.calledOnce.should.be.true(); - util.log.firstCall.args[0].indexOf("[metric] ").should.equal(0); - var body = JSON.parse(util.log.firstCall.args[0].substring(9)); + console.log.calledOnce.should.be.true(); + console.log.firstCall.args[0].indexOf("[metric]").should.not.equal(-1); + const parts = console.log.firstCall.args[0].split("[metric] ") + var body = JSON.parse(parts[1]) body.should.have.a.property("nodeid","testid"); body.should.have.a.property("event","node.test.testevent"); body.should.have.a.property("msgid","12345"); @@ -86,13 +87,13 @@ describe("@node-red/util/log", function() { it('it logs node type and name if provided',function() { log.log({level:log.INFO,type:"nodeType",msg:"test",name:"nodeName",id:"nodeId"}); - util.log.calledOnce.should.be.true(); - util.log.firstCall.args[0].indexOf("[nodeType:nodeName]").should.not.equal(-1); + console.log.calledOnce.should.be.true(); + console.log.firstCall.args[0].indexOf("[nodeType:nodeName]").should.not.equal(-1); }); it('it logs node type and id if no name provided',function() { log.log({level:log.INFO,type:"nodeType",msg:"test",id:"nodeId"}); - util.log.calledOnce.should.be.true(); - util.log.firstCall.args[0].indexOf("[nodeType:nodeId]").should.not.equal(-1); + console.log.calledOnce.should.be.true(); + console.log.firstCall.args[0].indexOf("[nodeType:nodeId]").should.not.equal(-1); }); it('ignores lower level messages and metrics', function() { @@ -104,12 +105,12 @@ describe("@node-red/util/log", function() { log.debug("This is a debug"); log.trace("This is a trace"); log.log({level:log.METRIC,msg:"testMetric"}); - sinon.assert.calledWithMatch(util.log,"[error] This is an error"); - sinon.assert.calledWithMatch(util.log,"[warn] This is a warn"); - sinon.assert.neverCalledWithMatch(util.log,"[info] This is an info"); - sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug"); - sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace"); - sinon.assert.neverCalledWithMatch(util.log,"[metric] "); + sinon.assert.calledWithMatch(console.log,"[error] This is an error"); + sinon.assert.calledWithMatch(console.log,"[warn] This is a warn"); + sinon.assert.neverCalledWithMatch(console.log,"[info] This is an info"); + sinon.assert.neverCalledWithMatch(console.log,"[debug] This is a debug"); + sinon.assert.neverCalledWithMatch(console.log,"[trace] This is a trace"); + sinon.assert.neverCalledWithMatch(console.log,"[metric] "); }); it('ignores lower level messages but accepts metrics', function() { var settings = {logging: { console: { level: 'log', metrics: true } } }; @@ -120,12 +121,12 @@ describe("@node-red/util/log", function() { log.debug("This is a debug"); log.trace("This is a trace"); log.log({level:log.METRIC,msg:"testMetric"}); - sinon.assert.calledWithMatch(util.log,"[error] This is an error"); - sinon.assert.calledWithMatch(util.log,"[warn] This is a warn"); - sinon.assert.calledWithMatch(util.log,"[info] This is an info"); - sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug"); - sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace"); - sinon.assert.calledWithMatch(util.log,"[metric] "); + sinon.assert.calledWithMatch(console.log,"[error] This is an error"); + sinon.assert.calledWithMatch(console.log,"[warn] This is a warn"); + sinon.assert.calledWithMatch(console.log,"[info] This is an info"); + sinon.assert.neverCalledWithMatch(console.log,"[debug] This is a debug"); + sinon.assert.neverCalledWithMatch(console.log,"[trace] This is a trace"); + sinon.assert.calledWithMatch(console.log,"[metric] "); }); it('default settings set to INFO and metrics off', function() { @@ -136,12 +137,12 @@ describe("@node-red/util/log", function() { log.debug("This is a debug"); log.trace("This is a trace"); log.log({level:log.METRIC,msg:"testMetric"}); - sinon.assert.calledWithMatch(util.log,"[error] This is an error"); - sinon.assert.calledWithMatch(util.log,"[warn] This is a warn"); - sinon.assert.calledWithMatch(util.log,"[info] This is an info"); - sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug"); - sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace"); - sinon.assert.neverCalledWithMatch(util.log,"[metric] "); + sinon.assert.calledWithMatch(console.log,"[error] This is an error"); + sinon.assert.calledWithMatch(console.log,"[warn] This is a warn"); + sinon.assert.calledWithMatch(console.log,"[info] This is an info"); + sinon.assert.neverCalledWithMatch(console.log,"[debug] This is a debug"); + sinon.assert.neverCalledWithMatch(console.log,"[trace] This is a trace"); + sinon.assert.neverCalledWithMatch(console.log,"[metric] "); }); it('no logger used if custom logger handler does not exist', function() { var settings = {logging: { customLogger: { level: 'trace', metrics: true } } }; @@ -152,12 +153,12 @@ describe("@node-red/util/log", function() { log.debug("This is a debug"); log.trace("This is a trace"); log.log({level:log.METRIC,msg:"testMetric"}); - sinon.assert.neverCalledWithMatch(util.log,"[error] This is an error"); - sinon.assert.neverCalledWithMatch(util.log,"[warn] This is a warn"); - sinon.assert.neverCalledWithMatch(util.log,"[info] This is an info"); - sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug"); - sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace"); - sinon.assert.neverCalledWithMatch(util.log,"[metric] "); + sinon.assert.neverCalledWithMatch(console.log,"[error] This is an error"); + sinon.assert.neverCalledWithMatch(console.log,"[warn] This is a warn"); + sinon.assert.neverCalledWithMatch(console.log,"[info] This is an info"); + sinon.assert.neverCalledWithMatch(console.log,"[debug] This is a debug"); + sinon.assert.neverCalledWithMatch(console.log,"[trace] This is a trace"); + sinon.assert.neverCalledWithMatch(console.log,"[metric] "); }); it('add a custom log handler directly', function() { @@ -244,7 +245,7 @@ describe("@node-red/util/log", function() { }, }; var ret = log.info(msg.msg); - sinon.assert.calledWithMatch(util.log,"my special message"); + sinon.assert.calledWithMatch(console.log,"my special message"); }); From 359775969258134bc539f7acfa49a07c654f1e19 Mon Sep 17 00:00:00 2001 From: Steve-Mcl Date: Thu, 12 Sep 2024 14:40:39 +0100 Subject: [PATCH 44/87] set status of mqtt nodes when deregistered from broker --- packages/node_modules/@node-red/nodes/core/network/10-mqtt.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index f91a7c7d7..db6cfba73 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -742,6 +742,7 @@ module.exports = function(RED) { }; node.deregister = function(mqttNode, done, autoDisconnect) { + setStatusDisconnected(mqttNode, false); delete node.users[mqttNode.id]; if (autoDisconnect && !node.closing && node.connected && Object.keys(node.users).length === 0) { node.disconnect(done); From 89839f433bb69b2b436f07b7c277d5925eef2bd1 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 13 Sep 2024 14:35:46 +0100 Subject: [PATCH 45/87] Do not include Junction type in quick-add for virtual links --- .../editor-client/src/js/ui/typeSearch.js | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js index 703b57309..216cc3e40 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js @@ -335,13 +335,25 @@ RED.typeSearch = (function() { } } function applyFilter(filter,type,def) { - return !def || !filter || - ( - (!filter.spliceMultiple) && - (!filter.type || type === filter.type) && - (!filter.input || type === 'junction' || def.inputs > 0) && - (!filter.output || type === 'junction' || def.outputs > 0) - ) + if (!filter) { + // No filter; allow everything + return true + } + if (type === 'junction') { + // Only allow Junction is there's no specific type filter + return !filter.type + } + if (filter.type) { + // Handle explicit type filter + return filter.type === type + } + if (!def) { + // No node definition available - allow it + return true + } + // Check if the filter is for input/outputs and apply + return (!filter.input || def.inputs > 0) && + (!filter.output || def.outputs > 0) } function refreshTypeList(opts) { var i; From 64cdee6d36a17ecf274f72eedbb9703a8a374df2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 13 Sep 2024 14:57:09 +0100 Subject: [PATCH 46/87] Update express --- package.json | 2 +- packages/node_modules/@node-red/editor-api/package.json | 2 +- packages/node_modules/@node-red/runtime/package.json | 2 +- packages/node_modules/node-red/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b0b5b1e8b..ae163fe62 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", - "express": "4.20.0", + "express": "4.21.0", "express-session": "1.18.0", "form-data": "4.0.0", "fs-extra": "11.2.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index f46a31a02..e8b09f443 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -23,7 +23,7 @@ "clone": "2.1.2", "cors": "2.8.5", "express-session": "1.18.0", - "express": "4.20.0", + "express": "4.21.0", "memorystore": "1.6.7", "mime": "3.0.0", "multer": "1.4.5-lts.1", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index a6ae8d8dc..2203b5f8e 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -20,7 +20,7 @@ "@node-red/util": "4.0.2", "async-mutex": "0.5.0", "clone": "2.1.2", - "express": "4.20.0", + "express": "4.21.0", "fs-extra": "11.2.0", "json-stringify-safe": "5.0.1", "rfdc": "^1.3.1" diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index a7de8cd80..3ea55b756 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -38,7 +38,7 @@ "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", - "express": "4.20.0", + "express": "4.21.0", "fs-extra": "11.2.0", "node-red-admin": "^4.0.1", "nopt": "5.0.0", From f44868384e7fb12d30f0ac1b5788074b6321b7fc Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 16 Sep 2024 11:55:05 +0100 Subject: [PATCH 47/87] Move SNI, ALPN and Verify Server cert out of check This moves the SNI, ALPN and the Verify Server Cert check out of the check for if the supplied certs/key are actually valid as these may be still required for correct behaviour. part of #4877 --- .../@node-red/nodes/core/network/05-tls.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/network/05-tls.js b/packages/node_modules/@node-red/nodes/core/network/05-tls.js index 888d749fd..f47067729 100644 --- a/packages/node_modules/@node-red/nodes/core/network/05-tls.js +++ b/packages/node_modules/@node-red/nodes/core/network/05-tls.js @@ -104,14 +104,14 @@ module.exports = function(RED) { if (this.credentials && this.credentials.passphrase) { opts.passphrase = this.credentials.passphrase; } - if (this.servername) { - opts.servername = this.servername; - } - if (this.alpnprotocol) { - opts.ALPNProtocols = [this.alpnprotocol]; - } - opts.rejectUnauthorized = this.verifyservercert; } + if (this.servername) { + opts.servername = this.servername; + } + if (this.alpnprotocol) { + opts.ALPNProtocols = [this.alpnprotocol]; + } + opts.rejectUnauthorized = this.verifyservercert; return opts; } From aa74d8160ac900cbac9935f1b96a96e51f69bd85 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 16 Sep 2024 16:39:41 +0100 Subject: [PATCH 48/87] Stay in quick-add mode following context menu insert Fixes #4881 --- .../@node-red/editor-client/src/js/ui/view.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index fd1205a30..40ec0d5bf 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -1209,7 +1209,11 @@ RED.view = (function() { lasso = null; } if (d3.event.touches || d3.event.button === 0) { - if ((mouse_mode === 0 || mouse_mode === RED.state.QUICK_JOINING) && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) { + if ( + (mouse_mode === 0 && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) + || + mouse_mode === RED.state.QUICK_JOINING + ) { // Trigger quick add dialog d3.event.stopPropagation(); clearSelection(); @@ -1285,7 +1289,6 @@ RED.view = (function() { } var mainPos = $("#red-ui-main-container").position(); - if (mouse_mode !== RED.state.QUICK_JOINING) { mouse_mode = RED.state.QUICK_JOINING; $(window).on('keyup',disableQuickJoinEventHandler); @@ -3057,8 +3060,8 @@ RED.view = (function() { } function disableQuickJoinEventHandler(evt) { - // Check for ctrl (all browsers), "Meta" (Chrome/FF), keyCode 91 (Safari) - if (evt.keyCode === 17 || evt.key === "Meta" || evt.keyCode === 91) { + // Check for ctrl (all browsers), "Meta" (Chrome/FF), keyCode 91 (Safari), or Escape + if (evt.keyCode === 17 || evt.key === "Meta" || evt.keyCode === 91 || evt.keyCode === 27) { resetMouseVars(); hideDragLines(); redraw(); From 83b30f1c18bcf16f0bec2d64458af77de942308e Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 16 Sep 2024 16:45:22 +0100 Subject: [PATCH 49/87] Fix linting --- .../node_modules/@node-red/editor-client/src/js/ui/view.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index 40ec0d5bf..ff0091e65 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -1210,10 +1210,9 @@ RED.view = (function() { } if (d3.event.touches || d3.event.button === 0) { if ( - (mouse_mode === 0 && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) - || - mouse_mode === RED.state.QUICK_JOINING - ) { + (mouse_mode === 0 && isControlPressed(d3.event) && !(d3.event.altKey || d3.event.shiftKey)) || + mouse_mode === RED.state.QUICK_JOINING + ) { // Trigger quick add dialog d3.event.stopPropagation(); clearSelection(); From 5a3e6925e54dfd47436a5c1f4bd72889730f0aab Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 17 Sep 2024 14:15:42 +0100 Subject: [PATCH 50/87] Update packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js --- .../@node-red/editor-client/src/js/ui/workspaces.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index 365d827f7..bd52498f1 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -909,7 +909,11 @@ RED.workspaces = (function() { document.title = `${documentTitle} : ${workspace.label}`; } else { var subflow = RED.nodes.subflow(RED.workspaces.active()); - document.title = `${documentTitle} : ${subflow.name}`; + if (subflow) { + document.title = `${documentTitle} : ${subflow.name}`; + } else { + document.title = documentTitle + } } RED.nodes.eachWorkspace(function(ws) { workspace_tabs.renameTab(ws.id,ws.label); From f7a43f83e5c3339c9edd51c354bab280971d6699 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 17 Sep 2024 14:23:43 +0100 Subject: [PATCH 51/87] Bump for 4.0.3 --- .github/workflows/tests.yml | 2 +- CHANGELOG.md | 35 +++++++++++++++++++ package.json | 2 +- .../@node-red/editor-api/package.json | 6 ++-- .../@node-red/editor-client/package.json | 2 +- .../node_modules/@node-red/nodes/package.json | 2 +- .../@node-red/registry/package.json | 4 +-- .../@node-red/runtime/package.json | 6 ++-- .../node_modules/@node-red/util/package.json | 2 +- packages/node_modules/node-red/package.json | 10 +++--- 10 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cf871716a..70d36deb1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18, 20, 22.4.x] + node-version: [18, 20, 22] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index e4ebd3087..6eaa3b7fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ +#### 4.0.3: Maintenance Release + +Editor + + - Refresh page title after changing tab name (#4850) @kazuhitoyokoi + - Add Japanese translations for v4.0.2 (again) (#4853) @kazuhitoyokoi + - Stay in quick-add mode following context menu insert (#4883) @knolleary + - Do not include Junction type in quick-add for virtual links (#4879) @knolleary + - Multiplayer cursor tracking (#4845) @knolleary + - Hide add-flow options when disabled via editorTheme (#4869) @knolleary + - Fix env-var config select when multiple defined (#4872) @knolleary + - Fix subflow outbound-link filter (#4857) @GogoVega + - Add French translations for v4.0.2 (#4856) @GogoVega + - Fix moving link wires (#4851) @knolleary + - Adjust type search dialog position to prevent x-overflow (#4844) @Steve-Mcl + - fix: modulesInUse might be undefined (#4838) @lorenz-maurer + - Add Japanese translations for v4.0.2 (#4849) @kazuhitoyokoi + - Fix menu to enable/disable selection when it's a group (#4828) @GogoVega + +Runtime + + - Update dependencies (#4874) @knolleary + - GitHub: Add citation file to enable "Cite this repository" feature (#4861) @lobis + - Remove use of util.log (#4875) @knolleary + +Nodes + + - Fix invalid property error in range node example (#4855) + - Fix typo in flow example name (#4854) @kazuhitoyokoi + - Move SNI, ALPN and Verify Server cert out of check (#4882) @hardillb + - Set status of mqtt nodes to "disconnected" when deregistered from broker (#4878) @Steve-Mcl + - MQTT: Ensure will payload is a string (#4873) @knolleary + - Let batch node terminate "early" if msg.parts set to end of sequence (#4829) @dceejay + - Fix unintentional Capitalisation in Split node name (#4835) @dceejay + #### 4.0.2: Maintenance Release Editor diff --git a/package.json b/package.json index ae163fe62..5c41a2999 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.2", + "version": "4.0.3", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index e8b09f443..59a265ca4 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/util": "4.0.2", - "@node-red/editor-client": "4.0.2", + "@node-red/util": "4.0.3", + "@node-red/editor-client": "4.0.3", "bcryptjs": "2.4.3", "body-parser": "1.20.3", "clone": "2.1.2", diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index 932afb7ac..7e65dcc1a 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index b5cbc16b9..dcbb59b24 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/nodes", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 1d54f76d8..2515b19b7 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/registry", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,7 +16,7 @@ } ], "dependencies": { - "@node-red/util": "4.0.2", + "@node-red/util": "4.0.3", "clone": "2.1.2", "fs-extra": "11.2.0", "semver": "7.5.4", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 2203b5f8e..67464f496 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/runtime", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/registry": "4.0.2", - "@node-red/util": "4.0.2", + "@node-red/registry": "4.0.3", + "@node-red/util": "4.0.3", "async-mutex": "0.5.0", "clone": "2.1.2", "express": "4.21.0", diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 1f25923bb..d747109dd 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/util", - "version": "4.0.2", + "version": "4.0.3", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index 3ea55b756..b6c767e9b 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.2", + "version": "4.0.3", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "flow" ], "dependencies": { - "@node-red/editor-api": "4.0.2", - "@node-red/runtime": "4.0.2", - "@node-red/util": "4.0.2", - "@node-red/nodes": "4.0.2", + "@node-red/editor-api": "4.0.3", + "@node-red/runtime": "4.0.3", + "@node-red/util": "4.0.3", + "@node-red/nodes": "4.0.3", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", From 32540dd0e6ef97a1e0de19afb31e0ef05460eded Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:16:53 +0200 Subject: [PATCH 52/87] Fix wrong unlock state when event is triggered --- .../@node-red/editor-client/src/js/ui/deploy.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js index 25a67907c..e429c1586 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js @@ -589,6 +589,7 @@ RED.deploy = (function() { RED.notify('

' + RED._("deploy.successfulDeploy") + '

', "success"); } const flowsToLock = new Set() + // Node's properties cannot be modified if its workspace is locked. function ensureUnlocked(id) { const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null); const isLocked = flow ? flow.locked : false; @@ -645,6 +646,9 @@ RED.deploy = (function() { RED.nodes.eachSubflow(function (subflow) { if (subflow.changed) { subflow.changed = false; + if (flowsToLock.has(subflow)) { + subflow.locked = true; + } RED.events.emit("subflows:change", subflow); } }); @@ -653,9 +657,13 @@ RED.deploy = (function() { ensureUnlocked(ws.z) ws.changed = false; delete ws.added + if (flowsToLock.has(ws)) { + ws.locked = true; + } RED.events.emit("flows:change", ws) } }); + // Ensures all workspaces/subflows to be locked have been locked. flowsToLock.forEach(flow => { flow.locked = true }) From 16c49306f35b389961ad7513bb2db792ec434bf2 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Thu, 26 Sep 2024 19:01:44 +0200 Subject: [PATCH 53/87] Fix link call node can call out of a subflow --- .../node_modules/@node-red/editor-client/src/js/nodes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index dacd6eeae..25e8c2185 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2408,7 +2408,7 @@ RED.nodes = (function() { } // If importing a link node, ensure both ends of each link are either: // - not in a subflow - // - both in the same subflow + // - both in the same subflow (not for link call node) if (/^link /.test(n.type) && n.links) { n.links = n.links.filter(function(id) { const otherNode = node_map[id] || RED.nodes.node(id); @@ -2419,6 +2419,9 @@ RED.nodes = (function() { if (otherNode.z === n.z) { // Both ends in the same flow/subflow return true + } else if (n.type === "link call") { + // Link call node can call out of a subflow + return true } else if (!!getSubflow(n.z) || !!getSubflow(otherNode.z)) { // One end is in a subflow - remove the link return false From cec7a86b54a60a1408704877221f1543e1d19997 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 27 Sep 2024 09:42:07 +0100 Subject: [PATCH 54/87] Update dev dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5c41a2999..6597530f2 100644 --- a/package.json +++ b/package.json @@ -86,10 +86,10 @@ "@node-rs/bcrypt": "1.10.4" }, "devDependencies": { - "dompurify": "2.4.1", + "dompurify": "2.5.7", "grunt": "1.6.1", "grunt-chmod": "~1.1.1", - "grunt-cli": "~1.4.3", + "grunt-cli": "~1.5.0", "grunt-concurrent": "3.0.0", "grunt-contrib-clean": "2.0.1", "grunt-contrib-compress": "2.0.0", @@ -100,7 +100,7 @@ "grunt-contrib-watch": "1.1.0", "grunt-jsdoc": "2.4.1", "grunt-jsdoc-to-markdown": "6.0.0", - "grunt-jsonlint": "2.1.3", + "grunt-jsonlint": "3.0.0", "grunt-mkdir": "~1.1.0", "grunt-npm-command": "~0.1.2", "grunt-sass": "~3.1.0", @@ -114,7 +114,7 @@ "minami": "1.2.3", "mocha": "9.2.2", "node-red-node-test-helper": "^0.3.3", - "nodemon": "2.0.20", + "nodemon": "3.1.7", "proxy": "^1.0.2", "sass": "1.62.1", "should": "13.2.3", From 1053fc5121f97e1374df49353d235c21723503ff Mon Sep 17 00:00:00 2001 From: Daniel Caspi Date: Fri, 27 Sep 2024 04:35:51 -0500 Subject: [PATCH 55/87] fix typo: depreciated --- .../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 bc89992e2..d26f0f56b 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 @@ -456,7 +456,7 @@ "staticTopic": "Subscribe to single topic", "dynamicTopic": "Dynamic subscription", "auto-connect": "Connect automatically", - "auto-mode-depreciated": "This option is depreciated. Please use the new auto-detect mode.", + "auto-mode-depreciated": "This option is deprecated. Please use the new auto-detect mode.", "none": "none", "other": "other" }, From e3acc49d5e0aee41c8bab84f34c49b4cf149fef4 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Tue, 1 Oct 2024 16:31:28 +0100 Subject: [PATCH 56/87] Allow msg.userProperties to have number values fixes #4899 --- .../node_modules/@node-red/nodes/core/network/10-mqtt.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index db6cfba73..bc6f9644d 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -158,9 +158,12 @@ module.exports = function(RED) { if(!keys || !keys.length) return null; keys.forEach(key => { let val = srcUserProperties[key]; - if(typeof val == "string") { + if(typeof val === "string") { count++; _clone[key] = val; + } else if (typeof val === "number") { + count++; + _clone[key] = val.toString(); } }); if(count) properties.userProperties = _clone; From 7650620a7875173152f68b1734748e376b8e7800 Mon Sep 17 00:00:00 2001 From: Joe Bordes Date: Fri, 4 Oct 2024 18:06:01 +0200 Subject: [PATCH 57/87] i18n(App) update with latest language file changes --- .../editor-client/locales/es-ES/editor.json | 55 ++++++- .../nodes/locales/es-ES/messages.json | 141 ++++++++++-------- .../nodes/locales/es-ES/network/31-tcpin.html | 2 + .../nodes/locales/es-ES/parsers/70-CSV.html | 5 +- .../runtime/locales/es-ES/runtime.json | 1 + 5 files changed, 133 insertions(+), 71 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/locales/es-ES/editor.json b/packages/node_modules/@node-red/editor-client/locales/es-ES/editor.json index 2655dfe27..eb2ef79d2 100644 --- a/packages/node_modules/@node-red/editor-client/locales/es-ES/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/es-ES/editor.json @@ -27,7 +27,8 @@ "lock": "Bloquear", "unlock": "Desbloquear", "locked": "Bloqueado", - "unlocked": "Desbloqueado" + "unlocked": "Desbloqueado", + "format": "Formato" }, "type": { "string": "texto", @@ -303,7 +304,8 @@ "missingType": "La entrada no es un flujo válido - elemento __index__ falta la propiedad 'type'" }, "conflictNotification1": "Algunos de los nodos que estás importando ya existen en tu espacio de trabajo.", - "conflictNotification2": "Selecciona qué nodos importar y si reemplazar los nodos existentes o importar una copia de los mismos." + "conflictNotification2": "Selecciona qué nodos importar y si reemplazar los nodos existentes o importar una copia de los mismos.", + "alreadyExists": "Este nodo ya existe" }, "copyMessagePath": "Ruta copiada", "copyMessageValue": "Valor copiado", @@ -371,8 +373,12 @@ "deleted": "eliminado", "flowDeleted": "flujo eliminado", "flowAdded": "flujo añadido", + "moved": "movido", "movedTo": "movido a __id__", - "movedFrom": "movido desde __id__" + "movedFrom": "movido desde __id__", + "none": "ninguno", + "position": "posición", + "wires": "conectores" }, "nodeCount": "__count__ nodo", "nodeCount_plural": "__count__ nodos", @@ -381,9 +387,14 @@ "reviewChanges": "Revisar Cambios", "noBinaryFileShowed": "No se puede mostrar el contenido del archivo binario", "viewCommitDiff": "Ver cambios de commit", + "commit": "Commit", "compareChanges": "Comparar Cambios", "saveConflict": "Guardar resolución de conflictos", "conflictHeader": "__resolved__ de __unresolved__ conflictos resueltos", + "localChanges": "Cambios Locales", + "remoteChanges": "Cambios Remotos", + "useLocalChanges": "utilizar cambios locales", + "useRemoteChanges": "utilizar cambios remotos", "commonVersionError": "La versión común no contiene JSON válido:", "oldVersionError": "La versión anterior no contiene JSON válido:", "newVersionError": "La versión nueva no contiene JSON válido:" @@ -551,7 +562,9 @@ "types": { "local": "Local", "examples": "Ejemplos" - } + }, + "type": "Tipo", + "name": "Nombre" }, "palette": { "noInfo": "no hay información disponible", @@ -613,6 +626,8 @@ }, "nodeCount": "__label__ nodo", "nodeCount_plural": "__label__ nodos", + "pluginCount": "__count__ extensión", + "pluginCount_plural": "__count__ extensiones", "moduleCount": "__count__ módulo disponible", "moduleCount_plural": "__count__ módulos disponibles", "inuse": "en uso", @@ -640,6 +655,7 @@ "errors": { "catalogLoadFailed": "

La carga del catálogo de nodos ha fallado

Revise la consola del navegador para mas información

", "installFailed": "

Fallo al instalar: __module__

__message__

Revise el log para mas información

", + "installTimeout": "

La instalación continúa en segundo plano.

Los nodos aparecerán en la paleta cuando finalice. Consulta el registro para obtener más información.

", "removeFailed": "

Fallo al eliminar: __module__

__message__

Revise el log para mas información

", "updateFailed": "

Fallo al actualizar: __module__

__message__

Revise el log para mas información

", "enableFailed": "

Fallo al activar: __module__

__message__

Revise el log para mas información

", @@ -654,6 +670,9 @@ "body":"

Eliminando '__module__'

La eliminación del nodo lo desinstalará de Node-RED. Es posible que el nodo siga utilizando recursos hasta que Node-RED sea reiniciado.

", "title": "Eliminar nodos" }, + "removePlugin": { + "body": "

Extensión __module__ eliminada. Vuelve a cargar el editor para borrar los elementos sobrantes.

" + }, "update": { "body":"

Actualizando '__module__'

La actualización del nodo requerirá un reinicio manual de Node-RED para completarse. Debe ser reiniciado manualmente.

", "title": "Actualizar nodos" @@ -665,7 +684,8 @@ "review": "Abrir información del nodo", "install": "Instalar", "remove": "Eliminar", - "update": "Actualizar" + "update": "Actualizar", + "understood": "Entendido" } } } @@ -718,6 +738,7 @@ "nodeHelp": "Ayuda de nodo", "showHelp": "Mostrar ayuda", "showInOutline": "Mostrar en controno", + "hideTopics": "Esconder temas", "showTopics": "Mostrar temas", "noHelp": "No hay ningun tema de ayuda seleccionado", "changeLog": "Registro de Cambios" @@ -792,6 +813,7 @@ "branches": "Ramas", "noBranches": "Sin ramas", "deleteConfirm": "¿Estás seguro de que quieres eliminar la rama local '__name__'? Esta acción no puede deshacerse.", + "deleteBranch": "Eliminar rama", "unmergedConfirm": "La rama local '__name__' tiene cambios no fusionados que se perderán. ¿Estás seguro de que quieres eliminarla?", "deleteUnmergedBranch": "Eliminar rama no fusionada", "gitRemotes": "Git remotes", @@ -913,6 +935,8 @@ } }, "typedInput": { + "selected": "__count__ seleccionado", + "selected_plural": "__count__ seleccionados", "type": { "str": "texto", "num": "número", @@ -923,7 +947,14 @@ "date": "marca tiempo", "jsonata": "expresión", "env": "variable de entorno", - "cred": "credencial" + "cred": "credencial", + "conf-types": "nodo configuración" + }, + "date": { + "format": { + "timestamp": "milisegundos desde epoch", + "object": "Objeto de fecha de JavaScript" + } } }, "editableList": { @@ -1205,6 +1236,18 @@ "diagnostics": { "title": "Información Sistema" }, + "languages": { + "de": "Deutsch", + "en-US": "English", + "es-ES": "Español (España)", + "fr": "Français", + "ja": "日本語", + "ko": "Korean", + "pt-BR": "Português (Brasil)", + "ru": "Русский", + "zh-CN": "简体中文", + "zh-TW": "繁體中文" + }, "validator": { "errors": { "invalid-json": "Datos JSON inválidos: __error__", diff --git a/packages/node_modules/@node-red/nodes/locales/es-ES/messages.json b/packages/node_modules/@node-red/nodes/locales/es-ES/messages.json index b8ac84f1c..19427e2fc 100644 --- a/packages/node_modules/@node-red/nodes/locales/es-ES/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/es-ES/messages.json @@ -513,15 +513,15 @@ "method": "Método", "url": "URL", "doc": "Docs", - "return": "Return", - "upload": "Accept file uploads?", - "status": "Status code", - "headers": "Headers", + "return": "Devolver", + "upload": "¿Aceptar cargas de archivos?", + "status": "Código de estado", + "headers": "Encabezados", "other": "otro", "paytoqs": { - "ignore": "Ignore", - "query": "Append to query-string parameters", - "body": "Send as request body" + "ignore": "Ignorar", + "query": "Agregar a los parámetros de la cadena de consulta", + "body": "Enviar como cuerpo de la solicitud" }, "utf8String": "texto UTF8", "binaryBuffer": "buffer binario", @@ -529,45 +529,45 @@ "authType": "Tipo", "bearerToken": "Token" }, - "setby": "- set by msg.method -", - "basicauth": "Use authentication", - "use-tls": "Enable secure (SSL/TLS) connection", - "tls-config": "TLS Configuration", - "basic": "basic authentication", - "digest": "digest authentication", - "bearer": "bearer authentication", - "use-proxy": "Use proxy", - "persist": "Enable connection keep-alive", - "proxy-config": "Proxy Configuration", - "use-proxyauth": "Use proxy authentication", - "noproxy-hosts": "Ignore hosts", - "senderr": "Only send non-2xx responses to Catch node", - "utf8": "a UTF-8 string", - "binary": "a binary buffer", - "json": "a parsed JSON object", + "setby": "- establecido por msg.method -", + "basicauth": "Usar autenticación", + "use-tls": "Habilitar conexión segura (SSL/TLS)", + "tls-config": "Configuración TLS", + "basic": "autenticación básica", + "digest": "autenticación digest", + "bearer": "autenticación bearer", + "use-proxy": "Usar proxy", + "persist": "Habilitar conexión activa (keep-alive)", + "proxy-config": "Configuración Proxy", + "use-proxyauth": "Usar autenticación de proxy", + "noproxy-hosts": "Ignorar hosts", + "senderr": "Enviar solo respuestas que no sean 2xx al nodo Catch", + "utf8": "una cadena UTF-8", + "binary": "un búfer binario", + "json": "un objeto JSON analizado", "tip": { - "in": "The url will be relative to ", - "res": "The messages sent to this node must originate from an http input node", + "in": "La URL será relativa a ", + "res": "Los mensajes enviados a este nodo deben originarse desde un nodo de http input", "req": "Tip: If the JSON parse fails the fetched string is returned as-is." }, - "httpreq": "http request", + "httpreq": "solicitud http", "errors": { - "not-created": "Cannot create http-in node when httpNodeRoot set to false", - "missing-path": "missing path", - "no-response": "No response object", - "json-error": "JSON parse error", - "no-url": "No url specified", - "deprecated-call": "Deprecated call to __method__", - "invalid-transport": "non-http transport requested", - "timeout-isnan": "Timeout value is not a valid number, ignoring", - "timeout-isnegative": "Timeout value is negative, ignoring", - "invalid-payload": "Invalid payload", - "invalid-url": "Invalid url" + "not-created": "No se puede crear el nodo http-in cuando httpNodeRoot está establecido en falso", + "missing-path": "falta la ruta", + "no-response": "No hay objeto de respuesta", + "json-error": "Error de análisis en JSON", + "no-url": "No se especificó ninguna URL", + "deprecated-call": "Llamada obsoleta a __method__", + "invalid-transport": "protocolo no-http solicitado", + "timeout-isnan": "El valor de tiempo de espera no es un número válido, se ignora", + "timeout-isnegative": "El valor de tiempo de espera es negativo, se ignora", + "invalid-payload": "payload Invalido", + "invalid-url": "URL Inválida" }, "status": { - "requesting": "requesting" + "requesting": "solicitando" }, - "insecureHTTPParser": "Disable strict HTTP parsing" + "insecureHTTPParser": "Deshabilitar el análisis estricto de HTTP" }, "websocket": { "label": { @@ -576,41 +576,42 @@ "url": "URL", "subprotocol": "Subprotocolo" }, - "listenon": "Listen on", - "connectto": "Connect to", - "sendrec": "Send/Receive", + "listenon": "Escuchar", + "connectto": "Conectar a", + "sendrec": "Enviar/Recibir", "payload": "payload", - "message": "entire message", - "sendheartbeat": "Send heartbeat", + "message": "mensaje completo", + "sendheartbeat": "Enviar latido", "tip": { - "path1": "By default, payload will contain the data to be sent over, or received from a websocket. The listener can be configured to send or receive the entire message object as a JSON formatted string.", - "path2": "This path will be relative to __path__.", - "url1": "URL should use ws:// or wss:// scheme and point to an existing websocket listener.", - "url2": "By default, payload will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string." + "path1": "De manera predeterminada, payload contendrá los datos que se enviarán o recibirán de un websocket. El receptor puede configurarse para enviar o recibir el objeto de mensaje completo como una cadena en formato JSON.", + "path2": "Esta ruta será relativa a __path__.", + "url1": "La URL debe usar el esquema ws:// o wss:// y apuntar a un receptor de websocket existente.", + "url2": "De manera predeterminada, payload contendrá los datos que se enviarán o recibirán de un websocket. El cliente puede configurarse para enviar o recibir el objeto de mensaje completo como una cadena en formato JSON", + "headers": "Los encabezados solo se envían durante el mecanismo de actualización del protocolo, de HTTP al protocolo WS/WSS." }, "status": { - "connected": "connected __count__", - "connected_plural": "connected __count__" + "connected": "__count__ conectado", + "connected_plural": "__count__ conectados" }, "errors": { - "connect-error": "An error occurred on the ws connection: ", - "send-error": "An error occurred while sending: ", - "missing-conf": "Missing server configuration", - "duplicate-path": "Cannot have two WebSocket listeners on the same path: __path__", - "missing-server": "Missing server configuration", - "missing-client": "Missing client configuration" + "connect-error": "Se produjo un error en la conexión ws:", + "send-error": "Se produjo un error al enviar: ", + "missing-conf": "Falta la configuración del servidor", + "duplicate-path": "No se pueden tener dos escuchas de WebSocket en la misma ruta: __path__", + "missing-server": "Falta la configuración del servidor", + "missing-client": "Falta la configuración del cliente" } }, "watch": { - "watch": "watch", + "watch": "observar", "label": { - "files": "File(s)", - "recursive": "Watch sub-directories recursively" + "files": "Fichero(s)", + "recursive": "Observar subdirectorios recursivamente" }, "placeholder": { - "files": "Comma-separated list of files and/or directories" + "files": "Lista de archivos y/o directorios separados por comas" }, - "tip": "On Windows you must use double back-slashes \\\\ in any directory names." + "tip": "En Windows, debes utilizar barras invertidas dobles \\\\ en cualquier nombre de directorio." }, "tcpin": { "label": { @@ -849,7 +850,13 @@ "newline": "Nueva línea", "usestrings": "analizar valores numéricos", "include_empty_strings": "incluir cadenas vacías", - "include_null_values": "incluir valores nulos" + "include_null_values": "incluir valores nulos", + "spec": "Analizador" + }, + "spec": { + "rfc": "RFC4180", + "legacy": "Legado", + "legacy_warning": "El modo legado se eliminará en una versión futura." }, "placeholder": { "columns": "nombres de columnas separados por comas" @@ -878,6 +885,7 @@ "once": "enviar encabezados una vez, hasta msg.reset" }, "errors": { + "bad_template": "Plantilla de columnas mal formada.", "csv_js": "Este nodo solo maneja cadenas CSV u objetos JS.", "obj_csv": "No se ha especificado ninguna plantilla de columnas para el objeto -> CSV.", "bad_csv": "Datos CSV con formato incorrecto: la salida probablemente esté corrupta." @@ -887,12 +895,14 @@ "label": { "select": "Selector", "output": "Salida", - "in": "en" + "in": "en", + "prefix": "Nombre de la propiedad para el contenido HTML" }, "output": { "html": "el contenido HTML de los elementos", "text": "sólo el contenido textual de los elementos", - "attr": "un objeto de cualquier atributo de los elementos" + "attr": "un objeto de cualquier atributo de los elementos", + "compl": "un objeto de cualquier atributo de los elementos y contenidos html" }, "format": { "single": "como un mensaje único que contiene una matriz", @@ -1007,6 +1017,7 @@ "objectSend": "Enviar un mensaje para cada par clave/valor", "strBuff": "Texto / Buffer", "array": "Array", + "splitThe": "Dividir el", "splitUsing": "Dividir usando", "splitLength": "Longitud fija de", "stream": "Manejar como un flujo de mensajes", @@ -1036,6 +1047,7 @@ "joinedUsing": "se unió usando", "send": "Enviar el mensaje:", "afterCount": "Después de varias partes del mensaje", + "useparts": "Usar la propiedad msg.parts existente", "count": "contar", "subsequent": "y cada mensaje posterior.", "afterTimeout": "Después de un tiempo de espera trás el primer mensaje", @@ -1102,6 +1114,7 @@ "too-many": "demasiados mensajes pendientes en el nodo de lotes", "unexpected": "modo inesperado", "no-parts": "ninguna propiedad 'parte' en el mensaje", + "honourParts": "Permitir que msg.parts también complete la operación por lotes.", "error": { "invalid-count": "Recuento no válido", "invalid-overlap": "Solapamiento no válido", diff --git a/packages/node_modules/@node-red/nodes/locales/es-ES/network/31-tcpin.html b/packages/node_modules/@node-red/nodes/locales/es-ES/network/31-tcpin.html index 0d25594b4..d9e07902a 100644 --- a/packages/node_modules/@node-red/nodes/locales/es-ES/network/31-tcpin.html +++ b/packages/node_modules/@node-red/nodes/locales/es-ES/network/31-tcpin.html @@ -24,12 +24,14 @@

Solo se envía el msg.payload.

Si msg.payload es una cadena que contiene una codificación Base64 de datos binarios, la opción de decodificación Base64 hará que se vuelva a convertir a binario antes de enviarse.

Si msg._session no está presente, la carga se envía a todos los clientes conectados.

+

En el modo Responder a, configurar msg.reset = true restablecerá la conexión especificada por _session.id, o todas las conexiones si no se especifica _session.id.

Nota: En algunos sistemas, es posible que necesites acceso raíz o de administrador para acceder a los puertos inferiores a 1024.

diff --git a/packages/node_modules/@node-red/nodes/locales/es-ES/parsers/70-CSV.html b/packages/node_modules/@node-red/nodes/locales/es-ES/parsers/70-CSV.html index 5dbbb88f0..940c65dfb 100644 --- a/packages/node_modules/@node-red/nodes/locales/es-ES/parsers/70-CSV.html +++ b/packages/node_modules/@node-red/nodes/locales/es-ES/parsers/70-CSV.html @@ -35,7 +35,9 @@

Detalles

-

La plantilla de columnas puede contener una lista ordenada de nombres de columnas. Al convertir CSV en un objeto, los nombres de las columnas se utilizarán como nombres de propiedades. Alternativamente, los nombres de las columnas se pueden tomar de la primera fila del CSV.

+

La plantilla de columnas puede contener una lista ordenada de nombres de columnas. Al convertir CSV en un objeto, los nombres de las columnas se utilizarán como nombres de propiedades. Alternativamente, los nombres de las columnas se pueden tomar de la primera fila del CSV. +

Cuando se selecciona el analizador RFC, la plantilla de columna debe ser compatible con RFC4180.

+

Al convertir a CSV, la plantilla de columnas se utiliza para identificar qué propiedades extraer del objeto y en qué orden.

Si la plantilla de columnas está en blanco, puede utilizar una lista simple de propiedades separadas por comas proporcionada en msg.columns para determinar qué extraer y en qué orden. Si ninguno de los dos está presente, todas las propiedades del objeto se muestran en el orden en que se encuentran en la primera fila.

Si la entrada es una matriz, entonces la plantilla de columnas solo se usa para generar opcionalmente una fila de títulos de columnas.

@@ -46,4 +48,5 @@

Si genera varios mensajes, tendrán su propiedad parts configurada y formarán una secuencia de mensajes completa.

Si el nodo está configurado para enviar encabezados de columna solo una vez, si se configura msg.reset en cualquier valor hará que el nodo reenvíe los encabezados.

Nota: la plantilla de columna debe estar separada por comas, incluso si se elige un separador diferente para los datos.

+

Nota: en el modo RFC, se generarán errores detectables para encabezados CSV mal formados y datos de carga útil de entrada no válidos

diff --git a/packages/node_modules/@node-red/runtime/locales/es-ES/runtime.json b/packages/node_modules/@node-red/runtime/locales/es-ES/runtime.json index 9fba64ad3..d1c2c44a9 100644 --- a/packages/node_modules/@node-red/runtime/locales/es-ES/runtime.json +++ b/packages/node_modules/@node-red/runtime/locales/es-ES/runtime.json @@ -25,6 +25,7 @@ "removing-modules": "Eliminando módulos de la configuración", "added-types": "Tipos de nodos añadidos:", "removed-types": "Tipos de nodos eliminados:", + "removed-plugins": "Extensiones eliminadas:", "install": { "invalid": "Nombre de módulo no válido", "installing": "Instalando módulo: __name__, versión: __version__", From bdb545d6ebd438189010ea55bd7ffba2c4a41bf8 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 7 Oct 2024 16:30:38 +0100 Subject: [PATCH 58/87] Update dependencies --- package.json | 14 +++++++------- packages/node_modules/@node-red/nodes/package.json | 6 +++--- .../node_modules/@node-red/registry/package.json | 4 ++-- packages/node_modules/@node-red/util/package.json | 2 +- packages/node_modules/node-red/package.json | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 6597530f2..952b95bc0 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "cheerio": "1.0.0-rc.10", "clone": "2.1.2", "content-type": "1.0.5", - "cookie": "0.6.0", + "cookie": "0.7.2", "cookie-parser": "1.4.6", "cors": "2.8.5", "cronosjs": "1.7.1", @@ -45,7 +45,7 @@ "express-session": "1.18.0", "form-data": "4.0.0", "fs-extra": "11.2.0", - "got": "12.6.0", + "got": "12.6.1", "hash-sum": "2.0.0", "hpagent": "1.2.0", "https-proxy-agent": "5.0.1", @@ -60,7 +60,7 @@ "memorystore": "1.6.7", "mime": "3.0.0", "moment": "2.30.1", - "moment-timezone": "0.5.45", + "moment-timezone": "0.5.46", "mqtt": "5.7.0", "multer": "1.4.5-lts.1", "mustache": "4.2.0", @@ -72,10 +72,10 @@ "passport": "0.7.0", "passport-http-bearer": "1.0.1", "passport-oauth2-client-password": "0.1.2", - "raw-body": "2.5.2", + "raw-body": "3.0.0", "rfdc": "^1.3.1", - "semver": "7.5.4", - "tar": "7.2.0", + "semver": "7.6.3", + "tar": "7.4.3", "tough-cookie": "^5.0.0", "uglify-js": "3.17.4", "uuid": "9.0.1", @@ -110,7 +110,7 @@ "jquery-i18next": "1.2.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", "marked": "4.3.0", - "mermaid": "^10.4.0", + "mermaid": "11.3.0", "minami": "1.2.3", "mocha": "9.2.2", "node-red-node-test-helper": "^0.3.3", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index dcbb59b24..72179409c 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -22,13 +22,13 @@ "cheerio": "1.0.0-rc.10", "content-type": "1.0.5", "cookie-parser": "1.4.6", - "cookie": "0.6.0", + "cookie": "0.7.2", "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", "form-data": "4.0.0", "fs-extra": "11.2.0", - "got": "12.6.0", + "got": "12.6.1", "hash-sum": "2.0.0", "hpagent": "1.2.0", "https-proxy-agent": "5.0.1", @@ -40,7 +40,7 @@ "mustache": "4.2.0", "node-watch": "0.7.4", "on-headers": "1.0.2", - "raw-body": "2.5.2", + "raw-body": "3.0.0", "tough-cookie": "^5.0.0", "uuid": "9.0.1", "ws": "7.5.10", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 2515b19b7..7c6e8ebcc 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -19,8 +19,8 @@ "@node-red/util": "4.0.3", "clone": "2.1.2", "fs-extra": "11.2.0", - "semver": "7.5.4", - "tar": "7.2.0", + "semver": "7.6.3", + "tar": "7.4.3", "uglify-js": "3.17.4" } } diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index d747109dd..67ed9d88b 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -21,6 +21,6 @@ "jsonata": "2.0.5", "lodash.clonedeep": "^4.5.0", "moment": "2.30.1", - "moment-timezone": "0.5.45" + "moment-timezone": "0.5.46" } } diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index b6c767e9b..2f61e8468 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -42,7 +42,7 @@ "fs-extra": "11.2.0", "node-red-admin": "^4.0.1", "nopt": "5.0.0", - "semver": "7.5.4" + "semver": "7.6.3" }, "optionalDependencies": { "@node-rs/bcrypt": "1.10.4" From 3812ed5ed3cd7b51b074025ae8eacdda31e6762e Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:13:13 +0200 Subject: [PATCH 59/87] Link call node cannot call a link in a subflow Co-authored-by: Nick O'Leary --- .../node_modules/@node-red/editor-client/src/js/nodes.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 25e8c2185..857068d4b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2419,12 +2419,13 @@ RED.nodes = (function() { if (otherNode.z === n.z) { // Both ends in the same flow/subflow return true - } else if (n.type === "link call") { - // Link call node can call out of a subflow - return true + } else if (n.type === "link call" && !!getSubflow(otherNode.z)) { + // Link call node can call out of a subflow as long as otherNode is + // not in a subflow + return false } else if (!!getSubflow(n.z) || !!getSubflow(otherNode.z)) { // One end is in a subflow - remove the link - return false + return false } return true }); From a0b4fc83726e647cfc2a6f6db2a529675d10785b Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Tue, 8 Oct 2024 13:58:29 +0100 Subject: [PATCH 60/87] Convert to string --- .../node_modules/@node-red/nodes/core/network/10-mqtt.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index bc6f9644d..2b4968483 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -161,9 +161,13 @@ module.exports = function(RED) { if(typeof val === "string") { count++; _clone[key] = val; - } else if (typeof val === "number") { + } else { count++; - _clone[key] = val.toString(); + try { + _clone[key] = JSON.stringify(val) + } catch (err) { + console.log('MQTT v5 Property value can not be converted to a String') + } } }); if(count) properties.userProperties = _clone; From d50ccea017e97552078a86324c76159957b66614 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Tue, 8 Oct 2024 16:51:09 +0100 Subject: [PATCH 61/87] Update packages/node_modules/@node-red/nodes/core/network/10-mqtt.js Co-authored-by: Nick O'Leary --- .../node_modules/@node-red/nodes/core/network/10-mqtt.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js index 2b4968483..afa0066f4 100644 --- a/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js +++ b/packages/node_modules/@node-red/nodes/core/network/10-mqtt.js @@ -161,12 +161,12 @@ module.exports = function(RED) { if(typeof val === "string") { count++; _clone[key] = val; - } else { - count++; + } else if (val !== undefined && val !== null) { try { _clone[key] = JSON.stringify(val) + count++; } catch (err) { - console.log('MQTT v5 Property value can not be converted to a String') + // Silently drop property } } }); From 49a3eded59e59b6dc1207fcd872233aa0cb2e701 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:10:28 +0200 Subject: [PATCH 62/87] Apply code review + add comments Co-authored-by: Nick O'Leary --- .../@node-red/editor-client/src/js/ui/deploy.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js index e429c1586..ed503bcfe 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js @@ -591,6 +591,7 @@ RED.deploy = (function() { const flowsToLock = new Set() // Node's properties cannot be modified if its workspace is locked. function ensureUnlocked(id) { + // TODO: `RED.nodes.subflow` is useless const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null); const isLocked = flow ? flow.locked : false; if (flow && isLocked) { @@ -643,27 +644,27 @@ RED.deploy = (function() { delete confNode.credentials; } }); + // Subflow cannot be locked RED.nodes.eachSubflow(function (subflow) { if (subflow.changed) { subflow.changed = false; - if (flowsToLock.has(subflow)) { - subflow.locked = true; - } RED.events.emit("subflows:change", subflow); } }); RED.nodes.eachWorkspace(function (ws) { if (ws.changed || ws.added) { - ensureUnlocked(ws.z) + // Ensure the Workspace is unlocked to modify its properties. + ensureUnlocked(ws.id); ws.changed = false; delete ws.added if (flowsToLock.has(ws)) { ws.locked = true; + flowsToLock.delete(ws); } RED.events.emit("flows:change", ws) } }); - // Ensures all workspaces/subflows to be locked have been locked. + // Ensures all workspaces to be locked have been locked. flowsToLock.forEach(flow => { flow.locked = true }) From a0033697ea435fdd69db51e8edb17439de5eba5a Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 9 Oct 2024 10:25:35 +0100 Subject: [PATCH 63/87] Update cookie --- package.json | 6 +++--- packages/node_modules/@node-red/editor-api/package.json | 4 ++-- packages/node_modules/@node-red/nodes/package.json | 2 +- packages/node_modules/@node-red/runtime/package.json | 2 +- packages/node_modules/node-red/package.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 952b95bc0..229ede53d 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,12 @@ "clone": "2.1.2", "content-type": "1.0.5", "cookie": "0.7.2", - "cookie-parser": "1.4.6", + "cookie-parser": "1.4.7", "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", - "express": "4.21.0", - "express-session": "1.18.0", + "express": "4.21.1", + "express-session": "1.18.1", "form-data": "4.0.0", "fs-extra": "11.2.0", "got": "12.6.1", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 59a265ca4..02d8cf673 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -22,8 +22,8 @@ "body-parser": "1.20.3", "clone": "2.1.2", "cors": "2.8.5", - "express-session": "1.18.0", - "express": "4.21.0", + "express-session": "1.18.1", + "express": "4.21.1", "memorystore": "1.6.7", "mime": "3.0.0", "multer": "1.4.5-lts.1", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index 72179409c..a2f82334a 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -21,7 +21,7 @@ "body-parser": "1.20.3", "cheerio": "1.0.0-rc.10", "content-type": "1.0.5", - "cookie-parser": "1.4.6", + "cookie-parser": "1.4.7", "cookie": "0.7.2", "cors": "2.8.5", "cronosjs": "1.7.1", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 67464f496..276e2ecef 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -20,7 +20,7 @@ "@node-red/util": "4.0.3", "async-mutex": "0.5.0", "clone": "2.1.2", - "express": "4.21.0", + "express": "4.21.1", "fs-extra": "11.2.0", "json-stringify-safe": "5.0.1", "rfdc": "^1.3.1" diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index 2f61e8468..b3fab303d 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -38,7 +38,7 @@ "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", - "express": "4.21.0", + "express": "4.21.1", "fs-extra": "11.2.0", "node-red-admin": "^4.0.1", "nopt": "5.0.0", From 90ea3c15b35e042f285aecf1fc7e234738f0ed19 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 9 Oct 2024 10:56:14 +0100 Subject: [PATCH 64/87] Bump for 4.0.4 release --- CHANGELOG.md | 17 +++++++++++++++++ package.json | 2 +- .../@node-red/editor-api/package.json | 6 +++--- .../@node-red/editor-client/package.json | 2 +- .../node_modules/@node-red/nodes/package.json | 2 +- .../@node-red/registry/package.json | 4 ++-- .../node_modules/@node-red/runtime/package.json | 6 +++--- .../node_modules/@node-red/util/package.json | 2 +- packages/node_modules/node-red/package.json | 10 +++++----- 9 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eaa3b7fa..5d51c45f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +#### 4.0.4: Maintenance Release + +Editor + + - Fix `link call` node can call out of a subflow (#4892) @GogoVega + - Fix wrong unlock state when event is triggered after deployment (#4889) @GogoVega + - i18n(App) update with latest language file changes (#4903) @joebordes + - fix typo: depreciated (#4895) @dxdc + +Runtime + + - Update dev dependencies (#4893) @knolleary + +Nodes + + - MQTT: Allow msg.userProperties to have number values (#4900) @hardillb + #### 4.0.3: Maintenance Release Editor diff --git a/package.json b/package.json index 229ede53d..9d30315fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.3", + "version": "4.0.4", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 02d8cf673..b1cdd9ad5 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/util": "4.0.3", - "@node-red/editor-client": "4.0.3", + "@node-red/util": "4.0.4", + "@node-red/editor-client": "4.0.4", "bcryptjs": "2.4.3", "body-parser": "1.20.3", "clone": "2.1.2", diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index 7e65dcc1a..587a32c6a 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index a2f82334a..7fdcb3a3e 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/nodes", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 7c6e8ebcc..229c5d31d 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/registry", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,7 +16,7 @@ } ], "dependencies": { - "@node-red/util": "4.0.3", + "@node-red/util": "4.0.4", "clone": "2.1.2", "fs-extra": "11.2.0", "semver": "7.6.3", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 276e2ecef..71d36b54a 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/runtime", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/registry": "4.0.3", - "@node-red/util": "4.0.3", + "@node-red/registry": "4.0.4", + "@node-red/util": "4.0.4", "async-mutex": "0.5.0", "clone": "2.1.2", "express": "4.21.1", diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 67ed9d88b..80ae1a517 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/util", - "version": "4.0.3", + "version": "4.0.4", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index b3fab303d..b7e87be84 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.3", + "version": "4.0.4", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "flow" ], "dependencies": { - "@node-red/editor-api": "4.0.3", - "@node-red/runtime": "4.0.3", - "@node-red/util": "4.0.3", - "@node-red/nodes": "4.0.3", + "@node-red/editor-api": "4.0.4", + "@node-red/runtime": "4.0.4", + "@node-red/util": "4.0.4", + "@node-red/nodes": "4.0.4", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", From 802b116b0140f8b06da7087b8de07c9f68139b28 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:53:33 +0200 Subject: [PATCH 65/87] Refix link call node can call out of a subflow --- packages/node_modules/@node-red/editor-client/src/js/nodes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 857068d4b..12e0a6ef1 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -2419,10 +2419,10 @@ RED.nodes = (function() { if (otherNode.z === n.z) { // Both ends in the same flow/subflow return true - } else if (n.type === "link call" && !!getSubflow(otherNode.z)) { + } else if (n.type === "link call" && !getSubflow(otherNode.z)) { // Link call node can call out of a subflow as long as otherNode is // not in a subflow - return false + return true } else if (!!getSubflow(n.z) || !!getSubflow(otherNode.z)) { // One end is in a subflow - remove the link return false From fe9354d10b893de689efaddaf120c690bb595049 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 10 Oct 2024 11:05:08 +0100 Subject: [PATCH 66/87] Bump for 4.0.5 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- .../node_modules/@node-red/editor-api/package.json | 6 +++--- .../node_modules/@node-red/editor-client/package.json | 2 +- packages/node_modules/@node-red/nodes/package.json | 2 +- packages/node_modules/@node-red/registry/package.json | 4 ++-- packages/node_modules/@node-red/runtime/package.json | 6 +++--- packages/node_modules/@node-red/util/package.json | 2 +- packages/node_modules/node-red/package.json | 10 +++++----- scripts/generate-publish-script.js | 8 +++++--- 10 files changed, 28 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d51c45f9..4b55ac4c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +#### 4.0.5: Maintenance Release + +Editor + + - Refix link call node can call out of a subflow (#4908) @GogoVega + #### 4.0.4: Maintenance Release Editor diff --git a/package.json b/package.json index 9d30315fd..c7fe644f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.4", + "version": "4.0.5", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index b1cdd9ad5..e58f2e9fb 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/util": "4.0.4", - "@node-red/editor-client": "4.0.4", + "@node-red/util": "4.0.5", + "@node-red/editor-client": "4.0.5", "bcryptjs": "2.4.3", "body-parser": "1.20.3", "clone": "2.1.2", diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index 587a32c6a..b6b7a2c73 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index 7fdcb3a3e..84db88466 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/nodes", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 229c5d31d..9437a5beb 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/registry", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,7 +16,7 @@ } ], "dependencies": { - "@node-red/util": "4.0.4", + "@node-red/util": "4.0.5", "clone": "2.1.2", "fs-extra": "11.2.0", "semver": "7.6.3", diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 71d36b54a..a160c402c 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/runtime", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,8 +16,8 @@ } ], "dependencies": { - "@node-red/registry": "4.0.4", - "@node-red/util": "4.0.4", + "@node-red/registry": "4.0.5", + "@node-red/util": "4.0.5", "async-mutex": "0.5.0", "clone": "2.1.2", "express": "4.21.1", diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 80ae1a517..c02ab3805 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/util", - "version": "4.0.4", + "version": "4.0.5", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/node-red/package.json b/packages/node_modules/node-red/package.json index b7e87be84..0969024ff 100644 --- a/packages/node_modules/node-red/package.json +++ b/packages/node_modules/node-red/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "4.0.4", + "version": "4.0.5", "description": "Low-code programming for event-driven applications", "homepage": "https://nodered.org", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "flow" ], "dependencies": { - "@node-red/editor-api": "4.0.4", - "@node-red/runtime": "4.0.4", - "@node-red/util": "4.0.4", - "@node-red/nodes": "4.0.4", + "@node-red/editor-api": "4.0.5", + "@node-red/runtime": "4.0.5", + "@node-red/util": "4.0.5", + "@node-red/nodes": "4.0.5", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "cors": "2.8.5", diff --git a/scripts/generate-publish-script.js b/scripts/generate-publish-script.js index 0b2a75cd0..c31b2dd9e 100644 --- a/scripts/generate-publish-script.js +++ b/scripts/generate-publish-script.js @@ -36,10 +36,12 @@ function generateScript() { packages.forEach(name => { const tarName = name.replace(/@/,"").replace(/\//,"-") lines.push(`npm publish ${tarName}-${version}.tgz ${tagArg}\n`); - if (updateNextToLatest) { - lines.push(`npm dist-tag add ${name}@${version} next\n`); - } }) + if (updateNextToLatest) { + packages.forEach(name => { + lines.push(`npm dist-tag add ${name}@${version} next\n`); + }) + } resolve(lines.join("")) }); } From a7b1ce0cf84acf25d1517af1be2ff0b06e5293b5 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:47:42 +0200 Subject: [PATCH 67/87] Improve the node name auto-generated with the first available nb --- .../editor-client/src/js/ui/view-tools.js | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js index f503beecb..22cb1eecd 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view-tools.js @@ -1102,18 +1102,27 @@ RED.view.tools = (function() { const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef) const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$') if (!typeIndex.hasOwnProperty(n.type)) { - const existingNodes = RED.nodes.filterNodes({type: n.type}) - let maxNameNumber = 0; - existingNodes.forEach(n => { - let match = defaultNodeNameRE.exec(n.name) + const existingNodes = RED.nodes.filterNodes({ type: n.type }); + const existingIds = existingNodes.reduce((ids, node) => { + let match = defaultNodeNameRE.exec(node.name); if (match) { - let nodeNumber = parseInt(match[1]) - if (nodeNumber > maxNameNumber) { - maxNameNumber = nodeNumber + const nodeNumber = parseInt(match[1], 10); + if (!ids.includes(nodeNumber)) { + ids.push(nodeNumber); } } - }) - typeIndex[n.type] = maxNameNumber + 1 + return ids; + }, []).sort((a, b) => a - b); + + let availableNameNumber = 1; + for (let i = 0; i < existingIds.length; i++) { + if (existingIds[i] !== availableNameNumber) { + break; + } + availableNameNumber++; + } + + typeIndex[n.type] = availableNameNumber; } if ((options.renameBlank && n.name === '') || (options.renameClash && defaultNodeNameRE.test(n.name))) { if (generateHistory) { From 2eba7548013a0bfba56369abc1bc58f61f61d3ca Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Sat, 12 Oct 2024 16:49:09 +0100 Subject: [PATCH 68/87] Fix trigger node date handling for latest time type input to fix #4914 --- .../@node-red/nodes/core/function/89-trigger.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index 16a00e99d..0fc6ad6fb 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -166,7 +166,13 @@ module.exports = function(RED) { if (err) { reject(err); } else { - msg.payload = value; + if (node.op1type === "date") { + let d = new Date(); + if (node.op1 == "1") { msg.payload = Date.now(); } + else if (node.op1 == "iso") { msg.payload = d.toISOString(); } + else { msg.payload = d; } + } + else { msg.payload = value; } resolve(); } }); @@ -213,7 +219,12 @@ module.exports = function(RED) { } else { msg2.payload = node.topics[topic].m2; - if (node.op2type === "date") { msg2.payload = Date.now(); } + if (node.op2type === "date") { + let d = new Date(); + if (node.op2 == "0") { msg2.payload = Date.now(); } + else if (node.op2 == "iso") { msg2.payload = d.toISOString(); } + else { msg2.payload = d; } + } if (node.second === true) { msgInfo.send([null,msg2]); } else { msgInfo.send(msg2); } } From 61fd01b8716e62d5f26fbcc1d56f47ca6d05db5d Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Sat, 12 Oct 2024 17:09:18 +0100 Subject: [PATCH 69/87] And add some tests --- test/nodes/core/function/89-trigger_spec.js | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index 33401e540..e86ed7a31 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -111,7 +111,15 @@ describe('trigger node', function() { try { if (rval) { msg.should.have.property("payload"); - should.deepEqual(msg.payload, rval); + if (type == "date" && val == "1") { + should.deepEqual(Math.round(msg.payload/10000), Math.round(rval/10000)); + } + else if (type == "date" && val == "iso") { + should.deepEqual(msg.payload.substr(0,11), rval.substr(0,11)); + } + else { + should.deepEqual(msg.payload, rval); + } } else { msg.should.have.property("payload", val); @@ -126,6 +134,7 @@ describe('trigger node', function() { }); it('should output 2st value when triggered ('+type+')', function(done) { + if (type == "date" && val == "1") { val = "0"; } var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"str", op2:val, op2type:type, duration:"20", wires:[["n2"]] }, {id:"n2", type:"helper"} ]; process.env[val] = rval; @@ -142,7 +151,15 @@ describe('trigger node', function() { else { if (rval) { msg.should.have.property("payload"); - should.deepEqual(msg.payload, rval); + if (type == "date" && val == "0") { + should.deepEqual(Math.round(msg.payload/10000), Math.round(rval/10000)); + } + else if (type == "date" && val == "iso") { + should.deepEqual(msg.payload.substr(0,11), rval.substr(0,11)); + } + else { + should.deepEqual(msg.payload, rval); + } } else { msg.should.have.property("payload", val); @@ -166,6 +183,9 @@ describe('trigger node', function() { var val_buf = "[1,2,3,4,5]"; basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf))); basicTest("env", "NR-TEST", "env-val"); + basicTest("date", "1", Date.now()); + basicTest("date", "iso", (new Date()).toISOString()); + // basicTest("date", "object", Date.now()); it('should output 1 then 0 when triggered (default)', function(done) { var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] }, From 892933ff758d240109fb0d711d322c73f672250d Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Sat, 12 Oct 2024 17:22:24 +0100 Subject: [PATCH 70/87] Update 89-trigger_spec.js --- test/nodes/core/function/89-trigger_spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index e86ed7a31..f78db0423 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -112,7 +112,7 @@ describe('trigger node', function() { if (rval) { msg.should.have.property("payload"); if (type == "date" && val == "1") { - should.deepEqual(Math.round(msg.payload/10000), Math.round(rval/10000)); + should.deepEqual(Math.round(msg.payload/1000000), Math.round(Date.now()/1000000)); } else if (type == "date" && val == "iso") { should.deepEqual(msg.payload.substr(0,11), rval.substr(0,11)); @@ -152,7 +152,7 @@ describe('trigger node', function() { if (rval) { msg.should.have.property("payload"); if (type == "date" && val == "0") { - should.deepEqual(Math.round(msg.payload/10000), Math.round(rval/10000)); + should.deepEqual(Math.round(msg.payload/1000000), parseInt(Date.now()/1000000)); } else if (type == "date" && val == "iso") { should.deepEqual(msg.payload.substr(0,11), rval.substr(0,11)); From d0ad62a82bd2b3afea4183aa99fb2509589d7226 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 21 Oct 2024 16:24:21 +0100 Subject: [PATCH 71/87] Revert trigger node fix --- .../@node-red/nodes/core/function/89-trigger.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index 0fc6ad6fb..16a00e99d 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -166,13 +166,7 @@ module.exports = function(RED) { if (err) { reject(err); } else { - if (node.op1type === "date") { - let d = new Date(); - if (node.op1 == "1") { msg.payload = Date.now(); } - else if (node.op1 == "iso") { msg.payload = d.toISOString(); } - else { msg.payload = d; } - } - else { msg.payload = value; } + msg.payload = value; resolve(); } }); @@ -219,12 +213,7 @@ module.exports = function(RED) { } else { msg2.payload = node.topics[topic].m2; - if (node.op2type === "date") { - let d = new Date(); - if (node.op2 == "0") { msg2.payload = Date.now(); } - else if (node.op2 == "iso") { msg2.payload = d.toISOString(); } - else { msg2.payload = d; } - } + if (node.op2type === "date") { msg2.payload = Date.now(); } if (node.second === true) { msgInfo.send([null,msg2]); } else { msgInfo.send(msg2); } } From b3aff3a3e6847f03ef851d98e68c80eafe27573d Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 21 Oct 2024 16:26:03 +0100 Subject: [PATCH 72/87] Ensure trigger node properties work with evaluateNodeProperty --- .../@node-red/nodes/core/function/89-trigger.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index 16a00e99d..f0aaaf393 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -24,6 +24,14 @@ module.exports = function(RED) { this.op2 = n.op2 || "0"; this.op1type = n.op1type || "str"; this.op2type = n.op2type || "str"; + // If the op1/2type is 'date', then we need to leave op1/2 alone so that + // evaluateNodeProperty works as expected. + if (this.op1type === 'date' && this.op1 === '1') { + this.op1 = '' + } + if (this.op2type === 'date' && this.op2 === '0') { + this.op2 = '' + } this.second = (n.outputs == 2) ? true : false; this.topic = n.topic || "topic"; @@ -213,7 +221,6 @@ module.exports = function(RED) { } else { msg2.payload = node.topics[topic].m2; - if (node.op2type === "date") { msg2.payload = Date.now(); } if (node.second === true) { msgInfo.send([null,msg2]); } else { msgInfo.send(msg2); } } From 2220956007347017a37d273ff8e1389f3bd48158 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 21 Oct 2024 16:35:11 +0100 Subject: [PATCH 73/87] Ensure trigger second output is revaluated for date types --- .../node_modules/@node-red/nodes/core/function/89-trigger.js | 2 +- test/nodes/core/function/89-trigger_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js index f0aaaf393..8b3625f2d 100644 --- a/packages/node_modules/@node-red/nodes/core/function/89-trigger.js +++ b/packages/node_modules/@node-red/nodes/core/function/89-trigger.js @@ -201,7 +201,7 @@ module.exports = function(RED) { if (node.op2type !== "nul") { var promise = Promise.resolve(); msg2 = RED.util.cloneMessage(msg); - if (node.op2type === "flow" || node.op2type === "global") { + if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "date") { promise = new Promise((resolve,reject) => { RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => { if (err) { diff --git a/test/nodes/core/function/89-trigger_spec.js b/test/nodes/core/function/89-trigger_spec.js index f78db0423..913298901 100644 --- a/test/nodes/core/function/89-trigger_spec.js +++ b/test/nodes/core/function/89-trigger_spec.js @@ -152,7 +152,7 @@ describe('trigger node', function() { if (rval) { msg.should.have.property("payload"); if (type == "date" && val == "0") { - should.deepEqual(Math.round(msg.payload/1000000), parseInt(Date.now()/1000000)); + ;(Math.round(msg.payload/1000000)).should.be.approximately(parseInt(Date.now()/1000000), 1); } else if (type == "date" && val == "iso") { should.deepEqual(msg.payload.substr(0,11), rval.substr(0,11)); From 7555e0644f3bc78cfa87f930ecbe9f7e99d3cb6c Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:15:24 +0200 Subject: [PATCH 74/87] Apply `envVarExcludes` setting to `RED.util.getSetting` into the function node --- .../nodes/core/function/10-function.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 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 0120d8c92..8d365722f 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 @@ -111,8 +111,6 @@ module.exports = function(RED) { throw new Error(RED._("function.error.externalModuleNotAllowed")); } - - var functionText = "var results = null;"+ "results = (async function(msg,__send__,__done__){ "+ "var __msgid__ = msg._msgid;"+ @@ -160,13 +158,26 @@ module.exports = function(RED) { node.outstandingIntervals = []; node.clearStatus = false; + const envVarExcludes = {}; + if (RED.settings.envVarExcludes && Array.isArray(RED.settings.envVarExcludes)) { + RED.settings.envVarExcludes.forEach((e) => envVarExcludes[e] = true); + } + var sandbox = { console:console, util:util, Buffer:Buffer, Date: Date, RED: { - util: RED.util + util: { + ...RED.util, + getSetting: function (node, name, flow) { + if (envVarExcludes[name]) { + return undefined; + } + return RED.util.getSetting(node, name, flow); + } + } }, __node__: { id: node.id, From 2fd7aee4dad20b8eea860f684dd80538e29e6892 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Thu, 24 Oct 2024 13:44:40 +0200 Subject: [PATCH 75/87] Move `envVarExcludes` to the top scope --- .../@node-red/nodes/core/function/10-function.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 8d365722f..413830b72 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 @@ -22,6 +22,11 @@ module.exports = function(RED) { var acorn = require("acorn"); var acornWalk = require("acorn-walk"); + const envVarExcludes = {}; + if (RED.settings.envVarExcludes && Array.isArray(RED.settings.envVarExcludes)) { + RED.settings.envVarExcludes.forEach((e) => envVarExcludes[e] = true); + } + function sendResults(node,send,_msgid,msgs,cloneFirstMessage) { if (msgs == null) { return; @@ -158,11 +163,6 @@ module.exports = function(RED) { node.outstandingIntervals = []; node.clearStatus = false; - const envVarExcludes = {}; - if (RED.settings.envVarExcludes && Array.isArray(RED.settings.envVarExcludes)) { - RED.settings.envVarExcludes.forEach((e) => envVarExcludes[e] = true); - } - var sandbox = { console:console, util:util, From 966064328f6fd92145729f7710da82cd98c3997d Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Fri, 25 Oct 2024 23:33:19 +0200 Subject: [PATCH 76/87] Add `oneditsave` credentials changes to history --- .../editor-client/src/js/ui/editor.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 1bdd134fb..b656af0b0 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -804,6 +804,17 @@ RED.editor = (function() { } } + const oldCreds = {}; + if (editing_node._def.credentials) { + for (const prop in editing_node._def.credentials) { + if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) { + if (prop in editing_node.credentials) { + oldCreds[prop] = editing_node.credentials[prop]; + } + } + } + } + try { const rc = editing_node._def.oneditsave.call(editing_node); if (rc === true) { @@ -835,6 +846,21 @@ RED.editor = (function() { } } } + + if (editing_node._def.credentials) { + for (const prop in editing_node._def.credentials) { + if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) { + if (oldCreds[prop] !== editing_node.credentials[prop]) { + if (editing_node.credentials[prop] === '__PWRD__') { + continue; + } + editState.changes.credentials = editState.changes.credentials || {}; + editState.changes.credentials[prop] = oldCreds[prop]; + editState.changed = true; + } + } + } + } } } From 70aed23ef0a0792d4044a93ec043438dbc586c22 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:31:36 +0100 Subject: [PATCH 77/87] Fix `envVarList` sortable value --- .../@node-red/editor-client/src/js/ui/editors/envVarList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js index dda5d1660..b974fbc50 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/envVarList.js @@ -131,7 +131,7 @@ RED.editor.envVarList = (function() { nameField.trigger('change'); } }, - sortable: ".red-ui-editableList-item-handle", + sortable: true, removable: false }); var parentEnv = {}; From f67268b89ad654fb57b2f10e02ea2ebc7b6b7da7 Mon Sep 17 00:00:00 2001 From: Gauthier Dandele <92022724+GogoVega@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:01:42 +0100 Subject: [PATCH 78/87] Revert and force getSetting to use the local node Co-authored-by: Nick O'Leary --- .../@node-red/nodes/core/function/10-function.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 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 413830b72..71f6e15d6 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 @@ -22,11 +22,6 @@ module.exports = function(RED) { var acorn = require("acorn"); var acornWalk = require("acorn-walk"); - const envVarExcludes = {}; - if (RED.settings.envVarExcludes && Array.isArray(RED.settings.envVarExcludes)) { - RED.settings.envVarExcludes.forEach((e) => envVarExcludes[e] = true); - } - function sendResults(node,send,_msgid,msgs,cloneFirstMessage) { if (msgs == null) { return; @@ -171,11 +166,9 @@ module.exports = function(RED) { RED: { util: { ...RED.util, - getSetting: function (node, name, flow) { - if (envVarExcludes[name]) { - return undefined; - } - return RED.util.getSetting(node, name, flow); + getSetting: function (_node, name, _flow) { + // Ensure `node` argument is the Function node and do not allow flow to be overridden. + return RED.util.getSetting(node, name); } } }, From a7ee31307e20a1412b928cf8d2e4b7edc3320afe Mon Sep 17 00:00:00 2001 From: Ersin Date: Tue, 29 Oct 2024 13:38:32 +0100 Subject: [PATCH 79/87] missing getSubscriptions in the docs while its implemented See: https://github.com/node-red/node-red/blob/master/packages/node_modules/%40node-red/nodes/core/network/10-mqtt.js#L1288 --- .../@node-red/nodes/locales/en-US/network/10-mqtt.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/network/10-mqtt.html b/packages/node_modules/@node-red/nodes/locales/en-US/network/10-mqtt.html index f4b0012ce..68f89ae4a 100644 --- a/packages/node_modules/@node-red/nodes/locales/en-US/network/10-mqtt.html +++ b/packages/node_modules/@node-red/nodes/locales/en-US/network/10-mqtt.html @@ -48,7 +48,8 @@
action string
the name of the action the node should perform. Available actions are: "connect", - "disconnect", "subscribe" and "unsubscribe".
+ "disconnect", "getSubscriptions", "subscribe" and + "unsubscribe".
topic string|object|array
For the "subscribe" and "unsubscribe" actions, this property provides the topic. It can be set as either:
    From 443492d6eb27be98e5a01176384cf3eea7b99645 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:12:13 +0100 Subject: [PATCH 80/87] Fix `setModulePendingUpdated` with plugins --- .../node_modules/@node-red/editor-client/src/js/nodes.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 12e0a6ef1..bcd1f8c5a 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -73,7 +73,13 @@ RED.nodes = (function() { var exports = { setModulePendingUpdated: function(module,version) { - moduleList[module].pending_version = version; + if (!!RED.plugins.getModule(module)) { + // The module updated is a plugin + RED.plugins.getModule(module).pending_version = version; + } else { + moduleList[module].pending_version = version; + } + RED.events.emit("registry:module-updated",{module:module,version:version}); }, getModule: function(module) { From 33a5b2527c929a6b06ed8d6a7da17bed297b5117 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 31 Oct 2024 17:06:13 +0000 Subject: [PATCH 81/87] Make delay node rate limit reset consistent - not send on reset. to fix #4830 --- .../@node-red/nodes/core/function/89-delay.js | 11 +++++---- test/nodes/core/function/89-delay_spec.js | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) 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 b0fc2ed86..caf0bd892 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 @@ -253,9 +253,11 @@ module.exports = function(RED) { if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) { node.rate = m.rate; } - send(m); - node.reportDepth(); - node.intervalID = setInterval(sendMsgFromBuffer, node.rate); + if (!msg.hasOwnProperty("reset")) { + send(m); + node.reportDepth(); + node.intervalID = setInterval(sendMsgFromBuffer, node.rate); + } done(); } } @@ -303,7 +305,8 @@ module.exports = function(RED) { node.droppedMsgs++; } } - } else { + } + else { if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) { node.rate = msg.rate; } diff --git a/test/nodes/core/function/89-delay_spec.js b/test/nodes/core/function/89-delay_spec.js index 46b0037bc..4fbf3df54 100644 --- a/test/nodes/core/function/89-delay_spec.js +++ b/test/nodes/core/function/89-delay_spec.js @@ -1009,6 +1009,29 @@ describe('delay Node', function() { }); }); + it('sending a msg with reset to empty queue doesnt send anything', function(done) { + this.timeout(2000); + var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]}, + {id:"helperNode1", type:"helper", wires:[]}]; + helper.load(delayNode, flow, function() { + var delayNode1 = helper.getNode("delayNode1"); + var helperNode1 = helper.getNode("helperNode1"); + var t = Date.now(); + var c = 0; + helperNode1.on("input", function(msg) { + console.log("Shold not get here") + done(e); + }); + + setTimeout( function() { + if (c === 0) { done(); } + }, 250); + + // send test messages + delayNode1.receive({payload:1,topic:"foo",reset:true}); // send something with blank topic + }); + }); + /* Messaging API support */ function mapiDoneTestHelper(done, pauseType, drop, msgAndTimings) { const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js"); From d3219f0600e11ae17577f2579514d0c212e47208 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 31 Oct 2024 17:21:53 +0000 Subject: [PATCH 82/87] do add to queue in case it needs to also be flushed --- .../@node-red/nodes/core/function/89-delay.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 caf0bd892..8f9964115 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 @@ -253,11 +253,15 @@ module.exports = function(RED) { if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) { node.rate = m.rate; } - if (!msg.hasOwnProperty("reset")) { - send(m); - node.reportDepth(); - node.intervalID = setInterval(sendMsgFromBuffer, node.rate); + if (msg.hasOwnProperty("reset")) { + if (msg.hasOwnProperty("flush")) { + node.buffer.push({msg: m, send: send, done: done}); + } } + else { send(m); } + + node.reportDepth(); + node.intervalID = setInterval(sendMsgFromBuffer, node.rate); done(); } } From abe0b60bf7b9f765ef172fe1ecf3b695f12d32a4 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:28:51 +0100 Subject: [PATCH 83/87] Remove disabled node types from QuickAddDialog list --- .../@node-red/editor-client/src/js/ui/typeSearch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js index 216cc3e40..9a83409da 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js @@ -382,7 +382,7 @@ RED.typeSearch = (function() { var items = []; RED.nodes.registry.getNodeTypes().forEach(function(t) { var def = RED.nodes.getType(t); - if (def.category !== 'config' && t !== 'unknown' && t !== 'tab') { + if (def.set.enabled && def.category !== 'config' && t !== 'unknown' && t !== 'tab') { items.push({type:t,def: def, label:getTypeLabel(t,def)}); } }); From 59a133cc13e5e0fc3b7bc8b84272377b9bd820bd Mon Sep 17 00:00:00 2001 From: Gauthier Dandele <92022724+GogoVega@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:28:40 +0100 Subject: [PATCH 84/87] Need to guard against subflows that doesn't have a set property Co-authored-by: Nick O'Leary --- .../@node-red/editor-client/src/js/ui/typeSearch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js index 9a83409da..f284f2464 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js @@ -382,7 +382,7 @@ RED.typeSearch = (function() { var items = []; RED.nodes.registry.getNodeTypes().forEach(function(t) { var def = RED.nodes.getType(t); - if (def.set.enabled && def.category !== 'config' && t !== 'unknown' && t !== 'tab') { + if (def.set?.enabled !== false && def.category !== 'config' && t !== 'unknown' && t !== 'tab') { items.push({type:t,def: def, label:getTypeLabel(t,def)}); } }); From ad615a76c8bb44686d5f481cefcb271184ef4c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B8=BF=E5=88=99?= Date: Thu, 14 Nov 2024 16:31:36 +0800 Subject: [PATCH 85/87] Change groups.length to groups.size Fix wrong length attribute of Set --- packages/node_modules/@node-red/editor-client/src/js/ui/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index ff0091e65..d59c651d6 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -288,7 +288,7 @@ RED.view = (function() { } selectedLinks.clearUnselected() }, - length: () => groups.length, + length: () => groups.size, forEach: (func) => { groups.forEach(func) }, toArray: () => [...groups], clear: function () { From 6d6e6fa416af2196c393b3bdb3bcb78c30616942 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Fri, 15 Nov 2024 14:30:47 +0100 Subject: [PATCH 86/87] Get the env config node from the parent subflow --- packages/node_modules/@node-red/runtime/lib/flows/util.js | 4 ++++ 1 file changed, 4 insertions(+) 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 fa25a26d0..6b7f659b9 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/util.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/util.js @@ -113,6 +113,10 @@ async function evaluateEnvProperties(flow, env, credentials) { resolve() }); })) + } else if (type === "conf-type" && /^\${[^}]+}$/.test(value)) { + // Get the config node from the parent subflow + const name = value.substring(2, value.length - 1); + value = flow.getSetting(name); } else { try { value = redUtil.evaluateNodeProperty(value, type, {_flow: flow}, null, null); From 4cb3ccc9844f1852effdde1aa104ec2232aba41a Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 18 Nov 2024 16:20:58 +0000 Subject: [PATCH 87/87] Rename variable to avoid confusion in view.js --- .../@node-red/editor-client/src/js/ui/view.js | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js index d59c651d6..245b6db75 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/view.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/view.js @@ -2689,22 +2689,21 @@ RED.view = (function() { addToRemovedLinks(reconnectResult.removedLinks) } - var startDirty = RED.nodes.dirty(); - var startChanged = false; - var selectedGroups = []; + const startDirty = RED.nodes.dirty(); + let movingSelectedGroups = []; if (movingSet.length() > 0) { for (var i=0;i=0; i--) { - var g = selectedGroups[i]; + for (i = movingSelectedGroups.length-1; i>=0; i--) { + var g = movingSelectedGroups[i]; removedGroups.push(g); RED.nodes.removeGroup(g); }