1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Allow a user to install missing modules from project settings

This commit is contained in:
Nick O'Leary 2018-01-22 13:46:11 +00:00
parent 7e27dd7678
commit ad6e55ca17
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
11 changed files with 549 additions and 425 deletions

View File

@ -73,191 +73,13 @@
RED.projects.showStartup(); RED.projects.showStartup();
} }
} }
completeLoad();
}); });
} else { } else {
// Projects disabled by the user // Projects disabled by the user
RED.sidebar.info.refresh() 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+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
info = RED.nodes.removeNodeSet(m.id);
if (info.added) {
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
$("body").append(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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+="<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+addedTypes.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeAdded", {count:addedTypes.length})+typeList,"success");
}
loadIconList();
} else if (topic == "notification/node/removed") {
for (i=0;i<msg.length;i++) {
m = msg[i];
info = RED.nodes.removeNodeSet(m.id);
if (info.added) {
typeList = "<ul><li>"+m.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
RED.notify(RED._("palette.event.nodeEnabled", {count:msg.types.length})+typeList,"success");
} else {
$.get('nodes/'+msg.id, function(data) {
$("body").append(data);
typeList = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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 = "<ul><li>"+msg.types.join("</li><li>")+"</li></ul>";
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() { function showAbout() {
$.get('red/about', function(data) { $.get('red/about', function(data) {
var aboutHeader = '<div style="text-align:center;">'+ var aboutHeader = '<div style="text-align:center;">'+

View File

@ -714,7 +714,9 @@ RED.nodes = (function() {
if (!$.isArray(newNodes)) { if (!$.isArray(newNodes)) {
newNodes = [newNodes]; newNodes = [newNodes];
} }
var isInitialLoad = false;
if (!initialLoad) { if (!initialLoad) {
isInitialLoad = true;
initialLoad = JSON.parse(JSON.stringify(newNodes)); initialLoad = JSON.parse(JSON.stringify(newNodes));
} }
var unknownTypes = []; var unknownTypes = [];
@ -735,7 +737,7 @@ RED.nodes = (function() {
} }
} }
if (unknownTypes.length > 0) { if (!isInitialLoad && unknownTypes.length > 0) {
var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>"; var typeList = "<ul><li>"+unknownTypes.join("</li><li>")+"</li></ul>";
var type = "type"+(unknownTypes.length > 1?"s":""); var type = "type"+(unknownTypes.length > 1?"s":"");
RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000); RED.notify("<strong>"+RED._("clipboard.importUnrecognised",{count:unknownTypes.length})+"</strong>"+typeList,"error",false,10000);
@ -1214,7 +1216,7 @@ RED.nodes = (function() {
RED.workspaces.remove(workspaces[id]); RED.workspaces.remove(workspaces[id]);
}); });
defaultWorkspace = null; defaultWorkspace = null;
initialLoad = null;
RED.nodes.dirty(false); RED.nodes.dirty(false);
RED.view.redraw(true); RED.view.redraw(true);
RED.palette.refresh(); RED.palette.refresh();

View File

@ -1678,7 +1678,6 @@ RED.diff = (function() {
function createUnifiedDiffTable(files,commitOptions) { function createUnifiedDiffTable(files,commitOptions) {
var diffPanel = $('<div></div>'); var diffPanel = $('<div></div>');
console.log(files);
files.forEach(function(file) { files.forEach(function(file) {
var hunks = file.hunks; var hunks = file.hunks;
var isBinary = file.binary; var isBinary = file.binary;

View File

@ -75,27 +75,21 @@ RED.palette.editor = (function() {
}); });
}) })
} }
function installNodeModule(id,version,shade,callback) { function installNodeModule(id,version,callback) {
var requestBody = { var requestBody = {
module: id module: id
}; };
if (callback === undefined) { if (version) {
callback = shade;
shade = version;
} else {
requestBody.version = version; requestBody.version = version;
} }
shade.show();
$.ajax({ $.ajax({
url:"nodes", url:"nodes",
type: "POST", type: "POST",
data: JSON.stringify(requestBody), data: JSON.stringify(requestBody),
contentType: "application/json; charset=utf-8" contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) { }).done(function(data,textStatus,xhr) {
shade.hide();
callback(); callback();
}).fail(function(xhr,textStatus,err) { }).fail(function(xhr,textStatus,err) {
shade.hide();
callback(xhr); callback(xhr);
}); });
} }
@ -604,24 +598,7 @@ RED.palette.editor = (function() {
if ($(this).hasClass('disabled')) { if ($(this).hasClass('disabled')) {
return; return;
} }
$("#palette-module-install-confirm").data('module',entry.name); update(entry,loadedIndex[entry.name].version,container,function(err){});
$("#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');
}) })
@ -629,16 +606,7 @@ RED.palette.editor = (function() {
removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000)); removeButton.attr('id','up_'+Math.floor(Math.random()*1000000000));
removeButton.click(function(evt) { removeButton.click(function(evt) {
evt.preventDefault(); evt.preventDefault();
remove(entry,container,function(err){});
$("#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');
}) })
if (!entry.local) { if (!entry.local) {
removeButton.hide(); removeButton.hide();
@ -836,22 +804,11 @@ RED.palette.editor = (function() {
$('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow); $('<span class="palette-module-updated"><i class="fa fa-calendar"></i> '+formatUpdatedAt(entry.updated_at)+'</span>').appendTo(metaRow);
var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow); var buttonRow = $('<div>',{class:"palette-module-meta"}).appendTo(headerRow);
var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow); var buttonGroup = $('<div>',{class:"palette-module-button-group"}).appendTo(buttonRow);
var shade = $('<div class="palette-module-shade hide"><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(container);
var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup); var installButton = $('<a href="#" class="editor-button editor-button-small"></a>').html(RED._('palette.editor.install')).appendTo(buttonGroup);
installButton.click(function(e) { installButton.click(function(e) {
e.preventDefault(); e.preventDefault();
if (!$(this).hasClass('disabled')) { if (!$(this).hasClass('disabled')) {
$("#palette-module-install-confirm").data('module',entry.id); install(entry,container,function(xhr) {});
$("#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');
} }
}) })
if (nodeEntries.hasOwnProperty(entry.id)) { if (nodeEntries.hasOwnProperty(entry.id)) {
@ -869,88 +826,126 @@ RED.palette.editor = (function() {
}); });
$('<div id="palette-module-install-shade" class="palette-module-shade hide"><div class="palette-module-shade-status"></div><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(installTab); $('<div id="palette-module-install-shade" class="palette-module-shade hide"><div class="palette-module-shade-status"></div><img src="red/images/spin.svg" class="palette-spinner"/></div>').appendTo(installTab);
}
$('<div id="palette-module-install-confirm" class="hide"><form class="form-horizontal"><div id="palette-module-install-confirm-body" class="node-dialog-confirm-row"></div></form></div>').appendTo(document.body); function update(entry,version,container,done) {
$("#palette-module-install-confirm").dialog({ if (RED.settings.theme('palette.editable') === false) {
title: RED._('palette.editor.confirm.title'), done(new Error('Palette not editable'));
return;
}
var notification = RED.notify(RED._("palette.editor.confirm.update.body",{module:entry.name}),{
modal: true, modal: true,
autoOpen: false, fixed: true,
width: 550,
height: "auto",
buttons: [ buttons: [
{ {
text: RED._("common.label.cancel"), text: RED._("common.label.cancel"),
click: function() { click: function() {
$( this ).dialog( "close" ); notification.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" );
} }
}, },
{ {
text: RED._("palette.editor.confirm.button.update"), text: RED._("palette.editor.confirm.button.update"),
class: "primary palette-module-install-confirm-button-update", class: "primary palette-module-install-confirm-button-update",
click: function() { click: function() {
var id = $(this).data('module'); var spinner = RED.utils.addSpinnerOverlay(container, true);
var version = $(this).data('version'); installNodeModule(entry.name,version,function(xhr) {
var shade = $(this).data('shade'); spinner.remove();
shade.show(); if (xhr) {
installNodeModule(id,version,shade,function(xhr) { if (xhr.responseJSON) {
if (xhr) { RED.notify(RED._('palette.editor.errors.updateFailed',{module: entry.name,message:xhr.responseJSON.message}));
if (xhr.responseJSON) { }
RED.notify(RED._('palette.editor.errors.updateFailed',{module: id,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 { return {
init: init init: init,
install: install
} }
})(); })();

View File

@ -262,14 +262,16 @@ RED.projects.settings = (function() {
var totalCount = 0; var totalCount = 0;
var unknownCount = 0; var unknownCount = 0;
var unusedCount = 0; var unusedCount = 0;
var notInstalledCount = 0;
for (var m in modulesInUse) { for (var m in modulesInUse) {
if (modulesInUse.hasOwnProperty(m)) { if (modulesInUse.hasOwnProperty(m)) {
depsList.editableList('addItem',{ depsList.editableList('addItem',{
module: modulesInUse[m].module, id: modulesInUse[m].module,
version: modulesInUse[m].version, version: modulesInUse[m].version,
count: modulesInUse[m].count, count: modulesInUse[m].count,
known: activeProject.dependencies.hasOwnProperty(m) known: activeProject.dependencies.hasOwnProperty(m),
installed: true
}); });
totalCount++; totalCount++;
if (modulesInUse[m].count === 0) { if (modulesInUse[m].count === 0) {
@ -284,29 +286,69 @@ RED.projects.settings = (function() {
if (activeProject.dependencies) { if (activeProject.dependencies) {
for (var m in activeProject.dependencies) { for (var m in activeProject.dependencies) {
if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) {
var installed = !!RED.nodes.registry.getModule(m);
depsList.editableList('addItem',{ depsList.editableList('addItem',{
module: m, id: m,
version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version, version: activeProject.dependencies[m], //RED.nodes.registry.getModule(module).version,
count: 0, count: 0,
known: true known: true,
installed: installed
}); });
totalCount++; totalCount++;
unusedCount++; if (installed) {
unusedCount++;
} else {
notInstalledCount++;
}
} }
} }
} }
if (unknownCount > 0) { // if (notInstalledCount > 0) {
depsList.editableList('addItem',{index:1, label:"Unlisted dependencies"}); // TODO: nls // depsList.editableList('addItem',{index:1, label:"Missing dependencies"}); // TODO: nls
} // }
if (unusedCount > 0) { // if (unknownCount > 0) {
depsList.editableList('addItem',{index:3, label:"Unused dependencies"}); // TODO: nls // 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) { if (totalCount === 0) {
depsList.editableList('addItem',{index:0, label:"None"}); // TODO: nls 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) { function editDependencies(activeProject,depsJSON,container,depsList) {
var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4); var json = depsJSON||JSON.stringify(activeProject.dependencies||{},"",4);
if (json === "{}") { if (json === "{}") {
@ -319,34 +361,12 @@ RED.projects.settings = (function() {
complete: function(v) { complete: function(v) {
try { try {
var parsed = JSON.parse(v); var parsed = JSON.parse(v);
var spinner = utils.addSpinnerOverlay(container); saveDependencies(depsList,container,parsed,function(err) {
var done = function(err,res) {
if (err) { if (err) {
return editDependencies(activeProject,v,container,depsList); return editDependencies(activeProject,v,container,depsList);
} }
activeProject.dependencies = parsed; activeProject.dependencies = parsed;
updateProjectDependencies(activeProject,depsList); 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) { } catch(err) {
editDependencies(activeProject,v,container,depsList); editDependencies(activeProject,v,container,depsList);
@ -378,59 +398,119 @@ RED.projects.settings = (function() {
row.parent().addClass("palette-module-section"); row.parent().addClass("palette-module-section");
} }
headerRow.text(entry.label); headerRow.text(entry.label);
if (RED.user.hasPermission("projects.write")) { // if (RED.user.hasPermission("projects.write")) {
if (entry.index === 1) { // if (entry.index === 1) {
var addButton = $('<button class="editor-button editor-button-small palette-module-button">add to project</button>').appendTo(headerRow).click(function(evt) { // var addButton = $('<button class="editor-button editor-button-small palette-module-button">add to project</button>').appendTo(headerRow).click(function(evt) {
evt.preventDefault(); // evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies); // var deps = $.extend(true, {}, activeProject.dependencies);
for (var m in modulesInUse) { // for (var m in modulesInUse) {
if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) { // if (modulesInUse.hasOwnProperty(m) && !modulesInUse[m].known) {
deps[m] = modulesInUse[m].version; // deps[m] = modulesInUse[m].version;
} // }
} // }
editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); // editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList);
}); // });
} else if (entry.index === 3) { // } else if (entry.index === 3) {
var removeButton = $('<button class="editor-button editor-button-small palette-module-button">remove from project</button>').appendTo(headerRow).click(function(evt) { // var removeButton = $('<button class="editor-button editor-button-small palette-module-button">remove from project</button>').appendTo(headerRow).click(function(evt) {
evt.preventDefault(); // evt.preventDefault();
var deps = $.extend(true, {}, activeProject.dependencies); // var deps = $.extend(true, {}, activeProject.dependencies);
for (var m in activeProject.dependencies) { // for (var m in activeProject.dependencies) {
if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) { // if (activeProject.dependencies.hasOwnProperty(m) && !modulesInUse.hasOwnProperty(m)) {
delete deps[m]; // delete deps[m];
} // }
} // }
editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList); // editDependencies(activeProject,JSON.stringify(deps,"",4),pane,depsList);
}); // });
} // }
} // }
} else { } else {
headerRow.addClass("palette-module-header"); 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; entry.element = headerRow;
var titleRow = $('<div class="palette-module-meta palette-module-name"></div>').appendTo(headerRow); var titleRow = $('<div class="palette-module-meta palette-module-name"></div>').appendTo(headerRow);
var icon = $('<i class="fa fa-'+(entry.known?'cube':'warning')+'"></i>').appendTo(titleRow); var iconClass = "fa-cube";
if (!entry.installed) {
iconClass = "fa-warning";
}
var icon = $('<i class="fa '+iconClass+'"></i>').appendTo(titleRow);
entry.icon = icon; entry.icon = icon;
$('<span>').html(entry.module).appendTo(titleRow); $('<span>').html(entry.id).appendTo(titleRow);
var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow); var metaRow = $('<div class="palette-module-meta palette-module-version"><i class="fa fa-tag"></i></div>').appendTo(headerRow);
var versionSpan = $('<span>').html(entry.version).appendTo(metaRow); var versionSpan = $('<span>').html(entry.version).appendTo(metaRow);
if (!entry.known) { metaRow = $('<div class="palette-module-meta"></div>').appendTo(headerRow);
headerRow.addClass("palette-module-unknown"); var buttons = $('<div class="palette-module-button-group"></div>').appendTo(metaRow);
} else if (entry.known && entry.count === 0) { if (RED.user.hasPermission("projects.write")) {
if (!entry.installed && RED.settings.theme('palette.editable') !== false) {
$('<a href="#" class="editor-button editor-button-small">install</a>').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) {
$('<a href="#" class="editor-button editor-button-small">remove from project</a>').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) {
$('<a href="#" class="editor-button editor-button-small">add to project</a>').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) { sort: function(A,B) {
if (A.index && B.index) { return A.id.localeCompare(B.id);
return A.index - B.index; // 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); // var Acategory = A.index?A.index:(A.known?(A.count>0?0:4):2);
if (Acategory === Bcategory) { // var Bcategory = B.index?B.index:(B.known?(B.count>0?0:4):2);
return A.module.localeCompare(B.module); // if (Acategory === Bcategory) {
} else { // return A.id.localeCompare(B.id);
return Acategory - Bcategory; // } else {
} // return Acategory - Bcategory;
// }
} }
}); });
@ -1332,8 +1412,30 @@ RED.projects.settings = (function() {
return pane; 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 utils;
var modulesInUse = {}; var modulesInUse = {};
function init(_utils) { function init(_utils) {
@ -1362,22 +1464,7 @@ RED.projects.settings = (function() {
} }
}); });
RED.events.on('nodes:add', function(n) { RED.events.on('nodes:add', _updateModulesInUse);
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:remove', function(n) { RED.events.on('nodes:remove', function(n) {
if (!/^subflow:/.test(n.type)) { if (!/^subflow:/.test(n.type)) {
var module = RED.nodes.registry.getNodeSetForType(n.type).module; var module = RED.nodes.registry.getNodeSetForType(n.type).module;

View File

@ -920,9 +920,9 @@ RED.projects = (function() {
// $('<label>Credentials encryption key</label>').appendTo(row); // $('<label>Credentials encryption key</label>').appendTo(row);
// projectSecretInput = $('<input type="text"></input>').appendTo(row); // projectSecretInput = $('<input type="text"></input>').appendTo(row);
switch(options.screen||"empty") { switch(options.screen||"empty") {
case "empty": console.log("createasempty"); createAsEmpty.click(); break; case "empty": createAsEmpty.click(); break;
case "open": console.log("opening"); openProject.click(); break; case "open": openProject.click(); break;
case "clone": console.log("cloning"); createAsClone.click(); break; case "clone": createAsClone.click(); break;
} }
setTimeout(function() { setTimeout(function() {
@ -1096,12 +1096,7 @@ RED.projects = (function() {
done(null,data); done(null,data);
}, },
400: { 400: {
'credentials_load_failed': function(error) { '*': done
done(error,null);
},
'unexpected_error': function(error) {
done(error,null);
}
}, },
} }
},{active:true}).then(function() { },{active:true}).then(function() {
@ -1538,6 +1533,10 @@ RED.projects = (function() {
resultCallback = responses[xhr.responseJSON.error]; resultCallback = responses[xhr.responseJSON.error];
resultCallbackArgs = xhr.responseJSON; resultCallbackArgs = xhr.responseJSON;
return; return;
} else if (responses['*']) {
resultCallback = responses['*'];
resultCallbackArgs = xhr.responseJSON;
return;
} }
} }
console.log("Unhandled error response:"); console.log("Unhandled error response:");
@ -1816,6 +1815,9 @@ RED.projects = (function() {
} }
RED.projects.settings.show('settings'); RED.projects.settings.show('settings');
}, },
showProjectDependencies: function() {
RED.projects.settings.show('deps');
},
createDefaultFileSet: createDefaultFileSet, createDefaultFileSet: createDefaultFileSet,
// showSidebar: showSidebar, // showSidebar: showSidebar,
refresh: refresh, refresh: refresh,

View File

@ -765,6 +765,14 @@ RED.utils = (function() {
return RED.text.bidi.enforceTextDirectionWithUCC(l); return RED.text.bidi.enforceTextDirectionWithUCC(l);
} }
function addSpinnerOverlay(container,contain) {
var spinner = $('<div class="projects-dialog-spinner "><img src="red/images/spin.svg"/></div>').appendTo(container);
if (contain) {
spinner.addClass('projects-dialog-spinner-contain');
}
return spinner;
}
return { return {
createObjectElement: buildMessageElement, createObjectElement: buildMessageElement,
getMessageProperty: getMessageProperty, getMessageProperty: getMessageProperty,
@ -774,5 +782,6 @@ RED.utils = (function() {
getDefaultNodeIcon: getDefaultNodeIcon, getDefaultNodeIcon: getDefaultNodeIcon,
getNodeIcon: getNodeIcon, getNodeIcon: getNodeIcon,
getNodeLabel: getNodeLabel, getNodeLabel: getNodeLabel,
addSpinnerOverlay: addSpinnerOverlay
} }
})(); })();

View File

@ -76,22 +76,6 @@
border-bottom: 1px solid $primary-border-color; border-bottom: 1px solid $primary-border-color;
text-align: right; 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 { .palette-module-shade-status {
color: #666; color: #666;
} }
@ -230,3 +214,19 @@
color: #666; 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;
}

View File

@ -313,7 +313,12 @@
// border: 1px dashed #bbb; // border: 1px dashed #bbb;
} }
.palette-module-unknown { .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 { i.fa-warning {
color: #b07575; //#b72828; color: #b07575; //#b72828;
} }

View File

@ -344,24 +344,24 @@
"sortRecent": "recent", "sortRecent": "recent",
"more": "+ __count__ more", "more": "+ __count__ more",
"errors": { "errors": {
"catalogLoadFailed": "Failed to load node catalogue.<br>Check the browser console for more information", "catalogLoadFailed": "<p>Failed to load node catalogue.</p><p>Check the browser console for more information</p>",
"installFailed": "Failed to install: __module__<br>__message__<br>Check the log for more information", "installFailed": "<p>Failed to install: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"removeFailed": "Failed to remove: __module__<br>__message__<br>Check the log for more information", "removeFailed": "<p>Failed to remove: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"updateFailed": "Failed to update: __module__<br>__message__<br>Check the log for more information", "updateFailed": "<p>Failed to update: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"enableFailed": "Failed to enable: __module__<br>__message__<br>Check the log for more information", "enableFailed": "<p>Failed to enable: __module__</p><p>__message__</p><p>Check the log for more information</p>",
"disableFailed": "Failed to disable: __module__<br>__message__<br>Check the log for more information" "disableFailed": "<p>Failed to disable: __module__</p><p>__message__</p><p>Check the log for more information</p>"
}, },
"confirm": { "confirm": {
"install": { "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":"<p>Installing '__module__'</p><p>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.</p>",
"title": "Install nodes" "title": "Install nodes"
}, },
"remove": { "remove": {
"body":"Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.", "body":"<p>Removing '__module__'</p><p>Removing the node will uninstall it from Node-RED. The node may continue to use resources until Node-RED is restarted.</p>",
"title": "Remove nodes" "title": "Remove nodes"
}, },
"update": { "update": {
"body":"Updating the node will require a restart of Node-RED to complete the update. This must be done manually.", "body":"<p>Updating '__module__'</p><p>Updating the node will require a restart of Node-RED to complete the update. This must be done manually.</p>",
"title": "Update nodes" "title": "Update nodes"
}, },
"cannotUpdate": { "cannotUpdate": {

View File

@ -99,7 +99,10 @@ function installModule(module,version) {
} }
var installDir = settings.userDir || process.env.NODE_RED_HOME || "."; 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 cwd: installDir
}, },
@ -186,7 +189,11 @@ function uninstallModule(module) {
var list = registry.removeModule(module); var list = registry.removeModule(module);
log.info(log._("server.install.uninstalling",{name: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 cwd: installDir
}, },