diff --git a/editor/js/main.js b/editor/js/main.js index 86ccf4cb4..62cdb7373 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -73,191 +73,13 @@ RED.projects.showStartup(); } } + completeLoad(); }); } else { // Projects disabled by the user RED.sidebar.info.refresh() + completeLoad(); } - - var persistentNotifications = {}; - RED.comms.subscribe("notification/#",function(topic,msg) { - var parts = topic.split("/"); - var notificationId = parts[1]; - if (notificationId === "runtime-deploy") { - // handled in ui/deploy.js - return; - } - if (notificationId === "node") { - // handled below - return; - } - if (notificationId === "project-update") { - RED.nodes.clear(); - RED.history.clear(); - RED.view.redraw(true); - RED.projects.refresh(function() { - loadFlows(function() { - var project = RED.projects.getActiveProject(); - var message = { - "change-branch":"Change to local branch '"+project.git.branches.local+"'", - "abort-merge":"Git merge aborted", - "loaded":"Project '"+msg.project+"' loaded", - "updated":"Project '"+msg.project+"' updated", - "pull":"Project '"+msg.project+"' reloaded", - "revert": "Project '"+msg.project+"' reloaded" - }[msg.action]; - RED.notify(message); - RED.sidebar.info.refresh() - }); - }); - return; - } - - if (msg.text) { - var text = RED._(msg.text,{default:msg.text}); - var options = { - type: msg.type, - fixed: msg.timeout === undefined, - timeout: msg.timeout, - id: notificationId - } - if (notificationId === "runtime-state") { - if (msg.error === "missing-types") { - text+=""; - options.buttons = [ - { - text: "Close", - click: function() { - persistentNotifications[notificationId].hideNotification(); - } - } - ] - } else if (msg.error === "credentials_load_failed") { - if (RED.user.hasPermission("projects.write")) { - options.buttons = [ - { - text: "Setup credentials", - click: function() { - persistentNotifications[notificationId].hideNotification(); - RED.projects.showCredentialsPrompt(); - } - } - ] - } - } else if (msg.error === "missing_flow_file") { - if (RED.user.hasPermission("projects.write")) { - options.buttons = [ - { - text: "Setup project files", - click: function() { - persistentNotifications[notificationId].hideNotification(); - RED.projects.showFilesPrompt(); - } - } - ] - } - } else if (msg.error === "project_empty") { - if (RED.user.hasPermission("projects.write")) { - options.buttons = [ - { - text: "No thanks", - click: function() { - persistentNotifications[notificationId].hideNotification(); - } - }, { - text: "Create default project files", - click: function() { - persistentNotifications[notificationId].hideNotification(); - RED.projects.createDefaultFileSet(); - } - } - ] - } - } - } - if (!persistentNotifications.hasOwnProperty(notificationId)) { - persistentNotifications[notificationId] = RED.notify(text,options); - } else { - persistentNotifications[notificationId].update(text,options); - } - } else if (persistentNotifications.hasOwnProperty(notificationId)) { - persistentNotifications[notificationId].close(); - delete persistentNotifications[notificationId]; - } - }); - RED.comms.subscribe("status/#",function(topic,msg) { - var parts = topic.split("/"); - var node = RED.nodes.node(parts[1]); - if (node) { - if (msg.hasOwnProperty("text")) { - if (msg.text[0] !== ".") { - msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); - } - } - node.status = msg; - node.dirty = true; - RED.view.redraw(); - } - }); - RED.comms.subscribe("notification/node/#",function(topic,msg) { - var i,m; - var typeList; - var info; - if (topic == "notification/node/added") { - var addedTypes = []; - msg.forEach(function(m) { - var id = m.id; - RED.nodes.addNodeSet(m); - addedTypes = addedTypes.concat(m.types); - RED.i18n.loadCatalog(id, function() { - $.get('nodes/'+id, function(data) { - $("body").append(data); - }); - }); - }); - if (addedTypes.length) { - typeList = ""; - RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success"); - } - loadIconList(); - } else if (topic == "notification/node/removed") { - for (i=0;i
  • ")+"
  • "; - RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success"); - } - } - loadIconList(); - } else if (topic == "notification/node/enabled") { - if (msg.types) { - info = RED.nodes.getNodeSet(msg.id); - if (info.added) { - RED.nodes.enableNodeSet(msg.id); - typeList = ""; - RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success"); - } else { - $.get('nodes/'+msg.id, function(data) { - $("body").append(data); - typeList = ""; - RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success"); - }); - } - } - } else if (topic == "notification/node/disabled") { - if (msg.types) { - RED.nodes.disableNodeSet(msg.id); - typeList = ""; - RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success"); - } - } else if (topic == "node/upgraded") { - RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success"); - RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version); - } - // Refresh flow library to ensure any examples are updated - RED.library.loadFlowLibrary(); - }); }); } }); @@ -286,6 +108,202 @@ }); } + function completeLoad() { + var persistentNotifications = {}; + RED.comms.subscribe("notification/#",function(topic,msg) { + var parts = topic.split("/"); + var notificationId = parts[1]; + if (notificationId === "runtime-deploy") { + // handled in ui/deploy.js + return; + } + if (notificationId === "node") { + // handled below + return; + } + if (notificationId === "project-update") { + RED.nodes.clear(); + RED.history.clear(); + RED.view.redraw(true); + RED.projects.refresh(function() { + loadFlows(function() { + var project = RED.projects.getActiveProject(); + var message = { + "change-branch":"Change to local branch '"+project.git.branches.local+"'", + "abort-merge":"Git merge aborted", + "loaded":"Project '"+msg.project+"' loaded", + "updated":"Project '"+msg.project+"' updated", + "pull":"Project '"+msg.project+"' reloaded", + "revert": "Project '"+msg.project+"' reloaded" + }[msg.action]; + RED.notify(message); + RED.sidebar.info.refresh() + }); + }); + return; + } + + if (msg.text) { + var text = RED._(msg.text,{default:msg.text}); + var options = { + type: msg.type, + fixed: msg.timeout === undefined, + timeout: msg.timeout, + id: notificationId + } + if (notificationId === "runtime-state") { + if (msg.error === "missing-types") { + text+=""; + if (!!RED.projects.getActiveProject()) { + options.buttons = [ + { + text: "Manage project dependencies", + click: function() { + persistentNotifications[notificationId].hideNotification(); + RED.projects.settings.show('deps'); + } + } + ] + // } else if (RED.settings.theme('palette.editable') !== false) { + } else { + options.buttons = [ + { + text: "Close", + click: function() { + persistentNotifications[notificationId].hideNotification(); + } + } + ] + } + } else if (msg.error === "credentials_load_failed") { + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "Setup credentials", + click: function() { + persistentNotifications[notificationId].hideNotification(); + RED.projects.showCredentialsPrompt(); + } + } + ] + } + } else if (msg.error === "missing_flow_file") { + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "Setup project files", + click: function() { + persistentNotifications[notificationId].hideNotification(); + RED.projects.showFilesPrompt(); + } + } + ] + } + } else if (msg.error === "project_empty") { + if (RED.user.hasPermission("projects.write")) { + options.buttons = [ + { + text: "No thanks", + click: function() { + persistentNotifications[notificationId].hideNotification(); + } + }, + { + text: "Create default project files", + click: function() { + persistentNotifications[notificationId].hideNotification(); + RED.projects.createDefaultFileSet(); + } + } + ] + } + } + } + if (!persistentNotifications.hasOwnProperty(notificationId)) { + persistentNotifications[notificationId] = RED.notify(text,options); + } else { + persistentNotifications[notificationId].update(text,options); + } + } else if (persistentNotifications.hasOwnProperty(notificationId)) { + persistentNotifications[notificationId].close(); + delete persistentNotifications[notificationId]; + } + }); + RED.comms.subscribe("status/#",function(topic,msg) { + var parts = topic.split("/"); + var node = RED.nodes.node(parts[1]); + if (node) { + if (msg.hasOwnProperty("text")) { + if (msg.text[0] !== ".") { + msg.text = node._(msg.text.toString(),{defaultValue:msg.text.toString()}); + } + } + node.status = msg; + node.dirty = true; + RED.view.redraw(); + } + }); + RED.comms.subscribe("notification/node/#",function(topic,msg) { + var i,m; + var typeList; + var info; + if (topic == "notification/node/added") { + var addedTypes = []; + msg.forEach(function(m) { + var id = m.id; + RED.nodes.addNodeSet(m); + addedTypes = addedTypes.concat(m.types); + RED.i18n.loadCatalog(id, function() { + $.get('nodes/'+id, function(data) { + $("body").append(data); + }); + }); + }); + if (addedTypes.length) { + typeList = ""; + RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success"); + } + loadIconList(); + } else if (topic == "notification/node/removed") { + for (i=0;i
  • ")+"
  • "; + RED.notify(RED._("palette.event.nodeRemoved", {count:m.types.length})+typeList,"success"); + } + } + loadIconList(); + } else if (topic == "notification/node/enabled") { + if (msg.types) { + info = RED.nodes.getNodeSet(msg.id); + if (info.added) { + RED.nodes.enableNodeSet(msg.id); + typeList = ""; + RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success"); + } else { + $.get('nodes/'+msg.id, function(data) { + $("body").append(data); + typeList = ""; + RED.notify(RED._("palette.event.nodeAdded", {count:msg.types.length})+typeList,"success"); + }); + } + } + } else if (topic == "notification/node/disabled") { + if (msg.types) { + RED.nodes.disableNodeSet(msg.id); + typeList = ""; + RED.notify(RED._("palette.event.nodeDisabled", {count:msg.types.length})+typeList,"success"); + } + } else if (topic == "node/upgraded") { + RED.notify(RED._("palette.event.nodeUpgraded", {module:msg.module,version:msg.version}),"success"); + RED.nodes.registry.setModulePendingUpdated(msg.module,msg.version); + } + // Refresh flow library to ensure any examples are updated + RED.library.loadFlowLibrary(); + }); + } + function showAbout() { $.get('red/about', function(data) { var aboutHeader = '
    '+ diff --git a/editor/js/nodes.js b/editor/js/nodes.js index 0e8882498..36f7a3291 100644 --- a/editor/js/nodes.js +++ b/editor/js/nodes.js @@ -714,7 +714,9 @@ RED.nodes = (function() { if (!$.isArray(newNodes)) { newNodes = [newNodes]; } + var isInitialLoad = false; if (!initialLoad) { + isInitialLoad = true; initialLoad = JSON.parse(JSON.stringify(newNodes)); } var unknownTypes = []; @@ -735,7 +737,7 @@ RED.nodes = (function() { } } - if (unknownTypes.length > 0) { + if (!isInitialLoad && unknownTypes.length > 0) { var typeList = "
    • "+unknownTypes.join("
    • ")+"
    "; var type = "type"+(unknownTypes.length > 1?"s":""); RED.notify(""+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+""+typeList,"error",false,10000); @@ -1214,7 +1216,7 @@ RED.nodes = (function() { RED.workspaces.remove(workspaces[id]); }); defaultWorkspace = null; - + initialLoad = null; RED.nodes.dirty(false); RED.view.redraw(true); RED.palette.refresh(); diff --git a/editor/js/ui/diff.js b/editor/js/ui/diff.js index 0d8a5cfbd..cfec75e75 100644 --- a/editor/js/ui/diff.js +++ b/editor/js/ui/diff.js @@ -1678,7 +1678,6 @@ RED.diff = (function() { function createUnifiedDiffTable(files,commitOptions) { var diffPanel = $('
    '); - console.log(files); files.forEach(function(file) { var hunks = file.hunks; var isBinary = file.binary; diff --git a/editor/js/ui/palette-editor.js b/editor/js/ui/palette-editor.js index fccf2c437..ad24ba826 100644 --- a/editor/js/ui/palette-editor.js +++ b/editor/js/ui/palette-editor.js @@ -75,27 +75,21 @@ RED.palette.editor = (function() { }); }) } - function installNodeModule(id,version,shade,callback) { + function installNodeModule(id,version,callback) { var requestBody = { module: id }; - if (callback === undefined) { - callback = shade; - shade = version; - } else { + if (version) { requestBody.version = version; } - shade.show(); $.ajax({ url:"nodes", type: "POST", data: JSON.stringify(requestBody), contentType: "application/json; charset=utf-8" }).done(function(data,textStatus,xhr) { - shade.hide(); callback(); }).fail(function(xhr,textStatus,err) { - shade.hide(); callback(xhr); }); } @@ -604,24 +598,7 @@ RED.palette.editor = (function() { if ($(this).hasClass('disabled')) { return; } - $("#palette-module-install-confirm").data('module',entry.name); - $("#palette-module-install-confirm").data('version',loadedIndex[entry.name].version); - $("#palette-module-install-confirm").data('shade',shade); - - $("#palette-module-install-confirm-body").html(entry.local? - RED._("palette.editor.confirm.update.body"): - RED._("palette.editor.confirm.cannotUpdate.body") - ); - $(".palette-module-install-confirm-button-install").hide(); - $(".palette-module-install-confirm-button-remove").hide(); - if (entry.local) { - $(".palette-module-install-confirm-button-update").show(); - } else { - $(".palette-module-install-confirm-button-update").hide(); - } - $("#palette-module-install-confirm") - .dialog('option', 'title',RED._("palette.editor.confirm.update.title")) - .dialog('open'); + update(entry,loadedIndex[entry.name].version,container,function(err){}); }) @@ -629,16 +606,7 @@ RED.palette.editor = (function() { removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000)); removeButton.click(function(evt) { evt.preventDefault(); - - $("#palette-module-install-confirm").data('module',entry.name); - $("#palette-module-install-confirm").data('shade',shade); - $("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.remove.body")); - $(".palette-module-install-confirm-button-install").hide(); - $(".palette-module-install-confirm-button-remove").show(); - $(".palette-module-install-confirm-button-update").hide(); - $("#palette-module-install-confirm") - .dialog('option', 'title', RED._("palette.editor.confirm.remove.title")) - .dialog('open'); + remove(entry,container,function(err){}); }) if (!entry.local) { removeButton.hide(); @@ -836,22 +804,11 @@ RED.palette.editor = (function() { $(' '+formatUpdatedAt(entry.updated_at)+'').appendTo(metaRow); var buttonRow = $('
    ',{class:"palette-module-meta"}).appendTo(headerRow); var buttonGroup = $('
    ',{class:"palette-module-button-group"}).appendTo(buttonRow); - var shade = $('
    ').appendTo(container); var installButton = $('').html(RED._('palette.editor.install')).appendTo(buttonGroup); installButton.click(function(e) { e.preventDefault(); if (!$(this).hasClass('disabled')) { - $("#palette-module-install-confirm").data('module',entry.id); - $("#palette-module-install-confirm").data('version',entry.version); - $("#palette-module-install-confirm").data('url',entry.url); - $("#palette-module-install-confirm").data('shade',shade); - $("#palette-module-install-confirm-body").html(RED._("palette.editor.confirm.install.body")); - $(".palette-module-install-confirm-button-install").show(); - $(".palette-module-install-confirm-button-remove").hide(); - $(".palette-module-install-confirm-button-update").hide(); - $("#palette-module-install-confirm") - .dialog('option', 'title', RED._("palette.editor.confirm.install.title")) - .dialog('open'); + install(entry,container,function(xhr) {}); } }) if (nodeEntries.hasOwnProperty(entry.id)) { @@ -869,88 +826,126 @@ RED.palette.editor = (function() { }); $('
    ').appendTo(installTab); - - $('
    ').appendTo(document.body); - $("#palette-module-install-confirm").dialog({ - title: RED._('palette.editor.confirm.title'), + } + function update(entry,version,container,done) { + if (RED.settings.theme('palette.editable') === false) { + done(new Error('Palette not editable')); + return; + } + var notification = RED.notify(RED._("palette.editor.confirm.update.body",{module:entry.name}),{ modal: true, - autoOpen: false, - width: 550, - height: "auto", + fixed: true, buttons: [ { text: RED._("common.label.cancel"), click: function() { - $( this ).dialog( "close" ); - } - }, - { - text: RED._("palette.editor.confirm.button.review"), - class: "primary palette-module-install-confirm-button-install", - click: function() { - var url = $(this).data('url'); - window.open(url); - } - }, - { - text: RED._("palette.editor.confirm.button.install"), - class: "primary palette-module-install-confirm-button-install", - click: function() { - var id = $(this).data('module'); - var version = $(this).data('version'); - var shade = $(this).data('shade'); - installNodeModule(id,version,shade,function(xhr) { - if (xhr) { - if (xhr.responseJSON) { - RED.notify(RED._('palette.editor.errors.installFailed',{module: id,message:xhr.responseJSON.message})); - } - } - }); - $( this ).dialog( "close" ); - } - }, - { - text: RED._("palette.editor.confirm.button.remove"), - class: "primary palette-module-install-confirm-button-remove", - click: function() { - var id = $(this).data('module'); - var shade = $(this).data('shade'); - shade.show(); - removeNodeModule(id, function(xhr) { - shade.hide(); - if (xhr) { - if (xhr.responseJSON) { - RED.notify(RED._('palette.editor.errors.removeFailed',{module: id,message:xhr.responseJSON.message})); - } - } - }) - - $( this ).dialog( "close" ); + notification.close(); } }, { text: RED._("palette.editor.confirm.button.update"), class: "primary palette-module-install-confirm-button-update", click: function() { - var id = $(this).data('module'); - var version = $(this).data('version'); - var shade = $(this).data('shade'); - shade.show(); - installNodeModule(id,version,shade,function(xhr) { - if (xhr) { - if (xhr.responseJSON) { - RED.notify(RED._('palette.editor.errors.updateFailed',{module: id,message:xhr.responseJSON.message})); - } - } + var spinner = RED.utils.addSpinnerOverlay(container, true); + installNodeModule(entry.name,version,function(xhr) { + spinner.remove(); + if (xhr) { + if (xhr.responseJSON) { + RED.notify(RED._('palette.editor.errors.updateFailed',{module: entry.name,message:xhr.responseJSON.message})); + } + } + done(xhr); }); - $( this ).dialog( "close" ); + notification.close(); } } ] }) } + function remove(entry,container,done) { + if (RED.settings.theme('palette.editable') === false) { + done(new Error('Palette not editable')); + return; + } + var notification = RED.notify(RED._("palette.editor.confirm.remove.body",{module:entry.name}),{ + modal: true, + fixed: true, + buttons: [ + { + text: RED._("common.label.cancel"), + click: function() { + notification.close(); + } + }, + { + text: RED._("palette.editor.confirm.button.remove"), + class: "primary palette-module-install-confirm-button-remove", + click: function() { + var spinner = RED.utils.addSpinnerOverlay(container, true); + removeNodeModule(entry.name, function(xhr) { + spinner.remove(); + if (xhr) { + if (xhr.responseJSON) { + RED.notify(RED._('palette.editor.errors.removeFailed',{module: entry.name,message:xhr.responseJSON.message})); + } + } + }) + notification.close(); + } + } + ] + }) + } + function install(entry,container,done) { + if (RED.settings.theme('palette.editable') === false) { + done(new Error('Palette not editable')); + return; + } + var buttons = [ + { + text: RED._("common.label.cancel"), + click: function() { + notification.close(); + } + } + ]; + if (entry.url) { + buttons.push({ + text: RED._("palette.editor.confirm.button.review"), + class: "primary palette-module-install-confirm-button-install", + click: function() { + var url = entry.url||""; + window.open(url); + } + }); + } + buttons.push({ + text: RED._("palette.editor.confirm.button.install"), + class: "primary palette-module-install-confirm-button-install", + click: function() { + var spinner = RED.utils.addSpinnerOverlay(container, true); + installNodeModule(entry.id,entry.version,function(xhr) { + spinner.remove(); + if (xhr) { + if (xhr.responseJSON) { + RED.notify(RED._('palette.editor.errors.installFailed',{module: entry.id,message:xhr.responseJSON.message})); + } + } + done(xhr); + }); + notification.close(); + } + }); + + var notification = RED.notify(RED._("palette.editor.confirm.install.body",{module:entry.id}),{ + modal: true, + fixed: true, + buttons: buttons + }) + } return { - init: init + init: init, + install: install } })(); diff --git a/editor/js/ui/projects/projectSettings.js b/editor/js/ui/projects/projectSettings.js index c4736a65c..62fce76aa 100644 --- a/editor/js/ui/projects/projectSettings.js +++ b/editor/js/ui/projects/projectSettings.js @@ -262,14 +262,16 @@ RED.projects.settings = (function() { var totalCount = 0; var unknownCount = 0; var unusedCount = 0; + var notInstalledCount = 0; for (var m in modulesInUse) { if (modulesInUse.hasOwnProperty(m)) { depsList.editableList('addItem',{ - module: modulesInUse[m].module, + id: modulesInUse[m].module, version: modulesInUse[m].version, count: modulesInUse[m].count, - known: activeProject.dependencies.hasOwnProperty(m) + known: activeProject.dependencies.hasOwnProperty(m), + installed: true }); totalCount++; if (modulesInUse[m].count === 0) { @@ -284,29 +286,69 @@ RED.projects.settings = (function() { if (activeProject.dependencies) { for (var m in activeProject.dependencies) { if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { + var installed = !!RED.nodes.registry.getModule(m); depsList.editableList('addItem',{ - module: m, + id: m, version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version, count: 0, - known: true + known: true, + installed: installed }); totalCount++; - unusedCount++; + if (installed) { + unusedCount++; + } else { + notInstalledCount++; + } } } } - if (unknownCount > 0) { - depsList.editableList('addItem',{index:1, label:"Unlisted dependencies"}); // TODO: nls - } - if (unusedCount > 0) { - depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls - } + // if (notInstalledCount > 0) { + // depsList.editableList('addItem',{index:1, label:"Missing dependencies"}); // TODO: nls + // } + // if (unknownCount > 0) { + // depsList.editableList('addItem',{index:1, label:"Unlisted dependencies"}); // TODO: nls + // } + // if (unusedCount > 0) { + // depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls + // } if (totalCount === 0) { depsList.editableList('addItem',{index:0, label:"None"}); // TODO: nls } } + function saveDependencies(depsList,container,dependencies,complete) { + var activeProject = RED.projects.getActiveProject(); + var spinner = utils.addSpinnerOverlay(container).addClass('projects-dialog-spinner-contain'); + var done = function(err,res) { + spinner.remove(); + if (err) { + return complete(err); + } + activeProject.dependencies = dependencies; + RED.sidebar.versionControl.refresh(true); + complete(); + } + utils.sendRequest({ + url: "projects/"+activeProject.name, + type: "PUT", + responses: { + 0: function(error) { + done(error,null); + }, + 200: function(data) { + RED.sidebar.versionControl.refresh(true); + done(null,data); + }, + 400: { + '*': function(error) { + done(error,null); + } + }, + } + },{dependencies:dependencies}); + } function editDependencies(activeProject,depsJSON,container,depsList) { var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4); if (json === "{}") { @@ -319,34 +361,12 @@ RED.projects.settings = (function() { complete: function(v) { try { var parsed = JSON.parse(v); - var spinner = utils.addSpinnerOverlay(container); - - var done = function(err,res) { + saveDependencies(depsList,container,parsed,function(err) { if (err) { return editDependencies(activeProject,v,container,depsList); } activeProject.dependencies = parsed; updateProjectDependencies(activeProject,depsList); - } - utils.sendRequest({ - url: "projects/"+activeProject.name, - type: "PUT", - responses: { - 0: function(error) { - done(error,null); - }, - 200: function(data) { - RED.sidebar.versionControl.refresh(true); - done(null,data); - }, - 400: { - 'unexpected_error': function(error) { - done(error,null); - } - }, - } - },{dependencies:parsed}).always(function() { - spinner.remove(); }); } catch(err) { editDependencies(activeProject,v,container,depsList); @@ -378,59 +398,119 @@ RED.projects.settings = (function() { row.parent().addClass("palette-module-section"); } headerRow.text(entry.label); - if (RED.user.hasPermission("projects.write")) { - if (entry.index === 1) { - var addButton = $('').appendTo(headerRow).click(function(evt) { - evt.preventDefault(); - var deps = $.extend(true, {}, activeProject.dependencies); - for (var m in modulesInUse) { - if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) { - deps[m] = modulesInUse[m].version; - } - } - editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); - }); - } else if (entry.index === 3) { - var removeButton = $('').appendTo(headerRow).click(function(evt) { - evt.preventDefault(); - var deps = $.extend(true, {}, activeProject.dependencies); - for (var m in activeProject.dependencies) { - if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { - delete deps[m]; - } - } - editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); - }); - } - } + // if (RED.user.hasPermission("projects.write")) { + // if (entry.index === 1) { + // var addButton = $('').appendTo(headerRow).click(function(evt) { + // evt.preventDefault(); + // var deps = $.extend(true, {}, activeProject.dependencies); + // for (var m in modulesInUse) { + // if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) { + // deps[m] = modulesInUse[m].version; + // } + // } + // editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); + // }); + // } else if (entry.index === 3) { + // var removeButton = $('').appendTo(headerRow).click(function(evt) { + // evt.preventDefault(); + // var deps = $.extend(true, {}, activeProject.dependencies); + // for (var m in activeProject.dependencies) { + // if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { + // delete deps[m]; + // } + // } + // editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); + // }); + // } + // } } else { headerRow.addClass("palette-module-header"); - headerRow.toggleClass("palette-module-unused",entry.count === 0); + if (!entry.installed) { + headerRow.addClass("palette-module-not-installed"); + } else if (entry.count === 0) { + headerRow.addClass("palette-module-unused"); + } else if (!entry.known) { + headerRow.addClass("palette-module-unknown"); + } + entry.element = headerRow; var titleRow = $('
    ').appendTo(headerRow); - var icon = $('').appendTo(titleRow); + var iconClass = "fa-cube"; + if (!entry.installed) { + iconClass = "fa-warning"; + } + var icon = $('').appendTo(titleRow); entry.icon = icon; - $('').html(entry.module).appendTo(titleRow); + $('').html(entry.id).appendTo(titleRow); var metaRow = $('
    ').appendTo(headerRow); var versionSpan = $('').html(entry.version).appendTo(metaRow); - if (!entry.known) { - headerRow.addClass("palette-module-unknown"); - } else if (entry.known && entry.count === 0) { - + metaRow = $('
    ').appendTo(headerRow); + var buttons = $('
    ').appendTo(metaRow); + if (RED.user.hasPermission("projects.write")) { + if (!entry.installed && RED.settings.theme('palette.editable') !== false) { + $('install').appendTo(buttons) + .click(function(evt) { + evt.preventDefault(); + RED.palette.editor.install(entry,row,function(err) { + if (!err) { + entry.installed = true; + var spinner = RED.utils.addSpinnerOverlay(row,true); + setTimeout(function() { + depsList.editableList('removeItem',entry); + refreshModuleInUseCounts(); + entry.count = modulesInUse[entry.id].count; + depsList.editableList('addItem',entry); + },500); + } + }); + }) + } else if (entry.known && entry.count === 0) { + $('remove from project').appendTo(buttons) + .click(function(evt) { + evt.preventDefault(); + var deps = $.extend(true, {}, activeProject.dependencies); + delete deps[entry.id]; + saveDependencies(depsList,row,deps,function(err) { + if (!err) { + row.fadeOut(200,function() { + depsList.editableList('removeItem',entry); + }); + } else { + console.log(err); + } + }); + }); + } else if (!entry.known) { + $('add to project').appendTo(buttons) + .click(function(evt) { + evt.preventDefault(); + var deps = $.extend(true, {}, activeProject.dependencies); + deps[entry.id] = modulesInUse[entry.id].version; + saveDependencies(depsList,row,deps,function(err) { + if (!err) { + buttons.remove(); + headerRow.removeClass("palette-module-unknown"); + } else { + console.log(err); + } + }); + }); + } } } }, sort: function(A,B) { - if (A.index && B.index) { - return A.index - B.index; - } - var Acategory = A.index?A.index:(A.known?(A.count>0?0:4):2); - var Bcategory = B.index?B.index:(B.known?(B.count>0?0:4):2); - if (Acategory === Bcategory) { - return A.module.localeCompare(B.module); - } else { - return Acategory - Bcategory; - } + return A.id.localeCompare(B.id); + // if (A.index && B.index) { + // return A.index - B.index; + // } + // var Acategory = A.index?A.index:(A.known?(A.count>0?0:4):2); + // var Bcategory = B.index?B.index:(B.known?(B.count>0?0:4):2); + // if (Acategory === Bcategory) { + // return A.id.localeCompare(B.id); + // } else { + // return Acategory - Bcategory; + // } } }); @@ -1332,8 +1412,30 @@ RED.projects.settings = (function() { return pane; } - var popover; + function refreshModuleInUseCounts() { + modulesInUse = {}; + RED.nodes.eachNode(_updateModulesInUse); + RED.nodes.eachConfig(_updateModulesInUse); + } + function _updateModulesInUse(n) { + if (!/^subflow:/.test(n.type)) { + var module = RED.nodes.registry.getNodeSetForType(n.type).module; + if (module !== 'node-red') { + if (!modulesInUse.hasOwnProperty(module)) { + modulesInUse[module] = { + module: module, + version: RED.nodes.registry.getModule(module).version, + count: 0, + known: false + } + } + modulesInUse[module].count++; + } + } + } + + var popover; var utils; var modulesInUse = {}; function init(_utils) { @@ -1362,22 +1464,7 @@ RED.projects.settings = (function() { } }); - RED.events.on('nodes:add', function(n) { - if (!/^subflow:/.test(n.type)) { - var module = RED.nodes.registry.getNodeSetForType(n.type).module; - if (module !== 'node-red') { - if (!modulesInUse.hasOwnProperty(module)) { - modulesInUse[module] = { - module: module, - version: RED.nodes.registry.getModule(module).version, - count: 0, - known: false - } - } - modulesInUse[module].count++; - } - } - }) + RED.events.on('nodes:add', _updateModulesInUse); RED.events.on('nodes:remove', function(n) { if (!/^subflow:/.test(n.type)) { var module = RED.nodes.registry.getNodeSetForType(n.type).module; diff --git a/editor/js/ui/projects/projects.js b/editor/js/ui/projects/projects.js index 6c542550d..45663e852 100644 --- a/editor/js/ui/projects/projects.js +++ b/editor/js/ui/projects/projects.js @@ -920,9 +920,9 @@ RED.projects = (function() { // $('').appendTo(row); // projectSecretInput = $('').appendTo(row); switch(options.screen||"empty") { - case "empty": console.log("createasempty"); createAsEmpty.click(); break; - case "open": console.log("opening"); openProject.click(); break; - case "clone": console.log("cloning"); createAsClone.click(); break; + case "empty": createAsEmpty.click(); break; + case "open": openProject.click(); break; + case "clone": createAsClone.click(); break; } setTimeout(function() { @@ -1096,12 +1096,7 @@ RED.projects = (function() { done(null,data); }, 400: { - 'credentials_load_failed': function(error) { - done(error,null); - }, - 'unexpected_error': function(error) { - done(error,null); - } + '*': done }, } },{active:true}).then(function() { @@ -1538,6 +1533,10 @@ RED.projects = (function() { resultCallback = responses[xhr.responseJSON.error]; resultCallbackArgs = xhr.responseJSON; return; + } else if (responses['*']) { + resultCallback = responses['*']; + resultCallbackArgs = xhr.responseJSON; + return; } } console.log("Unhandled error response:"); @@ -1816,6 +1815,9 @@ RED.projects = (function() { } RED.projects.settings.show('settings'); }, + showProjectDependencies: function() { + RED.projects.settings.show('deps'); + }, createDefaultFileSet: createDefaultFileSet, // showSidebar: showSidebar, refresh: refresh, diff --git a/editor/js/ui/utils.js b/editor/js/ui/utils.js index 53c6150c6..dc96ae37c 100644 --- a/editor/js/ui/utils.js +++ b/editor/js/ui/utils.js @@ -765,6 +765,14 @@ RED.utils = (function() { return RED.text.bidi.enforceTextDirectionWithUCC(l); } + function addSpinnerOverlay(container,contain) { + var spinner = $('
    ').appendTo(container); + if (contain) { + spinner.addClass('projects-dialog-spinner-contain'); + } + return spinner; + } + return { createObjectElement: buildMessageElement, getMessageProperty: getMessageProperty, @@ -774,5 +782,6 @@ RED.utils = (function() { getDefaultNodeIcon: getDefaultNodeIcon, getNodeIcon: getNodeIcon, getNodeLabel: getNodeLabel, + addSpinnerOverlay: addSpinnerOverlay } })(); diff --git a/editor/sass/palette-editor.scss b/editor/sass/palette-editor.scss index 0c83071b3..b2fb61df3 100644 --- a/editor/sass/palette-editor.scss +++ b/editor/sass/palette-editor.scss @@ -76,22 +76,6 @@ border-bottom: 1px solid $primary-border-color; text-align: right; } - .palette-module-button-group { - position: absolute; - right: 0; - bottom: 0; - a { - margin-left: 5px; - } - } - .palette-module-shade { - @include shade; - text-align: center; - padding-top: 20px; - } - #palette-module-install-shade { - padding-top: 80px; - } .palette-module-shade-status { color: #666; } @@ -230,3 +214,19 @@ color: #666; } +.palette-module-button-group { + position: absolute; + right: 0; + bottom: 0; + a { + margin-left: 5px; + } +} +.palette-module-shade { + @include shade; + text-align: center; + padding-top: 20px; +} +#palette-module-install-shade { + padding-top: 80px; +} diff --git a/editor/sass/projects.scss b/editor/sass/projects.scss index e230ed2cb..134e43a93 100644 --- a/editor/sass/projects.scss +++ b/editor/sass/projects.scss @@ -313,7 +313,12 @@ // border: 1px dashed #bbb; } .palette-module-unknown { - // border: 1px dashed #b72828; + border: 1px dashed #aaa; + background: #fafafa; + } + .palette-module-not-installed { + border: 1px dashed #b07575; + background: #fee; i.fa-warning { color: #b07575; //#b72828; } diff --git a/red/api/editor/locales/en-US/editor.json b/red/api/editor/locales/en-US/editor.json index 73a2b3758..d7ae5759c 100644 --- a/red/api/editor/locales/en-US/editor.json +++ b/red/api/editor/locales/en-US/editor.json @@ -344,24 +344,24 @@ "sortRecent": "recent", "more": "+ __count__ more", "errors": { - "catalogLoadFailed": "Failed to load node catalogue.
    Check the browser console for more information", - "installFailed": "Failed to install: __module__
    __message__
    Check the log for more information", - "removeFailed": "Failed to remove: __module__
    __message__
    Check the log for more information", - "updateFailed": "Failed to update: __module__
    __message__
    Check the log for more information", - "enableFailed": "Failed to enable: __module__
    __message__
    Check the log for more information", - "disableFailed": "Failed to disable: __module__
    __message__
    Check the log for more information" + "catalogLoadFailed": "

    Failed to load node catalogue.

    Check the browser console for more information

    ", + "installFailed": "

    Failed to install: __module__

    __message__

    Check the log for more information

    ", + "removeFailed": "

    Failed to remove: __module__

    __message__

    Check the log for more information

    ", + "updateFailed": "

    Failed to update: __module__

    __message__

    Check the log for more information

    ", + "enableFailed": "

    Failed to enable: __module__

    __message__

    Check the log for more information

    ", + "disableFailed": "

    Failed to disable: __module__

    __message__

    Check the log for more information

    " }, "confirm": { "install": { - "body":"Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED. ", + "body":"

    Installing '__module__'

    Before installing, please read the node's documentation. Some nodes have dependencies that cannot be automatically resolved and can require a restart of Node-RED.

    ", "title": "Install nodes" }, "remove": { - "body":"Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.", + "body":"

    Removing '__module__'

    Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.

    ", "title": "Remove nodes" }, "update": { - "body":"Updating the node will require a restart of Node-RED to complete the update. This must be done manually.", + "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" }, "cannotUpdate": { diff --git a/red/runtime/nodes/registry/installer.js b/red/runtime/nodes/registry/installer.js index a81d051ad..cb54b59d1 100644 --- a/red/runtime/nodes/registry/installer.js +++ b/red/runtime/nodes/registry/installer.js @@ -99,7 +99,10 @@ function installModule(module,version) { } var installDir = settings.userDir || process.env.NODE_RED_HOME || "."; - var child = child_process.execFile(npmCommand,['install','--save','--save-prefix="~"','--production',installName], + + var args = ['install','--save','--save-prefix="~"','--production',installName]; + log.trace(npmCommand + JSON.stringify(args)); + var child = child_process.execFile(npmCommand,args, { cwd: installDir }, @@ -186,7 +189,11 @@ function uninstallModule(module) { var list = registry.removeModule(module); log.info(log._("server.install.uninstalling",{name:module})); - var child = child_process.execFile(npmCommand,['remove','--save',module], + + var args = ['remove','--save',module]; + log.trace(npmCommand + JSON.stringify(args)); + + var child = child_process.execFile(npmCommand,args, { cwd: installDir },