@nyaruka/temba-components 0.131.1 → 0.131.3

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 (485) hide show
  1. package/.github/workflows/publish.yml +4 -1
  2. package/CHANGELOG.md +75 -1
  3. package/demo/components/floating-tabs/example.html +400 -0
  4. package/demo/components/flow/index.html +1 -1
  5. package/demo/data/flows/food-order.json +2 -2
  6. package/demo/data/flows/sample-flow.json +113 -125
  7. package/demo/data/flows/voicemail.json +613 -0
  8. package/demo/index.html +6 -0
  9. package/dist/locales/es.js +5 -5
  10. package/dist/locales/es.js.map +1 -1
  11. package/dist/locales/fr.js +5 -5
  12. package/dist/locales/fr.js.map +1 -1
  13. package/dist/locales/locale-codes.js +11 -2
  14. package/dist/locales/locale-codes.js.map +1 -1
  15. package/dist/locales/pt.js +5 -5
  16. package/dist/locales/pt.js.map +1 -1
  17. package/dist/static/svg/index.svg +1 -1
  18. package/dist/temba-components.js +1773 -662
  19. package/dist/temba-components.js.map +1 -1
  20. package/out-tsc/src/Icons.js +4 -1
  21. package/out-tsc/src/Icons.js.map +1 -1
  22. package/out-tsc/src/display/FloatingTab.js +167 -0
  23. package/out-tsc/src/display/FloatingTab.js.map +1 -0
  24. package/out-tsc/src/display/ProgressBar.js +22 -2
  25. package/out-tsc/src/display/ProgressBar.js.map +1 -1
  26. package/out-tsc/src/events.js.map +1 -1
  27. package/out-tsc/src/flow/CanvasMenu.js +200 -0
  28. package/out-tsc/src/flow/CanvasMenu.js.map +1 -0
  29. package/out-tsc/src/flow/CanvasNode.js +489 -47
  30. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  31. package/out-tsc/src/flow/Editor.js +1417 -67
  32. package/out-tsc/src/flow/Editor.js.map +1 -1
  33. package/out-tsc/src/flow/NodeEditor.js +479 -112
  34. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  35. package/out-tsc/src/flow/NodeTypeSelector.js +540 -0
  36. package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -0
  37. package/out-tsc/src/flow/StickyNote.js +12 -3
  38. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  39. package/out-tsc/src/flow/actions/add_contact_groups.js +4 -3
  40. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  41. package/out-tsc/src/flow/actions/add_contact_urn.js +63 -4
  42. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
  43. package/out-tsc/src/flow/actions/add_input_labels.js +4 -3
  44. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  45. package/out-tsc/src/flow/actions/play_audio.js +3 -2
  46. package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
  47. package/out-tsc/src/flow/actions/remove_contact_groups.js +7 -5
  48. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  49. package/out-tsc/src/flow/actions/request_optin.js +3 -2
  50. package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
  51. package/out-tsc/src/flow/actions/say_msg.js +3 -2
  52. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  53. package/out-tsc/src/flow/actions/send_broadcast.js +77 -23
  54. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  55. package/out-tsc/src/flow/actions/send_email.js +5 -5
  56. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  57. package/out-tsc/src/flow/actions/send_msg.js +101 -21
  58. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  59. package/out-tsc/src/flow/actions/set_contact_channel.js +6 -9
  60. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  61. package/out-tsc/src/flow/actions/set_contact_field.js +20 -20
  62. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  63. package/out-tsc/src/flow/actions/set_contact_language.js +3 -2
  64. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  65. package/out-tsc/src/flow/actions/set_contact_name.js +3 -12
  66. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
  67. package/out-tsc/src/flow/actions/set_contact_status.js +3 -2
  68. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  69. package/out-tsc/src/flow/actions/set_run_result.js +4 -3
  70. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  71. package/out-tsc/src/flow/actions/start_session.js +181 -6
  72. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  73. package/out-tsc/src/flow/config.js +11 -23
  74. package/out-tsc/src/flow/config.js.map +1 -1
  75. package/out-tsc/src/flow/currencies.js +45 -0
  76. package/out-tsc/src/flow/currencies.js.map +1 -0
  77. package/out-tsc/src/flow/nodes/shared-rules.js +257 -0
  78. package/out-tsc/src/flow/nodes/shared-rules.js.map +1 -0
  79. package/out-tsc/src/flow/nodes/shared.js +71 -0
  80. package/out-tsc/src/flow/nodes/shared.js.map +1 -0
  81. package/out-tsc/src/flow/nodes/split_by_airtime.js +211 -5
  82. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -1
  83. package/out-tsc/src/flow/nodes/split_by_contact_field.js +152 -3
  84. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
  85. package/out-tsc/src/flow/nodes/split_by_expression.js +73 -2
  86. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
  87. package/out-tsc/src/flow/nodes/split_by_groups.js +18 -10
  88. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
  89. package/out-tsc/src/flow/nodes/split_by_intent.js +8 -0
  90. package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -0
  91. package/out-tsc/src/flow/nodes/split_by_llm.js +11 -3
  92. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
  93. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +10 -3
  94. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  95. package/out-tsc/src/flow/nodes/split_by_random.js +10 -4
  96. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  97. package/out-tsc/src/flow/nodes/split_by_resthook.js +113 -0
  98. package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -0
  99. package/out-tsc/src/flow/nodes/split_by_run_result.js +211 -3
  100. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
  101. package/out-tsc/src/flow/nodes/split_by_scheme.js +158 -2
  102. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
  103. package/out-tsc/src/flow/nodes/split_by_subflow.js +13 -5
  104. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  105. package/out-tsc/src/flow/nodes/split_by_ticket.js +10 -3
  106. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  107. package/out-tsc/src/flow/nodes/split_by_webhook.js +10 -3
  108. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  109. package/out-tsc/src/flow/nodes/wait_for_digits.js +3 -2
  110. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  111. package/out-tsc/src/flow/nodes/wait_for_menu.js +3 -2
  112. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
  113. package/out-tsc/src/flow/nodes/wait_for_response.js +38 -568
  114. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  115. package/out-tsc/src/flow/types.js +86 -12
  116. package/out-tsc/src/flow/types.js.map +1 -1
  117. package/out-tsc/src/flow/utils.js +101 -14
  118. package/out-tsc/src/flow/utils.js.map +1 -1
  119. package/out-tsc/src/form/FieldRenderer.js +2 -4
  120. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  121. package/out-tsc/src/interfaces.js +3 -0
  122. package/out-tsc/src/interfaces.js.map +1 -1
  123. package/out-tsc/src/layout/FloatingWindow.js +346 -0
  124. package/out-tsc/src/layout/FloatingWindow.js.map +1 -0
  125. package/out-tsc/src/list/SortableList.js +98 -33
  126. package/out-tsc/src/list/SortableList.js.map +1 -1
  127. package/out-tsc/src/live/ContactChat.js +6 -25
  128. package/out-tsc/src/live/ContactChat.js.map +1 -1
  129. package/out-tsc/src/locales/es.js +5 -5
  130. package/out-tsc/src/locales/es.js.map +1 -1
  131. package/out-tsc/src/locales/fr.js +5 -5
  132. package/out-tsc/src/locales/fr.js.map +1 -1
  133. package/out-tsc/src/locales/locale-codes.js +11 -2
  134. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  135. package/out-tsc/src/locales/pt.js +5 -5
  136. package/out-tsc/src/locales/pt.js.map +1 -1
  137. package/out-tsc/src/store/AppState.js +120 -0
  138. package/out-tsc/src/store/AppState.js.map +1 -1
  139. package/out-tsc/src/utils.js +254 -13
  140. package/out-tsc/src/utils.js.map +1 -1
  141. package/out-tsc/temba-modules.js +8 -0
  142. package/out-tsc/temba-modules.js.map +1 -1
  143. package/out-tsc/test/ActionHelper.js +3 -3
  144. package/out-tsc/test/ActionHelper.js.map +1 -1
  145. package/out-tsc/test/NodeHelper.js +6 -3
  146. package/out-tsc/test/NodeHelper.js.map +1 -1
  147. package/out-tsc/test/actions/add_contact_urn.test.js +202 -0
  148. package/out-tsc/test/actions/add_contact_urn.test.js.map +1 -0
  149. package/out-tsc/test/actions/send_broadcast.test.js +148 -0
  150. package/out-tsc/test/actions/send_broadcast.test.js.map +1 -0
  151. package/out-tsc/test/actions/send_email.test.js +17 -23
  152. package/out-tsc/test/actions/send_email.test.js.map +1 -1
  153. package/out-tsc/test/actions/send_msg.test.js +33 -15
  154. package/out-tsc/test/actions/send_msg.test.js.map +1 -1
  155. package/out-tsc/test/actions/start_session.test.js +116 -0
  156. package/out-tsc/test/actions/start_session.test.js.map +1 -0
  157. package/out-tsc/test/nodes/split_by_airtime.test.js +604 -0
  158. package/out-tsc/test/nodes/split_by_airtime.test.js.map +1 -0
  159. package/out-tsc/test/nodes/split_by_contact_field.test.js +387 -0
  160. package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -0
  161. package/out-tsc/test/nodes/split_by_expression.test.js +614 -0
  162. package/out-tsc/test/nodes/split_by_expression.test.js.map +1 -0
  163. package/out-tsc/test/nodes/split_by_random.test.js +3 -3
  164. package/out-tsc/test/nodes/split_by_random.test.js.map +1 -1
  165. package/out-tsc/test/nodes/split_by_resthook.test.js +337 -0
  166. package/out-tsc/test/nodes/split_by_resthook.test.js.map +1 -0
  167. package/out-tsc/test/nodes/split_by_run_result.test.js +920 -0
  168. package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -0
  169. package/out-tsc/test/nodes/split_by_scheme.test.js +399 -0
  170. package/out-tsc/test/nodes/split_by_scheme.test.js.map +1 -0
  171. package/out-tsc/test/nodes/split_by_subflow.test.js +333 -0
  172. package/out-tsc/test/nodes/split_by_subflow.test.js.map +1 -0
  173. package/out-tsc/test/nodes/wait_for_digits.test.js +2 -2
  174. package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
  175. package/out-tsc/test/nodes/wait_for_response.test.js +2 -1
  176. package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -1
  177. package/out-tsc/test/temba-action-drag-between-nodes.test.js +252 -0
  178. package/out-tsc/test/temba-action-drag-between-nodes.test.js.map +1 -0
  179. package/out-tsc/test/temba-canvas-menu.test.js +122 -0
  180. package/out-tsc/test/temba-canvas-menu.test.js.map +1 -0
  181. package/out-tsc/test/temba-floating-tab.test.js +91 -0
  182. package/out-tsc/test/temba-floating-tab.test.js.map +1 -0
  183. package/out-tsc/test/temba-floating-window.test.js +301 -0
  184. package/out-tsc/test/temba-floating-window.test.js.map +1 -0
  185. package/out-tsc/test/temba-flow-editor-node.test.js +202 -2
  186. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  187. package/out-tsc/test/temba-flow-editor.test.js +7 -8
  188. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  189. package/out-tsc/test/temba-localization.test.js +471 -0
  190. package/out-tsc/test/temba-localization.test.js.map +1 -0
  191. package/out-tsc/test/temba-node-editor.test.js +3 -1
  192. package/out-tsc/test/temba-node-editor.test.js.map +1 -1
  193. package/out-tsc/test/temba-node-type-selector.test.js +265 -0
  194. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -0
  195. package/out-tsc/test/temba-omnibox.test.js +2 -1
  196. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  197. package/out-tsc/test/temba-sortable-list.test.js +51 -0
  198. package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
  199. package/out-tsc/test/temba-utils-index.test.js +1 -27
  200. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  201. package/out-tsc/test/utils.test.js +20 -0
  202. package/out-tsc/test/utils.test.js.map +1 -1
  203. package/package.json +2 -1
  204. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  205. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  206. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  207. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  208. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  209. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  210. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  211. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  212. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  213. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  214. package/screenshots/truth/actions/add_contact_urn/editor/expression-facebook.png +0 -0
  215. package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
  216. package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
  217. package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
  218. package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
  219. package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
  220. package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
  221. package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
  222. package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
  223. package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
  224. package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
  225. package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
  226. package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
  227. package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
  228. package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
  229. package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
  230. package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
  231. package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
  232. package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
  233. package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
  234. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  235. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  236. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  237. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  238. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  239. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  240. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  241. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  242. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  243. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  244. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  245. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  246. package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
  247. package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
  248. package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
  249. package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
  250. package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
  251. package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
  252. package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
  253. package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
  254. package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
  255. package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
  256. package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
  257. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  258. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  259. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  260. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  261. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  262. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  263. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  264. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  265. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  266. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  267. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  268. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  269. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  270. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  271. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  272. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  273. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  274. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  275. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  276. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  277. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  278. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  279. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  280. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  281. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  282. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  283. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  284. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  285. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  286. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  287. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  288. package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
  289. package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
  290. package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
  291. package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
  292. package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
  293. package/screenshots/truth/actions/start_session/editor/many-recipients.png +0 -0
  294. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  295. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  296. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  297. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  298. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  299. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  300. package/screenshots/truth/canvas-menu/open.png +0 -0
  301. package/screenshots/truth/editor/router.png +0 -0
  302. package/screenshots/truth/editor/wait.png +0 -0
  303. package/screenshots/truth/floating-tab/default.png +0 -0
  304. package/screenshots/truth/floating-tab/gray.png +0 -0
  305. package/screenshots/truth/floating-tab/green.png +0 -0
  306. package/screenshots/truth/floating-tab/hidden.png +0 -0
  307. package/screenshots/truth/floating-tab/hover.png +0 -0
  308. package/screenshots/truth/floating-tab/purple.png +0 -0
  309. package/screenshots/truth/floating-window/chromeless.png +0 -0
  310. package/screenshots/truth/floating-window/custom-size.png +0 -0
  311. package/screenshots/truth/floating-window/default.png +0 -0
  312. package/screenshots/truth/floating-window/with-header.png +0 -0
  313. package/screenshots/truth/list/fields-dragging.png +0 -0
  314. package/screenshots/truth/list/sortable-dragging.png +0 -0
  315. package/screenshots/truth/node-type-selector/action-mode.png +0 -0
  316. package/screenshots/truth/node-type-selector/split-mode.png +0 -0
  317. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  318. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  319. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  320. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  321. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  322. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  323. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  324. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  325. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  326. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  327. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  328. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  329. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  330. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  331. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  332. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  333. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  334. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  335. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  336. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  337. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  338. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  339. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  340. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  341. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  342. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  343. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  344. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  345. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  346. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  347. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  348. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  349. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  350. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
  351. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  352. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  353. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  354. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  355. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  356. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  357. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  358. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  359. package/src/Icons.ts +4 -1
  360. package/src/display/FloatingTab.ts +174 -0
  361. package/src/display/ProgressBar.ts +22 -2
  362. package/src/events.ts +2 -8
  363. package/src/flow/CanvasMenu.ts +217 -0
  364. package/src/flow/CanvasNode.ts +596 -40
  365. package/src/flow/Editor.ts +1721 -45
  366. package/src/flow/NodeEditor.ts +621 -144
  367. package/src/flow/NodeTypeSelector.ts +636 -0
  368. package/src/flow/StickyNote.ts +12 -3
  369. package/src/flow/actions/add_contact_groups.ts +5 -4
  370. package/src/flow/actions/add_contact_urn.ts +78 -4
  371. package/src/flow/actions/add_input_labels.ts +5 -4
  372. package/src/flow/actions/play_audio.ts +3 -2
  373. package/src/flow/actions/remove_contact_groups.ts +16 -6
  374. package/src/flow/actions/request_optin.ts +3 -2
  375. package/src/flow/actions/say_msg.ts +3 -2
  376. package/src/flow/actions/send_broadcast.ts +86 -23
  377. package/src/flow/actions/send_email.ts +12 -6
  378. package/src/flow/actions/send_msg.ts +155 -34
  379. package/src/flow/actions/set_contact_channel.ts +6 -11
  380. package/src/flow/actions/set_contact_field.ts +21 -25
  381. package/src/flow/actions/set_contact_language.ts +11 -4
  382. package/src/flow/actions/set_contact_name.ts +4 -15
  383. package/src/flow/actions/set_contact_status.ts +4 -3
  384. package/src/flow/actions/set_run_result.ts +5 -4
  385. package/src/flow/actions/start_session.ts +210 -6
  386. package/src/flow/config.ts +11 -23
  387. package/src/flow/currencies.ts +51 -0
  388. package/src/flow/nodes/shared-rules.ts +301 -0
  389. package/src/flow/nodes/shared.ts +87 -0
  390. package/src/flow/nodes/split_by_airtime.ts +255 -5
  391. package/src/flow/nodes/split_by_contact_field.ts +195 -3
  392. package/src/flow/nodes/split_by_expression.ts +104 -2
  393. package/src/flow/nodes/split_by_groups.ts +26 -11
  394. package/src/flow/nodes/split_by_intent.ts +8 -0
  395. package/src/flow/nodes/split_by_llm.ts +22 -4
  396. package/src/flow/nodes/split_by_llm_categorize.ts +22 -5
  397. package/src/flow/nodes/split_by_random.ts +16 -6
  398. package/src/flow/nodes/split_by_resthook.ts +140 -0
  399. package/src/flow/nodes/split_by_run_result.ts +259 -3
  400. package/src/flow/nodes/split_by_scheme.ts +202 -2
  401. package/src/flow/nodes/split_by_subflow.ts +17 -5
  402. package/src/flow/nodes/split_by_ticket.ts +15 -4
  403. package/src/flow/nodes/split_by_webhook.ts +17 -6
  404. package/src/flow/nodes/wait_for_digits.ts +3 -2
  405. package/src/flow/nodes/wait_for_menu.ts +3 -2
  406. package/src/flow/nodes/wait_for_response.ts +59 -680
  407. package/src/flow/types.ts +156 -23
  408. package/src/flow/utils.ts +108 -14
  409. package/src/form/FieldRenderer.ts +2 -4
  410. package/src/interfaces.ts +3 -0
  411. package/src/layout/FloatingWindow.ts +386 -0
  412. package/src/list/SortableList.ts +109 -34
  413. package/src/live/ContactChat.ts +7 -25
  414. package/src/locales/es.ts +18 -13
  415. package/src/locales/fr.ts +18 -13
  416. package/src/locales/locale-codes.ts +11 -2
  417. package/src/locales/pt.ts +18 -13
  418. package/src/store/AppState.ts +173 -0
  419. package/src/store/flow-definition.d.ts +2 -5
  420. package/src/utils.ts +332 -12
  421. package/static/api/channels.json +46 -0
  422. package/static/api/llms.json +18 -0
  423. package/static/api/resthooks.json +31 -0
  424. package/static/svg/index.svg +1 -1
  425. package/static/svg/work/traced/lightning-02.svg +1 -0
  426. package/static/svg/work/used/lightning-02.svg +3 -0
  427. package/temba-modules.ts +8 -0
  428. package/test/ActionHelper.ts +3 -3
  429. package/test/NodeHelper.ts +6 -3
  430. package/test/actions/add_contact_urn.test.ts +287 -0
  431. package/test/actions/send_broadcast.test.ts +190 -0
  432. package/test/actions/send_email.test.ts +17 -23
  433. package/test/actions/send_msg.test.ts +39 -15
  434. package/test/actions/start_session.test.ts +151 -0
  435. package/test/nodes/split_by_airtime.test.ts +673 -0
  436. package/test/nodes/split_by_contact_field.test.ts +451 -0
  437. package/test/nodes/split_by_expression.test.ts +751 -0
  438. package/test/nodes/split_by_random.test.ts +3 -3
  439. package/test/nodes/split_by_resthook.test.ts +398 -0
  440. package/test/nodes/split_by_run_result.test.ts +1109 -0
  441. package/test/nodes/split_by_scheme.test.ts +486 -0
  442. package/test/nodes/split_by_subflow.test.ts +381 -0
  443. package/test/nodes/wait_for_digits.test.ts +2 -2
  444. package/test/nodes/wait_for_response.test.ts +2 -1
  445. package/test/temba-action-drag-between-nodes.test.ts +301 -0
  446. package/test/temba-canvas-menu.test.ts +156 -0
  447. package/test/temba-floating-tab.test.ts +110 -0
  448. package/test/temba-floating-window.test.ts +477 -0
  449. package/test/temba-flow-editor-node.test.ts +246 -2
  450. package/test/temba-flow-editor.test.ts +7 -8
  451. package/test/temba-localization.test.ts +611 -0
  452. package/test/temba-node-editor.test.ts +3 -1
  453. package/test/temba-node-type-selector.test.ts +355 -0
  454. package/test/temba-omnibox.test.ts +2 -1
  455. package/test/temba-sortable-list.test.ts +69 -0
  456. package/test/temba-utils-index.test.ts +0 -35
  457. package/test/utils.test.ts +22 -0
  458. package/test-assets/contacts/history.json +14 -21
  459. package/test-assets/select/llms.json +2 -2
  460. package/web-dev-server.config.mjs +49 -1
  461. package/web-test-runner.config.mjs +0 -1
  462. package/out-tsc/src/flow/actions/call_classifier.js +0 -11
  463. package/out-tsc/src/flow/actions/call_classifier.js.map +0 -1
  464. package/out-tsc/src/flow/actions/call_resthook.js +0 -11
  465. package/out-tsc/src/flow/actions/call_resthook.js.map +0 -1
  466. package/out-tsc/src/flow/actions/split_by_expression_example.js +0 -77
  467. package/out-tsc/src/flow/actions/split_by_expression_example.js.map +0 -1
  468. package/out-tsc/src/flow/actions/transfer_airtime.js +0 -11
  469. package/out-tsc/src/flow/actions/transfer_airtime.js.map +0 -1
  470. package/out-tsc/src/flow/nodes/wait_for_audio.js +0 -7
  471. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +0 -1
  472. package/out-tsc/src/flow/nodes/wait_for_image.js +0 -7
  473. package/out-tsc/src/flow/nodes/wait_for_image.js.map +0 -1
  474. package/out-tsc/src/flow/nodes/wait_for_location.js +0 -7
  475. package/out-tsc/src/flow/nodes/wait_for_location.js.map +0 -1
  476. package/out-tsc/src/flow/nodes/wait_for_video.js +0 -7
  477. package/out-tsc/src/flow/nodes/wait_for_video.js.map +0 -1
  478. package/src/flow/actions/call_classifier.ts +0 -12
  479. package/src/flow/actions/call_resthook.ts +0 -12
  480. package/src/flow/actions/split_by_expression_example.ts +0 -88
  481. package/src/flow/actions/transfer_airtime.ts +0 -12
  482. package/src/flow/nodes/wait_for_audio.ts +0 -7
  483. package/src/flow/nodes/wait_for_image.ts +0 -7
  484. package/src/flow/nodes/wait_for_location.ts +0 -7
  485. package/src/flow/nodes/wait_for_video.ts +0 -7
