@nyaruka/temba-components 0.139.0 → 0.140.0

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 (155) hide show
  1. package/.github/workflows/cla.yml +1 -1
  2. package/.github/workflows/copilot-setup-steps.yml +6 -1
  3. package/CHANGELOG.md +17 -0
  4. package/demo/data/flows/sample-flow.json +24 -0
  5. package/dist/temba-components.js +562 -296
  6. package/dist/temba-components.js.map +1 -1
  7. package/out-tsc/src/display/Chat.js +10 -7
  8. package/out-tsc/src/display/Chat.js.map +1 -1
  9. package/out-tsc/src/display/Dropdown.js +3 -1
  10. package/out-tsc/src/display/Dropdown.js.map +1 -1
  11. package/out-tsc/src/display/FloatingTab.js +3 -3
  12. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  13. package/out-tsc/src/display/Thumbnail.js +163 -5
  14. package/out-tsc/src/display/Thumbnail.js.map +1 -1
  15. package/out-tsc/src/flow/CanvasNode.js +64 -22
  16. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  17. package/out-tsc/src/flow/Editor.js +142 -8
  18. package/out-tsc/src/flow/Editor.js.map +1 -1
  19. package/out-tsc/src/flow/NodeEditor.js +118 -10
  20. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  21. package/out-tsc/src/flow/StickyNote.js +13 -4
  22. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  23. package/out-tsc/src/flow/actions/audio-player.js +112 -0
  24. package/out-tsc/src/flow/actions/audio-player.js.map +1 -0
  25. package/out-tsc/src/flow/actions/enter_flow.js +43 -0
  26. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
  27. package/out-tsc/src/flow/actions/play_audio.js +57 -4
  28. package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
  29. package/out-tsc/src/flow/actions/say_msg.js +86 -3
  30. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  31. package/out-tsc/src/flow/config.js +11 -3
  32. package/out-tsc/src/flow/config.js.map +1 -1
  33. package/out-tsc/src/flow/nodes/shared-rules.js +1 -1
  34. package/out-tsc/src/flow/nodes/shared-rules.js.map +1 -1
  35. package/out-tsc/src/flow/nodes/terminal.js +7 -0
  36. package/out-tsc/src/flow/nodes/terminal.js.map +1 -0
  37. package/out-tsc/src/flow/nodes/wait_for_audio.js +77 -0
  38. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
  39. package/out-tsc/src/flow/nodes/wait_for_dial.js +151 -0
  40. package/out-tsc/src/flow/nodes/wait_for_dial.js.map +1 -0
  41. package/out-tsc/src/flow/nodes/wait_for_digits.js +61 -1
  42. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  43. package/out-tsc/src/flow/nodes/wait_for_menu.js +173 -2
  44. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
  45. package/out-tsc/src/flow/operators.js +21 -5
  46. package/out-tsc/src/flow/operators.js.map +1 -1
  47. package/out-tsc/src/flow/types.js.map +1 -1
  48. package/out-tsc/src/flow/utils.js +79 -3
  49. package/out-tsc/src/flow/utils.js.map +1 -1
  50. package/out-tsc/src/form/ArrayEditor.js +4 -2
  51. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  52. package/out-tsc/src/form/FieldRenderer.js +49 -0
  53. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  54. package/out-tsc/src/interfaces.js +1 -0
  55. package/out-tsc/src/interfaces.js.map +1 -1
  56. package/out-tsc/src/layout/Dialog.js +52 -7
  57. package/out-tsc/src/layout/Dialog.js.map +1 -1
  58. package/out-tsc/src/live/TembaChart.js.map +1 -1
  59. package/out-tsc/src/simulator/Simulator.js +10 -4
  60. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  61. package/out-tsc/src/store/AppState.js +89 -3
  62. package/out-tsc/src/store/AppState.js.map +1 -1
  63. package/out-tsc/test/actions/play_audio.test.js +118 -0
  64. package/out-tsc/test/actions/play_audio.test.js.map +1 -0
  65. package/out-tsc/test/actions/say_msg.test.js +158 -0
  66. package/out-tsc/test/actions/say_msg.test.js.map +1 -0
  67. package/out-tsc/test/nodes/wait_for_audio.test.js +156 -0
  68. package/out-tsc/test/nodes/wait_for_audio.test.js.map +1 -0
  69. package/out-tsc/test/nodes/wait_for_dial.test.js +336 -0
  70. package/out-tsc/test/nodes/wait_for_dial.test.js.map +1 -0
  71. package/out-tsc/test/nodes/wait_for_digits.test.js +198 -84
  72. package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
  73. package/out-tsc/test/nodes/wait_for_menu.test.js +340 -0
  74. package/out-tsc/test/nodes/wait_for_menu.test.js.map +1 -0
  75. package/out-tsc/test/temba-flow-collision.test.js +261 -6
  76. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  77. package/out-tsc/test/temba-node-type-selector.test.js +6 -6
  78. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
  79. package/package.json +1 -1
  80. package/screenshots/truth/actions/play_audio/editor/expression-url.png +0 -0
  81. package/screenshots/truth/actions/play_audio/editor/static-url.png +0 -0
  82. package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
  83. package/screenshots/truth/actions/play_audio/render/static-url.png +0 -0
  84. package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
  85. package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
  86. package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
  87. package/screenshots/truth/actions/say_msg/render/multiline-text.png +0 -0
  88. package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
  89. package/screenshots/truth/actions/say_msg/render/text-with-audio-url.png +0 -0
  90. package/screenshots/truth/editor/router.png +0 -0
  91. package/screenshots/truth/editor/wait.png +0 -0
  92. package/screenshots/truth/nodes/wait_for_audio/editor/basic-audio-wait.png +0 -0
  93. package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
  94. package/screenshots/truth/nodes/wait_for_dial/editor/basic-dial.png +0 -0
  95. package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
  96. package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
  97. package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
  98. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  99. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  100. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  101. package/screenshots/truth/nodes/wait_for_digits/render/digits-with-rules.png +0 -0
  102. package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
  103. package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
  104. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  105. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  106. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  107. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  108. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  109. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  110. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  111. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  112. package/src/display/Chat.ts +13 -7
  113. package/src/display/Dropdown.ts +3 -1
  114. package/src/display/FloatingTab.ts +3 -3
  115. package/src/display/Thumbnail.ts +162 -2
  116. package/src/flow/CanvasNode.ts +69 -23
  117. package/src/flow/Editor.ts +156 -13
  118. package/src/flow/NodeEditor.ts +137 -9
  119. package/src/flow/StickyNote.ts +14 -4
  120. package/src/flow/actions/audio-player.ts +127 -0
  121. package/src/flow/actions/enter_flow.ts +44 -0
  122. package/src/flow/actions/play_audio.ts +64 -5
  123. package/src/flow/actions/say_msg.ts +94 -4
  124. package/src/flow/config.ts +11 -3
  125. package/src/flow/nodes/shared-rules.ts +1 -1
  126. package/src/flow/nodes/terminal.ts +9 -0
  127. package/src/flow/nodes/wait_for_audio.ts +88 -0
  128. package/src/flow/nodes/wait_for_dial.ts +176 -0
  129. package/src/flow/nodes/wait_for_digits.ts +86 -2
  130. package/src/flow/nodes/wait_for_menu.ts +209 -3
  131. package/src/flow/operators.ts +23 -5
  132. package/src/flow/types.ts +23 -1
  133. package/src/flow/utils.ts +82 -3
  134. package/src/form/ArrayEditor.ts +4 -2
  135. package/src/form/FieldRenderer.ts +64 -1
  136. package/src/interfaces.ts +2 -1
  137. package/src/layout/Dialog.ts +53 -7
  138. package/src/live/TembaChart.ts +1 -1
  139. package/src/simulator/Simulator.ts +13 -4
  140. package/src/store/AppState.ts +105 -1
  141. package/src/store/flow-definition.d.ts +2 -0
  142. package/test/actions/play_audio.test.ts +155 -0
  143. package/test/actions/say_msg.test.ts +196 -0
  144. package/test/nodes/wait_for_audio.test.ts +182 -0
  145. package/test/nodes/wait_for_dial.test.ts +382 -0
  146. package/test/nodes/wait_for_digits.test.ts +233 -109
  147. package/test/nodes/wait_for_menu.test.ts +383 -0
  148. package/test/temba-flow-collision.test.ts +286 -6
  149. package/test/temba-node-type-selector.test.ts +6 -6
  150. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  151. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  152. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  153. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  154. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  155. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
