@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
@@ -1,7 +1,199 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
+ import { Node } from '../../store/flow-definition';
3
+ import { createRulesRouter } from '../../utils';
4
+ import {
5
+ getWaitForResponseOperators,
6
+ operatorsToSelectOptions,
7
+ getOperatorConfig
8
+ } from '../operators';
9
+ import {
10
+ resultNameField,
11
+ categoriesToLocalizationFormData,
12
+ localizationFormDataToCategories
13
+ } from './shared';
14
+ import {
15
+ createRulesArrayConfig,
16
+ extractUserRules,
17
+ casesToFormRules
18
+ } from './shared-rules';
19
+ import { SCHEMES } from '../utils';
20
+ import { html } from 'lit';
21
+
22
+ // System contact properties that can be split on
23
+ export const CONTACT_PROPERTIES = {
24
+ name: { id: 'name', name: 'Name', type: 'property' },
25
+ language: { id: 'language', name: 'Language', type: 'property' },
26
+ status: { id: 'status', name: 'Status', type: 'property' },
27
+ channel: { id: 'channel', name: 'Channel', type: 'property' }
28
+ };
29
+
30
+ // Helper to get operand for the selected field
31
+ const getOperandForField = (field: any): string => {
32
+ // For URN schemes, split on the URN path (the actual ID value like Facebook ID)
33
+ // Note: This is different from split_by_scheme which splits on the scheme type itself
34
+ if (field.type === 'scheme') {
35
+ // field.id or field.value will be the scheme name like 'facebook', 'whatsapp', etc
36
+ const schemeId = field.id || field.value;
37
+ return `@(default(urn_parts(urns.${schemeId}).path, ""))`;
38
+ }
39
+ // For system properties, use the id
40
+ if (field.type === 'property') {
41
+ return `@contact.${field.id}`;
42
+ }
43
+ // Fallback to key
44
+ return `@fields.${field.key}`;
45
+ };
2
46
 
