@kumologica/sdk 3.5.4 → 3.6.0-alpha7

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.
Files changed (36) hide show
  1. package/cli/cli.js +31 -8
  2. package/cli/commands/open.js +88 -15
  3. package/cli/commands/run.js +167 -0
  4. package/cli/commands/serve.js +139 -0
  5. package/package.json +5 -5
  6. package/src/app/main-process/main-window.js +1 -0
  7. package/src/app/main-process/modal-home.js +1 -0
  8. package/src/app/main-process/modal-newproject.js +1 -0
  9. package/src/app/main-process/modal-newtab.js +1 -0
  10. package/src/app/main-process/modal-nodelibrary.js +1 -0
  11. package/src/app/main-process/modal-renameTab.js +1 -0
  12. package/src/app/main-process/modal-welcome.js +1 -0
  13. package/src/app/main.js +179 -141
  14. package/src/app/preload.js +225 -139
  15. package/src/app/ui/editor-client/public/red/red.js +1943 -783
  16. package/src/app/ui/editor-client/public/red/red.min.js +2 -2
  17. package/src/app/ui/editor-client/public/red/style.min.css +1 -1
  18. package/src/app/ui/editor-client/public/vendor/ace-linters/javascript-service.js +10 -2
  19. package/src/app/ui/editor-client/src/js/red.js +183 -179
  20. package/src/app/ui/editor-client/src/js/ui/common/commandBox.js +107 -0
  21. package/src/app/ui/editor-client/src/js/ui/common/searchBox.js +91 -90
  22. package/src/app/ui/editor-client/src/js/ui/modules.js +164 -0
  23. package/src/app/ui/editor-client/src/js/ui/search.js +171 -123
  24. package/src/app/ui/editor-client/src/js/ui/sidebar.js +1 -1
  25. package/src/app/ui/editor-client/src/js/ui/ui-settings.js +419 -410
  26. package/src/app/ui/editor-client/src/sass/editor.scss +745 -746
  27. package/src/app/ui/editor-client/src/sass/forms.scss +1 -1
  28. package/src/app/ui/editor-client/src/sass/search.scss +16 -2
  29. package/src/app/ui/editor-client/src/sass/sidebar.scss +1 -1
  30. package/src/app/ui/editor-client/src/sass/style.scss +72 -69
  31. package/src/app/ui/editor-client/src/sass/ui/common/commandBox.scss +100 -0
  32. package/src/app/ui/editor-client/src/sass/ui/common/searchBox.scss +3 -2
  33. package/src/app/ui/editor-client/src/sass/ui-settings.scss +14 -14
  34. package/src/app/ui/editor-client/src/vendor/ace-linters/build/javascript-service.js +10 -2
  35. package/src/app/ui/editor-client/templates/index.mst +2 -2
  36. package/src/server/DesignerServer.js +152 -153
