From 5e9195ab99199f3cab9e3bfe02f636b41f39f7d2 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:24:43 +0100 Subject: [PATCH 1/6] Add function docs --- .../@node-red/editor-client/src/js/nodes.js | 25 ++++++++++++++++--- 1 file changed, 21 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 e5a66ccaf..8f69f24b2 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 @@ -1473,7 +1473,14 @@ RED.nodes = (function() { } /** * Converts the current node selection to an exportable JSON Object - **/ + * @param {Array} set the node selection to export + * @param {Object} options + * @param {Record} [options.exportedIds] + * @param {Record} [options.exportedSubflows] + * @param {Record} [options.exportedConfigNodes] + * @param {boolean} [options.includeModuleConfig] + * @returns {Array} + */ function createExportableNodeSet(set, { exportedIds, exportedSubflows, @@ -1561,9 +1568,13 @@ RED.nodes = (function() { return nns; } - // Create the Flow JSON for the current configuration - // opts.credentials (whether to include (known) credentials) - default: true - // opts.dimensions (whether to include node dimensions) - default: false + /** + * Converts the current configuration to an exportable JSON Object + * @param {object} opts + * @param {boolean} [opts.credentials] whether to include (known) credentials. Default `false`. + * @param {boolean} [opts.dimensions] whether to include node dimensions. Default `false`. + * @returns {Array} + */ function createCompleteNodeSet(opts) { var nns = []; var i; @@ -2990,6 +3001,12 @@ RED.nodes = (function() { } } } + + /** + * Gets the module list for the given nodes + * @param {Array} nodes the nodes to search in + * @returns {Record} an object with {[moduleName]: moduleVersion} + */ function getModuleListForNodes(nodes) { const modules = {} nodes.forEach(n => { From 44b4c7da24e1a9aeb89d0dfba1ae08e8502d7889 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 27 Oct 2024 13:26:47 +0100 Subject: [PATCH 2/6] Improve `getModuleListForNodes` + fix typo --- .../@node-red/editor-client/src/js/nodes.js | 18 ++++++++++++------ 1 file changed, 12 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 8f69f24b2..d676e0edb 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 @@ -3009,19 +3009,25 @@ RED.nodes = (function() { */ function getModuleListForNodes(nodes) { const modules = {} - nodes.forEach(n => { - const nodeSet = RED.nodes.registry.getNodeSetForType(n.type) - if (nodeSet) { - modules[nodeSet.module] = nodeSet.version + const typeSet = new Set() + nodes.forEach((n) => { + if (!typeSet.has(n.type)) { + typeSet.add(n.type) + const nodeSet = RED.nodes.registry.getNodeSetForType(n.type) + if (nodeSet) { + modules[nodeSet.module] = nodeSet.version + nodeSet.types.forEach((t) => typeSet.add(t)) + } } }) return modules } + function updateGlobalConfigModuleList(nodes) { const modules = getModuleListForNodes(nodes) delete modules['node-red'] const hasModules = (Object.keys(modules).length > 0) - let globalConfigNode = nodes.find(n => n.type === 'global-config') + let globalConfigNode = nodes.find((n) => n.type === 'global-config') if (!globalConfigNode && hasModules) { globalConfigNode = { id: RED.nodes.id(), @@ -3030,7 +3036,7 @@ RED.nodes = (function() { modules } nodes.push(globalConfigNode) - } else if (globalConfigNode) { + } else if (hasModules) { globalConfigNode.modules = modules } } From 8d310c6c1c89ec3e2629c133983926980e068584 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:30:33 +0100 Subject: [PATCH 3/6] Allow `core:manage-palette` action to auto install modules --- .../editor-client/locales/en-US/editor.json | 6 +- .../@node-red/editor-client/src/js/nodes.js | 18 ++++- .../editor-client/src/js/ui/palette-editor.js | 80 ++++++++++++++++++- 3 files changed, 99 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 c2e89133b..a89abb992 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 @@ -265,7 +265,7 @@ "download": "Download", "importUnrecognised": "Imported unrecognised type:", "importUnrecognised_plural": "Imported unrecognised types:", - "importWithModuleInfo": "Required dependencies missing", + "importWithModuleInfo": "Required modules missing", "importWithModuleInfoDesc": "These nodes are not currently installed in your palette and are required for the imported flow:", "importDuplicate": "Imported duplicate node:", "importDuplicate_plural": "Imported duplicate nodes:", @@ -616,6 +616,7 @@ "yearsMonthsV": "__y__ years, __count__ month ago", "yearsMonthsV_plural": "__y__ years, __count__ months ago" }, + "manageModules": "Manage modules", "nodeCount": "__label__ node", "nodeCount_plural": "__label__ nodes", "pluginCount": "__count__ plugin", @@ -631,7 +632,9 @@ "update": "update to __version__", "updated": "updated", "install": "install", + "installEverything": "Install everything", "installed": "installed", + "installing": "Module installation in progress: __module__", "conflict": "conflict", "conflictTip": "

This module cannot be installed as it includes a
node type that has already been installed

Conflicts with __module__

", "loading": "Loading catalogues...", @@ -641,6 +644,7 @@ "sortRelevance": "relevance", "sortAZ": "a-z", "sortRecent": "recent", + "successfulInstall": "Successfully installed modules", "more": "+ __count__ more", "upload": "Upload module tgz file", "refresh": "Refresh module list", 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 d676e0edb..e18c72eae 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 @@ -1971,15 +1971,27 @@ RED.nodes = (function() { // Provide option to install missing modules notificationOptions.buttons = [ { - text: "Manage dependencies", - class:"primary", + text: RED._("palette.editor.manageModules"), + class: "primary", click: function(e) { unknownNotification.close(); RED.actions.invoke('core:manage-palette', { view: 'install', filter: '"' + Object.keys(options.modules).join('", "') + '"' - }) + }); + } + }, + { + text: RED._("palette.editor.installEverything"), + class: "pull-left", + click: function(e) { + unknownNotification.close(); + + RED.actions.invoke('core:manage-palette', { + autoInstall: true, + modules: options.modules + }); } } ] diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js index 44e6146c8..644a094f4 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js @@ -626,6 +626,9 @@ RED.palette.editor = (function() { }) RED.actions.add("core:manage-palette", function(opts) { + if (opts && opts.autoInstall && opts.modules) { + autoInstallModules(opts.modules); + } else { RED.userSettings.show('palette'); if (opts) { if (opts.view) { @@ -639,7 +642,8 @@ RED.palette.editor = (function() { } } } - }); + } + }); RED.events.on('registry:module-updated', function(ns) { refreshNodeModule(ns.module); @@ -1501,6 +1505,80 @@ RED.palette.editor = (function() { }) } + function autoInstallModules(modules) { + if (RED.settings.get('externalModules.palette.allowInstall', true) === false) { + console.error(new Error('Palette not editable')); + return; + } + + let notification; + const notificationOptions = { + fixed: true, + buttons: [ + { + text: RED._("common.label.close"), + click: function () { + notification.close(); + } + }, { + text: RED._("eventLog.view"), + click: function () { + notification.close(); + RED.actions.invoke("core:show-event-log"); + } + } + ] + }; + + const moduleArray = Object.entries(modules); + const installModule = function (module) { + const [moduleName, moduleVersion] = module; + + const msg = RED.notify(RED._("palette.editor.installing", { module: moduleName })); + + if (!notification) { + notification = RED.notify(msg, notificationOptions); + } else { + notification.update(msg); + } + + // TODO: add spinner to a div below the title + //const spinner = RED.utils.addSpinnerOverlay(container, true); + + RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install") + " : " + moduleName + " " + moduleVersion); + + installNodeModule(moduleName, moduleVersion, undefined, function(xhr, textStatus, err) { + //spinner.close(); + if (err && xhr.status === 504) { + notification.update(RED._("palette.editor.errors.installTimeout"), { + modal: true, + fixed: true, + buttons: notificationOptions.buttons + }); + } else if (xhr) { + if (xhr.responseJSON) { + notification.update(RED._("palette.editor.errors.installFailed", { module: moduleName, message:xhr.responseJSON.message }), { + type: "error", + modal: true, + fixed: true, + buttons: notificationOptions.buttons + }); + } + } else { + if (moduleArray.length) { + installModule(moduleArray.shift()); + } else { + notification.update(RED._("palette.editor.successfulInstall"), { ...notificationOptions, type: "success", timeout: 1000 }); + } + } + }); + }; + + if (moduleArray.length) { + installModule(moduleArray.shift()); + } + } + return { init: init, install: install From 8255e62f314a22e02ae491d25a9299cd16f0ee06 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:33:28 +0100 Subject: [PATCH 4/6] Add note + nls to the "manage modules" button --- .../node_modules/@node-red/nodes/core/common/98-unknown.html | 2 +- .../node_modules/@node-red/nodes/locales/en-US/messages.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/node_modules/@node-red/nodes/core/common/98-unknown.html b/packages/node_modules/@node-red/nodes/core/common/98-unknown.html index 282ad3415..64c9e8e4e 100644 --- a/packages/node_modules/@node-red/nodes/core/common/98-unknown.html +++ b/packages/node_modules/@node-red/nodes/core/common/98-unknown.html @@ -3,7 +3,7 @@

- +

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..4cfe835e1 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 @@ -406,7 +406,8 @@ "label": { "unknown": "unknown" }, - "tip": "

This node is a type unknown to your installation of Node-RED.

If you deploy with the node in this state, it's configuration will be preserved, but the flow will not start until the missing type is installed.

See the Info side bar for more help

" + "manageModules": "Manage modules", + "tip": "

This node is a type unknown to your installation of Node-RED.

If you deploy with the node in this state, it's configuration will be preserved, but the flow will not start until the missing type is installed.

See the Info side bar for more help

You can also click the button below to open the palette and install the missing modules.

" }, "mqtt": { "label": { From 36e313c9ee2b8e125d7a9e43795f8a4e028dc5f3 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Sun, 27 Oct 2024 23:08:19 +0100 Subject: [PATCH 5/6] Add spinner + fix typos --- .../editor-client/src/js/ui/palette-editor.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js index 644a094f4..76a64cb82 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js @@ -1534,21 +1534,18 @@ RED.palette.editor = (function() { const installModule = function (module) { const [moduleName, moduleVersion] = module; - const msg = RED.notify(RED._("palette.editor.installing", { module: moduleName })); + const spinner = '
'; + const msg = "

" + RED._("palette.editor.installing", { module: moduleName }) + "

" + spinner; if (!notification) { notification = RED.notify(msg, notificationOptions); } else { - notification.update(msg); + notification.update(msg, notificationOptions); } - // TODO: add spinner to a div below the title - //const spinner = RED.utils.addSpinnerOverlay(container, true); - RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install") + " : " + moduleName + " " + moduleVersion); installNodeModule(moduleName, moduleVersion, undefined, function(xhr, textStatus, err) { - //spinner.close(); if (err && xhr.status === 504) { notification.update(RED._("palette.editor.errors.installTimeout"), { modal: true, @@ -1568,7 +1565,7 @@ RED.palette.editor = (function() { if (moduleArray.length) { installModule(moduleArray.shift()); } else { - notification.update(RED._("palette.editor.successfulInstall"), { ...notificationOptions, type: "success", timeout: 1000 }); + notification.update(RED._("palette.editor.successfulInstall"), { ...notificationOptions, type: "success", timeout: 10000 }); } } }); From 63798a3fca3fcc023cbb0a9c8d52fa5e5602c9e0 Mon Sep 17 00:00:00 2001 From: GogoVega <92022724+GogoVega@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:58:53 +0100 Subject: [PATCH 6/6] Replace `installEverything` by `InstallAll` --- .../@node-red/editor-client/locales/en-US/editor.json | 2 +- packages/node_modules/@node-red/editor-client/src/js/nodes.js | 2 +- 2 files changed, 2 insertions(+), 2 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 a89abb992..3cd8581a2 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 @@ -632,7 +632,7 @@ "update": "update to __version__", "updated": "updated", "install": "install", - "installEverything": "Install everything", + "installAll": "Install all", "installed": "installed", "installing": "Module installation in progress: __module__", "conflict": "conflict", 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 e18c72eae..07da9917f 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 @@ -1983,7 +1983,7 @@ RED.nodes = (function() { } }, { - text: RED._("palette.editor.installEverything"), + text: RED._("palette.editor.installAll"), class: "pull-left", click: function(e) { unknownNotification.close();