@@ -3,10 +3,13 @@ import { html, css } from 'lit';
3
3
  import { property, state } from 'lit/decorators.js';
4
4
  import { RapidElement } from '../RapidElement';
5
5
  import { NODE_CONFIG, ACTION_CONFIG } from './config';
6
+ import { ACTION_GROUP_METADATA, SPLIT_GROUP_METADATA } from './types';
6
7
  import { CustomEventType } from '../interfaces';
7
8
  import { generateUUID } from '../utils';
8
9
  import { FieldRenderer } from '../form/FieldRenderer';
9
10
  import { renderMarkdownInline } from '../markdown';
11
+ import { fromStore, zustand } from '../store/AppState';
12
+ import { getStore } from '../store/Store';
10
13
  export class NodeEditor extends RapidElement {
11
14
  constructor() {
12
15
  super(...arguments);
@@ -16,6 +19,7 @@ export class NodeEditor extends RapidElement {
16
19
  this.errors = {};
17
20
  this.groupCollapseState = {};
18
21
  this.groupHoverState = {};
22
+ this.revealedOptionalFields = new Set();
19
23
  }
20
24
  static get styles() {
21
25
  return css `
@@ -25,7 +29,6 @@ export class NodeEditor extends RapidElement {
25
29
  flex-direction: column;
26
30
  gap: 15px;
27
31
  min-width: 400px;
28
- padding-bottom: 40px;
29
32
 
30
33
  --color-bubble-bg: rgba(var(--primary-rgb), 0.7);
31
34
  --color-bubble-border: rgba(0, 0, 0, 0.2);
@@ -88,6 +91,28 @@ export class NodeEditor extends RapidElement {
88
91
  align-items: center;
89
92
  }
90
93
 
94
+ .form-row-wrapper {
95
+ display: flex;
96
+ flex-direction: column;
97
+ }
98
+
99
+ .form-row-label {
100
+ margin-bottom: 5px;
101
+ margin-left: 4px;
102
+ display: block;
103
+ font-weight: 400;
104
+ font-size: var(--label-size);
105
+ letter-spacing: 0.05em;
106
+ line-height: normal;
107
+ color: var(--color-label, #777);
108
+ }
109
+
110
+ .form-row-help {
111
+ font-size: 12px;
112
+ color: #666;
113
+ margin-top: 6px;
114
+ }
115
+
91
116
  .form-group {
92
117
  border: 1px solid #e0e0e0;
93
118
  border-radius: 6px;
@@ -276,6 +301,69 @@ export class NodeEditor extends RapidElement {
276
301
  .gutter-fields temba-select {
277
302
  min-width: 120px;
278
303
  }
304
+
305
+ .optional-field-link {
306
+ margin: 10px 0;
307
+ }
308
+
309
+ .optional-field-link a {
310
+ color: var(--color-link-primary, #0066cc);
311
+ text-decoration: none;
312
+ font-size: 13px;
313
+ cursor: pointer;
314
+ }
315
+
316
+ .optional-field-link a:hover {
317
+ text-decoration: underline;
318
+ }
319
+
320
+ .original-value {
321
+ background: #fff8dc;
322
+ padding: 10px;
323
+ border-radius: 4px;
324
+ font-size: 13px;
325
+ color: #666;
326
+ }
327
+
328
+ .original-value-content {
329
+ color: #333;
330
+ white-space: pre-wrap;
331
+ word-break: break-word;
332
+ }
333
+
334
+ .category-localization-table {
335
+ width: 100%;
336
+ display: flex;
337
+ flex-direction: column;
338
+ gap: 5px;
339
+ }
340
+
341
+ .category-localization-row {
342
+ display: grid;
343
+ grid-template-columns: 40% 60%;
344
+ }
345
+
346
+ .category-localization-row:last-child {
347
+ border-bottom: none;
348
+ }
349
+
350
+ .original-name {
351
+ padding: 10px 20px;
352
+ background: #fff8dc;
353
+ display: flex;
354
+ align-items: center;
355
+ border-radius: var(--curvature);
356
+ }
357
+
358
+ .localized-name {
359
+ padding: 10px;
360
+ display: flex;
361
+ align-items: center;
362
+ }
363
+
364
+ .localized-name temba-textinput {
365
+ width: 100%;
366
+ }
279
367
  `;
280
368
  }
281
369
  connectedCallback() {
@@ -307,11 +395,20 @@ export class NodeEditor extends RapidElement {
307
395
  this.isOpen = true;
308
396
  }
309
397
  initializeFormData() {
398
+ var _a, _b, _c, _d, _e;
310
399
  const nodeConfig = this.getNodeConfig();
311
400
  if ((!nodeConfig || nodeConfig.type === 'execute_actions') && this.action) {
312
401
  // Action editing mode - use action config
313
402
  const actionConfig = ACTION_CONFIG[this.action.type];
314
- if (actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.toFormData) {
403
+ // Check if we're in localization mode
404
+ if (this.isTranslating &&
405
+ (actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.localizable) &&
406
+ actionConfig.toLocalizationFormData) {
407
+ // Get localized values for this action
408
+ const localization = ((_c = (_b = (_a = this.flowDefinition) === null || _a === void 0 ? void 0 : _a.localization) === null || _b === void 0 ? void 0 : _b[this.languageCode]) === null || _c === void 0 ? void 0 : _c[this.action.uuid]) || {};
409
+ this.formData = actionConfig.toLocalizationFormData(this.action, localization);
410
+ }
411
+ else if (actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.toFormData) {
315
412
  this.formData = actionConfig.toFormData(this.action);
316
413
  }
317
414
  else {
@@ -325,8 +422,16 @@ export class NodeEditor extends RapidElement {
325
422
  else if (this.node) {
326
423
  // Node editing mode - use node config
327
424
  const nodeConfig = this.getNodeConfig();
328
- if (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.toFormData) {
329
- this.formData = nodeConfig.toFormData(this.node);
425
+ // Check if we're in localization mode for a node with localizable categories
426
+ if (this.isTranslating &&
427
+ (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.localizable) === 'categories' &&
428
+ nodeConfig.toLocalizationFormData) {
429
+ // Get localized values for this node's categories
430
+ const localization = ((_e = (_d = this.flowDefinition) === null || _d === void 0 ? void 0 : _d.localization) === null || _e === void 0 ? void 0 : _e[this.languageCode]) || {};
431
+ this.formData = nodeConfig.toLocalizationFormData(this.node, localization);
432
+ }
433
+ else if (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.toFormData) {
434
+ this.formData = nodeConfig.toFormData(this.node, this.nodeUI);
330
435
  }
331
436
  else {
332
437
  this.formData = { ...this.node };
@@ -433,8 +538,12 @@ export class NodeEditor extends RapidElement {
433
538
  return this.nodeUI.type ? NODE_CONFIG[this.nodeUI.type] : null;
434
539
  }
435
540
  getHeaderColor() {
541
+ var _a, _b;
436
542
  const config = this.getConfig();
437
- return (config === null || config === void 0 ? void 0 : config.color) || '#666666';
543
+ return (config === null || config === void 0 ? void 0 : config.group)
544
+ ? ((_a = ACTION_GROUP_METADATA[config.group]) === null || _a === void 0 ? void 0 : _a.color) ||
545
+ ((_b = SPLIT_GROUP_METADATA[config.group]) === null || _b === void 0 ? void 0 : _b.color)
546
+ : '#aaaaaa';
438
547
  }
439
548
  handleDialogButtonClick(event) {
440
549
  const button = event.detail.button;
@@ -446,24 +555,77 @@ export class NodeEditor extends RapidElement {
446
555
  }
447
556
  }
448
557
  handleSave() {
449
- // Validate the form
450
- const validation = this.validateForm();
451
- if (!validation.valid) {
452
- this.errors = validation.errors;
453
- // Expand any groups that contain validation errors
454
- this.expandGroupsWithErrors(validation.errors);
455
- return;
456
- }
457
- // Process form data to convert key-value arrays to Records before saving
558
+ var _a, _b, _c, _d;
559
+ // Process form data first
458
560
  const processedFormData = this.processFormDataForSave();
561
+ // Skip validation if we're in localization mode
562
+ // (localization only deals with translating text, not changing structure)
563
+ if (!this.isTranslating) {
564
+ // Validate the form
565
+ const validation = this.validateForm();
566
+ if (!validation.valid) {
567
+ this.errors = validation.errors;
568
+ // Expand any groups that contain validation errors
569
+ this.expandGroupsWithErrors(validation.errors);
570
+ return;
571
+ }
572
+ }
573
+ // Check if we're in localization mode
574
+ if (this.isTranslating) {
575
+ // Handle action localization
576
+ if (this.action) {
577
+ const actionConfig = ACTION_CONFIG[this.action.type];
578
+ if ((actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.localizable) &&
579
+ actionConfig.fromLocalizationFormData) {
580
+ // Save to localization structure
581
+ const localizationData = actionConfig.fromLocalizationFormData(processedFormData, this.action);
582
+ // Update the flow definition's localization
583
+ this.updateLocalization(this.languageCode, this.action.uuid, localizationData);
584
+ // Close the dialog
585
+ this.fireCustomEvent(CustomEventType.NodeEditCancelled, {});
586
+ return;
587
+ }
588
+ }
589
+ // Handle node localization (for router categories)
590
+ if (this.node) {
591
+ const nodeConfig = this.getNodeConfig();
592
+ if ((nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.localizable) === 'categories' &&
593
+ nodeConfig.fromLocalizationFormData) {
594
+ // Get localization data for all categories
595
+ const localizationData = nodeConfig.fromLocalizationFormData(processedFormData, this.node);
596
+ const languageLocalization = ((_b = (_a = this.flowDefinition) === null || _a === void 0 ? void 0 : _a.localization) === null || _b === void 0 ? void 0 : _b[this.languageCode]) || {};
597
+ const categories = ((_d = (_c = this.node) === null || _c === void 0 ? void 0 : _c.router) === null || _d === void 0 ? void 0 : _d.categories) || [];
598
+ categories.forEach((category) => {
599
+ const categoryUuid = category.uuid;
600
+ const nextLocalization = localizationData[categoryUuid];
601
+ if (nextLocalization) {
602
+ this.updateLocalization(this.languageCode, categoryUuid, nextLocalization);
603
+ }
604
+ else if (languageLocalization[categoryUuid]) {
605
+ // Remove existing localization when the translation was cleared
606
+ this.updateLocalization(this.languageCode, categoryUuid, {});
607
+ }
608
+ });
609
+ // Close the dialog
610
+ this.fireCustomEvent(CustomEventType.NodeEditCancelled, {});
611
+ return;
612
+ }
613
+ }
614
+ }
459
615
  // Determine whether to use node or action saving based on context
460
616
  // If we have a node with a router, always use node saving (even if action is set)
461
617
  // because router configuration is handled at the node level
462
618
  if (this.node && this.node.router) {
463
619
  // Node editing mode with router - use formDataToNode
464
620
  const updatedNode = this.formDataToNode(processedFormData);
621
+ // Generate UI config if the node config provides a toUIConfig function
622
+ const nodeConfig = this.getNodeConfig();
623
+ const uiConfig = (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.toUIConfig)
624
+ ? nodeConfig.toUIConfig(processedFormData)
625
+ : undefined;
465
626
  this.fireCustomEvent(CustomEventType.NodeSaved, {
466
- node: updatedNode
627
+ node: updatedNode,
628
+ uiConfig
467
629
  });
468
630
  }
469
631
  else if (this.action) {
@@ -476,11 +638,23 @@ export class NodeEditor extends RapidElement {
476
638
  else if (this.node) {
477
639
  // Node editing mode without router
478
640
  const updatedNode = this.formDataToNode(processedFormData);
641
+ // Generate UI config if the node config provides a toUIConfig function
642
+ const nodeConfig = this.getNodeConfig();
643
+ const uiConfig = (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.toUIConfig)
644
+ ? nodeConfig.toUIConfig(processedFormData)
645
+ : undefined;
479
646
  this.fireCustomEvent(CustomEventType.NodeSaved, {
480
- node: updatedNode
647
+ node: updatedNode,
648
+ uiConfig
481
649
  });
482
650
  }
483
651
  }
652
+ updateLocalization(languageCode, actionUuid, localizationData) {
653
+ // Use the store method to properly update localization with immer
654
+ zustand
655
+ .getState()
656
+ .updateLocalization(languageCode, actionUuid, localizationData);
657
+ }
484
658
  processFormDataForSave() {
485
659
  const processed = { ...this.formData };
486
660
  // Convert key-value arrays to Records
@@ -532,8 +706,9 @@ export class NodeEditor extends RapidElement {
532
706
  'There was an error creating' + ' "' + selected.name + '"';
533
707
  }
534
708
  }
535
- // Check required fields
536
- if (fieldConfig.required &&
709
+ // Check required fields (skip in localization mode since all fields are optional)
710
+ if (!this.isTranslating &&
711
+ fieldConfig.required &&
537
712
  (!value || (Array.isArray(value) && value.length === 0))) {
538
713
  errors[fieldName] = `${fieldConfig.label || fieldName} is required.`;
539
714
  }
@@ -642,8 +817,14 @@ export class NodeEditor extends RapidElement {
642
817
  if (!this.node)
643
818
  throw new Error('No node to update');
644
819
  let updatedNode = { ...this.node };
820
+ // Check if node config has fromFormData - if so, it handles the entire transformation
821
+ const nodeConfig = this.getNodeConfig();
822
+ const nodeHasFromFormData = (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.fromFormData) !== undefined;
645
823
  // Handle actions using action config transformations if available
646
- if (this.node.actions && this.node.actions.length > 0) {
824
+ // Skip this if the node has its own fromFormData (which handles actions itself)
825
+ if (!nodeHasFromFormData &&
826
+ this.node.actions &&
827
+ this.node.actions.length > 0) {
647
828
  updatedNode.actions = this.node.actions.map((action) => {
648
829
  // If we're editing a specific action, only transform that one
649
830
  if (this.action && action.uuid === this.action.uuid) {
@@ -664,53 +845,83 @@ export class NodeEditor extends RapidElement {
664
845
  });
665
846
  }
666
847
  // Handle router configuration using node config
667
- if (this.node.router) {
668
- const nodeConfig = this.getNodeConfig();
669
- if (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.fromFormData) {
670
- // Use node-specific form data transformation
671
- updatedNode = nodeConfig.fromFormData(formData, updatedNode);
848
+ if (nodeHasFromFormData) {
849
+ // Use node-specific form data transformation
850
+ // When a node has fromFormData, it's responsible for creating the entire
851
+ // node structure including actions and router (regardless of whether router exists yet)
852
+ updatedNode = nodeConfig.fromFormData(formData, updatedNode);
853
+ }
854
+ else if (this.node.router) {
855
+ // Default router handling when no nodeConfig.fromFormData
856
+ updatedNode.router = { ...this.node.router };
857
+ // Apply form data to router fields if they exist
858
+ if (formData.result_name !== undefined) {
859
+ updatedNode.router.result_name = formData.result_name;
672
860
  }
673
- else {
674
- // Default router handling
675
- updatedNode.router = { ...this.node.router };
676
- // Apply form data to router fields if they exist
677
- if (formData.result_name !== undefined) {
678
- updatedNode.router.result_name = formData.result_name;
679
- }
680
- // Handle preconfigured rules from node config
681
- if ((_a = nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.router) === null || _a === void 0 ? void 0 : _a.rules) {
682
- // Build a complete new set of categories and exits based on node config
683
- const existingCategories = updatedNode.router.categories || [];
684
- const existingExits = updatedNode.exits || [];
685
- const newCategories = [];
686
- const newExits = [];
687
- // Group rules by category name to handle multiple rules pointing to the same category
688
- const categoryNameToRules = new Map();
689
- nodeConfig.router.rules.forEach((rule) => {
690
- if (!categoryNameToRules.has(rule.categoryName)) {
691
- categoryNameToRules.set(rule.categoryName, []);
861
+ // Handle preconfigured rules from node config
862
+ if ((_a = nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.router) === null || _a === void 0 ? void 0 : _a.rules) {
863
+ // Build a complete new set of categories and exits based on node config
864
+ const existingCategories = updatedNode.router.categories || [];
865
+ const existingExits = updatedNode.exits || [];
866
+ const newCategories = [];
867
+ const newExits = [];
868
+ // Group rules by category name to handle multiple rules pointing to the same category
869
+ const categoryNameToRules = new Map();
870
+ nodeConfig.router.rules.forEach((rule) => {
871
+ if (!categoryNameToRules.has(rule.categoryName)) {
872
+ categoryNameToRules.set(rule.categoryName, []);
873
+ }
874
+ categoryNameToRules.get(rule.categoryName).push(rule);
875
+ });
876
+ // Create categories for all unique category names
877
+ categoryNameToRules.forEach((rules, categoryName) => {
878
+ // Check if category already exists to preserve its UUID and exit_uuid
879
+ const existingCategory = existingCategories.find((cat) => cat.name === categoryName);
880
+ if (existingCategory) {
881
+ // Preserve existing category and its associated exit
882
+ newCategories.push(existingCategory);
883
+ const associatedExit = existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid);
884
+ if (associatedExit) {
885
+ newExits.push(associatedExit);
692
886
  }
693
- categoryNameToRules.get(rule.categoryName).push(rule);
694
- });
695
- // Create categories for all unique category names
696
- categoryNameToRules.forEach((rules, categoryName) => {
697
- // Check if category already exists to preserve its UUID and exit_uuid
698
- const existingCategory = existingCategories.find((cat) => cat.name === categoryName);
699
- if (existingCategory) {
700
- // Preserve existing category and its associated exit
701
- newCategories.push(existingCategory);
702
- const associatedExit = existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid);
887
+ }
888
+ else {
889
+ // Create new category and exit
890
+ const categoryUuid = generateUUID();
891
+ const exitUuid = generateUUID();
892
+ newCategories.push({
893
+ uuid: categoryUuid,
894
+ name: categoryName,
895
+ exit_uuid: exitUuid
896
+ });
897
+ newExits.push({
898
+ uuid: exitUuid,
899
+ destination_uuid: null
900
+ });
901
+ }
902
+ });
903
+ // Add default category if specified
904
+ if (nodeConfig.router.defaultCategory) {
905
+ // Check if default category already exists in our new list
906
+ const existingDefault = newCategories.find((cat) => cat.name === nodeConfig.router.defaultCategory);
907
+ if (!existingDefault) {
908
+ // Check if it exists in the original categories
909
+ const originalDefault = existingCategories.find((cat) => cat.name === nodeConfig.router.defaultCategory);
910
+ if (originalDefault) {
911
+ // Preserve existing default category and its exit
912
+ newCategories.push(originalDefault);
913
+ const associatedExit = existingExits.find((exit) => exit.uuid === originalDefault.exit_uuid);
703
914
  if (associatedExit) {
704
915
  newExits.push(associatedExit);
705
916
  }
706
917
  }
707
918
  else {
708
- // Create new category and exit
919
+ // Create new default category and exit
709
920
  const categoryUuid = generateUUID();
710
921
  const exitUuid = generateUUID();
711
922
  newCategories.push({
712
923
  uuid: categoryUuid,
713
- name: categoryName,
924
+ name: nodeConfig.router.defaultCategory,
714
925
  exit_uuid: exitUuid
715
926
  });
716
927
  newExits.push({
@@ -718,42 +929,11 @@ export class NodeEditor extends RapidElement {
718
929
  destination_uuid: null
719
930
  });
720
931
  }
721
- });
722
- // Add default category if specified
723
- if (nodeConfig.router.defaultCategory) {
724
- // Check if default category already exists in our new list
725
- const existingDefault = newCategories.find((cat) => cat.name === nodeConfig.router.defaultCategory);
726
- if (!existingDefault) {
727
- // Check if it exists in the original categories
728
- const originalDefault = existingCategories.find((cat) => cat.name === nodeConfig.router.defaultCategory);
729
- if (originalDefault) {
730
- // Preserve existing default category and its exit
731
- newCategories.push(originalDefault);
732
- const associatedExit = existingExits.find((exit) => exit.uuid === originalDefault.exit_uuid);
733
- if (associatedExit) {
734
- newExits.push(associatedExit);
735
- }
736
- }
737
- else {
738
- // Create new default category and exit
739
- const categoryUuid = generateUUID();
740
- const exitUuid = generateUUID();
741
- newCategories.push({
742
- uuid: categoryUuid,
743
- name: nodeConfig.router.defaultCategory,
744
- exit_uuid: exitUuid
745
- });
746
- newExits.push({
747
- uuid: exitUuid,
748
- destination_uuid: null
749
- });
750
- }
751
- }
752
932
  }
753
- // Replace the entire categories and exits lists with our complete new sets
754
- updatedNode.router.categories = newCategories;
755
- updatedNode.exits = newExits;
756
933
  }
934
+ // Replace the entire categories and exits lists with our complete new sets
935
+ updatedNode.router.categories = newCategories;
936
+ updatedNode.exits = newExits;
757
937
  }
758
938
  }
759
939
  else {
@@ -862,36 +1042,144 @@ export class NodeEditor extends RapidElement {
862
1042
  }
863
1043
  });
864
1044
  }
865
- renderNewField(fieldName, config, value) {
1045
+ /**
1046
+ * Helper method to check if a field is visible based on its conditions
1047
+ */
1048
+ isFieldVisible(fieldName, config) {
866
1049
  var _a;
867
- // Check visibility condition
868
1050
  if ((_a = config.conditions) === null || _a === void 0 ? void 0 : _a.visible) {
869
1051
  try {
870
- const isVisible = config.conditions.visible(this.formData);
871
- if (!isVisible) {
872
- return html ``;
873
- }
1052
+ return config.conditions.visible(this.formData);
874
1053
  }
875
1054
  catch (error) {
876
1055
  console.error(`Error checking visibility for ${fieldName}:`, error);
877
1056
  // If there's an error, show the field by default
1057
+ return true;
878
1058
  }
879
1059
  }
1060
+ return true;
1061
+ }
1062
+ renderNewField(fieldName, config, value) {
1063
+ // Check visibility condition
1064
+ if (!this.isFieldVisible(fieldName, config)) {
1065
+ return html ``;
1066
+ }
880
1067
  const errors = this.errors[fieldName] ? [this.errors[fieldName]] : [];
881
1068
  // Build container style with maxWidth if specified
882
1069
  const containerStyle = config.maxWidth
883
1070
  ? `max-width: ${config.maxWidth};`
884
1071
  : '';
1072
+ // Render original value if in localization mode and action has the field
1073
+ const originalValueDisplay = this.isTranslating && this.action && fieldName in this.action
1074
+ ? this.renderOriginalValue(fieldName, this.action[fieldName])
1075
+ : html ``;
885
1076
  const fieldContent = this.renderFieldContent(fieldName, config, value, errors);
1077
+ const content = html ` ${originalValueDisplay} ${fieldContent} `;
886
1078
  // Wrap in container with style if maxWidth is specified
887
1079
  if (containerStyle) {
888
- return html `<div style="${containerStyle}">${fieldContent}</div>`;
1080
+ return html `<div style="${containerStyle}">${content}</div>`;
1081
+ }
1082
+ return content;
1083
+ }
1084
+ renderOptionalField(fieldName, config, value) {
1085
+ // If the field has a value or has been revealed, show it
1086
+ const hasValue = value && value.toString().trim() !== '';
1087
+ const isRevealed = this.revealedOptionalFields.has(fieldName);
1088
+ if (hasValue || isRevealed) {
1089
+ // Render the field normally
1090
+ return this.renderNewField(fieldName, config, value);
1091
+ }
1092
+ // Show the "Save as..." link
1093
+ return html `
1094
+ <div class="optional-field-link">
1095
+ <a
1096
+ href="#"
1097
+ @click="${(e) => {
1098
+ e.preventDefault();
1099
+ this.revealOptionalField(fieldName);
1100
+ }}"
1101
+ >
1102
+ ${config.optionalLink}
1103
+ </a>
1104
+ </div>
1105
+ `;
1106
+ }
1107
+ revealOptionalField(fieldName) {
1108
+ this.revealedOptionalFields = new Set([
1109
+ ...this.revealedOptionalFields,
1110
+ fieldName
1111
+ ]);
1112
+ }
1113
+ renderCategoryLocalizationTable() {
1114
+ const categories = this.formData.categories || {};
1115
+ const categoryEntries = Object.entries(categories);
1116
+ if (categoryEntries.length === 0) {
1117
+ return html `<div>No categories to localize</div>`;
1118
+ }
1119
+ const languageName = getStore().getLanguageName(this.languageCode);
1120
+ return html `
1121
+ <div class="category-localization-table">
1122
+ ${categoryEntries.map(([categoryUuid, categoryData]) => html `
1123
+ <div class="category-localization-row">
1124
+ <div class="original-name">${categoryData.originalName}</div>
1125
+ <div class="localized-name">
1126
+ <temba-textinput
1127
+ name="${categoryUuid}"
1128
+ placeholder="${languageName} Translation"
1129
+ value="${categoryData.localizedName || ''}"
1130
+ @change=${(e) => this.handleCategoryLocalizationChange(categoryUuid, e.target.value)}
1131
+ ></temba-textinput>
1132
+ </div>
1133
+ </div>
1134
+ `)}
1135
+ </div>
1136
+ `;
1137
+ }
1138
+ handleCategoryLocalizationChange(categoryUuid, value) {
1139
+ // Update formData with new localized value
1140
+ if (!this.formData.categories) {
1141
+ this.formData.categories = {};
889
1142
  }
890
- return fieldContent;
1143
+ if (!this.formData.categories[categoryUuid]) {
1144
+ this.formData.categories[categoryUuid] = {};
1145
+ }
1146
+ this.formData.categories[categoryUuid].localizedName = value;
1147
+ // Trigger a re-render
1148
+ this.requestUpdate();
1149
+ }
1150
+ renderOriginalValue(fieldName, originalValue) {
1151
+ // Format the original value for display
1152
+ let displayValue = '';
1153
+ if (Array.isArray(originalValue)) {
1154
+ if (originalValue.length === 0) {
1155
+ return html ``; // Don't show anything for empty arrays
1156
+ }
1157
+ // For arrays, join with commas
1158
+ displayValue = originalValue.join(', ');
1159
+ }
1160
+ else if (typeof originalValue === 'string') {
1161
+ displayValue = originalValue;
1162
+ }
1163
+ else if (originalValue) {
1164
+ displayValue = String(originalValue);
1165
+ }
1166
+ // Don't show if empty
1167
+ if (!displayValue || displayValue.trim() === '') {
1168
+ return html ``;
1169
+ }
1170
+ return html `
1171
+ <div class="original-value">
1172
+ <div class="original-value-content">${displayValue}</div>
1173
+ </div>
1174
+ `;
891
1175
  }
892
1176
  renderFieldContent(fieldName, config, value, errors) {
1177
+ // In localization mode, make all fields optional (not required)
1178
+ const fieldConfig = this.isTranslating
1179
+ ? { ...config, required: false }
1180
+ : config;
893
1181
  // Use FieldRenderer for consistent field rendering
894
- return FieldRenderer.renderField(fieldName, config, value, {
1182
+ return FieldRenderer.renderField(fieldName, fieldConfig, value, {
895
1183
  errors,
896
1184
  onChange: (e) => {
897
1185
  // Handle different change event types
@@ -977,7 +1265,12 @@ export class NodeEditor extends RapidElement {
977
1265
  case 'field':
978
1266
  if (config.form[item.field] && !renderedFields.has(item.field)) {
979
1267
  renderedFields.add(item.field);
980
- return this.renderNewField(item.field, config.form[item.field], this.formData[item.field]);
1268
+ const fieldConfig = config.form[item.field];
1269
+ // Handle optional link fields
1270
+ if (fieldConfig.optionalLink) {
1271
+ return this.renderOptionalField(item.field, fieldConfig, this.formData[item.field]);
1272
+ }
1273
+ return this.renderNewField(item.field, fieldConfig, this.formData[item.field]);
981
1274
  }
982
1275
  return html ``;
983
1276
  case 'row':
@@ -989,24 +1282,68 @@ export class NodeEditor extends RapidElement {
989
1282
  }
990
1283
  }
991
1284
  renderRow(rowConfig, config, renderedFields) {
992
- const { items, gap = '1rem' } = rowConfig;
1285
+ const { items, gap = '1rem', label, helpText } = rowConfig;
993
1286
  // Collect all fields from this row for width calculations
994
1287
  const fieldsInRow = this.collectFieldsFromItems(items);
995
1288
  const validFields = fieldsInRow.filter((fieldName) => { var _a; return (_a = config.form) === null || _a === void 0 ? void 0 : _a[fieldName]; });
996
- if (validFields.length === 0) {
1289
+ // Filter for visible fields only to handle conditional visibility
1290
+ const visibleFields = validFields.filter((fieldName) => {
1291
+ const fieldConfig = config.form[fieldName];
1292
+ return this.isFieldVisible(fieldName, fieldConfig);
1293
+ });
1294
+ if (visibleFields.length === 0) {
997
1295
  return html ``;
998
1296
  }
999
- // Calculate grid template columns based on field maxWidth constraints
1000
- const columns = validFields.map((fieldName) => {
1297
+ // Build a map of field flex styles
1298
+ // Fields with maxWidth get flex: 0 0 {maxWidth} (fixed)
1299
+ // Fields without maxWidth get flex: 1 1 0 (grow to fill space)
1300
+ const fieldFlexStyles = new Map();
1301
+ visibleFields.forEach((fieldName) => {
1001
1302
  const fieldConfig = config.form[fieldName];
1002
- return fieldConfig.maxWidth || '1fr';
1303
+ if (fieldConfig.maxWidth) {
1304
+ // Fixed width field: no grow, no shrink, basis = maxWidth
1305
+ fieldFlexStyles.set(fieldName, `flex: 0 0 ${fieldConfig.maxWidth};`);
1306
+ }
1307
+ else {
1308
+ // Flexible field: grow to fill remaining space
1309
+ fieldFlexStyles.set(fieldName, `flex: 1 1 0;`);
1310
+ }
1003
1311
  });
1312
+ const rowContent = html `
1313
+ <div class="form-row" style="display: flex; gap: ${gap};">
1314
+ ${items.map((item) => {
1315
+ // Get the field name from the item
1316
+ const fieldName = typeof item === 'string'
1317
+ ? item
1318
+ : item.type === 'field'
1319
+ ? item.field
1320
+ : null;
1321
+ // Get flex style for this field if it's a visible field
1322
+ const flexStyle = fieldName && fieldFlexStyles.has(fieldName)
1323
+ ? fieldFlexStyles.get(fieldName)
1324
+ : '';
1325
+ const itemContent = this.renderLayoutItem(item, config, renderedFields);
1326
+ // Wrap in a div with flex style if we have a flex style
1327
+ return flexStyle
1328
+ ? html `<div style="${flexStyle}">${itemContent}</div>`
1329
+ : itemContent;
1330
+ })}
1331
+ </div>
1332
+ `;
1333
+ // If no label or helpText, return just the row content
1334
+ if (!label && !helpText) {
1335
+ return rowContent;
1336
+ }
1337
+ // Otherwise, wrap with label on top, content, then helpText below (matching field pattern)
1004
1338
  return html `
1005
- <div
1006
- class="form-row"
1007
- style="display: grid; grid-template-columns: ${columns.join(' ')}; gap: ${gap};"
1008
- >
1009
- ${items.map((item) => this.renderLayoutItem(item, config, renderedFields))}
1339
+ <div class="form-row-wrapper">
1340
+ ${label ? html `<label class="form-row-label">${label}</label>` : ''}
1341
+ ${rowContent}
1342
+ ${helpText
1343
+ ? html `<div class="form-row-help">
1344
+ ${renderMarkdownInline(helpText)}
1345
+ </div>`
1346
+ : ''}
1010
1347
  </div>
1011
1348
  `;
1012
1349
  }
@@ -1186,6 +1523,12 @@ export class NodeEditor extends RapidElement {
1186
1523
  if (!config) {
1187
1524
  return html ` <div>No configuration available</div> `;
1188
1525
  }
1526
+ // Special rendering for category localization
1527
+ if (this.isTranslating &&
1528
+ config.localizable === 'categories' &&
1529
+ this.formData.categories) {
1530
+ return this.renderCategoryLocalizationTable();
1531
+ }
1189
1532
  // Use the new fields configuration system
1190
1533
  if (config.form) {
1191
1534
  // If layout is specified, use it
@@ -1230,6 +1573,10 @@ export class NodeEditor extends RapidElement {
1230
1573
  if (!(config === null || config === void 0 ? void 0 : config.gutter) || config.gutter.length === 0) {
1231
1574
  return html ``;
1232
1575
  }
1576
+ // Don't show gutter when localizing categories
1577
+ if (this.isTranslating && config.localizable === 'categories') {
1578
+ return html ``;
1579
+ }
1233
1580
  // Use the same layout rendering system for gutter fields
1234
1581
  const renderedFields = new Set();
1235
1582
  return html `
@@ -1299,17 +1646,25 @@ export class NodeEditor extends RapidElement {
1299
1646
  if (!this.isOpen) {
1300
1647
  return html ``;
1301
1648
  }
1302
- const headerColor = this.getHeaderColor();
1649
+ const headerColor = this.isTranslating ? '#505050' : this.getHeaderColor();
1650
+ const headerTextColor = this.isTranslating ? '#fff' : '#fff';
1303
1651
  const config = this.getConfig();
1304
1652
  const dialogSize = (config === null || config === void 0 ? void 0 : config.dialogSize) || 'medium'; // Default to 'large' if not specified
1653
+ const languageName = this.isTranslating
1654
+ ? getStore().getLanguageName(this.languageCode)
1655
+ : '';
1656
+ let header = (config === null || config === void 0 ? void 0 : config.name) || 'Edit';
1657
+ if (this.isTranslating) {
1658
+ header = languageName ? `${languageName} - ${header}` : header;
1659
+ }
1305
1660
  return html `
1306
1661
  <temba-dialog
1307
- header="${(config === null || config === void 0 ? void 0 : config.name) || 'Edit'}"
1662
+ header="${header}"
1308
1663
  .open="${this.isOpen}"
1309
1664
  @temba-button-clicked=${this.handleDialogButtonClick}
1310
1665
  primaryButtonName="Save"
1311
1666
  cancelButtonName="Cancel"
1312
- style="--header-bg: ${headerColor}"
1667
+ style="--header-bg: ${headerColor}; --header-text: ${headerTextColor};"
1313
1668
  size="${dialogSize}"
1314
1669
  >
1315
1670
  <div class="node-editor-form">
@@ -1351,4 +1706,16 @@ __decorate([
1351
1706
  __decorate([
1352
1707
  state()
1353
1708
  ], NodeEditor.prototype, "groupHoverState", void 0);
1709
+ __decorate([
1710
+ state()
1711
+ ], NodeEditor.prototype, "revealedOptionalFields", void 0);
1712
+ __decorate([
1713
+ fromStore(zustand, (state) => state.languageCode)
1714
+ ], NodeEditor.prototype, "languageCode", void 0);
1715
+ __decorate([
1716
+ fromStore(zustand, (state) => state.isTranslating)
1717
+ ], NodeEditor.prototype, "isTranslating", void 0);
1718
+ __decorate([
1719
+ fromStore(zustand, (state) => state.flowDefinition)
1720
+ ], NodeEditor.prototype, "flowDefinition", void 0);
1354
1721
  //# sourceMappingURL=NodeEditor.js.map