@@ -8,11 +8,11 @@ import { RapidElement } from '../RapidElement';
8
8
  import { repeat } from 'lit-html/directives/repeat.js';
9
9
  import { CustomEventType } from '../interfaces';
10
10
  import { generateUUID, postJSON, fetchResults, getClasses } from '../utils';
11
+ import { formatIssueMessage, getNodeBounds, calculateReflowPositions, snapToGrid } from './utils';
11
12
  import { ACTION_CONFIG, NODE_CONFIG } from './config';
12
13
  import { ACTION_GROUP_METADATA } from './types';
13
14
  import { Plumber, calculateFlowchartPath, ARROW_LENGTH, ARROW_HALF_WIDTH, CURSOR_GAP } from './Plumber';
14
15
  import { CanvasNode } from './CanvasNode';
15
- import { getNodeBounds, calculateReflowPositions, snapToGrid } from './utils';
16
16
  export function findNodeForExit(definition, exitUuid) {
17
17
  for (const node of definition.nodes) {
18
18
  const exit = node.exits.find((e) => e.uuid === exitUuid);
@@ -74,6 +74,10 @@ export class Editor extends RapidElement {
74
74
  -webkit-font-smoothing: antialiased;
75
75
  }
76
76
 
77
+ temba-floating-tab {
78
+ --floating-tab-right: 15px;
79
+ }
80
+
77
81
  #grid {
78
82
  position: relative;
79
83
  background-color: #f9f9f9;
@@ -207,7 +211,7 @@ export class Editor extends RapidElement {
207
211
  font-weight: 600;
208
212
  line-height: 0.9;
209
213
  cursor: pointer;
210
- z-index: 500;
214
+ z-index: 10;
211
215
  pointer-events: auto;
212
216
  white-space: nowrap;
213
217
  user-select: none;
@@ -522,6 +526,26 @@ export class Editor extends RapidElement {
522
526
  color: #9ca3af;
523
527
  white-space: nowrap;
524
528
  }
529
+
530
+ .issue-list-item {
531
+ display: flex;
532
+ align-items: center;
533
+ gap: 8px;
534
+ padding: 8px;
535
+ border-radius: 4px;
536
+ cursor: pointer;
537
+ font-size: 13px;
538
+ color: #333;
539
+ }
540
+
541
+ .issue-list-item:hover {
542
+ background: #fff5f5;
543
+ }
544
+
545
+ .issue-list-item temba-icon {
546
+ color: tomato;
547
+ flex-shrink: 0;
548
+ }
525
549
  `;
526
550
  }
527
551
  constructor() {
@@ -550,6 +574,7 @@ export class Editor extends RapidElement {
550
574
  // Canvas-relative source exit position (set at drag start)
551
575
  this.connectionSourceX = null;
552
576
  this.connectionSourceY = null;
577
+ this.issuesWindowHidden = true;
553
578
  this.localizationWindowHidden = true;
554
579
  this.translationFilters = {
555
580
  categories: false
@@ -569,6 +594,7 @@ export class Editor extends RapidElement {
569
594
  this.editingNode = null;
570
595
  this.editingNodeUI = null;
571
596
  this.editingAction = null;
597
+ this.dialogOrigin = null;
572
598
  this.isCreatingNewNode = false;
573
599
  this.pendingNodePosition = null;
574
600
  // Canvas drop state for dragging actions to canvas
@@ -915,6 +941,7 @@ export class Editor extends RapidElement {
915
941
  return;
916
942
  if (this.isReadOnly())
917
943
  return;
944
+ this.blurActiveContentEditable();
918
945
  const element = event.currentTarget;
919
946
  // Only start dragging if clicking on the element itself, not on exits or other interactive elements
920
947
  const target = event.target;
@@ -974,10 +1001,22 @@ export class Editor extends RapidElement {
974
1001
  // We clicked on empty canvas space, start selection
975
1002
  this.handleCanvasMouseDown(event);
976
1003
  }
1004
+ blurActiveContentEditable() {
1005
+ var _b;
1006
+ let active = document.activeElement;
1007
+ while ((_b = active === null || active === void 0 ? void 0 : active.shadowRoot) === null || _b === void 0 ? void 0 : _b.activeElement) {
1008
+ active = active.shadowRoot.activeElement;
1009
+ }
1010
+ if (active instanceof HTMLElement &&
1011
+ active.getAttribute('contenteditable') === 'true') {
1012
+ active.blur();
1013
+ }
1014
+ }
977
1015
  handleCanvasMouseDown(event) {
978
1016
  var _b;
979
1017
  if (this.isReadOnly())
980
1018
  return;
1019
+ this.blurActiveContentEditable();
981
1020
  const target = event.target;
982
1021
  if (target.id === 'canvas' || target.id === 'grid') {
983
1022
  // Ignore clicks on exits
@@ -1692,6 +1731,10 @@ export class Editor extends RapidElement {
1692
1731
  handleActionEditRequested(event) {
1693
1732
  // For action editing, we set the action and find the corresponding node
1694
1733
  this.editingAction = event.detail.action;
1734
+ this.dialogOrigin =
1735
+ event.detail.originX != null
1736
+ ? { x: event.detail.originX, y: event.detail.originY }
1737
+ : null;
1695
1738
  // Find the node that contains this action
1696
1739
  const nodeUuid = event.detail.nodeUuid;
1697
1740
  const node = this.definition.nodes.find((n) => n.uuid === nodeUuid);
@@ -1727,6 +1770,10 @@ export class Editor extends RapidElement {
1727
1770
  handleNodeEditRequested(event) {
1728
1771
  this.editingNode = event.detail.node;
1729
1772
  this.editingNodeUI = event.detail.nodeUI;
1773
+ this.dialogOrigin =
1774
+ event.detail.originX != null
1775
+ ? { x: event.detail.originX, y: event.detail.originY }
1776
+ : null;
1730
1777
  }
1731
1778
  handleNodeDeleted(event) {
1732
1779
  const nodeUuid = event.detail.uuid;
@@ -1797,6 +1844,7 @@ export class Editor extends RapidElement {
1797
1844
  this.editingNode = null;
1798
1845
  this.editingNodeUI = null;
1799
1846
  this.editingAction = null;
1847
+ this.dialogOrigin = null;
1800
1848
  }
1801
1849
  handleActionEditCanceled() {
1802
1850
  // If we were creating a new node, just discard it
@@ -2253,6 +2301,7 @@ export class Editor extends RapidElement {
2253
2301
  }
2254
2302
  this.localizationWindowHidden = false;
2255
2303
  this.revisionsWindowHidden = true;
2304
+ this.issuesWindowHidden = true;
2256
2305
  const alreadySelected = languages.some((lang) => lang.code === this.languageCode);
2257
2306
  if (!alreadySelected) {
2258
2307
  this.handleLanguageChange(languages[0].code);
@@ -2460,11 +2509,42 @@ export class Editor extends RapidElement {
2460
2509
  }
2461
2510
  this.autoTranslating = false;
2462
2511
  }
2512
+ handleIssuesTabClick() {
2513
+ this.issuesWindowHidden = false;
2514
+ this.revisionsWindowHidden = true;
2515
+ this.localizationWindowHidden = true;
2516
+ }
2517
+ handleIssuesWindowClosed() {
2518
+ this.issuesWindowHidden = true;
2519
+ }
2520
+ handleIssueItemClick(issue) {
2521
+ var _b;
2522
+ const issuesWindow = document.getElementById('issues-window');
2523
+ issuesWindow === null || issuesWindow === void 0 ? void 0 : issuesWindow.handleClose();
2524
+ this.issuesWindowHidden = true;
2525
+ this.focusNode(issue.node_uuid);
2526
+ const node = this.definition.nodes.find((n) => n.uuid === issue.node_uuid);
2527
+ if (!node)
2528
+ return;
2529
+ if (issue.action_uuid) {
2530
+ const action = (_b = node.actions) === null || _b === void 0 ? void 0 : _b.find((a) => a.uuid === issue.action_uuid);
2531
+ if (action) {
2532
+ this.editingAction = action;
2533
+ this.editingNode = node;
2534
+ this.editingNodeUI = this.definition._ui.nodes[issue.node_uuid];
2535
+ }
2536
+ }
2537
+ else {
2538
+ this.editingNode = node;
2539
+ this.editingNodeUI = this.definition._ui.nodes[issue.node_uuid];
2540
+ }
2541
+ }
2463
2542
  handleRevisionsTabClick() {
2464
2543
  if (this.revisionsWindowHidden) {
2465
2544
  this.fetchRevisions();
2466
2545
  this.revisionsWindowHidden = false;
2467
- this.localizationWindowHidden = true; // Close other window
2546
+ this.issuesWindowHidden = true;
2547
+ this.localizationWindowHidden = true;
2468
2548
  }
2469
2549
  }
2470
2550
  handleRevisionsWindowClosed() {
@@ -2565,6 +2645,51 @@ export class Editor extends RapidElement {
2565
2645
  // Fetch the latest version of the flow to ensure the store is up to date
2566
2646
  getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
2567
2647
  }
2648
+ renderIssuesTab() {
2649
+ var _b;
2650
+ if (!((_b = this.flowIssues) === null || _b === void 0 ? void 0 : _b.length))
2651
+ return '';
2652
+ return html `
2653
+ <temba-floating-tab
2654
+ id="issues-tab"
2655
+ icon="alert_warning"
2656
+ label="Flow Issues"
2657
+ color="tomato"
2658
+ order="1"
2659
+ .hidden=${!this.issuesWindowHidden}
2660
+ @temba-button-clicked=${this.handleIssuesTabClick}
2661
+ ></temba-floating-tab>
2662
+ `;
2663
+ }
2664
+ renderIssuesWindow() {
2665
+ var _b;
2666
+ if (!((_b = this.flowIssues) === null || _b === void 0 ? void 0 : _b.length))
2667
+ return '';
2668
+ return html `
2669
+ <temba-floating-window
2670
+ id="issues-window"
2671
+ header="Flow Issues"
2672
+ .width=${360}
2673
+ .maxHeight=${600}
2674
+ .top=${75}
2675
+ color="tomato"
2676
+ .hidden=${this.issuesWindowHidden}
2677
+ @temba-dialog-hidden=${this.handleIssuesWindowClosed}
2678
+ >
2679
+ <div style="display:flex; flex-direction:column; gap:2px;">
2680
+ ${this.flowIssues.map((issue) => html `
2681
+ <div
2682
+ class="issue-list-item"
2683
+ @click=${() => this.handleIssueItemClick(issue)}
2684
+ >
2685
+ <temba-icon name="alert_warning" size="1.2"></temba-icon>
2686
+ <span>${formatIssueMessage(issue)}</span>
2687
+ </div>
2688
+ `)}
2689
+ </div>
2690
+ </temba-floating-window>
2691
+ `;
2692
+ }
2568
2693
  renderRevisionsTab() {
2569
2694
  return html `
2570
2695
  <temba-floating-tab
@@ -2572,7 +2697,7 @@ export class Editor extends RapidElement {
2572
2697
  icon="revisions"
2573
2698
  label="Revisions"
2574
2699
  color="rgb(142, 94, 167)"
2575
- order="1"
2700
+ order="2"
2576
2701
  .hidden=${!this.revisionsWindowHidden && this.localizationWindowHidden}
2577
2702
  @temba-button-clicked=${this.handleRevisionsTabClick}
2578
2703
  ></temba-floating-tab>
@@ -2843,7 +2968,7 @@ export class Editor extends RapidElement {
2843
2968
  icon="language"
2844
2969
  label="Translate Flow"
2845
2970
  color="#6b7280"
2846
- order="2"
2971
+ order="3"
2847
2972
  .hidden=${!this.localizationWindowHidden}
2848
2973
  @temba-button-clicked=${this.handleLocalizationTabClick}
2849
2974
  ></temba-floating-tab>
@@ -2890,8 +3015,9 @@ export class Editor extends RapidElement {
2890
3015
  ${unsafeCSS(CanvasNode.styles.cssText)}
2891
3016
  </style>`;
2892
3017
  const stickies = ((_c = (_b = this.definition) === null || _b === void 0 ? void 0 : _b._ui) === null || _c === void 0 ? void 0 : _c.stickies) || {};
2893
- return html `${style} ${this.renderRevisionsWindow()}
2894
- ${this.renderLocalizationWindow()} ${this.renderAutoTranslateDialog()}
3018
+ return html `${style} ${this.renderIssuesWindow()}
3019
+ ${this.renderRevisionsWindow()} ${this.renderLocalizationWindow()}
3020
+ ${this.renderAutoTranslateDialog()}
2895
3021
  <div id="editor">
2896
3022
  <div
2897
3023
  id="grid"
@@ -2964,6 +3090,7 @@ export class Editor extends RapidElement {
2964
3090
  .node=${this.editingNode}
2965
3091
  .nodeUI=${this.editingNodeUI}
2966
3092
  .action=${this.editingAction}
3093
+ .dialogOrigin=${this.dialogOrigin}
2967
3094
  @temba-node-saved=${(e) => this.handleNodeSaved(e.detail.node, e.detail.uiConfig)}
2968
3095
  @temba-action-saved=${(e) => this.handleActionSaved(e.detail.action)}
2969
3096
  @temba-node-edit-cancelled=${this.handleNodeEditCanceled}
@@ -2977,7 +3104,8 @@ export class Editor extends RapidElement {
2977
3104
  .features=${this.features}
2978
3105
  ></temba-node-type-selector>`
2979
3106
  : ''}
2980
- ${this.renderRevisionsTab()} ${this.renderLocalizationTab()} `;
3107
+ ${this.renderIssuesTab()} ${this.renderRevisionsTab()}
3108
+ ${this.renderLocalizationTab()} `;
2981
3109
  }
2982
3110
  }
2983
3111
  __decorate([
@@ -3016,6 +3144,9 @@ __decorate([
3016
3144
  __decorate([
3017
3145
  fromStore(zustand, (state) => state.getCurrentActivity())
3018
3146
  ], Editor.prototype, "activityData", void 0);
3147
+ __decorate([
3148
+ fromStore(zustand, (state) => { var _b; return ((_b = state.flowInfo) === null || _b === void 0 ? void 0 : _b.issues) || []; })
3149
+ ], Editor.prototype, "flowIssues", void 0);
3019
3150
  __decorate([
3020
3151
  state()
3021
3152
  ], Editor.prototype, "isDragging", void 0);
@@ -3046,6 +3177,9 @@ __decorate([
3046
3177
  __decorate([
3047
3178
  state()
3048
3179
  ], Editor.prototype, "isValidTarget", void 0);
3180
+ __decorate([
3181
+ state()
3182
+ ], Editor.prototype, "issuesWindowHidden", void 0);
3049
3183
  __decorate([
3050
3184
  state()
3051
3185
  ], Editor.prototype, "localizationWindowHidden", void 0);