mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge 44e00b415e0d9c66abb30b6f7f3857bca215a869 into a7d59a2b7fb619dc510b6d09bb914bc953e2342d
This commit is contained in:
commit
a50bc2ad0f
@ -265,7 +265,7 @@
|
|||||||
"download": "Download",
|
"download": "Download",
|
||||||
"importUnrecognised": "Imported unrecognised type:",
|
"importUnrecognised": "Imported unrecognised type:",
|
||||||
"importUnrecognised_plural": "Imported unrecognised types:",
|
"importUnrecognised_plural": "Imported unrecognised types:",
|
||||||
"importWithModuleInfo": "Required dependencies missing",
|
"importWithModuleInfo": "Required modules missing",
|
||||||
"importWithModuleInfoDesc": "These nodes are not currently installed in your palette and are required for the imported flow:",
|
"importWithModuleInfoDesc": "These nodes are not currently installed in your palette and are required for the imported flow:",
|
||||||
"importDuplicate": "Imported duplicate node:",
|
"importDuplicate": "Imported duplicate node:",
|
||||||
"importDuplicate_plural": "Imported duplicate nodes:",
|
"importDuplicate_plural": "Imported duplicate nodes:",
|
||||||
@ -616,6 +616,7 @@
|
|||||||
"yearsMonthsV": "__y__ years, __count__ month ago",
|
"yearsMonthsV": "__y__ years, __count__ month ago",
|
||||||
"yearsMonthsV_plural": "__y__ years, __count__ months ago"
|
"yearsMonthsV_plural": "__y__ years, __count__ months ago"
|
||||||
},
|
},
|
||||||
|
"manageModules": "Manage modules",
|
||||||
"nodeCount": "__label__ node",
|
"nodeCount": "__label__ node",
|
||||||
"nodeCount_plural": "__label__ nodes",
|
"nodeCount_plural": "__label__ nodes",
|
||||||
"pluginCount": "__count__ plugin",
|
"pluginCount": "__count__ plugin",
|
||||||
@ -631,7 +632,9 @@
|
|||||||
"update": "update to __version__",
|
"update": "update to __version__",
|
||||||
"updated": "updated",
|
"updated": "updated",
|
||||||
"install": "install",
|
"install": "install",
|
||||||
|
"installAll": "Install all",
|
||||||
"installed": "installed",
|
"installed": "installed",
|
||||||
|
"installing": "Module installation in progress: __module__",
|
||||||
"conflict": "conflict",
|
"conflict": "conflict",
|
||||||
"conflictTip": "<p>This module cannot be installed as it includes a<br/>node type that has already been installed</p><p>Conflicts with <code>__module__</code></p>",
|
"conflictTip": "<p>This module cannot be installed as it includes a<br/>node type that has already been installed</p><p>Conflicts with <code>__module__</code></p>",
|
||||||
"loading": "Loading catalogues...",
|
"loading": "Loading catalogues...",
|
||||||
@ -641,6 +644,7 @@
|
|||||||
"sortRelevance": "relevance",
|
"sortRelevance": "relevance",
|
||||||
"sortAZ": "a-z",
|
"sortAZ": "a-z",
|
||||||
"sortRecent": "recent",
|
"sortRecent": "recent",
|
||||||
|
"successfulInstall": "Successfully installed modules",
|
||||||
"more": "+ __count__ more",
|
"more": "+ __count__ more",
|
||||||
"upload": "Upload module tgz file",
|
"upload": "Upload module tgz file",
|
||||||
"refresh": "Refresh module list",
|
"refresh": "Refresh module list",
|
||||||
|
@ -1473,7 +1473,14 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Converts the current node selection to an exportable JSON Object
|
* Converts the current node selection to an exportable JSON Object
|
||||||
**/
|
* @param {Array<Node>} set the node selection to export
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Record<string, boolean>} [options.exportedIds]
|
||||||
|
* @param {Record<string, boolean>} [options.exportedSubflows]
|
||||||
|
* @param {Record<string, boolean>} [options.exportedConfigNodes]
|
||||||
|
* @param {boolean} [options.includeModuleConfig]
|
||||||
|
* @returns {Array<Node>}
|
||||||
|
*/
|
||||||
function createExportableNodeSet(set, {
|
function createExportableNodeSet(set, {
|
||||||
exportedIds,
|
exportedIds,
|
||||||
exportedSubflows,
|
exportedSubflows,
|
||||||
@ -1561,10 +1568,14 @@ RED.nodes = (function() {
|
|||||||
return nns;
|
return nns;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the Flow JSON for the current configuration
|
/**
|
||||||
// opts.credentials (whether to include (known) credentials) - default: true
|
* Converts the current configuration to an exportable JSON Object
|
||||||
// opts.dimensions (whether to include node dimensions) - default: false
|
* @param {object} opts
|
||||||
// opts.includeModuleConfig (whether to include modules) - default: false
|
* @param {boolean} [opts.credentials] whether to include (known) credentials. Default `true`.
|
||||||
|
* @param {boolean} [opts.dimensions] whether to include node dimensions. Default `false`.
|
||||||
|
* @param {boolean} [opts.includeModuleConfig] whether to include modules. Default `false`.
|
||||||
|
* @returns {Array<Node>}
|
||||||
|
*/
|
||||||
function createCompleteNodeSet(opts) {
|
function createCompleteNodeSet(opts) {
|
||||||
var nns = [];
|
var nns = [];
|
||||||
var i;
|
var i;
|
||||||
@ -1963,7 +1974,7 @@ RED.nodes = (function() {
|
|||||||
// Provide option to install missing modules
|
// Provide option to install missing modules
|
||||||
notificationOptions.buttons = [
|
notificationOptions.buttons = [
|
||||||
{
|
{
|
||||||
text: "Manage dependencies",
|
text: RED._("palette.editor.manageModules"),
|
||||||
class: "primary",
|
class: "primary",
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
unknownNotification.close();
|
unknownNotification.close();
|
||||||
@ -1971,7 +1982,19 @@ RED.nodes = (function() {
|
|||||||
RED.actions.invoke('core:manage-palette', {
|
RED.actions.invoke('core:manage-palette', {
|
||||||
view: 'install',
|
view: 'install',
|
||||||
filter: '"' + Object.keys(options.modules).join('", "') + '"'
|
filter: '"' + Object.keys(options.modules).join('", "') + '"'
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: RED._("palette.editor.installAll"),
|
||||||
|
class: "pull-left",
|
||||||
|
click: function(e) {
|
||||||
|
unknownNotification.close();
|
||||||
|
|
||||||
|
RED.actions.invoke('core:manage-palette', {
|
||||||
|
autoInstall: true,
|
||||||
|
modules: options.modules
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -2993,21 +3016,33 @@ RED.nodes = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the module list for the given nodes
|
||||||
|
* @param {Array<Node>} nodes the nodes to search in
|
||||||
|
* @returns {Record<string, string>} an object with {[moduleName]: moduleVersion}
|
||||||
|
*/
|
||||||
function getModuleListForNodes(nodes) {
|
function getModuleListForNodes(nodes) {
|
||||||
const modules = {}
|
const modules = {}
|
||||||
nodes.forEach(n => {
|
const typeSet = new Set()
|
||||||
|
nodes.forEach((n) => {
|
||||||
|
if (!typeSet.has(n.type)) {
|
||||||
|
typeSet.add(n.type)
|
||||||
const nodeSet = RED.nodes.registry.getNodeSetForType(n.type)
|
const nodeSet = RED.nodes.registry.getNodeSetForType(n.type)
|
||||||
if (nodeSet) {
|
if (nodeSet) {
|
||||||
modules[nodeSet.module] = nodeSet.version
|
modules[nodeSet.module] = nodeSet.version
|
||||||
|
nodeSet.types.forEach((t) => typeSet.add(t))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return modules
|
return modules
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateGlobalConfigModuleList(nodes) {
|
function updateGlobalConfigModuleList(nodes) {
|
||||||
const modules = getModuleListForNodes(nodes)
|
const modules = getModuleListForNodes(nodes)
|
||||||
delete modules['node-red']
|
delete modules['node-red']
|
||||||
const hasModules = (Object.keys(modules).length > 0)
|
const hasModules = (Object.keys(modules).length > 0)
|
||||||
let globalConfigNode = nodes.find(n => n.type === 'global-config')
|
let globalConfigNode = nodes.find((n) => n.type === 'global-config')
|
||||||
if (!globalConfigNode && hasModules) {
|
if (!globalConfigNode && hasModules) {
|
||||||
globalConfigNode = {
|
globalConfigNode = {
|
||||||
id: RED.nodes.id(),
|
id: RED.nodes.id(),
|
||||||
@ -3016,7 +3051,7 @@ RED.nodes = (function() {
|
|||||||
modules
|
modules
|
||||||
}
|
}
|
||||||
nodes.push(globalConfigNode)
|
nodes.push(globalConfigNode)
|
||||||
} else if (globalConfigNode) {
|
} else if (hasModules) {
|
||||||
globalConfigNode.modules = modules
|
globalConfigNode.modules = modules
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -626,6 +626,9 @@ RED.palette.editor = (function() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
RED.actions.add("core:manage-palette", function(opts) {
|
RED.actions.add("core:manage-palette", function(opts) {
|
||||||
|
if (opts && opts.autoInstall && opts.modules) {
|
||||||
|
autoInstallModules(opts.modules);
|
||||||
|
} else {
|
||||||
RED.userSettings.show('palette');
|
RED.userSettings.show('palette');
|
||||||
if (opts) {
|
if (opts) {
|
||||||
if (opts.view) {
|
if (opts.view) {
|
||||||
@ -639,6 +642,7 @@ RED.palette.editor = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
RED.events.on('registry:module-updated', function(ns) {
|
RED.events.on('registry:module-updated', function(ns) {
|
||||||
@ -1501,6 +1505,77 @@ RED.palette.editor = (function() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function autoInstallModules(modules) {
|
||||||
|
if (RED.settings.get('externalModules.palette.allowInstall', true) === false) {
|
||||||
|
console.error(new Error('Palette not editable'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let notification;
|
||||||
|
const notificationOptions = {
|
||||||
|
fixed: true,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: RED._("common.label.close"),
|
||||||
|
click: function () {
|
||||||
|
notification.close();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
text: RED._("eventLog.view"),
|
||||||
|
click: function () {
|
||||||
|
notification.close();
|
||||||
|
RED.actions.invoke("core:show-event-log");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const moduleArray = Object.entries(modules);
|
||||||
|
const installModule = function (module) {
|
||||||
|
const [moduleName, moduleVersion] = module;
|
||||||
|
|
||||||
|
const spinner = '<div style="text-align: center; height: 100%; padding-top: 20px;"><img src="red/images/spin.svg" style="width: 60px;"/></div>';
|
||||||
|
const msg = "<p>" + RED._("palette.editor.installing", { module: moduleName }) + "</p>" + spinner;
|
||||||
|
|
||||||
|
if (!notification) {
|
||||||
|
notification = RED.notify(msg, notificationOptions);
|
||||||
|
} else {
|
||||||
|
notification.update(msg, notificationOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
RED.eventLog.startEvent(RED._("palette.editor.confirm.button.install") + " : " + moduleName + " " + moduleVersion);
|
||||||
|
|
||||||
|
installNodeModule(moduleName, moduleVersion, undefined, function(xhr, textStatus, err) {
|
||||||
|
if (err && xhr.status === 504) {
|
||||||
|
notification.update(RED._("palette.editor.errors.installTimeout"), {
|
||||||
|
modal: true,
|
||||||
|
fixed: true,
|
||||||
|
buttons: notificationOptions.buttons
|
||||||
|
});
|
||||||
|
} else if (xhr) {
|
||||||
|
if (xhr.responseJSON) {
|
||||||
|
notification.update(RED._("palette.editor.errors.installFailed", { module: moduleName, message:xhr.responseJSON.message }), {
|
||||||
|
type: "error",
|
||||||
|
modal: true,
|
||||||
|
fixed: true,
|
||||||
|
buttons: notificationOptions.buttons
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (moduleArray.length) {
|
||||||
|
installModule(moduleArray.shift());
|
||||||
|
} else {
|
||||||
|
notification.update(RED._("palette.editor.successfulInstall"), { ...notificationOptions, type: "success", timeout: 10000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (moduleArray.length) {
|
||||||
|
installModule(moduleArray.shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
init: init,
|
init: init,
|
||||||
install: install
|
install: install
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="form-tips">
|
<div class="form-tips">
|
||||||
<span data-i18n="[html]unknown.tip"></span>
|
<span data-i18n="[html]unknown.tip"></span>
|
||||||
<p id="unknown-module-known">
|
<p id="unknown-module-known">
|
||||||
<button id="unknown-manage-dependencies" class="red-ui-button">Manage dependencies</button>
|
<button id="unknown-manage-dependencies" class="red-ui-button"><span data-i18n="unknown.manageModules"></span></button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -406,7 +406,8 @@
|
|||||||
"label": {
|
"label": {
|
||||||
"unknown": "unknown"
|
"unknown": "unknown"
|
||||||
},
|
},
|
||||||
"tip": "<p>This node is a type unknown to your installation of Node-RED.</p><p><i>If you deploy with the node in this state, it's configuration will be preserved, but the flow will not start until the missing type is installed.</i></p><p>See the Info side bar for more help</p>"
|
"manageModules": "Manage modules",
|
||||||
|
"tip": "<p>This node is a type unknown to your installation of Node-RED.</p><p><i>If you deploy with the node in this state, it's configuration will be preserved, but the flow will not start until the missing type is installed.</i></p><p>See the Info side bar for more help</p><p>You can also click the button below to open the palette and install the missing modules.</p>"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"label": {
|
"label": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user