mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge branch 'dev' into button-add-config-node
This commit is contained in:
@@ -590,6 +590,8 @@
|
||||
},
|
||||
"nodeCount": "__label__ Node",
|
||||
"nodeCount_plural": "__label__ Nodes",
|
||||
"pluginCount": "__count__ Plugin",
|
||||
"pluginCount_plural": "__count__ Plugins",
|
||||
"moduleCount": "__count__ Modul verfügbar",
|
||||
"moduleCount_plural": "__count__ Module verfügbar",
|
||||
"inuse": "In Gebrauch",
|
||||
|
@@ -614,6 +614,8 @@
|
||||
},
|
||||
"nodeCount": "__label__ node",
|
||||
"nodeCount_plural": "__label__ nodes",
|
||||
"pluginCount": "__count__ plugin",
|
||||
"pluginCount_plural": "__count__ plugins",
|
||||
"moduleCount": "__count__ module available",
|
||||
"moduleCount_plural": "__count__ modules available",
|
||||
"inuse": "in use",
|
||||
|
@@ -924,7 +924,14 @@
|
||||
"date": "horodatage",
|
||||
"jsonata": "expression",
|
||||
"env": "variable d'environnement",
|
||||
"cred": "identifiant"
|
||||
"cred": "identifiant",
|
||||
"conf-types": "noeud de configuration"
|
||||
},
|
||||
"date": {
|
||||
"format": {
|
||||
"timestamp": "millisecondes depuis l'époque",
|
||||
"object": "Objet de date JavaScript"
|
||||
}
|
||||
}
|
||||
},
|
||||
"editableList": {
|
||||
|
@@ -26,6 +26,15 @@ RED.comms = (function() {
|
||||
var reconnectAttempts = 0;
|
||||
var active = false;
|
||||
|
||||
RED.events.on('login', function(username) {
|
||||
// User has logged in
|
||||
// Need to upgrade the connection to be authenticated
|
||||
if (ws && ws.readyState == 1) {
|
||||
const auth_tokens = RED.settings.get("auth-tokens");
|
||||
ws.send(JSON.stringify({auth:auth_tokens.access_token}))
|
||||
}
|
||||
})
|
||||
|
||||
function connectWS() {
|
||||
active = true;
|
||||
var wspath;
|
||||
@@ -56,6 +65,7 @@ RED.comms = (function() {
|
||||
ws.send(JSON.stringify({subscribe:t}));
|
||||
}
|
||||
}
|
||||
emit('connect')
|
||||
}
|
||||
|
||||
ws = new WebSocket(wspath);
|
||||
@@ -180,9 +190,53 @@ RED.comms = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function send(topic, msg) {
|
||||
if (ws && ws.readyState == 1) {
|
||||
ws.send(JSON.stringify({
|
||||
topic,
|
||||
data: msg
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const eventHandlers = {};
|
||||
function on(evt,func) {
|
||||
eventHandlers[evt] = eventHandlers[evt]||[];
|
||||
eventHandlers[evt].push(func);
|
||||
}
|
||||
function off(evt,func) {
|
||||
const handler = eventHandlers[evt];
|
||||
if (handler) {
|
||||
for (let i=0;i<handler.length;i++) {
|
||||
if (handler[i] === func) {
|
||||
handler.splice(i,1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function emit() {
|
||||
const evt = arguments[0]
|
||||
const args = Array.prototype.slice.call(arguments,1);
|
||||
if (eventHandlers[evt]) {
|
||||
let cpyHandlers = [...eventHandlers[evt]];
|
||||
for (let i=0;i<cpyHandlers.length;i++) {
|
||||
try {
|
||||
cpyHandlers[i].apply(null, args);
|
||||
} catch(err) {
|
||||
console.warn("RED.comms.emit error: ["+evt+"] "+(err.toString()));
|
||||
console.warn(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
connect: connectWS,
|
||||
subscribe: subscribe,
|
||||
unsubscribe:unsubscribe
|
||||
unsubscribe:unsubscribe,
|
||||
on,
|
||||
off,
|
||||
send
|
||||
}
|
||||
})();
|
||||
|
@@ -149,6 +149,8 @@ RED.nodes = (function() {
|
||||
},
|
||||
removeNodeSet: function(id) {
|
||||
var ns = nodeSets[id];
|
||||
if (!ns) { return {} }
|
||||
|
||||
for (var j=0;j<ns.types.length;j++) {
|
||||
delete typeToId[ns.types[j]];
|
||||
}
|
||||
@@ -572,12 +574,16 @@ RED.nodes = (function() {
|
||||
* @param {String} z tab id
|
||||
*/
|
||||
checkTabState: function (z) {
|
||||
const ws = workspaces[z]
|
||||
const ws = workspaces[z] || subflows[z]
|
||||
if (ws) {
|
||||
const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0
|
||||
if (Boolean(ws.contentsChanged) !== contentsChanged) {
|
||||
ws.contentsChanged = contentsChanged
|
||||
RED.events.emit("flows:change", ws);
|
||||
if (ws.type === 'tab') {
|
||||
RED.events.emit("flows:change", ws);
|
||||
} else {
|
||||
RED.events.emit("subflows:change", ws);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1050,7 +1056,22 @@ RED.nodes = (function() {
|
||||
RED.nodes.registerType("subflow:"+sf.id, {
|
||||
defaults:{
|
||||
name:{value:""},
|
||||
env:{value:[]}
|
||||
env:{value:[], validate: function(value) {
|
||||
const errors = []
|
||||
if (value) {
|
||||
value.forEach(env => {
|
||||
const r = RED.utils.validateTypedProperty(env.value, env.type)
|
||||
if (r !== true) {
|
||||
errors.push(env.name+': '+r)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (errors.length === 0) {
|
||||
return true
|
||||
} else {
|
||||
return errors
|
||||
}
|
||||
}}
|
||||
},
|
||||
icon: function() { return sf.icon||"subflow.svg" },
|
||||
category: sf.category || "subflows",
|
||||
|
@@ -1,6 +1,7 @@
|
||||
RED.plugins = (function() {
|
||||
var plugins = {};
|
||||
var pluginsByType = {};
|
||||
var moduleList = {};
|
||||
|
||||
function registerPlugin(id,definition) {
|
||||
plugins[id] = definition;
|
||||
@@ -38,9 +39,43 @@ RED.plugins = (function() {
|
||||
function getPluginsByType(type) {
|
||||
return pluginsByType[type] || [];
|
||||
}
|
||||
|
||||
function setPluginList(list) {
|
||||
for(let i=0;i<list.length;i++) {
|
||||
let p = list[i];
|
||||
addPlugin(p);
|
||||
}
|
||||
}
|
||||
|
||||
function addPlugin(p) {
|
||||
|
||||
moduleList[p.module] = moduleList[p.module] || {
|
||||
name:p.module,
|
||||
version:p.version,
|
||||
local:p.local,
|
||||
sets:{},
|
||||
plugin: true,
|
||||
id: p.id
|
||||
};
|
||||
if (p.pending_version) {
|
||||
moduleList[p.module].pending_version = p.pending_version;
|
||||
}
|
||||
moduleList[p.module].sets[p.name] = p;
|
||||
|
||||
RED.events.emit("registry:plugin-module-added",p.module);
|
||||
}
|
||||
|
||||
function getModule(module) {
|
||||
return moduleList[module];
|
||||
}
|
||||
|
||||
return {
|
||||
registerPlugin: registerPlugin,
|
||||
getPlugin: getPlugin,
|
||||
getPluginsByType: getPluginsByType
|
||||
getPluginsByType: getPluginsByType,
|
||||
|
||||
setPluginList: setPluginList,
|
||||
addPlugin: addPlugin,
|
||||
getModule: getModule
|
||||
}
|
||||
})();
|
||||
|
@@ -25,6 +25,7 @@ var RED = (function() {
|
||||
cache: false,
|
||||
url: 'plugins',
|
||||
success: function(data) {
|
||||
RED.plugins.setPluginList(data);
|
||||
loader.reportProgress(RED._("event.loadPlugins"), 13)
|
||||
RED.i18n.loadPluginCatalogs(function() {
|
||||
loadPlugins(function() {
|
||||
@@ -534,6 +535,41 @@ var RED = (function() {
|
||||
RED.view.redrawStatus(node);
|
||||
}
|
||||
});
|
||||
RED.comms.subscribe("notification/plugin/#",function(topic,msg) {
|
||||
if (topic == "notification/plugin/added") {
|
||||
RED.settings.refreshSettings(function(err, data) {
|
||||
let addedPlugins = [];
|
||||
msg.forEach(function(m) {
|
||||
let id = m.id;
|
||||
RED.plugins.addPlugin(m);
|
||||
|
||||
m.plugins.forEach((p) => {
|
||||
addedPlugins.push(p.id);
|
||||
})
|
||||
|
||||
RED.i18n.loadNodeCatalog(id, function() {
|
||||
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
|
||||
$.ajax({
|
||||
headers: {
|
||||
"Accept":"text/html",
|
||||
"Accept-Language": lang
|
||||
},
|
||||
cache: false,
|
||||
url: 'plugins/'+id,
|
||||
success: function(data) {
|
||||
appendPluginConfig(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
if (addedPlugins.length) {
|
||||
let pluginList = "<ul><li>"+addedPlugins.map(RED.utils.sanitize).join("</li><li>")+"</li></ul>";
|
||||
// ToDo: Adapt notification (node -> plugin)
|
||||
RED.notify(RED._("palette.event.nodeAdded", {count:addedPlugins.length})+pluginList,"success");
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
let pendingNodeRemovedNotifications = []
|
||||
let pendingNodeRemovedTimeout
|
||||
|
@@ -118,10 +118,16 @@ RED.contextMenu = (function () {
|
||||
onselect: 'core:split-wire-with-link-nodes',
|
||||
disabled: !canEdit || !hasLinks
|
||||
},
|
||||
null,
|
||||
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
|
||||
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
|
||||
null
|
||||
)
|
||||
if (RED.settings.theme("menu.menu-item-import-library", true)) {
|
||||
insertOptions.push(
|
||||
{ onselect: 'core:show-import-dialog', label: RED._('common.label.import')},
|
||||
{ onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if (hasSelection && canEdit) {
|
||||
const nodeOptions = []
|
||||
if (!hasMultipleSelection && !isGroup) {
|
||||
@@ -194,8 +200,14 @@ RED.contextMenu = (function () {
|
||||
{ onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() },
|
||||
{ onselect: 'core:delete-selection', label: RED._('keyboard.deleteSelected'), disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete },
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") },
|
||||
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") },
|
||||
)
|
||||
if (RED.settings.theme("menu.menu-item-export-library", true)) {
|
||||
menuItems.push(
|
||||
{ onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }
|
||||
)
|
||||
}
|
||||
menuItems.push(
|
||||
{ onselect: 'core:select-all-nodes', label: RED._("keyboard.selectAll") }
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -153,10 +153,6 @@ RED.envVar = (function() {
|
||||
}
|
||||
|
||||
function init(done) {
|
||||
if (!RED.user.hasPermission("settings.write")) {
|
||||
RED.notify(RED._("user.errors.settings"),"error");
|
||||
return;
|
||||
}
|
||||
RED.userSettings.add({
|
||||
id:'envvar',
|
||||
title: RED._("env-var.environment"),
|
||||
|
@@ -248,86 +248,106 @@ RED.palette.editor = (function() {
|
||||
var moduleInfo = nodeEntries[module].info;
|
||||
var nodeEntry = nodeEntries[module].elements;
|
||||
if (nodeEntry) {
|
||||
var activeTypeCount = 0;
|
||||
var typeCount = 0;
|
||||
var errorCount = 0;
|
||||
nodeEntry.errorList.empty();
|
||||
nodeEntries[module].totalUseCount = 0;
|
||||
nodeEntries[module].setUseCount = {};
|
||||
if (moduleInfo.plugin) {
|
||||
nodeEntry.enableButton.hide();
|
||||
nodeEntry.removeButton.show();
|
||||
|
||||
for (var setName in moduleInfo.sets) {
|
||||
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
||||
var inUseCount = 0;
|
||||
var set = moduleInfo.sets[setName];
|
||||
var setElements = nodeEntry.sets[setName];
|
||||
if (set.err) {
|
||||
errorCount++;
|
||||
var errMessage = set.err;
|
||||
if (set.err.message) {
|
||||
errMessage = set.err.message;
|
||||
} else if (set.err.code) {
|
||||
errMessage = set.err.code;
|
||||
let pluginCount = 0;
|
||||
for (let setName in moduleInfo.sets) {
|
||||
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
||||
let set = moduleInfo.sets[setName];
|
||||
if (set.plugins) {
|
||||
pluginCount += set.plugins.length;
|
||||
}
|
||||
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
|
||||
}
|
||||
if (set.enabled) {
|
||||
activeTypeCount += set.types.length;
|
||||
}
|
||||
typeCount += set.types.length;
|
||||
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
|
||||
var t = moduleInfo.sets[setName].types[i];
|
||||
inUseCount += (typesInUse[t]||0);
|
||||
var swatch = setElements.swatches[t];
|
||||
}
|
||||
|
||||
nodeEntry.setCount.text(RED._('palette.editor.pluginCount',{count:pluginCount,label:pluginCount}));
|
||||
|
||||
} else {
|
||||
var activeTypeCount = 0;
|
||||
var typeCount = 0;
|
||||
var errorCount = 0;
|
||||
nodeEntry.errorList.empty();
|
||||
nodeEntries[module].totalUseCount = 0;
|
||||
nodeEntries[module].setUseCount = {};
|
||||
|
||||
for (var setName in moduleInfo.sets) {
|
||||
if (moduleInfo.sets.hasOwnProperty(setName)) {
|
||||
var inUseCount = 0;
|
||||
const set = moduleInfo.sets[setName];
|
||||
const setElements = nodeEntry.sets[setName]
|
||||
|
||||
if (set.err) {
|
||||
errorCount++;
|
||||
var errMessage = set.err;
|
||||
if (set.err.message) {
|
||||
errMessage = set.err.message;
|
||||
} else if (set.err.code) {
|
||||
errMessage = set.err.code;
|
||||
}
|
||||
$("<li>").text(errMessage).appendTo(nodeEntry.errorList);
|
||||
}
|
||||
if (set.enabled) {
|
||||
var def = RED.nodes.getType(t);
|
||||
if (def && def.color) {
|
||||
swatch.css({background:RED.utils.getNodeColor(t,def)});
|
||||
swatch.css({border: "1px solid "+getContrastingBorder(swatch.css('backgroundColor'))})
|
||||
activeTypeCount += set.types.length;
|
||||
}
|
||||
typeCount += set.types.length;
|
||||
for (var i=0;i<moduleInfo.sets[setName].types.length;i++) {
|
||||
var t = moduleInfo.sets[setName].types[i];
|
||||
inUseCount += (typesInUse[t]||0);
|
||||
if (setElements && set.enabled) {
|
||||
var def = RED.nodes.getType(t);
|
||||
if (def && def.color) {
|
||||
setElements.swatches[t].css({background:RED.utils.getNodeColor(t,def)});
|
||||
setElements.swatches[t].css({border: "1px solid "+getContrastingBorder(setElements.swatches[t].css('backgroundColor'))})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeEntries[module].setUseCount[setName] = inUseCount;
|
||||
nodeEntries[module].totalUseCount += inUseCount;
|
||||
nodeEntries[module].setUseCount[setName] = inUseCount;
|
||||
nodeEntries[module].totalUseCount += inUseCount;
|
||||
|
||||
if (inUseCount > 0) {
|
||||
setElements.enableButton.text(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.addClass('disabled');
|
||||
} else {
|
||||
setElements.enableButton.removeClass('disabled');
|
||||
if (set.enabled) {
|
||||
setElements.enableButton.text(RED._('palette.editor.disable'));
|
||||
} else {
|
||||
setElements.enableButton.text(RED._('palette.editor.enable'));
|
||||
if (setElements) {
|
||||
if (inUseCount > 0) {
|
||||
setElements.enableButton.text(RED._('palette.editor.inuse'));
|
||||
setElements.enableButton.addClass('disabled');
|
||||
} else {
|
||||
setElements.enableButton.removeClass('disabled');
|
||||
if (set.enabled) {
|
||||
setElements.enableButton.text(RED._('palette.editor.disable'));
|
||||
} else {
|
||||
setElements.enableButton.text(RED._('palette.editor.enable'));
|
||||
}
|
||||
}
|
||||
setElements.setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
||||
}
|
||||
}
|
||||
setElements.setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount === 0) {
|
||||
nodeEntry.errorRow.hide()
|
||||
} else {
|
||||
nodeEntry.errorRow.show();
|
||||
}
|
||||
|
||||
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
||||
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
|
||||
if (nodeEntries[module].totalUseCount > 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.addClass('disabled');
|
||||
nodeEntry.removeButton.hide();
|
||||
} else {
|
||||
nodeEntry.enableButton.removeClass('disabled');
|
||||
if (moduleInfo.local) {
|
||||
nodeEntry.removeButton.css('display', 'inline-block');
|
||||
}
|
||||
if (activeTypeCount === 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
||||
if (errorCount === 0) {
|
||||
nodeEntry.errorRow.hide()
|
||||
} else {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
|
||||
nodeEntry.errorRow.show();
|
||||
}
|
||||
|
||||
var nodeCount = (activeTypeCount === typeCount)?typeCount:activeTypeCount+" / "+typeCount;
|
||||
nodeEntry.setCount.text(RED._('palette.editor.nodeCount',{count:typeCount,label:nodeCount}));
|
||||
|
||||
if (nodeEntries[module].totalUseCount > 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.inuse'));
|
||||
nodeEntry.enableButton.addClass('disabled');
|
||||
nodeEntry.removeButton.hide();
|
||||
} else {
|
||||
nodeEntry.enableButton.removeClass('disabled');
|
||||
if (moduleInfo.local) {
|
||||
nodeEntry.removeButton.css('display', 'inline-block');
|
||||
}
|
||||
if (activeTypeCount === 0) {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.enableall'));
|
||||
} else {
|
||||
nodeEntry.enableButton.text(RED._('palette.editor.disableall'));
|
||||
}
|
||||
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
||||
}
|
||||
nodeEntry.container.toggleClass("disabled",(activeTypeCount === 0));
|
||||
}
|
||||
}
|
||||
if (moduleInfo.pending_version) {
|
||||
@@ -678,6 +698,33 @@ RED.palette.editor = (function() {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
RED.events.on("registry:plugin-module-added", function(module) {
|
||||
|
||||
if (!nodeEntries.hasOwnProperty(module)) {
|
||||
nodeEntries[module] = {info:RED.plugins.getModule(module)};
|
||||
var index = [module];
|
||||
for (var s in nodeEntries[module].info.sets) {
|
||||
if (nodeEntries[module].info.sets.hasOwnProperty(s)) {
|
||||
index.push(s);
|
||||
index = index.concat(nodeEntries[module].info.sets[s].types)
|
||||
}
|
||||
}
|
||||
nodeEntries[module].index = index.join(",").toLowerCase();
|
||||
nodeList.editableList('addItem', nodeEntries[module]);
|
||||
} else {
|
||||
_refreshNodeModule(module);
|
||||
}
|
||||
|
||||
for (var i=0;i<filteredList.length;i++) {
|
||||
if (filteredList[i].info.id === module) {
|
||||
var installButton = filteredList[i].elements.installButton;
|
||||
installButton.addClass('disabled');
|
||||
installButton.text(RED._('palette.editor.installed'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var settingsPane;
|
||||
@@ -804,6 +851,7 @@ RED.palette.editor = (function() {
|
||||
errorRow: errorRow,
|
||||
errorList: errorList,
|
||||
setCount: setCount,
|
||||
setButton: setButton,
|
||||
container: container,
|
||||
shade: shade,
|
||||
versionSpan: versionSpan,
|
||||
@@ -814,49 +862,88 @@ RED.palette.editor = (function() {
|
||||
if (container.hasClass('expanded')) {
|
||||
container.removeClass('expanded');
|
||||
contentRow.slideUp();
|
||||
setTimeout(() => {
|
||||
contentRow.empty()
|
||||
}, 200)
|
||||
object.elements.sets = {}
|
||||
} else {
|
||||
container.addClass('expanded');
|
||||
populateSetList()
|
||||
contentRow.slideDown();
|
||||
}
|
||||
})
|
||||
|
||||
var setList = Object.keys(entry.sets)
|
||||
setList.sort(function(A,B) {
|
||||
return A.toLowerCase().localeCompare(B.toLowerCase());
|
||||
});
|
||||
setList.forEach(function(setName) {
|
||||
var set = entry.sets[setName];
|
||||
var setRow = $('<div>',{class:"red-ui-palette-module-set"}).appendTo(contentRow);
|
||||
var buttonGroup = $('<div>',{class:"red-ui-palette-module-set-button-group"}).appendTo(setRow);
|
||||
var typeSwatches = {};
|
||||
set.types.forEach(function(t) {
|
||||
var typeDiv = $('<div>',{class:"red-ui-palette-module-type"}).appendTo(setRow);
|
||||
typeSwatches[t] = $('<span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
$('<span>',{class:"red-ui-palette-module-type-node"}).text(t).appendTo(typeDiv);
|
||||
})
|
||||
var enableButton = $('<a href="#" class="red-ui-button red-ui-button-small"></a>').appendTo(buttonGroup);
|
||||
enableButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if (object.setUseCount[setName] === 0) {
|
||||
var currentSet = RED.nodes.registry.getNodeSet(set.id);
|
||||
shade.show();
|
||||
var newState = !currentSet.enabled
|
||||
changeNodeState(set.id,newState,shade,function(xhr){
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message}));
|
||||
const populateSetList = function () {
|
||||
var setList = Object.keys(entry.sets)
|
||||
setList.sort(function(A,B) {
|
||||
return A.toLowerCase().localeCompare(B.toLowerCase());
|
||||
});
|
||||
setList.forEach(function(setName) {
|
||||
var set = entry.sets[setName];
|
||||
var setRow = $('<div>',{class:"red-ui-palette-module-set"}).appendTo(contentRow);
|
||||
var buttonGroup = $('<div>',{class:"red-ui-palette-module-set-button-group"}).appendTo(setRow);
|
||||
var typeSwatches = {};
|
||||
let enableButton;
|
||||
if (set.types) {
|
||||
set.types.forEach(function(t) {
|
||||
var typeDiv = $('<div>',{class:"red-ui-palette-module-type"}).appendTo(setRow);
|
||||
typeSwatches[t] = $('<span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
if (set.enabled) {
|
||||
var def = RED.nodes.getType(t);
|
||||
if (def && def.color) {
|
||||
typeSwatches[t].css({background:RED.utils.getNodeColor(t,def)});
|
||||
typeSwatches[t].css({border: "1px solid "+getContrastingBorder(typeSwatches[t].css('backgroundColor'))})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
$('<span>',{class:"red-ui-palette-module-type-node"}).text(t).appendTo(typeDiv);
|
||||
})
|
||||
enableButton = $('<a href="#" class="red-ui-button red-ui-button-small"></a>').appendTo(buttonGroup);
|
||||
enableButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if (object.setUseCount[setName] === 0) {
|
||||
var currentSet = RED.nodes.registry.getNodeSet(set.id);
|
||||
shade.show();
|
||||
var newState = !currentSet.enabled
|
||||
changeNodeState(set.id,newState,shade,function(xhr){
|
||||
if (xhr) {
|
||||
if (xhr.responseJSON) {
|
||||
RED.notify(RED._('palette.editor.errors.'+(newState?'enable':'disable')+'Failed',{module: id,message:xhr.responseJSON.message}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
object.elements.sets[set.name] = {
|
||||
setRow: setRow,
|
||||
enableButton: enableButton,
|
||||
swatches: typeSwatches
|
||||
};
|
||||
});
|
||||
if (object.setUseCount[setName] > 0) {
|
||||
enableButton.text(RED._('palette.editor.inuse'));
|
||||
enableButton.addClass('disabled');
|
||||
} else {
|
||||
enableButton.removeClass('disabled');
|
||||
if (set.enabled) {
|
||||
enableButton.text(RED._('palette.editor.disable'));
|
||||
} else {
|
||||
enableButton.text(RED._('palette.editor.enable'));
|
||||
}
|
||||
}
|
||||
setRow.toggleClass("red-ui-palette-module-set-disabled",!set.enabled);
|
||||
|
||||
|
||||
}
|
||||
if (set.plugins) {
|
||||
set.plugins.forEach(function(p) {
|
||||
var typeDiv = $('<div>',{class:"red-ui-palette-module-type"}).appendTo(setRow);
|
||||
// typeSwatches[p.id] = $('<span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
$('<span><i class="fa fa-puzzle-piece" aria-hidden="true"></i> </span>',{class:"red-ui-palette-module-type-swatch"}).appendTo(typeDiv);
|
||||
$('<span>',{class:"red-ui-palette-module-type-node"}).text(p.id).appendTo(typeDiv);
|
||||
})
|
||||
}
|
||||
|
||||
object.elements.sets[set.name] = {
|
||||
setRow: setRow,
|
||||
enableButton: enableButton,
|
||||
swatches: typeSwatches
|
||||
};
|
||||
});
|
||||
}
|
||||
enableButton.on("click", function(evt) {
|
||||
evt.preventDefault();
|
||||
if (object.totalUseCount === 0) {
|
||||
@@ -1226,7 +1313,55 @@ RED.palette.editor = (function() {
|
||||
}
|
||||
}
|
||||
]
|
||||
}); }
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// dedicated list management for plugins
|
||||
if (entry.plugin) {
|
||||
|
||||
let e = nodeEntries[entry.name];
|
||||
if (e) {
|
||||
nodeList.editableList('removeItem', e);
|
||||
delete nodeEntries[entry.name];
|
||||
}
|
||||
|
||||
// We assume that a plugin that implements onremove
|
||||
// cleans the editor accordingly of its left-overs.
|
||||
let found_onremove = true;
|
||||
|
||||
let keys = Object.keys(entry.sets);
|
||||
keys.forEach((key) => {
|
||||
let set = entry.sets[key];
|
||||
for (let i=0; i<set.plugins?.length; i++) {
|
||||
let plgn = RED.plugins.getPlugin(set.plugins[i].id);
|
||||
if (plgn && plgn.onremove && typeof plgn.onremove === 'function') {
|
||||
plgn.onremove();
|
||||
} else {
|
||||
if (plgn && plgn.onadd && typeof plgn.onadd === 'function') {
|
||||
// if there's no 'onadd', there shouldn't be any left-overs
|
||||
found_onremove = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!found_onremove) {
|
||||
let removeNotify = RED.notify("Removed plugin " + entry.name + ". Please reload the editor to clear left-overs.",{
|
||||
modal: true,
|
||||
fixed: true,
|
||||
type: 'warning',
|
||||
buttons: [
|
||||
{
|
||||
text: "Understood",
|
||||
class:"primary",
|
||||
click: function(e) {
|
||||
removeNotify.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
notification.close();
|
||||
|
@@ -35,6 +35,10 @@ RED.palette = (function() {
|
||||
var categoryContainers = {};
|
||||
var sidebarControls;
|
||||
|
||||
let paletteState = { filter: "", collapsed: [] };
|
||||
|
||||
let filterRefreshTimeout
|
||||
|
||||
function createCategory(originalCategory,rootCategory,category,ns) {
|
||||
if ($("#red-ui-palette-base-category-"+rootCategory).length === 0) {
|
||||
createCategoryContainer(originalCategory,rootCategory, ns+":palette.label."+rootCategory);
|
||||
@@ -60,20 +64,57 @@ RED.palette = (function() {
|
||||
catDiv.data('label',label);
|
||||
categoryContainers[category] = {
|
||||
container: catDiv,
|
||||
close: function() {
|
||||
hide: function (instant) {
|
||||
if (instant) {
|
||||
catDiv.hide()
|
||||
} else {
|
||||
catDiv.slideUp()
|
||||
}
|
||||
},
|
||||
show: function () {
|
||||
catDiv.show()
|
||||
},
|
||||
isOpen: function () {
|
||||
return !!catDiv.hasClass("red-ui-palette-open")
|
||||
},
|
||||
getNodeCount: function (visibleOnly) {
|
||||
const nodes = catDiv.find(".red-ui-palette-node")
|
||||
if (visibleOnly) {
|
||||
return nodes.filter(function() { return $(this).css('display') !== 'none'}).length
|
||||
} else {
|
||||
return nodes.length
|
||||
}
|
||||
},
|
||||
close: function(instant, skipSaveState) {
|
||||
catDiv.removeClass("red-ui-palette-open");
|
||||
catDiv.addClass("red-ui-palette-closed");
|
||||
$("#red-ui-palette-base-category-"+category).slideUp();
|
||||
if (instant) {
|
||||
$("#red-ui-palette-base-category-"+category).hide();
|
||||
} else {
|
||||
$("#red-ui-palette-base-category-"+category).slideUp();
|
||||
}
|
||||
$("#red-ui-palette-header-"+category+" i").removeClass("expanded");
|
||||
if (!skipSaveState) {
|
||||
if (!paletteState.collapsed.includes(category)) {
|
||||
paletteState.collapsed.push(category);
|
||||
savePaletteState();
|
||||
}
|
||||
}
|
||||
},
|
||||
open: function() {
|
||||
open: function(skipSaveState) {
|
||||
catDiv.addClass("red-ui-palette-open");
|
||||
catDiv.removeClass("red-ui-palette-closed");
|
||||
$("#red-ui-palette-base-category-"+category).slideDown();
|
||||
$("#red-ui-palette-header-"+category+" i").addClass("expanded");
|
||||
if (!skipSaveState) {
|
||||
if (paletteState.collapsed.includes(category)) {
|
||||
paletteState.collapsed.splice(paletteState.collapsed.indexOf(category), 1);
|
||||
savePaletteState();
|
||||
}
|
||||
}
|
||||
},
|
||||
toggle: function() {
|
||||
if (catDiv.hasClass("red-ui-palette-open")) {
|
||||
if (categoryContainers[category].isOpen()) {
|
||||
categoryContainers[category].close();
|
||||
} else {
|
||||
categoryContainers[category].open();
|
||||
@@ -415,8 +456,16 @@ RED.palette = (function() {
|
||||
|
||||
var categoryNode = $("#red-ui-palette-container-"+rootCategory);
|
||||
if (categoryNode.find(".red-ui-palette-node").length === 1) {
|
||||
categoryContainers[rootCategory].open();
|
||||
if (!paletteState?.collapsed?.includes(rootCategory)) {
|
||||
categoryContainers[rootCategory].open();
|
||||
} else {
|
||||
categoryContainers[rootCategory].close(true);
|
||||
}
|
||||
}
|
||||
clearTimeout(filterRefreshTimeout)
|
||||
filterRefreshTimeout = setTimeout(() => {
|
||||
refreshFilter()
|
||||
}, 200)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -516,7 +565,8 @@ RED.palette = (function() {
|
||||
paletteNode.css("backgroundColor", sf.color);
|
||||
}
|
||||
|
||||
function filterChange(val) {
|
||||
function refreshFilter() {
|
||||
const val = $("#red-ui-palette-search input").val()
|
||||
var re = new RegExp(val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),'i');
|
||||
$("#red-ui-palette-container .red-ui-palette-node").each(function(i,el) {
|
||||
var currentLabel = $(el).attr("data-palette-label");
|
||||
@@ -528,16 +578,26 @@ RED.palette = (function() {
|
||||
}
|
||||
});
|
||||
|
||||
for (var category in categoryContainers) {
|
||||
for (let category in categoryContainers) {
|
||||
if (categoryContainers.hasOwnProperty(category)) {
|
||||
if (categoryContainers[category].container
|
||||
.find(".red-ui-palette-node")
|
||||
.filter(function() { return $(this).css('display') !== 'none'}).length === 0) {
|
||||
categoryContainers[category].close();
|
||||
categoryContainers[category].container.slideUp();
|
||||
const categorySection = categoryContainers[category]
|
||||
if (categorySection.getNodeCount(true) === 0) {
|
||||
categorySection.hide()
|
||||
} else {
|
||||
categoryContainers[category].open();
|
||||
categoryContainers[category].container.show();
|
||||
categorySection.show()
|
||||
if (val) {
|
||||
// There is a filter being applied and it has matched
|
||||
// something in this category - show the contents
|
||||
categorySection.open(true)
|
||||
} else {
|
||||
// No filter. Only show the category if it isn't in lastState
|
||||
if (!paletteState.collapsed.includes(category)) {
|
||||
categorySection.open(true)
|
||||
} else if (categorySection.isOpen()) {
|
||||
// This section should be collapsed but isn't - so make it so
|
||||
categorySection.close(true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,6 +613,9 @@ RED.palette = (function() {
|
||||
|
||||
$("#red-ui-palette > .red-ui-palette-spinner").show();
|
||||
|
||||
RED.events.on('logout', function () {
|
||||
RED.settings.removeLocal('palette-state')
|
||||
})
|
||||
|
||||
RED.events.on('registry:node-type-added', function(nodeType) {
|
||||
var def = RED.nodes.getType(nodeType);
|
||||
@@ -596,14 +659,14 @@ RED.palette = (function() {
|
||||
|
||||
RED.events.on("subflows:change",refreshSubflow);
|
||||
|
||||
|
||||
|
||||
$("#red-ui-palette-search input").searchBox({
|
||||
delay: 100,
|
||||
change: function() {
|
||||
filterChange($(this).val());
|
||||
refreshFilter();
|
||||
paletteState.filter = $(this).val();
|
||||
savePaletteState();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
sidebarControls = $('<div class="red-ui-sidebar-control-left"><i class="fa fa-chevron-left"></i></div>').appendTo($("#red-ui-palette"));
|
||||
RED.popover.tooltip(sidebarControls,RED._("keyboard.togglePalette"),"core:toggle-palette");
|
||||
@@ -669,7 +732,23 @@ RED.palette = (function() {
|
||||
togglePalette(state);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
paletteState = JSON.parse(RED.settings.getLocal("palette-state") || '{"filter":"", "collapsed": []}');
|
||||
if (paletteState.filter) {
|
||||
// Apply the category filter
|
||||
$("#red-ui-palette-search input").searchBox("value", paletteState.filter);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Unexpected error loading palette state from localStorage: ", error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
// Lazily tidy up any categories that haven't been reloaded
|
||||
paletteState.collapsed = paletteState.collapsed.filter(category => !!categoryContainers[category])
|
||||
savePaletteState()
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
function togglePalette(state) {
|
||||
if (!state) {
|
||||
$("#red-ui-main-container").addClass("red-ui-palette-closed");
|
||||
@@ -689,6 +768,15 @@ RED.palette = (function() {
|
||||
})
|
||||
return categories;
|
||||
}
|
||||
|
||||
function savePaletteState() {
|
||||
try {
|
||||
RED.settings.setLocal("palette-state", JSON.stringify(paletteState));
|
||||
} catch (error) {
|
||||
console.error("Unexpected error saving palette state to localStorage: ", error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
add:addNodeType,
|
||||
|
@@ -1280,14 +1280,20 @@ RED.subflow = (function() {
|
||||
var nodePropValue = nodeProp;
|
||||
if (prop.ui && prop.ui.type === "cred") {
|
||||
nodePropType = "cred";
|
||||
} else if (prop.ui && prop.ui.type === "conf-types") {
|
||||
nodePropType = prop.value.type
|
||||
} else {
|
||||
switch(typeof nodeProp) {
|
||||
case "string": nodePropType = "str"; break;
|
||||
case "number": nodePropType = "num"; break;
|
||||
case "boolean": nodePropType = "bool"; nodePropValue = nodeProp?"true":"false"; break;
|
||||
default:
|
||||
nodePropType = nodeProp.type;
|
||||
nodePropValue = nodeProp.value;
|
||||
if (nodeProp) {
|
||||
nodePropType = nodeProp.type;
|
||||
nodePropValue = nodeProp.value;
|
||||
} else {
|
||||
nodePropType = 'str'
|
||||
}
|
||||
}
|
||||
}
|
||||
var item = {
|
||||
|
@@ -158,8 +158,10 @@ RED.sidebar.help = (function() {
|
||||
|
||||
function refreshSubflow(sf) {
|
||||
var item = treeList.treeList('get',"node-type:subflow:"+sf.id);
|
||||
item.subflowLabel = sf._def.label().toLowerCase();
|
||||
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
|
||||
if (item) {
|
||||
item.subflowLabel = sf._def.label().toLowerCase();
|
||||
item.treeList.replaceElement(getNodeLabel({_def:sf._def,type:sf._def.label()}));
|
||||
}
|
||||
}
|
||||
|
||||
function hideTOC() {
|
||||
|
@@ -491,6 +491,11 @@ RED.workspaces = (function() {
|
||||
createWorkspaceTabs();
|
||||
RED.events.on("sidebar:resize",workspace_tabs.resize);
|
||||
|
||||
RED.events.on("workspace:clear", () => {
|
||||
// Reset the index used to generate new flow names
|
||||
workspaceIndex = 0
|
||||
})
|
||||
|
||||
RED.actions.add("core:show-next-tab",function() {
|
||||
var oldActive = activeWorkspace;
|
||||
workspace_tabs.nextTab();
|
||||
@@ -657,6 +662,9 @@ RED.workspaces = (function() {
|
||||
RED.events.on("flows:change", (ws) => {
|
||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
|
||||
})
|
||||
RED.events.on("subflows:change", (ws) => {
|
||||
$("#red-ui-tab-"+(ws.id.replace(".","-"))).toggleClass('red-ui-workspace-changed',!!(ws.contentsChanged || ws.changed || ws.added));
|
||||
})
|
||||
|
||||
hideWorkspace();
|
||||
}
|
||||
|
@@ -187,6 +187,7 @@ RED.user = (function() {
|
||||
}
|
||||
|
||||
function logout() {
|
||||
RED.events.emit('logout')
|
||||
var tokens = RED.settings.get("auth-tokens");
|
||||
var token = tokens?tokens.access_token:"";
|
||||
$.ajax({
|
||||
@@ -225,6 +226,7 @@ RED.user = (function() {
|
||||
});
|
||||
}
|
||||
});
|
||||
$('<i class="fa fa-user"></i>').appendTo("#red-ui-header-button-user");
|
||||
} else {
|
||||
RED.menu.addItem("red-ui-header-button-user",{
|
||||
id:"usermenu-item-username",
|
||||
@@ -237,6 +239,15 @@ RED.user = (function() {
|
||||
RED.user.logout();
|
||||
}
|
||||
});
|
||||
const userMenu = $("#red-ui-header-button-user")
|
||||
userMenu.empty()
|
||||
if (RED.settings.user.image) {
|
||||
$('<span class="user-profile"></span>').css({
|
||||
backgroundImage: "url("+RED.settings.user.image+")",
|
||||
}).appendTo(userMenu);
|
||||
} else {
|
||||
$('<i class="fa fa-user"></i>').appendTo(userMenu);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -247,14 +258,6 @@ RED.user = (function() {
|
||||
|
||||
var userMenu = $('<li><a id="red-ui-header-button-user" class="button hide" href="#"></a></li>')
|
||||
.prependTo(".red-ui-header-toolbar");
|
||||
if (RED.settings.user.image) {
|
||||
$('<span class="user-profile"></span>').css({
|
||||
backgroundImage: "url("+RED.settings.user.image+")",
|
||||
}).appendTo(userMenu.find("a"));
|
||||
} else {
|
||||
$('<i class="fa fa-user"></i>').appendTo(userMenu.find("a"));
|
||||
}
|
||||
|
||||
RED.menu.init({id:"red-ui-header-button-user",
|
||||
options: []
|
||||
});
|
||||
|
@@ -63,25 +63,29 @@
|
||||
}
|
||||
|
||||
.red-ui-header-toolbar {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
float: right;
|
||||
|
||||
> li {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 100%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
text-align: center;
|
||||
line-height: 40px;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
padding: 0px 12px;
|
||||
text-decoration: none;
|
||||
@@ -271,13 +275,13 @@
|
||||
color: var(--red-ui-header-menu-heading-color);
|
||||
}
|
||||
|
||||
#red-ui-header-button-user .user-profile {
|
||||
.user-profile {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 35px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,8 @@ export default {
|
||||
{
|
||||
title: {
|
||||
"en-US": "Timestamp formatting options",
|
||||
"ja": "タイムスタンプの形式の項目"
|
||||
"ja": "タイムスタンプの形式の項目",
|
||||
"fr": "Options de formatage de l'horodatage"
|
||||
},
|
||||
image: 'images/nr4-timestamp-formatting.png',
|
||||
description: {
|
||||
@@ -34,13 +35,21 @@ export default {
|
||||
<li>エポックからのミリ秒 - 従来動作と同じになるタイムスタンプの項目</li>
|
||||
<li>ISO 8601 - 多くのシステムで使用されている共通の形式</li>
|
||||
<li>JavaScript日付オブジェクト</li>
|
||||
</ul>`,
|
||||
"fr": `<p>Les noeuds qui vous permettent de définir un horodatage disposent désormais d'options sur le format dans lequel cet horodatage peut être défini.</p>
|
||||
<p>Nous gardons les choses simples en proposant trois options :<p>
|
||||
<ul>
|
||||
<li>Millisecondes depuis l'époque : il s'agit du comportement existant de l'option d'horodatage</li>
|
||||
<li>ISO 8601 : un format commun utilisé par de nombreux systèmes</li>
|
||||
<li>Objet Date JavaScript</li>
|
||||
</ul>`
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Auto-complete of flow/global and env types",
|
||||
"ja": "フロー/グローバル、環境変数の型の自動補完"
|
||||
"ja": "フロー/グローバル、環境変数の型の自動補完",
|
||||
"fr": "Saisie automatique des types de flux/global et env"
|
||||
},
|
||||
image: 'images/nr4-auto-complete.png',
|
||||
description: {
|
||||
@@ -48,13 +57,17 @@ export default {
|
||||
now all include auto-complete suggestions based on the live state of your flows.</p>
|
||||
`,
|
||||
"ja": `<p><code>flow</code>/<code>global</code>コンテキストや<code>env</code>の入力を、現在のフローの状態をもとに自動補完で提案するようになりました。</p>
|
||||
`
|
||||
`,
|
||||
"fr": `<p>Les entrées contextuelles <code>flow</code>/<code>global</code> et l'entrée <code>env</code>
|
||||
incluent désormais des suggestions de saisie semi-automatique basées sur l'état actuel de vos flux.</p>
|
||||
`,
|
||||
}
|
||||
},
|
||||
{
|
||||
title: {
|
||||
"en-US": "Config node customisation in Subflows",
|
||||
"ja": "サブフローでの設定ノードのカスタマイズ"
|
||||
"ja": "サブフローでの設定ノードのカスタマイズ",
|
||||
"fr": "Personnalisation du noeud de configuration dans les sous-flux"
|
||||
},
|
||||
image: 'images/nr4-sf-config.png',
|
||||
description: {
|
||||
@@ -65,6 +78,11 @@ export default {
|
||||
`,
|
||||
"ja": `<p>サブフローをカスタマイズして、選択した型の異なる設定ノードを各インスタンスが使用できるようになりました。</p>
|
||||
<p>例えば、MQTTブローカへ接続し、メッセージ受信と後処理を行うサブフローの各インスタンスに異なるブローカを指定することも可能です。</p>
|
||||
`,
|
||||
"fr": `<p>Les sous-flux peuvent désormais être personnalisés pour permettre à chaque instance d'utiliser un
|
||||
noeud de configuration d'un type sélectionné.</p>
|
||||
<p>Par exemple, chaque instance d'un sous-flux qui se connecte à un courtier MQTT et effectue un post-traitement
|
||||
des messages reçus peut être pointée vers un autre courtier.</p>
|
||||
`
|
||||
}
|
||||
},
|
||||
@@ -90,6 +108,14 @@ export default {
|
||||
<li>WebSocketノードのカスタマイズ可能なヘッダ</li>
|
||||
<li>Splitノードは、メッセージプロパティで操作できるようになりました</li>
|
||||
<li>他にも沢山あります...</li>
|
||||
</ul>`,
|
||||
"fr": `<p>Les noeuds principaux ont reçu de nombreux correctifs mineurs ainsi que des améliorations. La documentation a été mise à jour.
|
||||
Consultez le journal des modifications dans la barre latérale d'aide pour une liste complète. Ci-dessous, les changements les plus importants :</p>
|
||||
<ul>
|
||||
<li>Un mode CSV entièrement conforme à la norme RFC4180</li>
|
||||
<li>En-têtes personnalisables pour le noeud WebSocket</li>
|
||||
<li>Le noeud Split peut désormais fonctionner sur n'importe quelle propriété de message</li>
|
||||
<li>Et bien plus encore...</li>
|
||||
</ul>`
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user