3
47
  export const split_by_contact_field: NodeConfig = {
4
48
  type: 'split_by_contact_field',
5
- name: 'Split by <Contact Field Name>',
6
- color: COLORS.split
49
+ name: 'Split by Contact Field',
50
+ group: SPLIT_GROUPS.split,
51
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
52
+ dialogSize: 'large',
53
+ form: {
54
+ field: {
55
+ type: 'select',
56
+ required: true,
57
+ searchable: true,
58
+ clearable: false,
59
+ endpoint: '/api/v2/fields.json',
60
+ valueKey: 'key',
61
+ nameKey: 'name',
62
+ placeholder: 'Select a field...',
63
+ // Provide system properties as fixed options at the top
64
+ options: [
65
+ ...Object.values(CONTACT_PROPERTIES).map((prop) => ({
66
+ value: prop.id,
67
+ name: prop.name,
68
+ type: prop.type
69
+ })),
70
+ // Add all URN scheme options (they represent splitting on the URN value, like Facebook ID)
71
+ ...SCHEMES.filter((scheme) => !scheme.excludeFromSplit).map(
72
+ (scheme) => ({
73
+ value: scheme.scheme,
74
+ name: scheme.path,
75
+ type: 'scheme'
76
+ })
77
+ )
78
+ ]
79
+ },
80
+ rules: createRulesArrayConfig(
81
+ operatorsToSelectOptions(getWaitForResponseOperators()),
82
+ 'Define rules to split the contact field into categories'
83
+ ),
84
+ result_name: resultNameField
85
+ },
86
+ layout: ['field', 'rules', 'result_name'],
87
+ validate: (formData: FormData) => {
88
+ const errors: { [key: string]: string } = {};
89
+
90
+ if (!formData.field || formData.field.length === 0) {
91
+ errors.field = 'A field is required';
92
+ }
93
+
94
+ return {
95
+ valid: Object.keys(errors).length === 0,
96
+ errors
97
+ };
98
+ },
99
+ toFormData: (node: Node, nodeUI?: any) => {
100
+ // Get the field from the UI config operand (source of truth)
101
+ const field = nodeUI?.config?.operand || CONTACT_PROPERTIES.name;
102
+
103
+ // Extract rules from router cases using shared function
104
+ const rules = casesToFormRules(node);
105
+
106
+ return {
107
+ uuid: node.uuid,
108
+ field: [field],
109
+ rules: rules,
110
+ result_name: node.router?.result_name || ''
111
+ };
112
+ },
113
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
114
+ // Get selected field (it's an array from the select component)
115
+ const selectedField = formData.field?.[0];
116
+
117
+ if (!selectedField) {
118
+ return originalNode;
119
+ }
120
+
121
+ // Get operand for the selected field
122
+ const operand = getOperandForField(selectedField);
123
+
124
+ // Get user rules using shared extraction function
125
+ const userRules = extractUserRules(formData);
126
+
127
+ // Get existing router data for preservation
128
+ const existingCategories = originalNode.router?.categories || [];
129
+ const existingExits = originalNode.exits || [];
130
+ const existingCases = originalNode.router?.cases || [];
131
+
132
+ // Create router and exits using existing data when possible
133
+ const { router, exits } = createRulesRouter(
134
+ operand,
135
+ userRules,
136
+ getOperatorConfig,
137
+ existingCategories,
138
+ existingExits,
139
+ existingCases
140
+ );
141
+
142
+ // Build final router with result_name
143
+ const finalRouter: any = {
144
+ ...router
145
+ };
146
+
147
+ // Only set result_name if provided
148
+ if (formData.result_name && formData.result_name.trim() !== '') {
149
+ finalRouter.result_name = formData.result_name.trim();
150
+ }
151
+
152
+ return {
153
+ ...originalNode,
154
+ router: finalRouter,
155
+ exits: exits
156
+ };
157
+ },
158
+ toUIConfig: (formData: FormData) => {
159
+ // Get selected field (it's an array from the select component)
160
+ const selectedField = formData.field?.[0];
161
+
162
+ if (!selectedField) {
163
+ return {};
164
+ }
165
+
166
+ // For scheme types, the id should be the scheme name (facebook, whatsapp, etc)
167
+ // For custom fields, the id should be the field key
168
+ // For system properties, the id should be the property id
169
+ let operandId =
170
+ selectedField.id || selectedField.value || selectedField.key;
171
+
172
+ // If this is a scheme type, ensure we use the scheme name as the id
173
+ if (selectedField.type === 'scheme') {
174
+ operandId = selectedField.value || selectedField.id;
175
+ }
176
+
177
+ let type = selectedField.type;
178
+ if (type !== 'property' && type !== 'scheme') {
179
+ type = 'field';
180
+ }
181
+
182
+ // Return UI config with operand information for persistence
183
+ return {
184
+ operand: {
185
+ id: operandId,
186
+ name: selectedField.name || selectedField.label,
187
+ type
188
+ }
189
+ };
190
+ },
191
+ renderTitle: (node: Node, nodeUI?: any) => {
192
+ return html`<div>Split by ${nodeUI.config.operand.name}</div>`;
193
+ },
194
+
195
+ // Localization support for categories
196
+ localizable: 'categories',
197
+ toLocalizationFormData: categoriesToLocalizationFormData,
198
+ fromLocalizationFormData: localizationFormDataToCategories
7
199
  };
@@ -1,7 +1,109 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
+ import { Node } from '../../store/flow-definition';
3
+ import { createRulesRouter } from '../../utils';
4
+ import {
5
+ getWaitForResponseOperators,
6
+ operatorsToSelectOptions,
7
+ getOperatorConfig
8
+ } from '../operators';
9
+ import {
10
+ resultNameField,
11
+ categoriesToLocalizationFormData,
12
+ localizationFormDataToCategories
13
+ } from './shared';
14
+ import {
15
+ createRulesArrayConfig,
16
+ extractUserRules,
17
+ casesToFormRules
18
+ } from './shared-rules';
2
19
 
