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 3d949f8ca..3c0c36dff 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 @@ -115,8 +115,65 @@ RED.palette.editor = (function() { }); }) } - function installNodeModule(id,version,url,callback) { - var requestBody = { + + const moduleQueue = []; + const processQueue = function () { + if (moduleQueue.length === 0) { + return; + } + + const { type, body, callback } = moduleQueue[0]; + if (type === "install") { + RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install") + ` : ${body.module} ${body.version}`); + $.ajax({ + url: "nodes", + type: "POST", + data: JSON.stringify(body), + contentType: "application/json; charset=utf-8" + }).done(function(_data, _textStatus, _xhr) { + callback(); + }).fail(function(xhr, textStatus, err) { + callback(xhr, textStatus, err); + }).always(function () { + // Remove the task from the list + moduleQueue.shift(); + // Process the next task + processQueue(); + }); + } else if (type === "remove") { + RED.eventLog.startEvent(RED._("palette.editor.confirm.button.remove") + ` : ${body.id}`); + $.ajax({ + url: "nodes/" + body.id, + type: "DELETE" + }).done(function(_data, _textStatus, _xhr) { + callback(); + }).fail(function(xhr, _textStatus, _err) { + callback(xhr); + }).always(function () { + // Remove the task from the list + moduleQueue.shift(); + // Process the next task + processQueue(); + }); + } + }; + + /** + * Adds a module to the processing queue to install or remove it + * @param {string} type the type of request to apply to the module + * @param {Object} body an object with module info + * @param {(xhr?: JQuery.jqXHR, textStatus?: JQuery.Ajax.ErrorTextStatus, err?: string) => void} callback a callback function called when the request is done + */ + function addModuleToQueue(type, body, callback) { + moduleQueue.push({ type, body, callback }); + + if (moduleQueue.length === 1) { + processQueue(); + } + } + + function installNodeModule(id, version, url, callback) { + const requestBody = { module: id }; if (version) { @@ -125,26 +182,10 @@ RED.palette.editor = (function() { if (url) { requestBody.url = url; } - $.ajax({ - url:"nodes", - type: "POST", - data: JSON.stringify(requestBody), - contentType: "application/json; charset=utf-8" - }).done(function(data,textStatus,xhr) { - callback(); - }).fail(function(xhr,textStatus,err) { - callback(xhr,textStatus,err); - }); + addModuleToQueue("install", requestBody, callback); } - function removeNodeModule(id,callback) { - $.ajax({ - url:"nodes/"+id, - type: "DELETE" - }).done(function(data,textStatus,xhr) { - callback(); - }).fail(function(xhr,textStatus,err) { - callback(xhr); - }) + function removeNodeModule(id, callback) { + addModuleToQueue("remove", { id: id }, callback); } function refreshNodeModuleList() { @@ -1231,7 +1272,6 @@ RED.palette.editor = (function() { evt.preventDefault(); RED.actions.invoke("core:show-event-log"); }); - RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.name+" "+version); installNodeModule(entry.name,version,url,function(xhr) { spinner.remove(); if (xhr) { @@ -1290,7 +1330,6 @@ RED.palette.editor = (function() { evt.preventDefault(); RED.actions.invoke("core:show-event-log"); }); - RED.eventLog.startEvent(RED._("palette.editor.confirm.button.remove")+" : "+entry.name); removeNodeModule(entry.name, function(xhr) { spinner.remove(); if (xhr) { @@ -1404,7 +1443,6 @@ RED.palette.editor = (function() { evt.preventDefault(); RED.actions.invoke("core:show-event-log"); }); - RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install")+" : "+entry.id+" "+entry.version); installNodeModule(entry.id,entry.version,entry.pkg_url,function(xhr, textStatus,err) { spinner.remove(); if (err && xhr.status === 504) {