@node-red/editor-client 4.0.5 → 4.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/red/about +41 -0
- package/public/red/red.js +613 -241
- package/public/red/red.min.js +3 -3
- package/public/tours/first-flow.js +0 -82
package/public/red/red.js
CHANGED
|
@@ -1834,6 +1834,37 @@ RED.user = (function() {
|
|
|
1834
1834
|
}
|
|
1835
1835
|
|
|
1836
1836
|
|
|
1837
|
+
} else {
|
|
1838
|
+
if (data.prompts) {
|
|
1839
|
+
if (data.loginMessage) {
|
|
1840
|
+
const sessionMessages = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
|
|
1841
|
+
$('<div>').text(data.loginMessage).appendTo(sessionMessages);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
i = 0;
|
|
1845
|
+
for (;i<data.prompts.length;i++) {
|
|
1846
|
+
var field = data.prompts[i];
|
|
1847
|
+
var row = $("<div/>",{class:"form-row",style:"text-align: center"}).appendTo("#node-dialog-login-fields");
|
|
1848
|
+
var loginButton = $('<a href="#" class="red-ui-button"></a>',{style: "padding: 10px"}).appendTo(row).on("click", function() {
|
|
1849
|
+
document.location = field.url;
|
|
1850
|
+
});
|
|
1851
|
+
if (field.image) {
|
|
1852
|
+
$("<img>",{src:field.image}).appendTo(loginButton);
|
|
1853
|
+
} else if (field.label) {
|
|
1854
|
+
var label = $('<span></span>').text(field.label);
|
|
1855
|
+
if (field.icon) {
|
|
1856
|
+
$('<i></i>',{class: "fa fa-2x "+field.icon, style:"vertical-align: middle"}).appendTo(loginButton);
|
|
1857
|
+
label.css({
|
|
1858
|
+
"verticalAlign":"middle",
|
|
1859
|
+
"marginLeft":"8px"
|
|
1860
|
+
});
|
|
1861
|
+
|
|
1862
|
+
}
|
|
1863
|
+
label.appendTo(loginButton);
|
|
1864
|
+
}
|
|
1865
|
+
loginButton.button();
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1837
1868
|
}
|
|
1838
1869
|
if (opts.cancelable) {
|
|
1839
1870
|
$("#node-dialog-login-cancel").button().on("click", function( event ) {
|
|
@@ -4495,7 +4526,13 @@ RED.nodes = (function() {
|
|
|
4495
4526
|
|
|
4496
4527
|
var exports = {
|
|
4497
4528
|
setModulePendingUpdated: function(module,version) {
|
|
4498
|
-
|
|
4529
|
+
if (!!RED.plugins.getModule(module)) {
|
|
4530
|
+
// The module updated is a plugin
|
|
4531
|
+
RED.plugins.getModule(module).pending_version = version;
|
|
4532
|
+
} else {
|
|
4533
|
+
moduleList[module].pending_version = version;
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4499
4536
|
RED.events.emit("registry:module-updated",{module:module,version:version});
|
|
4500
4537
|
},
|
|
4501
4538
|
getModule: function(module) {
|
|
@@ -5123,12 +5160,15 @@ RED.nodes = (function() {
|
|
|
5123
5160
|
}
|
|
5124
5161
|
n["_"] = RED._;
|
|
5125
5162
|
}
|
|
5163
|
+
|
|
5164
|
+
// Both node and config node can use a config node
|
|
5165
|
+
updateConfigNodeUsers(newNode, { action: "add" });
|
|
5166
|
+
|
|
5126
5167
|
if (n._def.category == "config") {
|
|
5127
|
-
configNodes[n.id] =
|
|
5168
|
+
configNodes[n.id] = newNode;
|
|
5128
5169
|
} else {
|
|
5129
5170
|
if (n.wires && (n.wires.length > n.outputs)) { n.outputs = n.wires.length; }
|
|
5130
5171
|
n.dirty = true;
|
|
5131
|
-
updateConfigNodeUsers(n);
|
|
5132
5172
|
if (n._def.category == "subflows" && typeof n.i === "undefined") {
|
|
5133
5173
|
var nextId = 0;
|
|
5134
5174
|
RED.nodes.eachNode(function(node) {
|
|
@@ -5190,9 +5230,11 @@ RED.nodes = (function() {
|
|
|
5190
5230
|
var removedLinks = [];
|
|
5191
5231
|
var removedNodes = [];
|
|
5192
5232
|
var node;
|
|
5233
|
+
|
|
5193
5234
|
if (id in configNodes) {
|
|
5194
5235
|
node = configNodes[id];
|
|
5195
5236
|
delete configNodes[id];
|
|
5237
|
+
updateConfigNodeUsers(node, { action: "remove" });
|
|
5196
5238
|
RED.events.emit('nodes:remove',node);
|
|
5197
5239
|
RED.workspaces.refresh();
|
|
5198
5240
|
} else if (allNodes.hasNode(id)) {
|
|
@@ -5201,6 +5243,9 @@ RED.nodes = (function() {
|
|
|
5201
5243
|
delete nodeLinks[id];
|
|
5202
5244
|
removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
|
|
5203
5245
|
removedLinks.forEach(removeLink);
|
|
5246
|
+
updateConfigNodeUsers(node, { action: "remove" });
|
|
5247
|
+
|
|
5248
|
+
// TODO: Legacy code for exclusive config node
|
|
5204
5249
|
var updatedConfigNode = false;
|
|
5205
5250
|
for (var d in node._def.defaults) {
|
|
5206
5251
|
if (node._def.defaults.hasOwnProperty(d)) {
|
|
@@ -5214,10 +5259,6 @@ RED.nodes = (function() {
|
|
|
5214
5259
|
if (configNode._def.exclusive) {
|
|
5215
5260
|
removeNode(node[d]);
|
|
5216
5261
|
removedNodes.push(configNode);
|
|
5217
|
-
} else {
|
|
5218
|
-
var users = configNode.users;
|
|
5219
|
-
users.splice(users.indexOf(node),1);
|
|
5220
|
-
RED.events.emit('nodes:change',configNode)
|
|
5221
5262
|
}
|
|
5222
5263
|
}
|
|
5223
5264
|
}
|
|
@@ -5454,23 +5495,34 @@ RED.nodes = (function() {
|
|
|
5454
5495
|
return {nodes:removedNodes,links:removedLinks, groups: removedGroups, junctions: removedJunctions};
|
|
5455
5496
|
}
|
|
5456
5497
|
|
|
5498
|
+
/**
|
|
5499
|
+
* Add a Subflow to the Workspace
|
|
5500
|
+
*
|
|
5501
|
+
* @param {object} sf The Subflow to add.
|
|
5502
|
+
* @param {boolean|undefined} createNewIds Whether to update the name.
|
|
5503
|
+
*/
|
|
5457
5504
|
function addSubflow(sf, createNewIds) {
|
|
5458
5505
|
if (createNewIds) {
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5506
|
+
// Update the Subflow name to highlight that this is a copy
|
|
5507
|
+
const subflowNames = Object.keys(subflows).map(function (sfid) {
|
|
5508
|
+
return subflows[sfid].name || "";
|
|
5509
|
+
})
|
|
5510
|
+
subflowNames.sort()
|
|
5462
5511
|
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
var subflowName = sf.name;
|
|
5512
|
+
let copyNumber = 1;
|
|
5513
|
+
let subflowName = sf.name;
|
|
5466
5514
|
subflowNames.forEach(function(name) {
|
|
5467
5515
|
if (subflowName == name) {
|
|
5516
|
+
subflowName = sf.name + " (" + copyNumber + ")";
|
|
5468
5517
|
copyNumber++;
|
|
5469
|
-
subflowName = sf.name+" ("+copyNumber+")";
|
|
5470
5518
|
}
|
|
5471
5519
|
});
|
|
5520
|
+
|
|
5472
5521
|
sf.name = subflowName;
|
|
5473
5522
|
}
|
|
5523
|
+
|
|
5524
|
+
sf.instances = [];
|
|
5525
|
+
|
|
5474
5526
|
subflows[sf.id] = sf;
|
|
5475
5527
|
allNodes.addTab(sf.id);
|
|
5476
5528
|
linkTabMap[sf.id] = [];
|
|
@@ -5523,7 +5575,7 @@ RED.nodes = (function() {
|
|
|
5523
5575
|
module: "node-red"
|
|
5524
5576
|
}
|
|
5525
5577
|
});
|
|
5526
|
-
|
|
5578
|
+
|
|
5527
5579
|
sf._def = RED.nodes.getType("subflow:"+sf.id);
|
|
5528
5580
|
RED.events.emit("subflows:add",sf);
|
|
5529
5581
|
}
|
|
@@ -6165,7 +6217,8 @@ RED.nodes = (function() {
|
|
|
6165
6217
|
// Remove the old subflow definition - but leave the instances in place
|
|
6166
6218
|
var removalResult = RED.subflow.removeSubflow(n.id, true);
|
|
6167
6219
|
// Create the list of nodes for the new subflow def
|
|
6168
|
-
|
|
6220
|
+
// Need to sort the list in order to remove missing nodes
|
|
6221
|
+
var subflowNodes = [n].concat(zMap[n.id]).filter((s) => !!s);
|
|
6169
6222
|
// Import the new subflow - no clashes should occur as we've removed
|
|
6170
6223
|
// the old version
|
|
6171
6224
|
var result = importNodes(subflowNodes);
|
|
@@ -6202,9 +6255,20 @@ RED.nodes = (function() {
|
|
|
6202
6255
|
// Replace config nodes
|
|
6203
6256
|
//
|
|
6204
6257
|
configNodeIds.forEach(function(id) {
|
|
6205
|
-
|
|
6258
|
+
const configNode = getNode(id);
|
|
6259
|
+
const currentUserCount = configNode.users;
|
|
6260
|
+
|
|
6261
|
+
// Add a snapshot of the Config Node
|
|
6262
|
+
removedNodes = removedNodes.concat(convertNode(configNode));
|
|
6263
|
+
|
|
6264
|
+
// Remove the Config Node instance
|
|
6206
6265
|
removeNode(id);
|
|
6207
|
-
|
|
6266
|
+
|
|
6267
|
+
// Import the new one
|
|
6268
|
+
importNodes([newConfigNodes[id]]);
|
|
6269
|
+
|
|
6270
|
+
// Re-attributes the user count
|
|
6271
|
+
getNode(id).users = currentUserCount;
|
|
6208
6272
|
});
|
|
6209
6273
|
|
|
6210
6274
|
return {
|
|
@@ -6445,6 +6509,8 @@ RED.nodes = (function() {
|
|
|
6445
6509
|
if (matchingSubflow) {
|
|
6446
6510
|
subflow_denylist[n.id] = matchingSubflow;
|
|
6447
6511
|
} else {
|
|
6512
|
+
const oldId = n.id;
|
|
6513
|
+
|
|
6448
6514
|
subflow_map[n.id] = n;
|
|
6449
6515
|
if (createNewIds || options.importMap[n.id] === "copy") {
|
|
6450
6516
|
nid = getID();
|
|
@@ -6472,7 +6538,7 @@ RED.nodes = (function() {
|
|
|
6472
6538
|
n.status.id = getID();
|
|
6473
6539
|
}
|
|
6474
6540
|
new_subflows.push(n);
|
|
6475
|
-
addSubflow(n,createNewIds || options.importMap[
|
|
6541
|
+
addSubflow(n,createNewIds || options.importMap[oldId] === "copy");
|
|
6476
6542
|
}
|
|
6477
6543
|
}
|
|
6478
6544
|
}
|
|
@@ -6581,6 +6647,21 @@ RED.nodes = (function() {
|
|
|
6581
6647
|
}
|
|
6582
6648
|
}
|
|
6583
6649
|
|
|
6650
|
+
// Config node can use another config node, must ensure that this other
|
|
6651
|
+
// config node is added before to exists when updating the user list
|
|
6652
|
+
const configNodeFilter = function (node) {
|
|
6653
|
+
let count = 0;
|
|
6654
|
+
if (node._def?.defaults) {
|
|
6655
|
+
for (const def of Object.values(node._def.defaults)) {
|
|
6656
|
+
if (def.type) {
|
|
6657
|
+
count++;
|
|
6658
|
+
}
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
return count;
|
|
6662
|
+
};
|
|
6663
|
+
new_nodes.sort((a, b) => configNodeFilter(a) - configNodeFilter(b));
|
|
6664
|
+
|
|
6584
6665
|
// Find regular flow nodes and subflow instances
|
|
6585
6666
|
for (i=0;i<newNodes.length;i++) {
|
|
6586
6667
|
n = newNodes[i];
|
|
@@ -6592,7 +6673,7 @@ RED.nodes = (function() {
|
|
|
6592
6673
|
x:parseFloat(n.x || 0),
|
|
6593
6674
|
y:parseFloat(n.y || 0),
|
|
6594
6675
|
z:n.z,
|
|
6595
|
-
type:
|
|
6676
|
+
type: n.type,
|
|
6596
6677
|
info: n.info,
|
|
6597
6678
|
changed:false,
|
|
6598
6679
|
_config:{}
|
|
@@ -6653,7 +6734,6 @@ RED.nodes = (function() {
|
|
|
6653
6734
|
}
|
|
6654
6735
|
}
|
|
6655
6736
|
}
|
|
6656
|
-
node.type = n.type;
|
|
6657
6737
|
node._def = def;
|
|
6658
6738
|
if (node.type === "group") {
|
|
6659
6739
|
node._def = RED.group.def;
|
|
@@ -6683,6 +6763,15 @@ RED.nodes = (function() {
|
|
|
6683
6763
|
outputs: n.outputs|| (n.wires && n.wires.length) || 0,
|
|
6684
6764
|
set: registry.getNodeSet("node-red/unknown")
|
|
6685
6765
|
}
|
|
6766
|
+
var orig = {};
|
|
6767
|
+
for (var p in n) {
|
|
6768
|
+
if (n.hasOwnProperty(p) && p!="x" && p!="y" && p!="z" && p!="id" && p!="wires") {
|
|
6769
|
+
orig[p] = n[p];
|
|
6770
|
+
}
|
|
6771
|
+
}
|
|
6772
|
+
node._orig = orig;
|
|
6773
|
+
node.name = n.type;
|
|
6774
|
+
node.type = "unknown";
|
|
6686
6775
|
} else {
|
|
6687
6776
|
if (subflow_denylist[parentId] || createNewIds || options.importMap[n.id] === "copy") {
|
|
6688
6777
|
parentId = subflow.id;
|
|
@@ -6743,29 +6832,31 @@ RED.nodes = (function() {
|
|
|
6743
6832
|
node.type = "unknown";
|
|
6744
6833
|
}
|
|
6745
6834
|
if (node._def.category != "config") {
|
|
6746
|
-
if (n.hasOwnProperty('inputs')) {
|
|
6747
|
-
node.inputs = n.inputs;
|
|
6835
|
+
if (n.hasOwnProperty('inputs') && node._def.defaults.hasOwnProperty("inputs")) {
|
|
6836
|
+
node.inputs = parseInt(n.inputs, 10);
|
|
6748
6837
|
node._config.inputs = JSON.stringify(n.inputs);
|
|
6749
6838
|
} else {
|
|
6750
6839
|
node.inputs = node._def.inputs;
|
|
6751
6840
|
}
|
|
6752
|
-
if (n.hasOwnProperty('outputs')) {
|
|
6753
|
-
node.outputs = n.outputs;
|
|
6841
|
+
if (n.hasOwnProperty('outputs') && node._def.defaults.hasOwnProperty("outputs")) {
|
|
6842
|
+
node.outputs = parseInt(n.outputs, 10);
|
|
6754
6843
|
node._config.outputs = JSON.stringify(n.outputs);
|
|
6755
6844
|
} else {
|
|
6756
6845
|
node.outputs = node._def.outputs;
|
|
6757
6846
|
}
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
} else {
|
|
6764
|
-
// The node declares outputs in its defaults, but has not got a valid value
|
|
6765
|
-
// Defer to the length of the wires array
|
|
6847
|
+
|
|
6848
|
+
// The node declares outputs in its defaults, but has not got a valid value
|
|
6849
|
+
// Defer to the length of the wires array
|
|
6850
|
+
if (node.hasOwnProperty('wires')) {
|
|
6851
|
+
if (isNaN(node.outputs)) {
|
|
6766
6852
|
node.outputs = node.wires.length;
|
|
6853
|
+
} else if (node.wires.length > node.outputs) {
|
|
6854
|
+
// If 'wires' is longer than outputs, clip wires
|
|
6855
|
+
console.log("Warning: node.wires longer than node.outputs - trimming wires:", node.id, " wires:", node.wires.length, " outputs:", node.outputs);
|
|
6856
|
+
node.wires = node.wires.slice(0, node.outputs);
|
|
6767
6857
|
}
|
|
6768
6858
|
}
|
|
6859
|
+
|
|
6769
6860
|
for (d in node._def.defaults) {
|
|
6770
6861
|
if (node._def.defaults.hasOwnProperty(d) && d !== 'inputs' && d !== 'outputs') {
|
|
6771
6862
|
node[d] = n[d];
|
|
@@ -6862,11 +6953,6 @@ RED.nodes = (function() {
|
|
|
6862
6953
|
nodeList = nodeList.map(function(id) {
|
|
6863
6954
|
var node = node_map[id];
|
|
6864
6955
|
if (node) {
|
|
6865
|
-
if (node._def.category === 'config') {
|
|
6866
|
-
if (node.users.indexOf(n) === -1) {
|
|
6867
|
-
node.users.push(n);
|
|
6868
|
-
}
|
|
6869
|
-
}
|
|
6870
6956
|
return node.id;
|
|
6871
6957
|
}
|
|
6872
6958
|
return id;
|
|
@@ -6880,9 +6966,11 @@ RED.nodes = (function() {
|
|
|
6880
6966
|
n = new_subflows[i];
|
|
6881
6967
|
n.in.forEach(function(input) {
|
|
6882
6968
|
input.wires.forEach(function(wire) {
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6969
|
+
if (node_map.hasOwnProperty(wire.id)) {
|
|
6970
|
+
var link = {source:input, sourcePort:0, target:node_map[wire.id]};
|
|
6971
|
+
addLink(link);
|
|
6972
|
+
new_links.push(link);
|
|
6973
|
+
}
|
|
6886
6974
|
});
|
|
6887
6975
|
delete input.wires;
|
|
6888
6976
|
});
|
|
@@ -6891,11 +6979,13 @@ RED.nodes = (function() {
|
|
|
6891
6979
|
var link;
|
|
6892
6980
|
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
|
6893
6981
|
link = {source:n.in[wire.port], sourcePort:wire.port,target:output};
|
|
6894
|
-
} else {
|
|
6982
|
+
} else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) {
|
|
6895
6983
|
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:output};
|
|
6896
6984
|
}
|
|
6897
|
-
|
|
6898
|
-
|
|
6985
|
+
if (link) {
|
|
6986
|
+
addLink(link);
|
|
6987
|
+
new_links.push(link);
|
|
6988
|
+
}
|
|
6899
6989
|
});
|
|
6900
6990
|
delete output.wires;
|
|
6901
6991
|
});
|
|
@@ -6904,11 +6994,13 @@ RED.nodes = (function() {
|
|
|
6904
6994
|
var link;
|
|
6905
6995
|
if (subflow_map[wire.id] && subflow_map[wire.id].id == n.id) {
|
|
6906
6996
|
link = {source:n.in[wire.port], sourcePort:wire.port,target:n.status};
|
|
6907
|
-
} else {
|
|
6997
|
+
} else if (node_map.hasOwnProperty(wire.id) || subflow_map.hasOwnProperty(wire.id)) {
|
|
6908
6998
|
link = {source:node_map[wire.id]||subflow_map[wire.id], sourcePort:wire.port,target:n.status};
|
|
6909
6999
|
}
|
|
6910
|
-
|
|
6911
|
-
|
|
7000
|
+
if (link) {
|
|
7001
|
+
addLink(link);
|
|
7002
|
+
new_links.push(link);
|
|
7003
|
+
}
|
|
6912
7004
|
});
|
|
6913
7005
|
delete n.status.wires;
|
|
6914
7006
|
}
|
|
@@ -7087,25 +7179,79 @@ RED.nodes = (function() {
|
|
|
7087
7179
|
return result;
|
|
7088
7180
|
}
|
|
7089
7181
|
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7182
|
+
/**
|
|
7183
|
+
* Update any config nodes referenced by the provided node to ensure
|
|
7184
|
+
* their 'users' list is correct.
|
|
7185
|
+
*
|
|
7186
|
+
* @param {object} node The node in which to check if it contains references
|
|
7187
|
+
* @param {object} options Options to apply.
|
|
7188
|
+
* @param {"add" | "remove"} [options.action] Add or remove the node from
|
|
7189
|
+
* the Config Node users list. Default `add`.
|
|
7190
|
+
* @param {boolean} [options.emitEvent] Emit the `nodes:changes` event.
|
|
7191
|
+
* Default true.
|
|
7192
|
+
*/
|
|
7193
|
+
function updateConfigNodeUsers(node, options) {
|
|
7194
|
+
const defaultOptions = { action: "add", emitEvent: true };
|
|
7195
|
+
options = Object.assign({}, defaultOptions, options);
|
|
7196
|
+
|
|
7197
|
+
for (var d in node._def.defaults) {
|
|
7198
|
+
if (node._def.defaults.hasOwnProperty(d)) {
|
|
7199
|
+
var property = node._def.defaults[d];
|
|
7095
7200
|
if (property.type) {
|
|
7096
7201
|
var type = registry.getNodeType(property.type);
|
|
7202
|
+
// Need to ensure the type is a config node to not treat links nodes
|
|
7097
7203
|
if (type && type.category == "config") {
|
|
7098
|
-
var configNode = configNodes[
|
|
7204
|
+
var configNode = configNodes[node[d]];
|
|
7099
7205
|
if (configNode) {
|
|
7100
|
-
if (
|
|
7101
|
-
configNode.users.
|
|
7102
|
-
|
|
7206
|
+
if (options.action === "add") {
|
|
7207
|
+
if (configNode.users.indexOf(node) === -1) {
|
|
7208
|
+
configNode.users.push(node);
|
|
7209
|
+
if (options.emitEvent) {
|
|
7210
|
+
RED.events.emit('nodes:change', configNode);
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
} else if (options.action === "remove") {
|
|
7214
|
+
if (configNode.users.indexOf(node) !== -1) {
|
|
7215
|
+
const users = configNode.users;
|
|
7216
|
+
users.splice(users.indexOf(node), 1);
|
|
7217
|
+
if (options.emitEvent) {
|
|
7218
|
+
RED.events.emit('nodes:change', configNode);
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7103
7221
|
}
|
|
7104
7222
|
}
|
|
7105
7223
|
}
|
|
7106
7224
|
}
|
|
7107
7225
|
}
|
|
7108
7226
|
}
|
|
7227
|
+
|
|
7228
|
+
// Subflows can have config node env
|
|
7229
|
+
if (node.type.indexOf("subflow:") === 0) {
|
|
7230
|
+
node.env?.forEach((prop) => {
|
|
7231
|
+
if (prop.type === "conf-type" && prop.value) {
|
|
7232
|
+
// Add the node to the config node users
|
|
7233
|
+
const configNode = getNode(prop.value);
|
|
7234
|
+
if (configNode) {
|
|
7235
|
+
if (options.action === "add") {
|
|
7236
|
+
if (configNode.users.indexOf(node) === -1) {
|
|
7237
|
+
configNode.users.push(node);
|
|
7238
|
+
if (options.emitEvent) {
|
|
7239
|
+
RED.events.emit('nodes:change', configNode);
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
} else if (options.action === "remove") {
|
|
7243
|
+
if (configNode.users.indexOf(node) !== -1) {
|
|
7244
|
+
const users = configNode.users;
|
|
7245
|
+
users.splice(users.indexOf(node), 1);
|
|
7246
|
+
if (options.emitEvent) {
|
|
7247
|
+
RED.events.emit('nodes:change', configNode);
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
}
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
});
|
|
7254
|
+
}
|
|
7109
7255
|
}
|
|
7110
7256
|
|
|
7111
7257
|
function flowVersion(version) {
|
|
@@ -8882,10 +9028,61 @@ RED.history = (function() {
|
|
|
8882
9028
|
RED.events.emit("nodes:change",newConfigNode);
|
|
8883
9029
|
}
|
|
8884
9030
|
});
|
|
9031
|
+
} else if (i === "env" && ev.node.type.indexOf("subflow:") === 0) {
|
|
9032
|
+
// Subflow can have config node in node.env
|
|
9033
|
+
let nodeList = ev.node.env || [];
|
|
9034
|
+
nodeList = nodeList.reduce((list, prop) => {
|
|
9035
|
+
if (prop.type === "conf-type" && prop.value) {
|
|
9036
|
+
list.push(prop.value);
|
|
9037
|
+
}
|
|
9038
|
+
return list;
|
|
9039
|
+
}, []);
|
|
9040
|
+
|
|
9041
|
+
nodeList.forEach(function(id) {
|
|
9042
|
+
const configNode = RED.nodes.node(id);
|
|
9043
|
+
if (configNode) {
|
|
9044
|
+
if (configNode.users.indexOf(ev.node) !== -1) {
|
|
9045
|
+
configNode.users.splice(configNode.users.indexOf(ev.node), 1);
|
|
9046
|
+
RED.events.emit("nodes:change", configNode);
|
|
9047
|
+
}
|
|
9048
|
+
}
|
|
9049
|
+
});
|
|
9050
|
+
|
|
9051
|
+
nodeList = ev.changes.env || [];
|
|
9052
|
+
nodeList = nodeList.reduce((list, prop) => {
|
|
9053
|
+
if (prop.type === "conf-type" && prop.value) {
|
|
9054
|
+
list.push(prop.value);
|
|
9055
|
+
}
|
|
9056
|
+
return list;
|
|
9057
|
+
}, []);
|
|
9058
|
+
|
|
9059
|
+
nodeList.forEach(function(id) {
|
|
9060
|
+
const configNode = RED.nodes.node(id);
|
|
9061
|
+
if (configNode) {
|
|
9062
|
+
if (configNode.users.indexOf(ev.node) === -1) {
|
|
9063
|
+
configNode.users.push(ev.node);
|
|
9064
|
+
RED.events.emit("nodes:change", configNode);
|
|
9065
|
+
}
|
|
9066
|
+
}
|
|
9067
|
+
});
|
|
9068
|
+
}
|
|
9069
|
+
if (i === "credentials" && ev.changes[i]) {
|
|
9070
|
+
// Reset - Only want to keep the changes
|
|
9071
|
+
inverseEv.changes[i] = {};
|
|
9072
|
+
for (const [key, value] of Object.entries(ev.changes[i])) {
|
|
9073
|
+
// Edge case: node.credentials is cleared after a deploy, so we can't
|
|
9074
|
+
// capture values for the inverse event when undoing past a deploy
|
|
9075
|
+
if (ev.node.credentials) {
|
|
9076
|
+
inverseEv.changes[i][key] = ev.node.credentials[key];
|
|
9077
|
+
}
|
|
9078
|
+
ev.node.credentials[key] = value;
|
|
9079
|
+
}
|
|
9080
|
+
} else {
|
|
9081
|
+
ev.node[i] = ev.changes[i];
|
|
8885
9082
|
}
|
|
8886
|
-
ev.node[i] = ev.changes[i];
|
|
8887
9083
|
}
|
|
8888
9084
|
}
|
|
9085
|
+
|
|
8889
9086
|
ev.node.dirty = true;
|
|
8890
9087
|
ev.node.changed = ev.changed;
|
|
8891
9088
|
|
|
@@ -8965,6 +9162,24 @@ RED.history = (function() {
|
|
|
8965
9162
|
RED.editor.updateNodeProperties(ev.node,outputMap);
|
|
8966
9163
|
RED.editor.validateNode(ev.node);
|
|
8967
9164
|
}
|
|
9165
|
+
// If it's a Config Node, validate user nodes too.
|
|
9166
|
+
// NOTE: The Config Node must be validated before validating users.
|
|
9167
|
+
if (ev.node.users) {
|
|
9168
|
+
const validatedNodes = new Set();
|
|
9169
|
+
const userStack = ev.node.users.slice();
|
|
9170
|
+
|
|
9171
|
+
validatedNodes.add(ev.node.id);
|
|
9172
|
+
while (userStack.length) {
|
|
9173
|
+
const node = userStack.pop();
|
|
9174
|
+
if (!validatedNodes.has(node.id)) {
|
|
9175
|
+
validatedNodes.add(node.id);
|
|
9176
|
+
if (node.users) {
|
|
9177
|
+
userStack.push(...node.users);
|
|
9178
|
+
}
|
|
9179
|
+
RED.editor.validateNode(node);
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9182
|
+
}
|
|
8968
9183
|
if (ev.links) {
|
|
8969
9184
|
inverseEv.createdLinks = [];
|
|
8970
9185
|
for (i=0;i<ev.links.length;i++) {
|
|
@@ -22218,7 +22433,7 @@ RED.view = (function() {
|
|
|
22218
22433
|
}
|
|
22219
22434
|
selectedLinks.clearUnselected()
|
|
22220
22435
|
},
|
|
22221
|
-
length: () => groups.
|
|
22436
|
+
length: () => groups.size,
|
|
22222
22437
|
forEach: (func) => { groups.forEach(func) },
|
|
22223
22438
|
toArray: () => [...groups],
|
|
22224
22439
|
clear: function () {
|
|
@@ -22251,8 +22466,8 @@ RED.view = (function() {
|
|
|
22251
22466
|
evt.stopPropagation()
|
|
22252
22467
|
RED.contextMenu.show({
|
|
22253
22468
|
type: 'workspace',
|
|
22254
|
-
x:evt.clientX
|
|
22255
|
-
y:evt.clientY
|
|
22469
|
+
x: evt.clientX,
|
|
22470
|
+
y: evt.clientY
|
|
22256
22471
|
})
|
|
22257
22472
|
return false
|
|
22258
22473
|
})
|
|
@@ -24619,22 +24834,21 @@ RED.view = (function() {
|
|
|
24619
24834
|
addToRemovedLinks(reconnectResult.removedLinks)
|
|
24620
24835
|
}
|
|
24621
24836
|
|
|
24622
|
-
|
|
24623
|
-
|
|
24624
|
-
var selectedGroups = [];
|
|
24837
|
+
const startDirty = RED.nodes.dirty();
|
|
24838
|
+
let movingSelectedGroups = [];
|
|
24625
24839
|
if (movingSet.length() > 0) {
|
|
24626
24840
|
|
|
24627
24841
|
for (var i=0;i<movingSet.length();i++) {
|
|
24628
24842
|
node = movingSet.get(i).n;
|
|
24629
24843
|
if (node.type === "group") {
|
|
24630
|
-
|
|
24844
|
+
movingSelectedGroups.push(node);
|
|
24631
24845
|
}
|
|
24632
24846
|
}
|
|
24633
24847
|
// Make sure we have identified all groups about to be deleted
|
|
24634
|
-
for (i=0;i<
|
|
24635
|
-
|
|
24636
|
-
if (n.type === "group" &&
|
|
24637
|
-
|
|
24848
|
+
for (i=0;i<movingSelectedGroups.length;i++) {
|
|
24849
|
+
movingSelectedGroups[i].nodes.forEach(function(n) {
|
|
24850
|
+
if (n.type === "group" && movingSelectedGroups.indexOf(n) === -1) {
|
|
24851
|
+
movingSelectedGroups.push(n);
|
|
24638
24852
|
}
|
|
24639
24853
|
})
|
|
24640
24854
|
}
|
|
@@ -24651,7 +24865,7 @@ RED.view = (function() {
|
|
|
24651
24865
|
addToRemovedLinks(removedEntities.links);
|
|
24652
24866
|
if (node.g) {
|
|
24653
24867
|
var group = RED.nodes.group(node.g);
|
|
24654
|
-
if (
|
|
24868
|
+
if (movingSelectedGroups.indexOf(group) === -1) {
|
|
24655
24869
|
// Don't use RED.group.removeFromGroup as that emits
|
|
24656
24870
|
// a change event on the node - but we're deleting it
|
|
24657
24871
|
var index = group.nodes.indexOf(node);
|
|
@@ -24665,7 +24879,7 @@ RED.view = (function() {
|
|
|
24665
24879
|
removedLinks = removedLinks.concat(result.links);
|
|
24666
24880
|
if (node.g) {
|
|
24667
24881
|
var group = RED.nodes.group(node.g);
|
|
24668
|
-
if (
|
|
24882
|
+
if (movingSelectedGroups.indexOf(group) === -1) {
|
|
24669
24883
|
// Don't use RED.group.removeFromGroup as that emits
|
|
24670
24884
|
// a change event on the node - but we're deleting it
|
|
24671
24885
|
var index = group.nodes.indexOf(node);
|
|
@@ -24687,8 +24901,8 @@ RED.view = (function() {
|
|
|
24687
24901
|
|
|
24688
24902
|
// Groups must be removed in the right order - from inner-most
|
|
24689
24903
|
// to outermost.
|
|
24690
|
-
for (i =
|
|
24691
|
-
var g =
|
|
24904
|
+
for (i = movingSelectedGroups.length-1; i>=0; i--) {
|
|
24905
|
+
var g = movingSelectedGroups[i];
|
|
24692
24906
|
removedGroups.push(g);
|
|
24693
24907
|
RED.nodes.removeGroup(g);
|
|
24694
24908
|
}
|
|
@@ -27105,8 +27319,8 @@ RED.view = (function() {
|
|
|
27105
27319
|
var delta = Infinity;
|
|
27106
27320
|
for (var i = 0; i < lineLength; i++) {
|
|
27107
27321
|
var linePos = pathLine.getPointAtLength(i);
|
|
27108
|
-
var posDeltaX = Math.abs(linePos.x-d3.event.offsetX)
|
|
27109
|
-
var posDeltaY = Math.abs(linePos.y-d3.event.offsetY)
|
|
27322
|
+
var posDeltaX = Math.abs(linePos.x-(d3.event.offsetX / scaleFactor))
|
|
27323
|
+
var posDeltaY = Math.abs(linePos.y-(d3.event.offsetY / scaleFactor))
|
|
27110
27324
|
var posDelta = posDeltaX*posDeltaX + posDeltaY*posDeltaY
|
|
27111
27325
|
if (posDelta < delta) {
|
|
27112
27326
|
pos = linePos
|
|
@@ -28440,7 +28654,7 @@ RED.view = (function() {
|
|
|
28440
28654
|
}
|
|
28441
28655
|
let badgeRDX = 0;
|
|
28442
28656
|
let badgeLDX = 0;
|
|
28443
|
-
|
|
28657
|
+
const scale = RED.view.scale()
|
|
28444
28658
|
for (let i=0,l=evt.el.__annotations__.length;i<l;i++) {
|
|
28445
28659
|
const annotation = evt.el.__annotations__[i];
|
|
28446
28660
|
if (annotations.hasOwnProperty(annotation.id)) {
|
|
@@ -28471,15 +28685,17 @@ RED.view = (function() {
|
|
|
28471
28685
|
}
|
|
28472
28686
|
if (isBadge) {
|
|
28473
28687
|
if (showAnnotation) {
|
|
28474
|
-
|
|
28688
|
+
// getBoundingClientRect is in real-world scale so needs to be adjusted according to
|
|
28689
|
+
// the current scale factor
|
|
28690
|
+
const rectWidth = annotation.element.getBoundingClientRect().width / scale;
|
|
28475
28691
|
let annotationX
|
|
28476
28692
|
if (!opts.align || opts.align === 'right') {
|
|
28477
|
-
annotationX = evt.node.w - 3 - badgeRDX -
|
|
28478
|
-
badgeRDX +=
|
|
28693
|
+
annotationX = evt.node.w - 3 - badgeRDX - rectWidth
|
|
28694
|
+
badgeRDX += rectWidth + 4;
|
|
28479
28695
|
|
|
28480
28696
|
} else if (opts.align === 'left') {
|
|
28481
28697
|
annotationX = 3 + badgeLDX
|
|
28482
|
-
badgeLDX +=
|
|
28698
|
+
badgeLDX += rectWidth + 4;
|
|
28483
28699
|
}
|
|
28484
28700
|
annotation.element.setAttribute("transform", "translate("+annotationX+", -8)");
|
|
28485
28701
|
}
|
|
@@ -29870,18 +30086,27 @@ RED.view.tools = (function() {
|
|
|
29870
30086
|
const paletteLabel = RED.utils.getPaletteLabel(n.type, nodeDef)
|
|
29871
30087
|
const defaultNodeNameRE = new RegExp('^'+paletteLabel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')+' (\\d+)$')
|
|
29872
30088
|
if (!typeIndex.hasOwnProperty(n.type)) {
|
|
29873
|
-
const existingNodes = RED.nodes.filterNodes({type: n.type})
|
|
29874
|
-
|
|
29875
|
-
|
|
29876
|
-
let match = defaultNodeNameRE.exec(n.name)
|
|
30089
|
+
const existingNodes = RED.nodes.filterNodes({ type: n.type });
|
|
30090
|
+
const existingIds = existingNodes.reduce((ids, node) => {
|
|
30091
|
+
let match = defaultNodeNameRE.exec(node.name);
|
|
29877
30092
|
if (match) {
|
|
29878
|
-
|
|
29879
|
-
if (nodeNumber
|
|
29880
|
-
|
|
30093
|
+
const nodeNumber = parseInt(match[1], 10);
|
|
30094
|
+
if (!ids.includes(nodeNumber)) {
|
|
30095
|
+
ids.push(nodeNumber);
|
|
29881
30096
|
}
|
|
29882
30097
|
}
|
|
29883
|
-
|
|
29884
|
-
|
|
30098
|
+
return ids;
|
|
30099
|
+
}, []).sort((a, b) => a - b);
|
|
30100
|
+
|
|
30101
|
+
let availableNameNumber = 1;
|
|
30102
|
+
for (let i = 0; i < existingIds.length; i++) {
|
|
30103
|
+
if (existingIds[i] !== availableNameNumber) {
|
|
30104
|
+
break;
|
|
30105
|
+
}
|
|
30106
|
+
availableNameNumber++;
|
|
30107
|
+
}
|
|
30108
|
+
|
|
30109
|
+
typeIndex[n.type] = availableNameNumber;
|
|
29885
30110
|
}
|
|
29886
30111
|
if ((options.renameBlank && n.name === '') || (options.renameClash && defaultNodeNameRE.test(n.name))) {
|
|
29887
30112
|
if (generateHistory) {
|
|
@@ -29913,11 +30138,11 @@ RED.view.tools = (function() {
|
|
|
29913
30138
|
}
|
|
29914
30139
|
}
|
|
29915
30140
|
|
|
29916
|
-
function addJunctionsToWires(
|
|
30141
|
+
function addJunctionsToWires(options = {}) {
|
|
29917
30142
|
if (RED.workspaces.isLocked()) {
|
|
29918
30143
|
return
|
|
29919
30144
|
}
|
|
29920
|
-
let wiresToSplit = wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
|
30145
|
+
let wiresToSplit = options.wires || (RED.view.selection().links && RED.view.selection().links.filter(e => !e.link));
|
|
29921
30146
|
if (!wiresToSplit) {
|
|
29922
30147
|
return
|
|
29923
30148
|
}
|
|
@@ -29965,21 +30190,26 @@ RED.view.tools = (function() {
|
|
|
29965
30190
|
if (links.length === 0) {
|
|
29966
30191
|
return
|
|
29967
30192
|
}
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
|
|
29971
|
-
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
29976
|
-
|
|
29977
|
-
|
|
29978
|
-
|
|
29979
|
-
|
|
29980
|
-
|
|
29981
|
-
|
|
29982
|
-
|
|
30193
|
+
if (addedJunctions.length === 0 && Object.hasOwn(options, 'x') && Object.hasOwn(options, 'y')) {
|
|
30194
|
+
junction.x = options.x
|
|
30195
|
+
junction.y = options.y
|
|
30196
|
+
} else {
|
|
30197
|
+
let pointCount = 0
|
|
30198
|
+
links.forEach(function(l) {
|
|
30199
|
+
if (l._sliceLocation) {
|
|
30200
|
+
junction.x += l._sliceLocation.x
|
|
30201
|
+
junction.y += l._sliceLocation.y
|
|
30202
|
+
delete l._sliceLocation
|
|
30203
|
+
pointCount++
|
|
30204
|
+
} else {
|
|
30205
|
+
junction.x += l.source.x + l.source.w/2 + l.target.x - l.target.w/2
|
|
30206
|
+
junction.y += l.source.y + l.target.y
|
|
30207
|
+
pointCount += 2
|
|
30208
|
+
}
|
|
30209
|
+
})
|
|
30210
|
+
junction.x = Math.round(junction.x/pointCount)
|
|
30211
|
+
junction.y = Math.round(junction.y/pointCount)
|
|
30212
|
+
}
|
|
29983
30213
|
if (RED.view.snapGrid) {
|
|
29984
30214
|
let gridSize = RED.view.gridSize()
|
|
29985
30215
|
junction.x = (gridSize*Math.round(junction.x/gridSize));
|
|
@@ -30169,7 +30399,7 @@ RED.view.tools = (function() {
|
|
|
30169
30399
|
RED.actions.add("core:wire-multiple-to-node", function() { wireMultipleToNode() })
|
|
30170
30400
|
|
|
30171
30401
|
RED.actions.add("core:split-wire-with-link-nodes", function () { splitWiresWithLinkNodes() });
|
|
30172
|
-
RED.actions.add("core:split-wires-with-junctions", function () { addJunctionsToWires() });
|
|
30402
|
+
RED.actions.add("core:split-wires-with-junctions", function (options) { addJunctionsToWires(options) });
|
|
30173
30403
|
|
|
30174
30404
|
RED.actions.add("core:generate-node-names", generateNodeNames )
|
|
30175
30405
|
|
|
@@ -36156,6 +36386,20 @@ RED.editor = (function() {
|
|
|
36156
36386
|
}
|
|
36157
36387
|
}
|
|
36158
36388
|
|
|
36389
|
+
const oldCreds = {};
|
|
36390
|
+
if (editing_node._def.credentials) {
|
|
36391
|
+
for (const prop in editing_node._def.credentials) {
|
|
36392
|
+
if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) {
|
|
36393
|
+
if (editing_node._def.credentials[prop].type === 'password') {
|
|
36394
|
+
oldCreds['has_' + prop] = editing_node.credentials['has_' + prop];
|
|
36395
|
+
}
|
|
36396
|
+
if (prop in editing_node.credentials) {
|
|
36397
|
+
oldCreds[prop] = editing_node.credentials[prop];
|
|
36398
|
+
}
|
|
36399
|
+
}
|
|
36400
|
+
}
|
|
36401
|
+
}
|
|
36402
|
+
|
|
36159
36403
|
try {
|
|
36160
36404
|
const rc = editing_node._def.oneditsave.call(editing_node);
|
|
36161
36405
|
if (rc === true) {
|
|
@@ -36187,6 +36431,25 @@ RED.editor = (function() {
|
|
|
36187
36431
|
}
|
|
36188
36432
|
}
|
|
36189
36433
|
}
|
|
36434
|
+
|
|
36435
|
+
if (editing_node._def.credentials) {
|
|
36436
|
+
for (const prop in editing_node._def.credentials) {
|
|
36437
|
+
if (Object.prototype.hasOwnProperty.call(editing_node._def.credentials, prop)) {
|
|
36438
|
+
if (oldCreds[prop] !== editing_node.credentials[prop]) {
|
|
36439
|
+
if (editing_node.credentials[prop] === '__PWRD__') {
|
|
36440
|
+
// The password may not exist in oldCreds
|
|
36441
|
+
// The value '__PWRD__' means the password exists,
|
|
36442
|
+
// so ignore this change
|
|
36443
|
+
continue;
|
|
36444
|
+
}
|
|
36445
|
+
editState.changes.credentials = editState.changes.credentials || {};
|
|
36446
|
+
editState.changes.credentials['has_' + prop] = oldCreds['has_' + prop];
|
|
36447
|
+
editState.changes.credentials[prop] = oldCreds[prop];
|
|
36448
|
+
editState.changed = true;
|
|
36449
|
+
}
|
|
36450
|
+
}
|
|
36451
|
+
}
|
|
36452
|
+
}
|
|
36190
36453
|
}
|
|
36191
36454
|
}
|
|
36192
36455
|
|
|
@@ -36829,134 +37092,181 @@ RED.editor = (function() {
|
|
|
36829
37092
|
},
|
|
36830
37093
|
{
|
|
36831
37094
|
id: "node-config-dialog-ok",
|
|
36832
|
-
text: adding?RED._("editor.configAdd"):RED._("editor.configUpdate"),
|
|
37095
|
+
text: adding ? RED._("editor.configAdd") : RED._("editor.configUpdate"),
|
|
36833
37096
|
class: "primary",
|
|
36834
37097
|
click: function() {
|
|
36835
|
-
|
|
37098
|
+
// TODO: Already defined
|
|
37099
|
+
const configProperty = name;
|
|
37100
|
+
const configType = type;
|
|
37101
|
+
const configTypeDef = RED.nodes.getType(configType);
|
|
37102
|
+
|
|
37103
|
+
const wasChanged = editing_config_node.changed;
|
|
37104
|
+
const editState = {
|
|
36836
37105
|
changes: {},
|
|
36837
37106
|
changed: false,
|
|
36838
37107
|
outputMap: null
|
|
36839
37108
|
};
|
|
36840
|
-
|
|
36841
|
-
|
|
36842
|
-
|
|
36843
|
-
var configAdding = adding;
|
|
36844
|
-
var configTypeDef = RED.nodes.getType(configType);
|
|
36845
|
-
var d;
|
|
36846
|
-
var input;
|
|
36847
|
-
|
|
36848
|
-
if (configTypeDef.oneditsave) {
|
|
36849
|
-
try {
|
|
36850
|
-
configTypeDef.oneditsave.call(editing_config_node);
|
|
36851
|
-
} catch(err) {
|
|
36852
|
-
console.warn("oneditsave",editing_config_node.id,editing_config_node.type,err.toString());
|
|
36853
|
-
}
|
|
36854
|
-
}
|
|
36855
|
-
|
|
36856
|
-
for (d in configTypeDef.defaults) {
|
|
36857
|
-
if (configTypeDef.defaults.hasOwnProperty(d)) {
|
|
36858
|
-
var newValue;
|
|
36859
|
-
input = $("#node-config-input-"+d);
|
|
36860
|
-
if (input.attr('type') === "checkbox") {
|
|
36861
|
-
newValue = input.prop('checked');
|
|
36862
|
-
} else if ("format" in configTypeDef.defaults[d] && configTypeDef.defaults[d].format !== "" && input[0].nodeName === "DIV") {
|
|
36863
|
-
newValue = input.text();
|
|
36864
|
-
} else {
|
|
36865
|
-
newValue = input.val();
|
|
36866
|
-
}
|
|
36867
|
-
if (newValue != null && newValue !== editing_config_node[d]) {
|
|
36868
|
-
if (editing_config_node._def.defaults[d].type) {
|
|
36869
|
-
if (newValue == "_ADD_") {
|
|
36870
|
-
newValue = "";
|
|
36871
|
-
}
|
|
36872
|
-
// Change to a related config node
|
|
36873
|
-
var configNode = RED.nodes.node(editing_config_node[d]);
|
|
36874
|
-
if (configNode) {
|
|
36875
|
-
var users = configNode.users;
|
|
36876
|
-
users.splice(users.indexOf(editing_config_node),1);
|
|
36877
|
-
RED.events.emit("nodes:change",configNode);
|
|
36878
|
-
}
|
|
36879
|
-
configNode = RED.nodes.node(newValue);
|
|
36880
|
-
if (configNode) {
|
|
36881
|
-
configNode.users.push(editing_config_node);
|
|
36882
|
-
RED.events.emit("nodes:change",configNode);
|
|
36883
|
-
}
|
|
36884
|
-
}
|
|
36885
|
-
editing_config_node[d] = newValue;
|
|
36886
|
-
}
|
|
36887
|
-
}
|
|
36888
|
-
}
|
|
37109
|
+
|
|
37110
|
+
// Call `oneditsave` and search for changes
|
|
37111
|
+
handleEditSave(editing_config_node, editState);
|
|
36889
37112
|
|
|
36890
|
-
|
|
37113
|
+
// Search for changes in the edit box (panes)
|
|
37114
|
+
activeEditPanes.forEach(function (pane) {
|
|
36891
37115
|
if (pane.apply) {
|
|
36892
37116
|
pane.apply.call(pane, editState);
|
|
36893
37117
|
}
|
|
36894
|
-
})
|
|
36895
|
-
|
|
36896
|
-
editing_config_node.label = configTypeDef.label;
|
|
37118
|
+
});
|
|
36897
37119
|
|
|
36898
|
-
|
|
36899
|
-
editing_config_node.
|
|
37120
|
+
// TODO: Why?
|
|
37121
|
+
editing_config_node.label = configTypeDef.label
|
|
36900
37122
|
|
|
37123
|
+
// Check if disabled has changed
|
|
36901
37124
|
if ($("#node-config-input-node-disabled").prop('checked')) {
|
|
36902
37125
|
if (editing_config_node.d !== true) {
|
|
37126
|
+
editState.changes.d = editing_config_node.d;
|
|
37127
|
+
editState.changed = true;
|
|
36903
37128
|
editing_config_node.d = true;
|
|
36904
37129
|
}
|
|
36905
37130
|
} else {
|
|
36906
37131
|
if (editing_config_node.d === true) {
|
|
37132
|
+
editState.changes.d = editing_config_node.d;
|
|
37133
|
+
editState.changed = true;
|
|
36907
37134
|
delete editing_config_node.d;
|
|
36908
37135
|
}
|
|
36909
37136
|
}
|
|
36910
37137
|
|
|
37138
|
+
// NOTE: must be undefined if no scope used
|
|
37139
|
+
const scope = $("#red-ui-editor-config-scope").val() || undefined;
|
|
37140
|
+
|
|
37141
|
+
// Check if the scope has changed
|
|
37142
|
+
if (editing_config_node.z !== scope) {
|
|
37143
|
+
editState.changes.z = editing_config_node.z;
|
|
37144
|
+
editState.changed = true;
|
|
37145
|
+
editing_config_node.z = scope;
|
|
37146
|
+
}
|
|
37147
|
+
|
|
37148
|
+
// Search for nodes that use this config node that are no longer
|
|
37149
|
+
// in scope, so must be removed
|
|
37150
|
+
const historyEvents = [];
|
|
36911
37151
|
if (scope) {
|
|
36912
|
-
|
|
36913
|
-
|
|
36914
|
-
|
|
36915
|
-
|
|
36916
|
-
for (
|
|
36917
|
-
if (
|
|
36918
|
-
if (
|
|
36919
|
-
|
|
36920
|
-
|
|
36921
|
-
|
|
36922
|
-
|
|
36923
|
-
|
|
36924
|
-
|
|
36925
|
-
|
|
36926
|
-
|
|
36927
|
-
|
|
37152
|
+
const newUsers = editing_config_node.users.filter(function (node) {
|
|
37153
|
+
let keepNode = false;
|
|
37154
|
+
let nodeModified = null;
|
|
37155
|
+
|
|
37156
|
+
for (const d in node._def.defaults) {
|
|
37157
|
+
if (node._def.defaults.hasOwnProperty(d)) {
|
|
37158
|
+
if (node._def.defaults[d].type === editing_config_node.type) {
|
|
37159
|
+
if (node[d] === editing_config_node.id) {
|
|
37160
|
+
if (node.z === editing_config_node.z) {
|
|
37161
|
+
// The node is kept only if at least one property uses
|
|
37162
|
+
// this config node in the correct scope.
|
|
37163
|
+
keepNode = true;
|
|
37164
|
+
} else {
|
|
37165
|
+
if (!nodeModified) {
|
|
37166
|
+
nodeModified = {
|
|
37167
|
+
t: "edit",
|
|
37168
|
+
node: node,
|
|
37169
|
+
changes: { [d]: node[d] },
|
|
37170
|
+
changed: node.changed,
|
|
37171
|
+
dirty: node.dirty
|
|
37172
|
+
};
|
|
37173
|
+
} else {
|
|
37174
|
+
nodeModified.changes[d] = node[d];
|
|
37175
|
+
}
|
|
37176
|
+
|
|
37177
|
+
// Remove the reference to the config node
|
|
37178
|
+
node[d] = "";
|
|
37179
|
+
}
|
|
37180
|
+
}
|
|
36928
37181
|
}
|
|
36929
37182
|
}
|
|
36930
37183
|
}
|
|
36931
|
-
|
|
37184
|
+
|
|
37185
|
+
// Add the node modified to the history
|
|
37186
|
+
if (nodeModified) {
|
|
37187
|
+
historyEvents.push(nodeModified);
|
|
37188
|
+
}
|
|
37189
|
+
|
|
37190
|
+
// Mark as changed and revalidate this node
|
|
37191
|
+
if (!keepNode) {
|
|
37192
|
+
node.changed = true;
|
|
37193
|
+
node.dirty = true;
|
|
37194
|
+
validateNode(node);
|
|
37195
|
+
RED.events.emit("nodes:change", node);
|
|
37196
|
+
}
|
|
37197
|
+
|
|
37198
|
+
return keepNode;
|
|
36932
37199
|
});
|
|
37200
|
+
|
|
37201
|
+
// Check if users are changed
|
|
37202
|
+
if (editing_config_node.users.length !== newUsers.length) {
|
|
37203
|
+
editState.changes.users = editing_config_node.users;
|
|
37204
|
+
editState.changed = true;
|
|
37205
|
+
editing_config_node.users = newUsers;
|
|
37206
|
+
}
|
|
36933
37207
|
}
|
|
36934
37208
|
|
|
36935
|
-
if (
|
|
36936
|
-
|
|
37209
|
+
if (editState.changed) {
|
|
37210
|
+
// Set the congig node as changed
|
|
37211
|
+
editing_config_node.changed = true;
|
|
36937
37212
|
}
|
|
36938
37213
|
|
|
37214
|
+
// Now, validate the config node
|
|
36939
37215
|
validateNode(editing_config_node);
|
|
36940
|
-
var validatedNodes = {};
|
|
36941
|
-
validatedNodes[editing_config_node.id] = true;
|
|
36942
37216
|
|
|
36943
|
-
|
|
36944
|
-
|
|
36945
|
-
|
|
36946
|
-
|
|
36947
|
-
|
|
36948
|
-
|
|
36949
|
-
|
|
37217
|
+
// And validate nodes using this config node too
|
|
37218
|
+
const validatedNodes = new Set();
|
|
37219
|
+
const userStack = editing_config_node.users.slice();
|
|
37220
|
+
|
|
37221
|
+
validatedNodes.add(editing_config_node.id);
|
|
37222
|
+
while (userStack.length) {
|
|
37223
|
+
const node = userStack.pop();
|
|
37224
|
+
if (!validatedNodes.has(node.id)) {
|
|
37225
|
+
validatedNodes.add(node.id);
|
|
37226
|
+
if (node.users) {
|
|
37227
|
+
userStack.push(...node.users);
|
|
36950
37228
|
}
|
|
36951
|
-
validateNode(
|
|
37229
|
+
validateNode(node);
|
|
36952
37230
|
}
|
|
36953
37231
|
}
|
|
36954
|
-
|
|
36955
|
-
|
|
36956
|
-
|
|
36957
|
-
|
|
36958
|
-
|
|
37232
|
+
|
|
37233
|
+
let historyEvent = {
|
|
37234
|
+
t: "edit",
|
|
37235
|
+
node: editing_config_node,
|
|
37236
|
+
changes: editState.changes,
|
|
37237
|
+
changed: wasChanged,
|
|
37238
|
+
dirty: RED.nodes.dirty()
|
|
37239
|
+
};
|
|
37240
|
+
|
|
37241
|
+
if (historyEvents.length) {
|
|
37242
|
+
// Need a multi events
|
|
37243
|
+
historyEvent = {
|
|
37244
|
+
t: "multi",
|
|
37245
|
+
events: [historyEvent].concat(historyEvents),
|
|
37246
|
+
dirty: historyEvent.dirty
|
|
37247
|
+
};
|
|
37248
|
+
}
|
|
37249
|
+
|
|
37250
|
+
if (!adding) {
|
|
37251
|
+
// This event is triggered when the edit box is saved,
|
|
37252
|
+
// regardless of whether there are any modifications.
|
|
37253
|
+
RED.events.emit("editor:save", editing_config_node);
|
|
37254
|
+
}
|
|
37255
|
+
|
|
37256
|
+
if (editState.changed) {
|
|
37257
|
+
if (adding) {
|
|
37258
|
+
RED.history.push({ t: "add", nodes: [editing_config_node.id], dirty: RED.nodes.dirty() });
|
|
37259
|
+
// Add the new config node and trigger the `nodes:add` event
|
|
37260
|
+
RED.nodes.add(editing_config_node);
|
|
37261
|
+
} else {
|
|
37262
|
+
RED.history.push(historyEvent);
|
|
37263
|
+
RED.events.emit("nodes:change", editing_config_node);
|
|
37264
|
+
}
|
|
37265
|
+
|
|
37266
|
+
RED.nodes.dirty(true);
|
|
37267
|
+
RED.view.redraw(true);
|
|
36959
37268
|
}
|
|
37269
|
+
|
|
36960
37270
|
RED.tray.close(function() {
|
|
36961
37271
|
var filter = null;
|
|
36962
37272
|
// when editing a config via subflow edit panel, the `configProperty` will not
|
|
@@ -38238,10 +38548,31 @@ RED.editor = (function() {
|
|
|
38238
38548
|
apply: function(editState) {
|
|
38239
38549
|
var old_env = node.env;
|
|
38240
38550
|
var new_env = [];
|
|
38551
|
+
|
|
38241
38552
|
if (/^subflow:/.test(node.type)) {
|
|
38553
|
+
// Get the list of environment variables from the node properties
|
|
38242
38554
|
new_env = RED.subflow.exportSubflowInstanceEnv(node);
|
|
38243
38555
|
}
|
|
38244
38556
|
|
|
38557
|
+
if (old_env && old_env.length) {
|
|
38558
|
+
old_env.forEach(function (prop) {
|
|
38559
|
+
if (prop.type === "conf-type" && prop.value) {
|
|
38560
|
+
const stillInUse = new_env?.some((p) => p.type === "conf-type" && p.name === prop.name && p.value === prop.value);
|
|
38561
|
+
if (!stillInUse) {
|
|
38562
|
+
// Remove the node from the config node users
|
|
38563
|
+
// Only for empty value or modified
|
|
38564
|
+
const configNode = RED.nodes.node(prop.value);
|
|
38565
|
+
if (configNode) {
|
|
38566
|
+
if (configNode.users.indexOf(node) !== -1) {
|
|
38567
|
+
configNode.users.splice(configNode.users.indexOf(node), 1);
|
|
38568
|
+
RED.events.emit('nodes:change', configNode)
|
|
38569
|
+
}
|
|
38570
|
+
}
|
|
38571
|
+
}
|
|
38572
|
+
}
|
|
38573
|
+
});
|
|
38574
|
+
}
|
|
38575
|
+
|
|
38245
38576
|
// Get the values from the Properties table tab
|
|
38246
38577
|
var items = this.list.editableList('items');
|
|
38247
38578
|
items.each(function (i,el) {
|
|
@@ -38259,7 +38590,6 @@ RED.editor = (function() {
|
|
|
38259
38590
|
}
|
|
38260
38591
|
});
|
|
38261
38592
|
|
|
38262
|
-
|
|
38263
38593
|
if (new_env && new_env.length > 0) {
|
|
38264
38594
|
new_env.forEach(function(prop) {
|
|
38265
38595
|
if (prop.type === "cred") {
|
|
@@ -38270,6 +38600,15 @@ RED.editor = (function() {
|
|
|
38270
38600
|
editState.changed = true;
|
|
38271
38601
|
}
|
|
38272
38602
|
delete prop.value;
|
|
38603
|
+
} else if (prop.type === "conf-type" && prop.value) {
|
|
38604
|
+
const configNode = RED.nodes.node(prop.value);
|
|
38605
|
+
if (configNode) {
|
|
38606
|
+
if (configNode.users.indexOf(node) === -1) {
|
|
38607
|
+
// Add the node to the config node users
|
|
38608
|
+
configNode.users.push(node);
|
|
38609
|
+
RED.events.emit('nodes:change', configNode);
|
|
38610
|
+
}
|
|
38611
|
+
}
|
|
38273
38612
|
}
|
|
38274
38613
|
});
|
|
38275
38614
|
}
|
|
@@ -38395,6 +38734,7 @@ RED.editor = (function() {
|
|
|
38395
38734
|
apply: function(editState) {
|
|
38396
38735
|
var newValue;
|
|
38397
38736
|
var d;
|
|
38737
|
+
// If the node is a subflow, the node's properties (exepts name) are saved by `envProperties`
|
|
38398
38738
|
if (node._def.defaults) {
|
|
38399
38739
|
for (d in node._def.defaults) {
|
|
38400
38740
|
if (node._def.defaults.hasOwnProperty(d)) {
|
|
@@ -38482,9 +38822,16 @@ RED.editor = (function() {
|
|
|
38482
38822
|
}
|
|
38483
38823
|
}
|
|
38484
38824
|
if (node._def.credentials) {
|
|
38485
|
-
|
|
38486
|
-
|
|
38487
|
-
|
|
38825
|
+
const credDefinition = node._def.credentials;
|
|
38826
|
+
const credChanges = updateNodeCredentials(node, credDefinition, this.inputClass);
|
|
38827
|
+
|
|
38828
|
+
if (Object.keys(credChanges).length) {
|
|
38829
|
+
editState.changed = true;
|
|
38830
|
+
editState.changes.credentials = {
|
|
38831
|
+
...(editState.changes.credentials || {}),
|
|
38832
|
+
...credChanges
|
|
38833
|
+
};
|
|
38834
|
+
}
|
|
38488
38835
|
}
|
|
38489
38836
|
}
|
|
38490
38837
|
}
|
|
@@ -38512,10 +38859,11 @@ RED.editor = (function() {
|
|
|
38512
38859
|
* @param node - the node containing the credentials
|
|
38513
38860
|
* @param credDefinition - definition of the credentials
|
|
38514
38861
|
* @param prefix - prefix of the input fields
|
|
38515
|
-
* @return {
|
|
38862
|
+
* @return {object} an object containing the modified properties
|
|
38516
38863
|
*/
|
|
38517
38864
|
function updateNodeCredentials(node, credDefinition, prefix) {
|
|
38518
|
-
|
|
38865
|
+
const changes = {};
|
|
38866
|
+
|
|
38519
38867
|
if (!node.credentials) {
|
|
38520
38868
|
node.credentials = {_:{}};
|
|
38521
38869
|
} else if (!node.credentials._) {
|
|
@@ -38528,24 +38876,35 @@ RED.editor = (function() {
|
|
|
38528
38876
|
if (input.length > 0) {
|
|
38529
38877
|
var value = input.val();
|
|
38530
38878
|
if (credDefinition[cred].type == 'password') {
|
|
38531
|
-
|
|
38532
|
-
|
|
38533
|
-
|
|
38879
|
+
if (value === '__PWRD__') {
|
|
38880
|
+
// A cred value exists - no changes
|
|
38881
|
+
} else if (value === '' && node.credentials['has_' + cred] === false) {
|
|
38882
|
+
// Empty cred value exists - no changes
|
|
38883
|
+
} else if (value === node.credentials[cred]) {
|
|
38884
|
+
// A cred value exists locally in the editor - no changes
|
|
38885
|
+
// Like the user sets a value, saves the config,
|
|
38886
|
+
// reopens the config and save the config again
|
|
38887
|
+
} else {
|
|
38888
|
+
changes['has_' + cred] = node.credentials['has_' + cred];
|
|
38889
|
+
changes[cred] = node.credentials[cred];
|
|
38890
|
+
node.credentials[cred] = value;
|
|
38534
38891
|
}
|
|
38535
|
-
changed = true;
|
|
38536
38892
|
|
|
38537
|
-
|
|
38538
|
-
|
|
38539
|
-
|
|
38540
|
-
|
|
38893
|
+
node.credentials['has_' + cred] = (value !== '');
|
|
38894
|
+
} else {
|
|
38895
|
+
// Since these creds are loaded by the editor,
|
|
38896
|
+
// values can be directly compared
|
|
38897
|
+
if (value !== node.credentials[cred]) {
|
|
38898
|
+
changes[cred] = node.credentials[cred];
|
|
38899
|
+
node.credentials[cred] = value;
|
|
38900
|
+
}
|
|
38541
38901
|
}
|
|
38542
38902
|
}
|
|
38543
38903
|
}
|
|
38544
38904
|
}
|
|
38545
|
-
return changed;
|
|
38546
|
-
}
|
|
38547
|
-
|
|
38548
38905
|
|
|
38906
|
+
return changes;
|
|
38907
|
+
}
|
|
38549
38908
|
})();
|
|
38550
38909
|
;(function() {
|
|
38551
38910
|
var _subflowModulePaneTemplate = '<form class="dialog-form form-horizontal" autocomplete="off">'+
|
|
@@ -39400,7 +39759,7 @@ RED.editor = (function() {
|
|
|
39400
39759
|
nameField.trigger('change');
|
|
39401
39760
|
}
|
|
39402
39761
|
},
|
|
39403
|
-
sortable:
|
|
39762
|
+
sortable: true,
|
|
39404
39763
|
removable: false
|
|
39405
39764
|
});
|
|
39406
39765
|
var parentEnv = {};
|
|
@@ -44109,6 +44468,30 @@ RED.clipboard = (function() {
|
|
|
44109
44468
|
},100);
|
|
44110
44469
|
}
|
|
44111
44470
|
|
|
44471
|
+
/**
|
|
44472
|
+
* Validates if the provided string looks like valid flow json
|
|
44473
|
+
* @param {string} flowString the string to validate
|
|
44474
|
+
* @returns If valid, returns the node array
|
|
44475
|
+
*/
|
|
44476
|
+
function validateFlowString(flowString) {
|
|
44477
|
+
const res = JSON.parse(flowString)
|
|
44478
|
+
if (!Array.isArray(res)) {
|
|
44479
|
+
throw new Error(RED._("clipboard.import.errors.notArray"));
|
|
44480
|
+
}
|
|
44481
|
+
for (let i = 0; i < res.length; i++) {
|
|
44482
|
+
if (typeof res[i] !== "object") {
|
|
44483
|
+
throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
|
|
44484
|
+
}
|
|
44485
|
+
if (!Object.hasOwn(res[i], 'id')) {
|
|
44486
|
+
throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
|
|
44487
|
+
}
|
|
44488
|
+
if (!Object.hasOwn(res[i], 'type')) {
|
|
44489
|
+
throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
|
|
44490
|
+
}
|
|
44491
|
+
}
|
|
44492
|
+
return res
|
|
44493
|
+
}
|
|
44494
|
+
|
|
44112
44495
|
var validateImportTimeout;
|
|
44113
44496
|
function validateImport() {
|
|
44114
44497
|
if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") {
|
|
@@ -44126,21 +44509,7 @@ RED.clipboard = (function() {
|
|
|
44126
44509
|
return;
|
|
44127
44510
|
}
|
|
44128
44511
|
try {
|
|
44129
|
-
|
|
44130
|
-
throw new Error(RED._("clipboard.import.errors.notArray"));
|
|
44131
|
-
}
|
|
44132
|
-
var res = JSON.parse(v);
|
|
44133
|
-
for (var i=0;i<res.length;i++) {
|
|
44134
|
-
if (typeof res[i] !== "object") {
|
|
44135
|
-
throw new Error(RED._("clipboard.import.errors.itemNotObject",{index:i}));
|
|
44136
|
-
}
|
|
44137
|
-
if (!res[i].hasOwnProperty('id')) {
|
|
44138
|
-
throw new Error(RED._("clipboard.import.errors.missingId",{index:i}));
|
|
44139
|
-
}
|
|
44140
|
-
if (!res[i].hasOwnProperty('type')) {
|
|
44141
|
-
throw new Error(RED._("clipboard.import.errors.missingType",{index:i}));
|
|
44142
|
-
}
|
|
44143
|
-
}
|
|
44512
|
+
validateFlowString(v)
|
|
44144
44513
|
currentPopoverError = null;
|
|
44145
44514
|
popover.close(true);
|
|
44146
44515
|
importInput.removeClass("input-error");
|
|
@@ -44773,16 +45142,16 @@ RED.clipboard = (function() {
|
|
|
44773
45142
|
}
|
|
44774
45143
|
|
|
44775
45144
|
function importNodes(nodesStr,addFlow) {
|
|
44776
|
-
|
|
45145
|
+
let newNodes = nodesStr;
|
|
44777
45146
|
if (typeof nodesStr === 'string') {
|
|
44778
45147
|
try {
|
|
44779
45148
|
nodesStr = nodesStr.trim();
|
|
44780
45149
|
if (nodesStr.length === 0) {
|
|
44781
45150
|
return;
|
|
44782
45151
|
}
|
|
44783
|
-
newNodes =
|
|
45152
|
+
newNodes = validateFlowString(nodesStr)
|
|
44784
45153
|
} catch(err) {
|
|
44785
|
-
|
|
45154
|
+
const e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
|
|
44786
45155
|
e.code = "NODE_RED";
|
|
44787
45156
|
throw e;
|
|
44788
45157
|
}
|
|
@@ -45117,6 +45486,7 @@ RED.clipboard = (function() {
|
|
|
45117
45486
|
}
|
|
45118
45487
|
}
|
|
45119
45488
|
} catch(err) {
|
|
45489
|
+
console.warn('Import failed: ', err)
|
|
45120
45490
|
// Ensure any errors throw above doesn't stop the drop target from
|
|
45121
45491
|
// being hidden.
|
|
45122
45492
|
}
|
|
@@ -47081,15 +47451,15 @@ RED.search = (function() {
|
|
|
47081
47451
|
}
|
|
47082
47452
|
}
|
|
47083
47453
|
|
|
47454
|
+
const scale = RED.view.scale()
|
|
47084
47455
|
const offset = $("#red-ui-workspace-chart").offset()
|
|
47085
|
-
|
|
47086
|
-
let
|
|
47087
|
-
let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()
|
|
47456
|
+
let addX = (options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / scale
|
|
47457
|
+
let addY = (options.y - offset.top + $("#red-ui-workspace-chart").scrollTop()) / scale
|
|
47088
47458
|
|
|
47089
47459
|
if (RED.view.snapGrid) {
|
|
47090
47460
|
const gridSize = RED.view.gridSize()
|
|
47091
|
-
addX = gridSize * Math.
|
|
47092
|
-
addY = gridSize * Math.
|
|
47461
|
+
addX = gridSize * Math.round(addX / gridSize)
|
|
47462
|
+
addY = gridSize * Math.round(addY / gridSize)
|
|
47093
47463
|
}
|
|
47094
47464
|
|
|
47095
47465
|
if (RED.settings.theme("menu.menu-item-action-list", true)) {
|
|
@@ -47114,7 +47484,9 @@ RED.search = (function() {
|
|
|
47114
47484
|
},
|
|
47115
47485
|
(hasLinks) ? { // has least 1 wire selected
|
|
47116
47486
|
label: RED._("contextMenu.junction"),
|
|
47117
|
-
onselect:
|
|
47487
|
+
onselect: function () {
|
|
47488
|
+
RED.actions.invoke('core:split-wires-with-junctions', { x: addX, y: addY })
|
|
47489
|
+
},
|
|
47118
47490
|
disabled: !canEdit || !hasLinks
|
|
47119
47491
|
} : {
|
|
47120
47492
|
label: RED._("contextMenu.junction"),
|
|
@@ -47924,7 +48296,7 @@ RED.actionList = (function() {
|
|
|
47924
48296
|
var items = [];
|
|
47925
48297
|
RED.nodes.registry.getNodeTypes().forEach(function(t) {
|
|
47926
48298
|
var def = RED.nodes.getType(t);
|
|
47927
|
-
if (def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
|
|
48299
|
+
if (def.set?.enabled !== false && def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
|
|
47928
48300
|
items.push({type:t,def: def, label:getTypeLabel(t,def)});
|
|
47929
48301
|
}
|
|
47930
48302
|
});
|
|
@@ -49351,7 +49723,7 @@ RED.subflow = (function() {
|
|
|
49351
49723
|
item.value = ""+input.prop("checked");
|
|
49352
49724
|
break;
|
|
49353
49725
|
case "conf-types":
|
|
49354
|
-
item.value = input.val()
|
|
49726
|
+
item.value = input.val() === "_ADD_" ? "" : input.val();
|
|
49355
49727
|
item.type = "conf-type"
|
|
49356
49728
|
}
|
|
49357
49729
|
if (ui.type === "cred" || item.type !== data.parent.type || item.value !== data.parent.value) {
|