3
20
  export const split_by_expression: NodeConfig = {
4
21
  type: 'split_by_expression',
5
22
  name: 'Split by Expression',
6
- color: COLORS.split
23
+ group: SPLIT_GROUPS.split,
24
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
25
+ dialogSize: 'large',
26
+ form: {
27
+ operand: {
28
+ type: 'text',
29
+ label: 'Expression',
30
+ helpText: 'The expression to evaluate and split on',
31
+ required: true,
32
+ evaluated: true,
33
+ placeholder: '@fields.age'
34
+ },
35
+ rules: createRulesArrayConfig(
36
+ operatorsToSelectOptions(getWaitForResponseOperators()),
37
+ 'Define rules to categorize the expression result'
38
+ ),
39
+ result_name: resultNameField
40
+ },
41
+ layout: ['operand', 'rules', 'result_name'],
42
+ validate: (formData: FormData) => {
43
+ const errors: { [key: string]: string } = {};
44
+
45
+ // Validate operand is provided
46
+ if (!formData.operand || formData.operand.trim() === '') {
47
+ errors.operand = 'Expression is required';
48
+ }
49
+
50
+ return {
51
+ valid: Object.keys(errors).length === 0,
52
+ errors
53
+ };
54
+ },
55
+ toFormData: (node: Node) => {
56
+ // Extract rules from router cases using shared function
57
+ const rules = casesToFormRules(node);
58
+
59
+ return {
60
+ uuid: node.uuid,
61
+ operand: node.router?.operand || '@input.text',
62
+ rules: rules,
63
+ result_name: node.router?.result_name || ''
64
+ };
65
+ },
66
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
67
+ // Get user rules using shared extraction function
68
+ const userRules = extractUserRules(formData);
69
+
70
+ // Get operand from form data
71
+ const operand = formData.operand?.trim() || '@input.text';
72
+
73
+ // Get existing router data for preservation
74
+ const existingCategories = originalNode.router?.categories || [];
75
+ const existingExits = originalNode.exits || [];
76
+ const existingCases = originalNode.router?.cases || [];
77
+
78
+ // Create router and exits using existing data when possible
79
+ const { router, exits } = createRulesRouter(
80
+ operand,
81
+ userRules,
82
+ getOperatorConfig,
83
+ existingCategories,
84
+ existingExits,
85
+ existingCases
86
+ );
87
+
88
+ // Build final router with result_name
89
+ const finalRouter: any = {
90
+ ...router
91
+ };
92
+
93
+ // Only set result_name if provided
94
+ if (formData.result_name && formData.result_name.trim() !== '') {
95
+ finalRouter.result_name = formData.result_name.trim();
96
+ }
97
+
98
+ return {
99
+ ...originalNode,
100
+ router: finalRouter,
101
+ exits: exits
102
+ };
103
+ },
104
+
105
+ // Localization support for categories
106
+ localizable: 'categories',
107
+ toLocalizationFormData: categoriesToLocalizationFormData,
108
+ fromLocalizationFormData: localizationFormDataToCategories
7
109
  };
@@ -1,13 +1,19 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, Category, Exit, Case } from '../../store/flow-definition.d';
3
3
  import { generateUUID } from '../../utils';
4
+ import {
5
+ resultNameField,
6
+ categoriesToLocalizationFormData,
7
+ localizationFormDataToCategories
8
+ } from './shared';
4
9
 
5
10
  // Helper function to create a switch router with group cases
6
11
  const createGroupRouter = (
7
12
  userGroups: { uuid: string; name: string }[],
8
13
  existingCategories: Category[] = [],
9
14
  existingExits: Exit[] = [],
10
- existingCases: Case[] = []
15
+ existingCases: Case[] = [],
16
+ resultName: string = ''
11
17
  ) => {
12
18
  const categories: Category[] = [];
13
19
  const exits: Exit[] = [];
@@ -82,7 +88,7 @@ const createGroupRouter = (
82
88
  categories: categories,
83
89
  default_category_uuid: otherCategoryUuid,
84
90
  operand: '@contact.groups',
85
- result_name: ''
91
+ result_name: resultName
86
92
  },
87
93
  exits: exits
88
94
  };
