@node-red/editor-client 4.0.6 → 4.0.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/editor-client",
3
- "version": "4.0.6",
3
+ "version": "4.0.8",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
package/public/red/about CHANGED
@@ -1,3 +1,17 @@
1
+ #### 4.0.7: Maintenance Release
2
+
3
+ Editor
4
+
5
+ - Fix config node sort order when importing (#5000) @knolleary
6
+
7
+ #### 4.0.7: Maintenance Release
8
+
9
+ Editor
10
+
11
+ - Fix def can be undefined if the type is missing (#4997) @GogoVega
12
+ - Fix the user list of nested config node (#4995) @GogoVega
13
+ - Support custom login message and button (#4993) @knolleary
14
+
1
15
  #### 4.0.6: Maintenance Release
2
16
 
3
17
  Editor
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 ) {
@@ -5129,12 +5160,15 @@ RED.nodes = (function() {
5129
5160
  }
5130
5161
  n["_"] = RED._;
5131
5162
  }
5163
+
5164
+ // Both node and config node can use a config node
5165
+ updateConfigNodeUsers(newNode, { action: "add" });
5166
+
5132
5167
  if (n._def.category == "config") {
5133
5168
  configNodes[n.id] = newNode;
5134
5169
  } else {
5135
5170
  if (n.wires && (n.wires.length > n.outputs)) { n.outputs = n.wires.length; }
5136
5171
  n.dirty = true;
5137
- updateConfigNodeUsers(newNode, { action: "add" });
5138
5172
  if (n._def.category == "subflows" && typeof n.i === "undefined") {
5139
5173
  var nextId = 0;
5140
5174
  RED.nodes.eachNode(function(node) {
@@ -5196,9 +5230,11 @@ RED.nodes = (function() {
5196
5230
  var removedLinks = [];
5197
5231
  var removedNodes = [];
5198
5232
  var node;
5233
+
5199
5234
  if (id in configNodes) {
5200
5235
  node = configNodes[id];
5201
5236
  delete configNodes[id];
5237
+ updateConfigNodeUsers(node, { action: "remove" });
5202
5238
  RED.events.emit('nodes:remove',node);
5203
5239
  RED.workspaces.refresh();
5204
5240
  } else if (allNodes.hasNode(id)) {
@@ -5208,6 +5244,8 @@ RED.nodes = (function() {
5208
5244
  removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
5209
5245
  removedLinks.forEach(removeLink);
5210
5246
  updateConfigNodeUsers(node, { action: "remove" });
5247
+
5248
+ // TODO: Legacy code for exclusive config node
5211
5249
  var updatedConfigNode = false;
5212
5250
  for (var d in node._def.defaults) {
5213
5251
  if (node._def.defaults.hasOwnProperty(d)) {
@@ -6514,6 +6552,8 @@ RED.nodes = (function() {
6514
6552
  activeWorkspace = RED.workspaces.active();
6515
6553
  }
6516
6554
 
6555
+ const pendingConfigNodes = []
6556
+ const pendingConfigNodeIds = new Set()
6517
6557
  // Find all config nodes and add them
6518
6558
  for (i=0;i<newNodes.length;i++) {
6519
6559
  n = newNodes[i];
@@ -6573,7 +6613,8 @@ RED.nodes = (function() {
6573
6613
  type:n.type,
6574
6614
  info: n.info,
6575
6615
  users:[],
6576
- _config:{}
6616
+ _config:{},
6617
+ _configNodeReferences: new Set()
6577
6618
  };
6578
6619
  if (!n.z) {
6579
6620
  delete configNode.z;
@@ -6588,6 +6629,9 @@ RED.nodes = (function() {
6588
6629
  if (def.defaults.hasOwnProperty(d)) {
6589
6630
  configNode[d] = n[d];
6590
6631
  configNode._config[d] = JSON.stringify(n[d]);
6632
+ if (def.defaults[d].type) {
6633
+ configNode._configNodeReferences.add(n[d])
6634
+ }
6591
6635
  }
6592
6636
  }
6593
6637
  if (def.hasOwnProperty('credentials') && n.hasOwnProperty('credentials')) {
@@ -6604,11 +6648,55 @@ RED.nodes = (function() {
6604
6648
  configNode.id = getID();
6605
6649
  }
6606
6650
  node_map[n.id] = configNode;
6607
- new_nodes.push(configNode);
6651
+ pendingConfigNodes.push(configNode);
6652
+ pendingConfigNodeIds.add(configNode.id)
6608
6653
  }
6609
6654
  }
6610
6655
  }
6611
6656
 
6657
+ // We need to sort new_nodes (which only contains config nodes at this point)
6658
+ // to ensure they get added in the right order. If NodeA depends on NodeB, then
6659
+ // NodeB must be added first.
6660
+
6661
+ // Limit us to 5 full iterations of the list - this should be more than
6662
+ // enough to process the list as config->config node relationships are
6663
+ // not very common
6664
+ let iterationLimit = pendingConfigNodes.length * 5
6665
+ const handledConfigNodes = new Set()
6666
+ while (pendingConfigNodes.length > 0 && iterationLimit > 0) {
6667
+ const node = pendingConfigNodes.shift()
6668
+ let hasPending = false
6669
+ // Loop through the nodes referenced by this node to see if anything
6670
+ // is pending
6671
+ node._configNodeReferences.forEach(id => {
6672
+ if (pendingConfigNodeIds.has(id) && !handledConfigNodes.has(id)) {
6673
+ // This reference is for a node we know is in this import, but
6674
+ // it isn't added yet - flag as pending
6675
+ hasPending = true
6676
+ }
6677
+ })
6678
+ if (!hasPending) {
6679
+ // This node has no pending config node references - safe to add
6680
+ delete node._configNodeReferences
6681
+ new_nodes.push(node)
6682
+ handledConfigNodes.add(node.id)
6683
+ } else {
6684
+ // This node has pending config node references
6685
+ // Put to the back of the queue
6686
+ pendingConfigNodes.push(node)
6687
+ }
6688
+ iterationLimit--
6689
+ }
6690
+ if (pendingConfigNodes.length > 0) {
6691
+ // We exceeded the iteration count. Could be due to reference loops
6692
+ // between the config nodes. At this point, just add the remaining
6693
+ // nodes as-is
6694
+ pendingConfigNodes.forEach(node => {
6695
+ delete node._configNodeReferences
6696
+ new_nodes.push(node)
6697
+ })
6698
+ }
6699
+
6612
6700
  // Find regular flow nodes and subflow instances
6613
6701
  for (i=0;i<newNodes.length;i++) {
6614
6702
  n = newNodes[i];
@@ -6779,13 +6867,13 @@ RED.nodes = (function() {
6779
6867
  node.type = "unknown";
6780
6868
  }
6781
6869
  if (node._def.category != "config") {
6782
- if (n.hasOwnProperty('inputs') && def.defaults.hasOwnProperty("inputs")) {
6870
+ if (n.hasOwnProperty('inputs') && node._def.defaults.hasOwnProperty("inputs")) {
6783
6871
  node.inputs = parseInt(n.inputs, 10);
6784
6872
  node._config.inputs = JSON.stringify(n.inputs);
6785
6873
  } else {
6786
6874
  node.inputs = node._def.inputs;
6787
6875
  }
6788
- if (n.hasOwnProperty('outputs') && def.defaults.hasOwnProperty("outputs")) {
6876
+ if (n.hasOwnProperty('outputs') && node._def.defaults.hasOwnProperty("outputs")) {
6789
6877
  node.outputs = parseInt(n.outputs, 10);
6790
6878
  node._config.outputs = JSON.stringify(n.outputs);
6791
6879
  } else {
@@ -7146,6 +7234,7 @@ RED.nodes = (function() {
7146
7234
  var property = node._def.defaults[d];
7147
7235
  if (property.type) {
7148
7236
  var type = registry.getNodeType(property.type);
7237
+ // Need to ensure the type is a config node to not treat links nodes
7149
7238
  if (type && type.category == "config") {
7150
7239
  var configNode = configNodes[node[d]];
7151
7240
  if (configNode) {