@node-red/editor-client 3.0.0-beta.3 → 3.0.0-beta.4

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/public/red/red.js CHANGED
@@ -388,6 +388,10 @@ var RED = (function() {
388
388
  // handled below
389
389
  return;
390
390
  }
391
+ if (notificationId === "flows-run-state") {
392
+ // handled in editor-client/src/js/runtime.js
393
+ return;
394
+ }
391
395
  if (notificationId === "project-update") {
392
396
  loader.start(RED._("event.loadingProject"), 0);
393
397
  RED.nodes.clear();
@@ -423,7 +427,6 @@ var RED = (function() {
423
427
  id: notificationId
424
428
  }
425
429
  if (notificationId === "runtime-state") {
426
- RED.events.emit("runtime-state",msg);
427
430
  if (msg.error === "safe-mode") {
428
431
  options.buttons = [
429
432
  {
@@ -564,9 +567,9 @@ var RED = (function() {
564
567
  } else if (persistentNotifications.hasOwnProperty(notificationId)) {
565
568
  persistentNotifications[notificationId].close();
566
569
  delete persistentNotifications[notificationId];
567
- if (notificationId === 'runtime-state') {
568
- RED.events.emit("runtime-state",msg);
569
- }
570
+ }
571
+ if (notificationId === 'runtime-state') {
572
+ RED.events.emit("runtime-state",msg);
570
573
  }
571
574
  });
572
575
  RED.comms.subscribe("status/#",function(topic,msg) {
@@ -838,6 +841,7 @@ var RED = (function() {
838
841
  RED.keyboard.init(buildMainMenu);
839
842
 
840
843
  RED.nodes.init();
844
+ RED.runtime.init()
841
845
  RED.comms.connect();
842
846
 
843
847
  $("#red-ui-main-container").show();
@@ -2080,6 +2084,42 @@ RED.comms = (function() {
2080
2084
  unsubscribe:unsubscribe
2081
2085
  }
2082
2086
  })();
2087
+ ;RED.runtime = (function() {
2088
+ let state = ""
2089
+ let settings = { ui: false, enabled: false };
2090
+ const STOPPED = "stop"
2091
+ const STARTED = "start"
2092
+ const SAFE = "safe"
2093
+
2094
+ return {
2095
+ init: function() {
2096
+ // refresh the current runtime status from server
2097
+ settings = Object.assign({}, settings, RED.settings.runtimeState);
2098
+ RED.events.on("runtime-state", function(msg) {
2099
+ if (msg.state) {
2100
+ const currentState = state
2101
+ state = msg.state
2102
+ $(".red-ui-flow-node-button").toggleClass("red-ui-flow-node-button-stopped", state !== STARTED)
2103
+ if(settings.enabled === true && settings.ui === true) {
2104
+ RED.menu.setVisible("deploymenu-item-runtime-stop", state === STARTED)
2105
+ RED.menu.setVisible("deploymenu-item-runtime-start", state !== STARTED)
2106
+ }
2107
+ // Do not notify the user about this event if:
2108
+ // - This is the very first event we've received after loading the editor (currentState = '')
2109
+ // - The state matches what we already thought was the case (state === currentState)
2110
+ // - The event was triggered by a deploy (msg.deploy === true)
2111
+ // - The event is a safe mode event - that gets notified separately
2112
+ if (currentState !== '' && state !== currentState && !msg.deploy && state !== SAFE) {
2113
+ RED.notify(RED._("notification.state.flows"+(state === STOPPED?'Stopped':'Started'), msg), "success")
2114
+ }
2115
+ }
2116
+ });
2117
+ },
2118
+ get started() {
2119
+ return state === STARTED
2120
+ }
2121
+ }
2122
+ })()
2083
2123
  ;/**
2084
2124
  * Copyright JS Foundation and other contributors, http://js.foundation
2085
2125
  *
@@ -3636,7 +3676,7 @@ RED.state = {
3636
3676
  * limitations under the License.
3637
3677
  **/
3638
3678
 
3639
- /**
3679
+ /**
3640
3680
  * An Interface to nodes and utility functions for creating/adding/deleting nodes and links
3641
3681
  * @namespace RED.nodes
3642
3682
  */
@@ -5276,21 +5316,19 @@ RED.nodes = (function() {
5276
5316
  * Options:
5277
5317
  * - generateIds - whether to replace all node ids
5278
5318
  * - addFlow - whether to import nodes to a new tab
5279
- * - importToCurrent
5319
+ * - reimport - if node has a .z property, dont overwrite it
5320
+ * Only applicible when `generateIds` is false
5280
5321
  * - importMap - how to resolve any conflicts.
5281
5322
  * - id:import - import as-is
5282
5323
  * - id:copy - import with new id
5283
5324
  * - id:replace - import over the top of existing
5284
5325
  */
5285
5326
  function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) {
5286
- options = options || {
5287
- generateIds: false,
5288
- addFlow: false,
5289
- }
5290
- options.importMap = options.importMap || {};
5291
-
5292
- var createNewIds = options.generateIds;
5293
- var createMissingWorkspace = options.addFlow;
5327
+ const defOpts = { generateIds: false, addFlow: false, reimport: false, importMap: {} }
5328
+ options = Object.assign({}, defOpts, options)
5329
+ const createNewIds = options.generateIds;
5330
+ const reimport = (!createNewIds && !!options.reimport)
5331
+ const createMissingWorkspace = options.addFlow;
5294
5332
  var i;
5295
5333
  var n;
5296
5334
  var newNodes;
@@ -5591,7 +5629,8 @@ RED.nodes = (function() {
5591
5629
  }
5592
5630
  }
5593
5631
  } else {
5594
- if (n.z && !workspace_map[n.z] && !subflow_map[n.z]) {
5632
+ const keepNodesCurrentZ = reimport && n.z && RED.workspaces.contains(n.z)
5633
+ if (!keepNodesCurrentZ && n.z && !workspace_map[n.z] && !subflow_map[n.z]) {
5595
5634
  n.z = activeWorkspace;
5596
5635
  }
5597
5636
  }
@@ -5692,7 +5731,8 @@ RED.nodes = (function() {
5692
5731
  node.id = getID();
5693
5732
  } else {
5694
5733
  node.id = n.id;
5695
- if (node.z == null || (!workspace_map[node.z] && !subflow_map[node.z])) {
5734
+ const keepNodesCurrentZ = reimport && node.z && RED.workspaces.contains(node.z)
5735
+ if (!keepNodesCurrentZ && (node.z == null || (!workspace_map[node.z] && !subflow_map[node.z]))) {
5696
5736
  if (createMissingWorkspace) {
5697
5737
  if (missingWorkspace === null) {
5698
5738
  missingWorkspace = RED.workspaces.add(null,true);
@@ -6391,7 +6431,7 @@ RED.nodes = (function() {
6391
6431
  // Force the redraw to be synchronous so the view updates
6392
6432
  // *now* and removes the unknown node
6393
6433
  RED.view.redraw(true, true);
6394
- var result = importNodes(reimportList,{generateIds:false});
6434
+ var result = importNodes(reimportList,{generateIds:false, reimport: true});
6395
6435
  var newNodeMap = {};
6396
6436
  result.nodes.forEach(function(n) {
6397
6437
  newNodeMap[n.id] = n;
@@ -10080,6 +10120,7 @@ RED.utils = (function() {
10080
10120
  * - multi : boolean - if true, .selected will return an array of results
10081
10121
  * otherwise, returns the first selected item
10082
10122
  * - sortable: boolean/string - TODO: see editableList
10123
+ * - selectable: boolean - default true - whether individual items can be selected
10083
10124
  * - rootSortable: boolean - if 'sortable' is set, then setting this to
10084
10125
  * false, prevents items being sorted to the
10085
10126
  * top level of the tree
@@ -10177,6 +10218,7 @@ RED.utils = (function() {
10177
10218
  switch(evt.keyCode) {
10178
10219
  case 32: // SPACE
10179
10220
  case 13: // ENTER
10221
+ if (!that.options.selectable) { return }
10180
10222
  if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) {
10181
10223
  return
10182
10224
  }
@@ -11281,6 +11323,8 @@ RED.menu = (function() {
11281
11323
  if (opt.options) {
11282
11324
  item.addClass("red-ui-menu-dropdown-submenu"+(opt.direction!=='right'?" pull-left":""));
11283
11325
  var submenu = $('<ul id="'+opt.id+'-submenu" class="red-ui-menu-dropdown"></ul>').appendTo(item);
11326
+ var hasIcons = false
11327
+ var hasSubmenus = false
11284
11328
 
11285
11329
  for (var i=0;i<opt.options.length;i++) {
11286
11330
 
@@ -11292,6 +11336,8 @@ RED.menu = (function() {
11292
11336
  opt.options[i].onpostselect = opt.onpostselect
11293
11337
  }
11294
11338
  opt.options[i].direction = opt.direction
11339
+ hasIcons = hasIcons || (opt.options[i].icon);
11340
+ hasSubmenus = hasSubmenus || (opt.options[i].options);
11295
11341
  }
11296
11342
 
11297
11343
  var li = createMenuItem(opt.options[i]);
@@ -11299,10 +11345,21 @@ RED.menu = (function() {
11299
11345
  li.appendTo(submenu);
11300
11346
  }
11301
11347
  }
11348
+ if (!hasIcons) {
11349
+ submenu.addClass("red-ui-menu-dropdown-noicons")
11350
+ }
11351
+ if (hasSubmenus) {
11352
+ submenu.addClass("red-ui-menu-dropdown-submenus")
11353
+ }
11354
+
11355
+
11302
11356
  }
11303
11357
  if (opt.disabled) {
11304
11358
  item.addClass("disabled");
11305
11359
  }
11360
+ if (opt.visible === false) {
11361
+ item.addClass("hide");
11362
+ }
11306
11363
  }
11307
11364
 
11308
11365
 
@@ -11339,6 +11396,8 @@ RED.menu = (function() {
11339
11396
  }
11340
11397
 
11341
11398
  var lastAddedSeparator = false;
11399
+ var hasSubmenus = false;
11400
+ var hasIcons = false;
11342
11401
  for (var i=0;i<options.options.length;i++) {
11343
11402
  var opt = options.options[i];
11344
11403
  if (opt) {
@@ -11351,6 +11410,8 @@ RED.menu = (function() {
11351
11410
  opt.direction = options.direction || 'left'
11352
11411
  }
11353
11412
  if (opt !== null || !lastAddedSeparator) {
11413
+ hasIcons = hasIcons || (opt && opt.icon);
11414
+ hasSubmenus = hasSubmenus || (opt && opt.options);
11354
11415
  var li = createMenuItem(opt);
11355
11416
  if (li) {
11356
11417
  li.appendTo(topMenu);
@@ -11358,7 +11419,12 @@ RED.menu = (function() {
11358
11419
  }
11359
11420
  }
11360
11421
  }
11361
-
11422
+ if (!hasIcons) {
11423
+ topMenu.addClass("red-ui-menu-dropdown-noicons")
11424
+ }
11425
+ if (hasSubmenus) {
11426
+ topMenu.addClass("red-ui-menu-dropdown-submenus")
11427
+ }
11362
11428
  return topMenu;
11363
11429
  }
11364
11430
 
@@ -11430,6 +11496,14 @@ RED.menu = (function() {
11430
11496
  }
11431
11497
  }
11432
11498
 
11499
+ function setVisible(id,state) {
11500
+ if (!state) {
11501
+ $("#"+id).parent().addClass("hide");
11502
+ } else {
11503
+ $("#"+id).parent().removeClass("hide");
11504
+ }
11505
+ }
11506
+
11433
11507
  function addItem(id,opt) {
11434
11508
  var item = createMenuItem(opt);
11435
11509
  if (opt !== null && opt.group) {
@@ -11486,6 +11560,7 @@ RED.menu = (function() {
11486
11560
  isSelected: isSelected,
11487
11561
  toggleSelected: toggleSelected,
11488
11562
  setDisabled: setDisabled,
11563
+ setVisible: setVisible,
11489
11564
  addItem: addItem,
11490
11565
  removeItem: removeItem,
11491
11566
  setAction: setAction,
@@ -15362,16 +15437,18 @@ RED.deploy = (function() {
15362
15437
  '</a>'+
15363
15438
  '<a id="red-ui-header-button-deploy-options" class="red-ui-deploy-button" href="#"><i class="fa fa-caret-down"></i></a>'+
15364
15439
  '</span></li>').prependTo(".red-ui-header-toolbar");
15365
- RED.menu.init({id:"red-ui-header-button-deploy-options",
15366
- options: [
15367
- {id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
15368
- {id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
15369
- {id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
15370
- null,
15371
- {id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"},
15372
-
15373
- ]
15374
- });
15440
+ const mainMenuItems = [
15441
+ {id:"deploymenu-item-full",toggle:"deploy-type",icon:"red/images/deploy-full.svg",label:RED._("deploy.full"),sublabel:RED._("deploy.fullDesc"),selected: true, onselect:function(s) { if(s){changeDeploymentType("full")}}},
15442
+ {id:"deploymenu-item-flow",toggle:"deploy-type",icon:"red/images/deploy-flows.svg",label:RED._("deploy.modifiedFlows"),sublabel:RED._("deploy.modifiedFlowsDesc"), onselect:function(s) {if(s){changeDeploymentType("flows")}}},
15443
+ {id:"deploymenu-item-node",toggle:"deploy-type",icon:"red/images/deploy-nodes.svg",label:RED._("deploy.modifiedNodes"),sublabel:RED._("deploy.modifiedNodesDesc"),onselect:function(s) { if(s){changeDeploymentType("nodes")}}},
15444
+ null
15445
+ ]
15446
+ if (RED.settings.runtimeState && RED.settings.runtimeState.ui === true) {
15447
+ mainMenuItems.push({id:"deploymenu-item-runtime-start", icon:"red/images/start.svg",label:"Start"/*RED._("deploy.startFlows")*/,sublabel:"Start Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:start-flows", visible:false})
15448
+ mainMenuItems.push({id:"deploymenu-item-runtime-stop", icon:"red/images/stop.svg",label:"Stop"/*RED._("deploy.startFlows")*/,sublabel:"Stop Flows" /*RED._("deploy.startFlowsDesc")*/,onselect:"core:stop-flows", visible:false})
15449
+ }
15450
+ mainMenuItems.push({id:"deploymenu-item-reload", icon:"red/images/deploy-reload.svg",label:RED._("deploy.restartFlows"),sublabel:RED._("deploy.restartFlowsDesc"),onselect:"core:restart-flows"})
15451
+ RED.menu.init({id:"red-ui-header-button-deploy-options", options: mainMenuItems });
15375
15452
  } else if (type == "simple") {
15376
15453
  var label = options.label || RED._("deploy.deploy");
15377
15454
  var icon = 'red/images/deploy-full-o.svg';
@@ -15399,6 +15476,10 @@ RED.deploy = (function() {
15399
15476
 
15400
15477
  RED.actions.add("core:deploy-flows",save);
15401
15478
  if (type === "default") {
15479
+ if (RED.settings.runtimeState && RED.settings.runtimeState.ui === true) {
15480
+ RED.actions.add("core:stop-flows",function() { stopStartFlows("stop") });
15481
+ RED.actions.add("core:start-flows",function() { stopStartFlows("start") });
15482
+ }
15402
15483
  RED.actions.add("core:restart-flows",restart);
15403
15484
  RED.actions.add("core:set-deploy-type-to-full",function() { RED.menu.setSelected("deploymenu-item-full",true);});
15404
15485
  RED.actions.add("core:set-deploy-type-to-modified-flows",function() { RED.menu.setSelected("deploymenu-item-flow",true); });
@@ -15569,18 +15650,73 @@ RED.deploy = (function() {
15569
15650
  function sanitize(html) {
15570
15651
  return html.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")
15571
15652
  }
15572
- function restart() {
15573
- var startTime = Date.now();
15574
- $(".red-ui-deploy-button-content").css('opacity',0);
15575
- $(".red-ui-deploy-button-spinner").show();
15576
- var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
15577
- $("#red-ui-header-button-deploy").addClass("disabled");
15578
- deployInflight = true;
15653
+
15654
+ function shadeShow() {
15579
15655
  $("#red-ui-header-shade").show();
15580
15656
  $("#red-ui-editor-shade").show();
15581
15657
  $("#red-ui-palette-shade").show();
15582
15658
  $("#red-ui-sidebar-shade").show();
15583
-
15659
+ }
15660
+ function shadeHide() {
15661
+ $("#red-ui-header-shade").hide();
15662
+ $("#red-ui-editor-shade").hide();
15663
+ $("#red-ui-palette-shade").hide();
15664
+ $("#red-ui-sidebar-shade").hide();
15665
+ }
15666
+ function deployButtonSetBusy(){
15667
+ $(".red-ui-deploy-button-content").css('opacity',0);
15668
+ $(".red-ui-deploy-button-spinner").show();
15669
+ $("#red-ui-header-button-deploy").addClass("disabled");
15670
+ }
15671
+ function deployButtonClearBusy(){
15672
+ $(".red-ui-deploy-button-content").css('opacity',1);
15673
+ $(".red-ui-deploy-button-spinner").hide();
15674
+ }
15675
+ function stopStartFlows(state) {
15676
+ const startTime = Date.now()
15677
+ const deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled")
15678
+ deployInflight = true
15679
+ deployButtonSetBusy()
15680
+ shadeShow()
15681
+ $.ajax({
15682
+ url:"flows/state",
15683
+ type: "POST",
15684
+ data: {state: state}
15685
+ }).done(function(data,textStatus,xhr) {
15686
+ if (deployWasEnabled) {
15687
+ $("#red-ui-header-button-deploy").removeClass("disabled")
15688
+ }
15689
+ }).fail(function(xhr,textStatus,err) {
15690
+ if (deployWasEnabled) {
15691
+ $("#red-ui-header-button-deploy").removeClass("disabled")
15692
+ }
15693
+ if (xhr.status === 401) {
15694
+ RED.notify(RED._("notification.error", { message: RED._("user.notAuthorized") }), "error")
15695
+ } else if (xhr.responseText) {
15696
+ const errorDetail = { message: err ? (err + "") : "" }
15697
+ try {
15698
+ errorDetail.message = JSON.parse(xhr.responseText).message
15699
+ } finally {
15700
+ errorDetail.message = errorDetail.message || xhr.responseText
15701
+ }
15702
+ RED.notify(RED._("notification.error", errorDetail), "error")
15703
+ } else {
15704
+ RED.notify(RED._("notification.error", { message: RED._("deploy.errors.noResponse") }), "error")
15705
+ }
15706
+ }).always(function() {
15707
+ const delta = Math.max(0, 300 - (Date.now() - startTime))
15708
+ setTimeout(function () {
15709
+ deployButtonClearBusy()
15710
+ shadeHide()
15711
+ deployInflight = false
15712
+ }, delta);
15713
+ });
15714
+ }
15715
+ function restart() {
15716
+ var startTime = Date.now();
15717
+ var deployWasEnabled = !$("#red-ui-header-button-deploy").hasClass("disabled");
15718
+ deployInflight = true;
15719
+ deployButtonSetBusy();
15584
15720
  $.ajax({
15585
15721
  url:"flows",
15586
15722
  type: "POST",
@@ -15606,15 +15742,10 @@ RED.deploy = (function() {
15606
15742
  RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
15607
15743
  }
15608
15744
  }).always(function() {
15609
- deployInflight = false;
15610
15745
  var delta = Math.max(0,300-(Date.now()-startTime));
15611
15746
  setTimeout(function() {
15612
- $(".red-ui-deploy-button-content").css('opacity',1);
15613
- $(".red-ui-deploy-button-spinner").hide();
15614
- $("#red-ui-header-shade").hide();
15615
- $("#red-ui-editor-shade").hide();
15616
- $("#red-ui-palette-shade").hide();
15617
- $("#red-ui-sidebar-shade").hide();
15747
+ deployButtonClearBusy();
15748
+ deployInflight = false;
15618
15749
  },delta);
15619
15750
  });
15620
15751
  }
@@ -15749,21 +15880,14 @@ RED.deploy = (function() {
15749
15880
  const nns = RED.nodes.createCompleteNodeSet();
15750
15881
  const startTime = Date.now();
15751
15882
 
15752
- $(".red-ui-deploy-button-content").css('opacity', 0);
15753
- $(".red-ui-deploy-button-spinner").show();
15754
- $("#red-ui-header-button-deploy").addClass("disabled");
15755
-
15883
+ deployButtonSetBusy();
15756
15884
  const data = { flows: nns };
15757
-
15758
15885
  if (!force) {
15759
15886
  data.rev = RED.nodes.version();
15760
15887
  }
15761
15888
 
15762
15889
  deployInflight = true;
15763
- $("#red-ui-header-shade").show();
15764
- $("#red-ui-editor-shade").show();
15765
- $("#red-ui-palette-shade").show();
15766
- $("#red-ui-sidebar-shade").show();
15890
+ shadeShow();
15767
15891
  $.ajax({
15768
15892
  url: "flows",
15769
15893
  type: "POST",
@@ -15849,15 +15973,11 @@ RED.deploy = (function() {
15849
15973
  RED.notify(RED._("deploy.deployFailed", { message: RED._("deploy.errors.noResponse") }), "error");
15850
15974
  }
15851
15975
  }).always(function () {
15852
- deployInflight = false;
15853
15976
  const delta = Math.max(0, 300 - (Date.now() - startTime));
15854
15977
  setTimeout(function () {
15855
- $(".red-ui-deploy-button-content").css('opacity', 1);
15856
- $(".red-ui-deploy-button-spinner").hide();
15857
- $("#red-ui-header-shade").hide();
15858
- $("#red-ui-editor-shade").hide();
15859
- $("#red-ui-palette-shade").hide();
15860
- $("#red-ui-sidebar-shade").hide();
15978
+ deployInflight = false;
15979
+ deployButtonClearBusy()
15980
+ shadeHide()
15861
15981
  }, delta);
15862
15982
  });
15863
15983
  }
@@ -19146,9 +19266,22 @@ RED.workspaces = (function() {
19146
19266
  onselect: "core:show-last-hidden-flow"
19147
19267
  }
19148
19268
  ]
19149
- if (hideStack.length > 0) {
19269
+ let hiddenFlows = new Set()
19270
+ for (let i = 0; i < hideStack.length; i++) {
19271
+ let ids = hideStack[i]
19272
+ if (!Array.isArray(ids)) {
19273
+ ids = [ids]
19274
+ }
19275
+ ids.forEach(id => {
19276
+ if (RED.nodes.workspace(id)) {
19277
+ hiddenFlows.add(id)
19278
+ }
19279
+ })
19280
+ }
19281
+ const flowCount = hiddenFlows.size;
19282
+ if (flowCount > 0) {
19150
19283
  menuItems.unshift({
19151
- label: RED._("workspace.hiddenFlows",{count: hideStack.length}),
19284
+ label: RED._("workspace.hiddenFlows",{count: flowCount}),
19152
19285
  onselect: "core:list-hidden-flows"
19153
19286
  })
19154
19287
  }
@@ -20539,6 +20672,7 @@ RED.view = (function() {
20539
20672
  if (RED.view.DEBUG) {
20540
20673
  console.warn("canvasMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
20541
20674
  }
20675
+ RED.contextMenu.hide();
20542
20676
  if (mouse_mode === RED.state.SELECTING_NODE) {
20543
20677
  d3.event.stopPropagation();
20544
20678
  return;
@@ -20622,8 +20756,8 @@ RED.view = (function() {
20622
20756
  var oy = point[1];
20623
20757
 
20624
20758
  const offset = $("#red-ui-workspace-chart").offset()
20625
- var clientX = ox + offset.left
20626
- var clientY = oy + offset.top
20759
+ var clientX = ox + offset.left - $("#red-ui-workspace-chart").scrollLeft()
20760
+ var clientY = oy + offset.top - $("#red-ui-workspace-chart").scrollTop()
20627
20761
 
20628
20762
  if (RED.settings.get("editor").view['view-snap-grid']) {
20629
20763
  // eventLayer.append("circle").attr("cx",point[0]).attr("cy",point[1]).attr("r","2").attr('fill','red')
@@ -21330,6 +21464,9 @@ RED.view = (function() {
21330
21464
  }
21331
21465
  var i;
21332
21466
  var historyEvent;
21467
+ if (d3.event.button === 2) {
21468
+ return
21469
+ }
21333
21470
  if (mouse_mode === RED.state.PANNING) {
21334
21471
  resetMouseVars();
21335
21472
  return
@@ -22454,6 +22591,7 @@ RED.view = (function() {
22454
22591
 
22455
22592
  function portMouseDown(d,portType,portIndex, evt) {
22456
22593
  if (RED.view.DEBUG) { console.warn("portMouseDown", mouse_mode,d,portType,portIndex); }
22594
+ RED.contextMenu.hide();
22457
22595
  evt = evt || d3.event;
22458
22596
  if (evt === 1) {
22459
22597
  return;
@@ -22962,6 +23100,7 @@ RED.view = (function() {
22962
23100
  function nodeMouseDown(d) {
22963
23101
  if (RED.view.DEBUG) { console.warn("nodeMouseDown", mouse_mode,d); }
22964
23102
  focusView();
23103
+ RED.contextMenu.hide();
22965
23104
  if (d3.event.button === 1) {
22966
23105
  return;
22967
23106
  }
@@ -23344,6 +23483,7 @@ RED.view = (function() {
23344
23483
  if (RED.view.DEBUG) {
23345
23484
  console.warn("linkMouseDown", { mouse_mode, point: d3.mouse(this), event: d3.event });
23346
23485
  }
23486
+ RED.contextMenu.hide();
23347
23487
  if (mouse_mode === RED.state.SELECTING_NODE) {
23348
23488
  d3.event.stopPropagation();
23349
23489
  return;
@@ -23403,6 +23543,9 @@ RED.view = (function() {
23403
23543
  }
23404
23544
 
23405
23545
  function groupMouseUp(g) {
23546
+ if (RED.view.DEBUG) {
23547
+ console.warn("groupMouseUp", { mouse_mode, event: d3.event });
23548
+ }
23406
23549
  if (dblClickPrimed && mousedown_group == g && clickElapsed > 0 && clickElapsed < dblClickInterval) {
23407
23550
  mouse_mode = RED.state.DEFAULT;
23408
23551
  RED.editor.editGroup(g);
@@ -23418,6 +23561,10 @@ RED.view = (function() {
23418
23561
  // return
23419
23562
  // }
23420
23563
 
23564
+ if (RED.view.DEBUG) {
23565
+ console.warn("groupMouseDown", { mouse_mode, point: mouse, event: d3.event });
23566
+ }
23567
+ RED.contextMenu.hide();
23421
23568
  focusView();
23422
23569
  if (d3.event.button === 1) {
23423
23570
  return;
@@ -24414,6 +24561,9 @@ RED.view = (function() {
24414
24561
  if (d._def.button) {
24415
24562
  var buttonEnabled = isButtonEnabled(d);
24416
24563
  this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-disabled", !buttonEnabled);
24564
+ if (RED.runtime && Object.hasOwn(RED.runtime,'started')) {
24565
+ this.__buttonGroup__.classList.toggle("red-ui-flow-node-button-stopped", !RED.runtime.started);
24566
+ }
24417
24567
 
24418
24568
  var x = d._def.align == "right"?d.w-6:-25;
24419
24569
  if (d._def.button.toggle && !d[d._def.button.toggle]) {
@@ -25409,6 +25559,7 @@ RED.view = (function() {
25409
25559
  * @private
25410
25560
  */
25411
25561
  function createNode(type, x, y, z) {
25562
+ const wasDirty = RED.nodes.dirty()
25412
25563
  var m = /^subflow:(.+)$/.exec(type);
25413
25564
  var activeSubflow = z ? RED.nodes.subflow(z) : null;
25414
25565
  if (activeSubflow && m) {
@@ -25467,7 +25618,7 @@ RED.view = (function() {
25467
25618
  var historyEvent = {
25468
25619
  t: "add",
25469
25620
  nodes: [nn.id],
25470
- dirty: RED.nodes.dirty()
25621
+ dirty: wasDirty
25471
25622
  }
25472
25623
  if (activeSubflow) {
25473
25624
  var subflowRefresh = RED.subflow.refresh(true);
@@ -27062,13 +27213,14 @@ RED.view.tools = (function() {
27062
27213
  * - it uses `<paletteLabel> <N>` - where N is the next available integer that
27063
27214
  * doesn't clash with any existing nodes of that type
27064
27215
  * @param {Object} node The node to set the name of - if not provided, uses current selection
27216
+ * @param {{ renameBlank: boolean, renameClash: boolean, generateHistory: boolean }} options Possible options are `renameBlank`, `renameClash` and `generateHistory`
27065
27217
  */
27066
27218
  function generateNodeNames(node, options) {
27067
- options = options || {
27219
+ options = Object.assign({
27068
27220
  renameBlank: true,
27069
27221
  renameClash: true,
27070
27222
  generateHistory: true
27071
- }
27223
+ }, options)
27072
27224
  let nodes = node;
27073
27225
  if (node) {
27074
27226
  if (!Array.isArray(node)) {
@@ -29620,10 +29772,8 @@ RED.sidebar.help = (function() {
29620
29772
  var helpSection;
29621
29773
  var panels;
29622
29774
  var panelRatio;
29623
- var helpTopics = [];
29624
29775
  var treeList;
29625
29776
  var tocPanel;
29626
- var helpIndex = {};
29627
29777
 
29628
29778
  function resizeStack() {
29629
29779
  var h = $(content).parent().height() - toolbar.outerHeight();
@@ -29697,7 +29847,10 @@ RED.sidebar.help = (function() {
29697
29847
  var pendingContentLoad;
29698
29848
  treeList.on('treelistselect', function(e,item) {
29699
29849
  pendingContentLoad = item;
29700
- if (item.nodeType) {
29850
+ if (item.tour) {
29851
+ RED.tourGuide.run(item.tour);
29852
+ }
29853
+ else if (item.nodeType) {
29701
29854
  showNodeTypeHelp(item.nodeType);
29702
29855
  } else if (item.content) {
29703
29856
  helpSection.empty();
@@ -29789,7 +29942,6 @@ RED.sidebar.help = (function() {
29789
29942
  }
29790
29943
 
29791
29944
  function refreshHelpIndex() {
29792
- helpTopics = [];
29793
29945
  var modules = RED.nodes.registry.getModuleList();
29794
29946
  var moduleNames = Object.keys(modules);
29795
29947
  moduleNames.sort();
@@ -29798,15 +29950,32 @@ RED.sidebar.help = (function() {
29798
29950
  label: RED._("sidebar.help.nodeHelp"),
29799
29951
  children: [],
29800
29952
  expanded: true
29801
- }
29953
+ };
29954
+ var tours = RED.tourGuide.list().map(function (item) {
29955
+ return {
29956
+ icon: "fa fa-play-circle-o",
29957
+ label: item.label,
29958
+ tour: item.path,
29959
+ };
29960
+ });
29802
29961
  var helpData = [
29803
29962
  {
29804
- id: 'changelog',
29805
- label: "Node-RED v"+RED.settings.version,
29806
- content: getChangelog
29963
+ label: "Node-RED",
29964
+ children: [
29965
+ {
29966
+ id: 'changelog',
29967
+ label: RED._("sidebar.help.changeLog"),
29968
+ content: getChangelog
29969
+ },
29970
+ {
29971
+ label: RED._("tourGuide.welcomeTours"),
29972
+ children: tours
29973
+ }
29974
+
29975
+ ]
29807
29976
  },
29808
29977
  nodeHelp
29809
- ]
29978
+ ];
29810
29979
  var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)});
29811
29980
  if (subflows.length > 0) {
29812
29981
  nodeHelp.children.push({
@@ -34152,8 +34321,7 @@ RED.editor = (function() {
34152
34321
  if (!node._def.defaults || !node._def.defaults.hasOwnProperty("icon")) {
34153
34322
  var icon = $("#red-ui-editor-node-icon").val()||"";
34154
34323
  if (!this.isDefaultIcon) {
34155
- if ((icon !== node.icon) &&
34156
- (icon !== "")) {
34324
+ if ((node.icon && icon !== node.icon) || (!node.icon && icon !== "")) {
34157
34325
  editState.changes.icon = node.icon;
34158
34326
  node.icon = icon;
34159
34327
  editState.changed = true;
@@ -35459,7 +35627,7 @@ RED.editor = (function() {
35459
35627
 
35460
35628
  const MONACO = "monaco";
35461
35629
  const ACE = "ace";
35462
- const defaultEditor = ACE;
35630
+ const defaultEditor = MONACO;
35463
35631
  const DEFAULT_SETTINGS = { lib: defaultEditor, options: {} };
35464
35632
  var selectedCodeEditor = null;
35465
35633
  var initialised = false;
@@ -35486,12 +35654,12 @@ RED.editor = (function() {
35486
35654
  }
35487
35655
 
35488
35656
  function create(options) {
35489
- //TODO: (quandry - for consideration)
35657
+ //TODO: (quandry - for consideration)
35490
35658
  // Below, I had to create a hidden element if options.id || options.element is not in the DOM
35491
- // I have seen 1 node calling `this.editor = RED.editor.createEditor()` with an
35659
+ // I have seen 1 node calling `this.editor = RED.editor.createEditor()` with an
35492
35660
  // invalid (non existing html element selector) (e.g. node-red-contrib-components does this)
35493
- // This causes monaco to throw an error when attempting to hook up its events to the dom & the rest of the 'oneditperapre'
35494
- // code is thus skipped.
35661
+ // This causes monaco to throw an error when attempting to hook up its events to the dom & the rest of the 'oneditperapre'
35662
+ // code is thus skipped.
35495
35663
  // In ACE mode, creating an ACE editor (with an invalid ID) allows the editor to be created (but obviously there is no UI)
35496
35664
  // Because one (or more) contrib nodes have left this bad code in place, how would we handle this?
35497
35665
  // For compatibility, I have decided to create a hidden element so that at least an editor is created & errors do not occur.
@@ -35517,7 +35685,7 @@ RED.editor = (function() {
35517
35685
  return this.editor.create(options);//fallback to ACE
35518
35686
  }
35519
35687
  }
35520
-
35688
+
35521
35689
  return {
35522
35690
  init: init,
35523
35691
  /**
@@ -35529,7 +35697,7 @@ RED.editor = (function() {
35529
35697
  },
35530
35698
  /**
35531
35699
  * Get user selected code editor
35532
- * @return {string} Returns
35700
+ * @return {string} Returns
35533
35701
  * @memberof RED.editor.codeEditor
35534
35702
  */
35535
35703
  get editor() {
@@ -35542,7 +35710,8 @@ RED.editor = (function() {
35542
35710
  */
35543
35711
  create: create
35544
35712
  }
35545
- })();;RED.editor.colorPicker = RED.colorPicker = (function() {
35713
+ })();
35714
+ ;RED.editor.colorPicker = RED.colorPicker = (function() {
35546
35715
 
35547
35716
  function create(options) {
35548
35717
  var color = options.value;
@@ -35794,8 +35963,12 @@ RED.editor = (function() {
35794
35963
  style: "width:100%",
35795
35964
  class: "node-input-env-value",
35796
35965
  type: "text",
35797
- }).attr("autocomplete","disable").appendTo(envRow)
35798
- valueField.typedInput({default:'str',types:isTemplateNode?DEFAULT_ENV_TYPE_LIST:DEFAULT_ENV_TYPE_LIST_INC_CRED});
35966
+ }).attr("autocomplete","disable").appendTo(envRow);
35967
+ var types = (opt.ui && opt.ui.opts && opt.ui.opts.types);
35968
+ if (!types) {
35969
+ types = isTemplateNode ? DEFAULT_ENV_TYPE_LIST : DEFAULT_ENV_TYPE_LIST_INC_CRED;
35970
+ }
35971
+ valueField.typedInput({default:'str',types:types});
35799
35972
  valueField.typedInput('type', opt.type);
35800
35973
  if (opt.type === "cred") {
35801
35974
  if (opt.value) {
@@ -35847,6 +36020,11 @@ RED.editor = (function() {
35847
36020
  }
35848
36021
  opt.ui.label = opt.ui.label || {};
35849
36022
  opt.ui.type = opt.ui.type || "input";
36023
+ if ((opt.ui.type === "cred") &&
36024
+ opt.ui.opts &&
36025
+ opt.ui.opts.types) {
36026
+ opt.ui.type = "input";
36027
+ }
35850
36028
 
35851
36029
  var uiRow = $('<div/>').appendTo(container).hide();
35852
36030
  // save current info for reverting on cancel
@@ -37476,6 +37654,7 @@ RED.editor = (function() {
37476
37654
  var container = $("#red-ui-editor-type-json-tab-ui-container").css({"height":"100%"});
37477
37655
  var filterDepth = Infinity;
37478
37656
  var list = $('<div class="red-ui-debug-msg-payload red-ui-editor-type-json-editor">').appendTo(container).treeList({
37657
+ selectable: false,
37479
37658
  rootSortable: false,
37480
37659
  sortable: ".red-ui-editor-type-json-editor-item-handle",
37481
37660
  }).on("treelistchangeparent", function(event, evt) {
@@ -43246,10 +43425,10 @@ RED.search = (function() {
43246
43425
  const menuItems = [
43247
43426
  { onselect: 'core:show-action-list', onpostselect: function() {} },
43248
43427
  {
43249
- label: 'Insert',
43428
+ label: RED._("contextMenu.insert"),
43250
43429
  options: [
43251
43430
  {
43252
- label: 'Node',
43431
+ label: RED._("contextMenu.node"),
43253
43432
  onselect: function() {
43254
43433
  RED.view.showQuickAddDialog({
43255
43434
  position: [ options.x - offset.left, options.y - offset.top ],
@@ -43260,12 +43439,12 @@ RED.search = (function() {
43260
43439
  }
43261
43440
  },
43262
43441
  {
43263
- label: 'Junction',
43442
+ label: RED._("contextMenu.junction"),
43264
43443
  onselect: 'core:split-wires-with-junctions',
43265
43444
  disabled: hasSelection || !hasLinks
43266
43445
  },
43267
43446
  {
43268
- label: 'Link Nodes',
43447
+ label: RED._("contextMenu.linkNodes"),
43269
43448
  onselect: 'core:split-wire-with-link-nodes',
43270
43449
  disabled: hasSelection || !hasLinks
43271
43450
  }
@@ -43368,7 +43547,8 @@ RED.search = (function() {
43368
43547
  }
43369
43548
 
43370
43549
  return {
43371
- show: show
43550
+ show: show,
43551
+ hide: disposeMenu
43372
43552
  }
43373
43553
  })()
43374
43554
  ;/**
@@ -52943,9 +53123,30 @@ RED.touch.radialMenu = (function() {
52943
53123
  })
52944
53124
  }
52945
53125
 
53126
+ function listTour() {
53127
+ return [
53128
+ {
53129
+ id: "3_0",
53130
+ label: "3.0.0-beta.4",
53131
+ path: "./tours/welcome.js"
53132
+ },
53133
+ {
53134
+ id: "2_2",
53135
+ label: "2.2.0",
53136
+ path: "./tours/2.2/welcome.js"
53137
+ },
53138
+ {
53139
+ id: "2_1",
53140
+ label: "2.1.0",
53141
+ path: "./tours/2.1/welcome.js"
53142
+ }
53143
+ ];
53144
+ }
53145
+
52946
53146
  return {
52947
53147
  load: loadTour,
52948
53148
  run: run,
53149
+ list: listTour,
52949
53150
  reset: function() {
52950
53151
  RED.settings.set("editor.tours.welcome",'');
52951
53152
  }