@@ -91,7 +97,8 @@ const createGroupRouter = (
91
97
  export const split_by_groups: NodeConfig = {
92
98
  type: 'split_by_groups',
93
99
  name: 'Split by Group',
94
- color: COLORS.split,
100
+ group: SPLIT_GROUPS.split,
101
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
95
102
  form: {
96
103
  groups: {
97
104
  type: 'select',
@@ -121,10 +128,11 @@ export const split_by_groups: NodeConfig = {
121
128
  }
122
129
  return null;
123
130
  }
124
- }
131
+ },
132
+ result_name: resultNameField
125
133
  },
126
- layout: ['groups'],
127
- validate: (formData: any) => {
134
+ layout: ['groups', 'result_name'],
135
+ validate: (formData: FormData) => {
128
136
  const errors: { [key: string]: string } = {};
129
137
 
130
138
  if (
@@ -157,10 +165,11 @@ export const split_by_groups: NodeConfig = {
157
165
 
158
166
  return {
159
167
  uuid: node.uuid,
160
- groups: groups
168
+ groups: groups,
169
+ result_name: node.router?.result_name || ''
161
170
  };
162
171
  },
163
- fromFormData: (formData: any, originalNode: Node): Node => {
172
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
164
173
  // Get selected groups
165
174
  const selectedGroups = (formData.groups || [])
166
175
  .filter((group: any) => group?.uuid || group?.arbitrary)
@@ -178,7 +187,8 @@ export const split_by_groups: NodeConfig = {
178
187
  selectedGroups,
179
188
  existingCategories,
180
189
  existingExits,
181
- existingCases
190
+ existingCases,
191
+ formData.result_name || ''
182
192
  );
183
193
 
184
194
  // Return the complete node
@@ -192,5 +202,10 @@ export const split_by_groups: NodeConfig = {
192
202
  router: {
193
203
  type: 'switch',
194
204
  operand: '@contact.groups'
195
- }
205
+ },
206
+
207
+ // Localization support for categories
208
+ localizable: 'categories',
209
+ toLocalizationFormData: categoriesToLocalizationFormData,
210
+ fromLocalizationFormData: localizationFormDataToCategories
196
211
  };
@@ -0,0 +1,8 @@
1
+ import { NodeConfig, ACTION_GROUPS, FlowTypes } from '../types';
2
+
3
+ export const split_by_llm_categorize: NodeConfig = {
4
+ type: 'split_by_intent',
5
+ name: 'Call classifier',
6
+ group: ACTION_GROUPS.services,
7
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND]
8
+ };
@@ -1,12 +1,25 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import {
2
+ ACTION_GROUPS,
3
+ FormData,
4
+ NodeConfig,
5
+ FlowTypes,
6
+ Features
7
+ } from '../types';
2
8
  import { CallLLM, Node } from '../../store/flow-definition';
3
9
  import { generateUUID, createSuccessFailureRouter } from '../../utils';
4
10
  import { html } from 'lit';
11
+ import {
12
+ categoriesToLocalizationFormData,
13
+ localizationFormDataToCategories
14
+ } from './shared';
5
15
 
6
16
  export const split_by_llm: NodeConfig = {
7
17
  type: 'split_by_llm',
8
18
  name: 'Call AI',
9
- color: COLORS.call,
19
+ group: ACTION_GROUPS.services,
20
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
21
+ features: [Features.AI],
22
+ showAsAction: true,
10
23
  render: (node: Node) => {
11
24
  const callLlmAction = node.actions?.find(
12
25
  (action) => action.type === 'call_llm'
@@ -68,7 +81,7 @@ export const split_by_llm: NodeConfig = {
68
81
  instructions: callLlmAction?.instructions || ''
69
82
  };
70
83
  },
71
- fromFormData: (formData: any, originalNode: Node): Node => {
84
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
72
85
  // Get LLM selection
73
86
  const llmSelection =
74
87
  Array.isArray(formData.llm) && formData.llm.length > 0
@@ -116,5 +129,10 @@ export const split_by_llm: NodeConfig = {
116
129
  router: router,
117
130
  exits: exits
118
131
  };
119
- }
132
+ },
133
+
134
+ // Localization support for categories
135
+ localizable: 'categories',
136
+ toLocalizationFormData: categoriesToLocalizationFormData,
137
+ fromLocalizationFormData: localizationFormDataToCategories
120
138
  };
@@ -1,12 +1,24 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import {
2
+ FormData,
3
+ NodeConfig,
4
+ ACTION_GROUPS,
5
+ FlowTypes,
6
+ Features
7
+ } from '../types';
2
8
  import { CallLLM, Node } from '../../store/flow-definition';
3
9
  import { generateUUID, createMultiCategoryRouter } from '../../utils';
4
10
  import { html } from 'lit';
11
+ import {
12
+ categoriesToLocalizationFormData,
13
+ localizationFormDataToCategories
14
+ } from './shared';
5
15
 
6
16
  export const split_by_llm_categorize: NodeConfig = {
7
17
  type: 'split_by_llm_categorize',
8
18
  name: 'Split by AI',
9
- color: COLORS.call,
19
+ group: ACTION_GROUPS.services,
20
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
21
+ features: [Features.AI],
10
22
  form: {
11
23
  llm: {
12
24
  type: 'select',
@@ -48,7 +60,7 @@ export const split_by_llm_categorize: NodeConfig = {
48
60
  }
49
61
  },
50
62
  layout: ['llm', 'input', 'categories'],
51
- validate: (formData: any) => {
63
+ validate: (formData: FormData) => {
52
64
  const errors: { [key: string]: string } = {};
53
65
 
54
66
  // Check for duplicate category names
@@ -117,7 +129,7 @@ export const split_by_llm_categorize: NodeConfig = {
117
129
  categories: categories
118
130
  };
119
131
  },
120
- fromFormData: (formData: any, originalNode: Node): Node => {
132
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
121
133
  // Get LLM selection
122
134
  const llmSelection =
123
135
  Array.isArray(formData.llm) && formData.llm.length > 0
@@ -171,5 +183,10 @@ export const split_by_llm_categorize: NodeConfig = {
171
183
  router: router,
172
184
  exits: exits
173
185
  };
174
- }
186
+ },
187
+
188
+ // Localization support for categories
189
+ localizable: 'categories',
190
+ toLocalizationFormData: categoriesToLocalizationFormData,
191
+ fromLocalizationFormData: localizationFormDataToCategories
175
192
  };
@@ -1,6 +1,10 @@
1
- import { COLORS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, Category, Exit } from '../../store/flow-definition.d';
3
3
  import { generateUUID } from '../../utils';
4
+ import {
5
+ categoriesToLocalizationFormData,
6
+ localizationFormDataToCategories
7
+ } from './shared';
4
8
 
5
9
  // Helper function to create a random router with categories
6
10
  const createRandomRouter = (
@@ -47,8 +51,9 @@ const createRandomRouter = (
47
51
 
48
52
  export const split_by_random: NodeConfig = {
49
53
  type: 'split_by_random',
50
- name: 'Split by Random',
51
- color: COLORS.split,
54
+ name: 'Random Split',
55
+ group: SPLIT_GROUPS.split,
56
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
52
57
  form: {
53
58
  categories: {
54
59
  type: 'array',
@@ -72,7 +77,7 @@ export const split_by_random: NodeConfig = {
72
77
  }
73
78
  },
74
79
  layout: ['categories'],
75
- validate: (formData: any) => {
80
+ validate: (formData: FormData) => {
76
81
  const errors: { [key: string]: string } = {};
77
82
 
78
83
  // Check for duplicate category names
@@ -129,7 +134,7 @@ export const split_by_random: NodeConfig = {
129
134
  categories: categories
130
135
  };
131
136
  },
132
- fromFormData: (formData: any, originalNode: Node): Node => {
137
+ fromFormData: (formData: FormData, originalNode: Node): Node => {
133
138
  // Get user categories
134
139
  const userCategories = (formData.categories || [])
135
140
  .filter((item: any) => item?.name?.trim())
@@ -155,5 +160,10 @@ export const split_by_random: NodeConfig = {
155
160
  },
156
161
  router: {
157
162
  type: 'random'
158
- }
163
+ },
164
+
165
+ // Localization support for categories
166
+ localizable: 'categories',
167
+ toLocalizationFormData: categoriesToLocalizationFormData,
168
+ fromLocalizationFormData: localizationFormDataToCategories
159
169
  };