@@ -11,15 +11,15 @@ RED.search = (function () {
11
11
  var results = [];
12
12
 
13
13
  function indexProperty(node, label, property) {
14
- if (typeof property === 'string' || typeof property === 'number') {
15
- property = ('' + property).toLowerCase();
14
+ if (typeof property === "string" || typeof property === "number") {
15
+ property = ("" + property).toLowerCase();
16
16
  index[property] = index[property] || {};
17
17
  index[property][node.id] = { node: node, label: label };
18
18
  } else if (Array.isArray(property)) {
19
19
  property.forEach(function (prop) {
20
20
  indexProperty(node, label, prop);
21
21
  });
22
- } else if (typeof property === 'object') {
22
+ } else if (typeof property === "object") {
23
23
  for (var prop in property) {
24
24
  if (property.hasOwnProperty(prop)) {
25
25
  indexProperty(node, label, property[prop]);
@@ -30,13 +30,13 @@ RED.search = (function () {
30
30
  function indexNode(n) {
31
31
  var l = RED.utils.getNodeLabel(n);
32
32
  if (l) {
33
- l = ('' + l).toLowerCase();
33
+ l = ("" + l).toLowerCase();
34
34
  index[l] = index[l] || {};
35
35
  index[l][n.id] = { node: n, label: l };
36
36
  }
37
- l = l || n.label || n.name || n.id || '';
37
+ l = l || n.label || n.name || n.id || "";
38
38
 
39
- var properties = ['id', 'type', 'name', 'label', 'info'];
39
+ var properties = ["id", "type", "name", "label", "info"];
40
40
  if (n._def && n._def.defaults) {
41
41
  properties = properties.concat(Object.keys(n._def.defaults));
42
42
  }
@@ -64,14 +64,14 @@ RED.search = (function () {
64
64
 
65
65
  /**
66
66
  * User search when typing it the search box...
67
- * @param {string} val
67
+ * @param {string} val
68
68
  */
69
69
  function search(val) {
70
- searchResults.editableList('empty');
70
+ searchResults.editableList("empty");
71
71
  var typeFilter;
72
72
  var m = /(?:^| )type:([^ ]+)/.exec(val);
73
73
  if (m) {
74
- val = val.replace(/(?:^| )type:[^ ]+/, '');
74
+ val = val.replace(/(?:^| )type:[^ ]+/, "");
75
75
  typeFilter = m[1];
76
76
  }
77
77
 
@@ -83,27 +83,25 @@ RED.search = (function () {
83
83
  // Excluding tabs
84
84
  // results = results.filter((r) => r.node.type !== 'tab');
85
85
  for (i = 0; i < Math.min(results.length, 25); i++) {
86
- searchResults.editableList('addItem', results[i]);
86
+ searchResults.editableList("addItem", results[i]);
87
87
  }
88
88
  } else {
89
- searchResults.editableList('addItem', {});
89
+ searchResults.editableList("addItem", {});
90
90
  }
91
91
  } else {
92
92
  let commands = searchCommands();
93
- commands.forEach(c => {
94
- searchResults.editableList('addItem', c);
93
+ commands.forEach((c) => {
94
+ searchResults.editableList("addItem", c);
95
95
  });
96
96
 
97
- let results = $('#search-result-list');
97
+ let results = $("#search-result-list");
98
98
  $('<div class="searchSeparator"></div>').appendTo(results);
99
99
 
100
-
101
100
  let allNodes = searchNodes();
102
101
 
103
- allNodes.forEach(n => {
104
- searchResults.editableList('addItem', n);
105
- })
106
-
102
+ allNodes.forEach((n) => {
103
+ searchResults.editableList("addItem", n);
104
+ });
107
105
  }
108
106
  }
109
107
 
@@ -142,56 +140,89 @@ RED.search = (function () {
142
140
  results.push(nodes[list[i]]);
143
141
  }
144
142
  } else {
145
- let setResults = new Set()
143
+ let setResults = new Set();
146
144
  for (const i in index) {
147
- index[i].forEach(n => {
145
+ index[i].forEach((n) => {
148
146
  if (setResults.has(n.node.id)) return;
149
147
  else {
150
148
  setResults.add(n.node.id);
151
- if (n.node.type === 'tab') {
149
+ if (n.node.type === "tab") {
152
150
  results.push({ label: n.node.label, node: n.node });
153
151
  } else {
154
152
  results.push({ label: n.node.name, node: n.node });
155
153
  }
156
154
  }
157
- })
155
+ });
158
156
  }
159
-
160
157
  }
161
158
  return results;
162
-
163
159
  }
164
160
  /**
165
161
  * Returns a list of commands that will be added to the search window when it is opened
166
162
  */
167
163
  function searchCommands() {
168
-
169
164
  return [
170
- { type: 'command', title: 'Open Settings', action: 'core:settings:open', shortcut: `${CtrlOrCmd()} /` },
171
- { type: 'command', title: 'Show Project Info', action: 'core:project-info' },
172
165
  {
173
- type: 'command', title: 'Run Test...', cb: () => {
174
- if (!$('.sidebar-test').is(':visible')) {
175
- $('#red-ui-tab-test-link-button').click();
166
+ type: "command",
167
+ title: "Open Settings",
168
+ action: "core:settings:open",
169
+ shortcut: `${CtrlOrCmd()} /`,
170
+ },
171
+ {
172
+ type: "command",
173
+ title: "Show Project Info",
174
+ action: "core:project-info",
175
+ },
176
+ {
177
+ type: "command",
178
+ title: "Run Test...",
179
+ cb: () => {
180
+ if (!$(".sidebar-test").is(":visible")) {
181
+ $("#red-ui-tab-test-link-button").click();
176
182
  }
177
183
 
178
- $('#test-sidebar-run-btn').click();
179
- }
184
+ $("#test-sidebar-run-btn").click();
185
+ },
180
186
  },
181
187
  {
182
- type: 'command', title: 'Open Log Viewer', cb: () => {
183
- $('#workspace-terminal').toggle()
184
- }, shortcut: `${CtrlOrCmd()} T`
188
+ type: "command",
189
+ title: "Open Log Viewer",
190
+ cb: () => {
191
+ $("#workspace-terminal").toggle();
192
+ },
193
+ shortcut: `${CtrlOrCmd()} T`,
194
+ },
195
+ {
196
+ type: "command",
197
+ title: "Import Flow",
198
+ action: "core:show-import-dialog",
199
+ shortcut: `${CtrlOrCmd()} I`,
200
+ },
201
+ {
202
+ type: "command",
203
+ title: "Export Flow",
204
+ action: "core:show-export-dialog",
205
+ shortcut: `${CtrlOrCmd()} E`,
185
206
  },
186
- { type: 'command', title: 'Import Flow', action: 'core:show-import-dialog', shortcut: `${CtrlOrCmd()} I` },
187
- { type: 'command', title: 'Export Flow', action: 'core:show-export-dialog', shortcut: `${CtrlOrCmd()} E` },
188
207
  // { type: 'command', title: 'SignIn to Kumologica.dev', action: 'core:signup:show' },
189
208
  {
190
- type: 'command', title: 'Help: Documentation', cb: () => {
191
- window.__kumologica.electron.shell.openExternal('https://docs.kumologica.com/docs/guide/Intro.html');
192
- }
193
- }
194
- ]
209
+ type: "command",
210
+ title: "Task: npm install",
211
+ action: "npm:install",
212
+ cb: () => {
213
+ RED.actions.invoke("core:search:close");
214
+ },
215
+ },
216
+ {
217
+ type: "command",
218
+ title: "Help: Documentation",
219
+ cb: () => {
220
+ window.__kumologica.electron.shell.openExternal(
221
+ "https://docs.kumologica.com/docs/guide/Intro.html"
222
+ );
223
+ },
224
+ },
225
+ ];
195
226
  }
196
227
 
197
228
  function CtrlOrCmd() {
@@ -199,7 +230,7 @@ RED.search = (function () {
199
230
  }
200
231
 
201
232
  function ensureSelectedIsVisible() {
202
- var selectedEntry = searchResults.find('li.selected');
233
+ var selectedEntry = searchResults.find("li.selected");
203
234
  if (selectedEntry.length === 1) {
204
235
  var scrollWindow = searchResults.parent();
205
236
  var scrollHeight = scrollWindow.height();
@@ -208,21 +239,31 @@ RED.search = (function () {
208
239
  var h = selectedEntry.height();
209
240
  if (y + h > scrollHeight) {
210
241
  scrollWindow.animate(
211
- { scrollTop: '-=' + (scrollHeight - (y + h) - 10) },
242
+ { scrollTop: "-=" + (scrollHeight - (y + h) - 10) },
212
243
  50
213
244
  );
214
245
  } else if (y < 0) {
215
- scrollWindow.animate({ scrollTop: '+=' + (y - 10) }, 50);
246
+ scrollWindow.animate({ scrollTop: "+=" + (y - 10) }, 50);
216
247
  }
217
248
  }
218
249
  }
219
250
 
251
+ function shouldInvokeCommand(value) {
252
+ if (value.startsWith("npm install")) {
253
+ RED.actions.invoke("core:search:close");
254
+ RED.actions.invoke("npm:install", value);
255
+ RED.modules.updateValue(value);
256
+ return true;
257
+ } else {
258
+ return false;
259
+ }
260
+ }
220
261
  function createDialog() {
221
- dialog = $('<div>', {
222
- id: 'red-ui-search',
223
- class: 'red-ui-search',
224
- }).appendTo('#main-container');
225
- var searchDiv = $('<div>', { class: 'red-ui-search-container' }).appendTo(
262
+ dialog = $("<div>", {
263
+ id: "red-ui-search",
264
+ class: "red-ui-search",
265
+ }).appendTo("#main-container");
266
+ var searchDiv = $("<div>", { class: "red-ui-search-container" }).appendTo(
226
267
  dialog
227
268
  );
228
269
  searchInput = $(
@@ -230,25 +271,30 @@ RED.search = (function () {
230
271
  )
231
272
  .appendTo(searchDiv)
232
273
  .searchBox({
233
- delay: 200,
274
+ delay: 100,
234
275
  change: function () {
235
- search($(this).val());
276
+ let value = $(this).val();
277
+ if (!shouldInvokeCommand(value)) {
278
+ search($(this).val());
279
+ }
236
280
  },
237
281
  });
238
282
 
239
- searchInput.on('keydown', function (evt) {
283
+ searchInput.on("keydown", function (evt) {
240
284
  var children;
241
- if (results.length > 0) {
285
+
286
+ // Check for embedded commands
287
+ if (!shouldInvokeCommand(evt.target.value) && results.length > 0) {
242
288
  if (evt.keyCode === 40) {
243
289
  // Down
244
290
  children = searchResults.children();
245
291
  if (selected < children.length - 1) {
246
292
  if (selected > -1) {
247
- $(children[selected]).removeClass('selected');
293
+ $(children[selected]).removeClass("selected");
248
294
  }
249
295
  selected++;
250
296
  }
251
- $(children[selected]).addClass('selected');
297
+ $(children[selected]).addClass("selected");
252
298
  ensureSelectedIsVisible();
253
299
  evt.preventDefault();
254
300
  } else if (evt.keyCode === 38) {
@@ -256,11 +302,11 @@ RED.search = (function () {
256
302
  children = searchResults.children();
257
303
  if (selected > 0) {
258
304
  if (selected < children.length) {
259
- $(children[selected]).removeClass('selected');
305
+ $(children[selected]).removeClass("selected");
260
306
  }
261
307
  selected--;
262
308
  }
263
- $(children[selected]).addClass('selected');
309
+ $(children[selected]).addClass("selected");
264
310
  ensureSelectedIsVisible();
265
311
  evt.preventDefault();
266
312
  } else if (evt.keyCode === 13) {
@@ -273,13 +319,13 @@ RED.search = (function () {
273
319
  });
274
320
  searchInput.i18n();
275
321
 
276
- var searchResultsDiv = $('<div>', {
277
- class: 'red-ui-search-results-container',
322
+ var searchResultsDiv = $("<div>", {
323
+ class: "red-ui-search-results-container",
278
324
  }).appendTo(dialog);
279
325
 
280
- searchResults = $('<ol>', {
281
- id: 'search-result-list',
282
- style: 'position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;',
326
+ searchResults = $("<ol>", {
327
+ id: "search-result-list",
328
+ style: "position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;",
283
329
  })
284
330
  .appendTo(searchResultsDiv)
285
331
  .editableList({
@@ -287,36 +333,38 @@ RED.search = (function () {
287
333
  addItem: function (container, i, object) {
288
334
  var node = object.node;
289
335
 
290
- // If node === undefined and object is object => object is the command
336
+ // If node === undefined and object is object => object is the command
291
337
  // If node === undefiend and object is empty => user search yield no results
292
338
  // otherwise is a normal search ...
293
339
 
294
340
  if (node === undefined && !object) {
295
341
  // case of user search yield no results
296
- $('<div>', { class: 'red-ui-search-empty' })
297
- .text('No matches found')
342
+ $("<div>", { class: "red-ui-search-empty" })
343
+ .text("No matches found")
298
344
  .appendTo(container);
299
345
  } else if (node === undefined && object) {
300
346
  // case of initial display of options (commands & tabs ) ... (object is a command)
301
- if (object.type === 'command') {
302
-
347
+ if (object.type === "command") {
303
348
  // Main result container
304
- var div = $('<a>', {
305
- href: '#',
306
- class: 'red-ui-search-result',
349
+ var div = $("<a>", {
350
+ href: "#",
351
+ class: "red-ui-search-result",
307
352
  }).appendTo(container);
308
353
 
309
354
  // Command title here
310
- var contentDescription = $('<div>', {
311
- class: 'red-ui-search-result-description',
355
+ var contentDescription = $("<div>", {
356
+ class: "red-ui-search-result-description",
312
357
  }).appendTo(div);
313
358
 
314
- $('<div>', { class: 'red-ui-search-result-command-label', style: 'width:95%' })
359
+ $("<div>", {
360
+ class: "red-ui-search-result-command-label",
361
+ style: "width:95%",
362
+ })
315
363
  .text(object.title)
316
364
  .appendTo(contentDescription);
317
365
 
318
366
  // Type of object (command)
319
- $('<div>', { class: 'red-ui-search-result-command-shortcut' })
367
+ $("<div>", { class: "red-ui-search-result-command-shortcut" })
320
368
  .text(object.shortcut)
321
369
  .appendTo(div);
322
370
 
@@ -325,46 +373,48 @@ RED.search = (function () {
325
373
  if (object.action) {
326
374
  hide();
327
375
  window.setTimeout(() => {
328
- RED.actions.invoke(object.action)
329
- }, 10)
376
+ RED.actions.invoke(object.action);
377
+ }, 10);
330
378
  } else {
331
379
  hide();
332
380
  window.setTimeout(() => {
333
- object.cb()
334
- }, 10)
381
+ object.cb();
382
+ }, 10);
335
383
  }
336
-
337
384
  });
338
385
  }
339
-
340
386
  } else {
341
387
  var def = node._def;
342
- var div = $('<a>', {
343
- href: '#',
344
- class: 'red-ui-search-result',
388
+ var div = $("<a>", {
389
+ href: "#",
390
+ class: "red-ui-search-result",
345
391
  }).appendTo(container);
346
392
 
347
393
  // ::: Part of the description
348
- var contentDescription = $('<div>', {
349
- class: 'red-ui-search-result-description',
394
+ var contentDescription = $("<div>", {
395
+ class: "red-ui-search-result-description",
350
396
  }).appendTo(div);
351
397
 
352
- // ::: Part of the icon here...
353
- var nodeDiv = $('<div>', {
354
- class: 'ui-search-result-node',
398
+ // ::: Part of the icon here...
399
+ var nodeDiv = $("<div>", {
400
+ class: "ui-search-result-node",
355
401
  }).appendTo(contentDescription);
356
402
 
357
403
  var colour = RED.utils.getNodeColor(node.type, def);
358
404
  var icon_url = RED.utils.getNodeIcon(def, node);
359
405
 
360
- if (node.type === 'tab') {
361
- var iconContainer = $('<div/>', {
362
- class: 'palette_icon_container',
406
+ if (node.type === "tab") {
407
+ var iconContainer = $("<div/>", {
408
+ class: "palette_icon_container",
363
409
  }).appendTo(nodeDiv);
364
- RED.utils.createIconElement('icons/kumologica-core/kumologica-tab.png', iconContainer, true);
410
+ RED.utils.createIconElement(
411
+ "icons/kumologica-core/kumologica-tab.png",
412
+ iconContainer,
413
+ true
414
+ );
365
415
  } else {
366
- var iconContainer = $('<div/>', {
367
- class: 'palette_icon_container',
416
+ var iconContainer = $("<div/>", {
417
+ class: "palette_icon_container",
368
418
  }).appendTo(nodeDiv);
369
419
  RED.utils.createIconElement(icon_url, iconContainer, true);
370
420
  }
@@ -373,22 +423,22 @@ RED.search = (function () {
373
423
  var workspace = RED.nodes.workspace(node.z);
374
424
  if (!workspace) {
375
425
  workspace = RED.nodes.subflow(node.z);
376
- workspace = 'subflow:' + workspace.name;
426
+ workspace = "subflow:" + workspace.name;
377
427
  } else {
378
428
  workspace = workspace.label; //'flow:' + workspace.label
379
429
  }
380
- $('<div>', { class: 'red-ui-search-result-node-flow' })
430
+ $("<div>", { class: "red-ui-search-result-node-flow" })
381
431
  .text(workspace)
382
432
  .appendTo(div);
383
433
  }
384
434
 
385
- $('<div>', { class: 'red-ui-search-result-node-label' })
435
+ $("<div>", { class: "red-ui-search-result-node-label" })
386
436
  .text(object.label || node.id)
387
437
  .appendTo(contentDescription);
388
- $('<div>', { class: 'red-ui-search-result-node-type' })
438
+ $("<div>", { class: "red-ui-search-result-node-type" })
389
439
  .text(node.type)
390
440
  .appendTo(contentDescription);
391
- $('<div>', { class: 'red-ui-search-result-node-id' })
441
+ $("<div>", { class: "red-ui-search-result-node-id" })
392
442
  .text(node.id)
393
443
  .appendTo(contentDescription);
394
444
 
@@ -415,15 +465,15 @@ RED.search = (function () {
415
465
 
416
466
  function show(v) {
417
467
  // Disable the project dialog
418
- RED.actions.invoke('core:project-info:close');
419
- RED.actions.invoke('core:settings:close');
468
+ RED.actions.invoke("core:project-info:close");
469
+ RED.actions.invoke("core:settings:close");
420
470
 
421
471
  if (!visible) {
422
- RED.keyboard.add('*', 'escape', function () {
472
+ RED.keyboard.add("*", "escape", function () {
423
473
  hide();
424
474
  });
425
475
 
426
- $('#main-container').click(() => {
476
+ $("#main-container").click(() => {
427
477
  hide();
428
478
  });
429
479
 
@@ -433,24 +483,22 @@ RED.search = (function () {
433
483
  createDialog();
434
484
  }
435
485
  dialog.slideDown(300);
436
- searchInput.searchBox('value', v);
437
- RED.events.emit('search:open');
486
+ searchInput.searchBox("value", v);
487
+ RED.events.emit("search:open");
438
488
  visible = true;
439
489
  window.setTimeout(() => {
440
- searchInput.focus()
490
+ searchInput.focus();
441
491
  }, 50);
442
492
 
443
493
  // Populate search results with commands and tabs at least
444
494
  search();
445
495
  }
446
-
447
-
448
496
  }
449
497
 
450
498
  function hide() {
451
499
  if (visible) {
452
- $('#main-container').off('click');
453
- RED.keyboard.remove('escape');
500
+ $("#main-container").off("click");
501
+ RED.keyboard.remove("escape");
454
502
  visible = false;
455
503
  // $('#header-shade').hide();
456
504
  // $('#editor-shade').hide();
@@ -459,28 +507,28 @@ RED.search = (function () {
459
507
  // $('#sidebar-separator').show();
460
508
  if (dialog !== null) {
461
509
  dialog.slideUp(200, function () {
462
- searchInput.searchBox('value', '');
510
+ searchInput.searchBox("value", "");
463
511
  });
464
512
  }
465
- RED.events.emit('search:close');
513
+ RED.events.emit("search:close");
466
514
  }
467
515
  }
468
516
 
469
517
  function init() {
470
- RED.actions.add('core:search', show);
471
- RED.actions.add('core:search:close', hide);
518
+ RED.actions.add("core:search", show);
519
+ RED.actions.add("core:search:close", hide);
472
520
 
473
- RED.events.on('type-search:open', function () {
521
+ RED.events.on("type-search:open", function () {
474
522
  disabled = true;
475
523
  });
476
- RED.events.on('type-search:close', function () {
524
+ RED.events.on("type-search:close", function () {
477
525
  disabled = false;
478
526
  });
479
527
 
480
- $('#header-shade').on('mousedown', hide);
481
- $('#editor-shade').on('mousedown', hide);
482
- $('#palette-shade').on('mousedown', hide);
483
- $('#sidebar-shade').on('mousedown', hide);
528
+ $("#header-shade").on("mousedown", hide);
529
+ $("#editor-shade").on("mousedown", hide);
530
+ $("#palette-shade").on("mousedown", hide);
531
+ $("#sidebar-shade").on("mousedown", hide);
484
532
  }
485
533
 
486
534
  return {
@@ -488,6 +536,6 @@ RED.search = (function () {
488
536
  show: show,
489
537
  hide: hide,
490
538
  reveal: reveal,
491
- revealByNodeId: revealByNodeId
539
+ revealByNodeId: revealByNodeId,
492
540
  };
493
541
  })();
@@ -305,7 +305,7 @@ RED.sidebar = (function () {
305
305
  RED.sidebar.info.init();
306
306
  RED.sidebar.test.init();
307
307
  RED.sidebar.git.init();
308
- //RED.sidebar.kumohub.init();
308
+ RED.sidebar.kumohub.init();
309
309
  RED.sidebar.azure.init();
310
310
  RED.sidebar.awsDeploy.init();
311
311