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 9cc557efd..5367d85d7 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
@@ -630,6 +630,7 @@
"remove": "remove",
"update": "update to __version__",
"updated": "updated",
+ "updating": "Updating...",
"install": "install",
"installed": "installed",
"conflict": "conflict",
@@ -669,6 +670,9 @@
"body": "
Updating '__module__'
Updating the node will require a restart of Node-RED to complete the update. This must be done manually.
",
"title": "Update nodes"
},
+ "updateAll": {
+ "body": "Updating __count__ nodes
Updating the nodes will require a restart of Node-RED to complete the update. This must be done manually.
"
+ },
"cannotUpdate": {
"body": "An update for this node is available, but it is not installed in a location that the palette manager can update.
Please refer to the documentation for how to update this node."
},
@@ -677,8 +681,12 @@
"install": "Install",
"remove": "Remove",
"update": "Update",
+ "updateAll": "Update all",
"understood": "Understood"
}
+ },
+ "progress": {
+ "updated": "Updated __count__/__total__ 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 3926ca430..8e6491bed 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
@@ -509,6 +509,24 @@ RED.palette.editor = (function() {
} else {
refreshNodeModuleList();
updateCatalogFilter(loadedCatalogs)
+
+ const updateAllButton = $(nodesTabFooter).find("#red-ui-palette-button-updateAll");
+ const progressRow = $(nodesTabFooter).find(".red-ui-palette-footer-progress");
+
+ // Update the "Update all" button when the Palette opening
+ if (updateAllButton.length) {
+ updateAllButton.text(RED._("palette.editor.confirm.button.updateAll"));
+ if (updateAvailable.length) {
+ updateAllButton.removeClass("disabled");
+ } else {
+ updateAllButton.addClass("disabled");
+ }
+ }
+
+ // Set progress to empty when the Palette opening
+ if (progressRow.length) {
+ progressRow.text("");
+ }
}
}
@@ -620,6 +638,7 @@ RED.palette.editor = (function() {
let editorTabs;
let settingsPane;
+ let nodesTabFooter;
function init() {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
@@ -877,7 +896,6 @@ RED.palette.editor = (function() {
update(entry,loadedIndex[entry.name].version,loadedIndex[entry.name].pkg_url,container,function(err){});
})
-
var removeButton = $('').text(RED._('palette.editor.remove')).appendTo(buttonGroup);
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
removeButton.on("click", function(evt) {
@@ -1010,6 +1028,25 @@ RED.palette.editor = (function() {
}
}
})
+
+ nodesTabFooter = $('', { class: "red-ui-palette-footer" }).appendTo(modulesTab);
+ const buttonRow = $('
', { class: "red-ui-palette-footer-button" }).appendTo(nodesTabFooter);
+ const updateAllButton = $('
').appendTo(buttonRow);
+ $('').appendTo(nodesTabFooter);
+ $('
').appendTo(updateAllButton);
+
+ updateAllButton.on("click", function (evt) {
+ evt.preventDefault();
+ if (updateAllButton.hasClass("disabled")) {
+ return;
+ }
+
+ updateAllButton.text(RED._("palette.editor.updating"));
+ updateAllButton.addClass("disabled");
+ autoUpdateModules(function () {
+ updateAllButton.text(RED._("palette.editor.updated"));
+ });
+ });
}
function createInstallTab(content) {
@@ -1254,6 +1291,81 @@ RED.palette.editor = (function() {
$('').appendTo(installTab);
}
+ function autoUpdateModules(done) {
+ if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
+ console.error(new Error('Update failed: Palette not editable'));
+ return;
+ }
+
+ const updateAllButton = $(nodesTabFooter).find("#red-ui-palette-button-updateAll");
+ const progressRow = $(nodesTabFooter).find(".red-ui-palette-footer-progress");
+ const modules = updateAvailable.slice();
+ const runUpdate = function () {
+ modules.forEach(function (moduleName, i) {
+ if (moduleName in nodeEntries) {
+ const { version, pkg_url } = loadedIndex[moduleName];
+ const updatedCount = i + 1;
+ installNodeModule(moduleName, version, pkg_url, function (xhr) {
+ if (xhr) {
+ if (xhr.responseJSON) {
+ const notification = RED.notify(RED._("palette.editor.errors.updateFailed", { module: moduleName, message: xhr.responseJSON.message }), {
+ type: "error",
+ modal: true,
+ 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");
+ }
+ }
+ ]
+ });
+ }
+ } else {
+ progressRow.text(RED._("palette.editor.progress.updated", {
+ count: updatedCount,
+ total: modules.length
+ }));
+ if (i === modules.length - 1) {
+ done();
+ }
+ }
+ });
+ }
+ });
+ }
+
+ const notification = RED.notify(RED._("palette.editor.confirm.updateAll.body", { count: updateAvailable.length }), {
+ modal: true,
+ fixed: true,
+ buttons: [
+ {
+ text: RED._("common.label.cancel"),
+ click: function () {
+ notification.close();
+ updateAllButton.removeClass("disabled");
+ updateAllButton.text(RED._("palette.editor.confirm.button.updateAll"));
+ }
+ },
+ {
+ text: RED._("palette.editor.confirm.button.updateAll"),
+ class: "primary red-ui-palette-module-install-confirm-button-update",
+ click: function () {
+ notification.close();
+ runUpdate();
+ }
+ },
+ ]
+ });
+ }
+
function update(entry,version,url,container,done) {
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
done(new Error('Palette not editable'));
diff --git a/packages/node_modules/@node-red/editor-client/src/sass/palette-editor.scss b/packages/node_modules/@node-red/editor-client/src/sass/palette-editor.scss
index 47a91d917..1cb29508a 100644
--- a/packages/node_modules/@node-red/editor-client/src/sass/palette-editor.scss
+++ b/packages/node_modules/@node-red/editor-client/src/sass/palette-editor.scss
@@ -306,6 +306,16 @@ button.red-ui-palette-editor-upload-button {
}
}
+.red-ui-palette-footer-button,
+.red-ui-palette-footer-progress {
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 5px;
+}
+.red-ui-palette-footer-progress {
+ color: var(--red-ui-secondary-text-color);
+}
+
button.red-ui-update-status {
width: auto;
padding: 0 3px;