@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
@@ -0,0 +1,636 @@
1
+ import { css, html, TemplateResult } from 'lit';
2
+ import { property, state } from 'lit/decorators.js';
3
+ import { RapidElement } from '../RapidElement';
4
+ import { CustomEventType } from '../interfaces';
5
+ import { NODE_CONFIG, ACTION_CONFIG } from './config';
6
+ import {
7
+ NodeConfig,
8
+ ActionConfig,
9
+ ACTION_GROUPS,
10
+ SPLIT_GROUPS,
11
+ ACTION_GROUP_METADATA,
12
+ SPLIT_GROUP_METADATA
13
+ } from './types';
14
+
15
+ /**
16
+ * Event detail for node type selection
17
+ */
18
+ export interface NodeTypeSelection {
19
+ nodeType: string;
20
+ position: { x: number; y: number };
21
+ }
22
+
23
+ /**
24
+ * Categorizes node types for display
25
+ */
26
+ interface NodeCategory {
27
+ name: string;
28
+ description: string;
29
+ color: string;
30
+ items: Array<{ type: string; config: NodeConfig | ActionConfig }>;
31
+ isBranching?: boolean; // true if this category contains actions that branch/split
32
+ }
33
+
34
+ /**
35
+ * NodeTypeSelector - A dialog for selecting which type of node to create
36
+ * Shows categorized lists of available actions and splits
37
+ */
38
+ export class NodeTypeSelector extends RapidElement {
39
+ static get styles() {
40
+ return css`
41
+ :host {
42
+ position: fixed;
43
+ top: 0;
44
+ left: 0;
45
+ right: 0;
46
+ bottom: 0;
47
+ z-index: 10001;
48
+ display: none;
49
+ }
50
+
51
+ :host([open]) {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ }
56
+
57
+ .overlay {
58
+ position: absolute;
59
+ top: 0;
60
+ left: 0;
61
+ right: 0;
62
+ bottom: 0;
63
+ background: rgba(0, 0, 0, 0.5);
64
+ }
65
+
66
+ .dialog {
67
+ position: relative;
68
+ background: white;
69
+ border-radius: var(--curvature);
70
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
71
+ max-width: 700px;
72
+ max-height: 80vh;
73
+ width: 90%;
74
+ display: flex;
75
+ flex-direction: column;
76
+ }
77
+
78
+ .header {
79
+ padding: 1.5em;
80
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
81
+ }
82
+
83
+ .header h2 {
84
+ margin: 0;
85
+ font-size: 1.5rem;
86
+ font-weight: 600;
87
+ color: var(--color-text-dark);
88
+ }
89
+
90
+ .content {
91
+ overflow-y: auto;
92
+ overflow-x: hidden;
93
+ flex: 1;
94
+ padding: 0;
95
+ }
96
+
97
+ .section-regular {
98
+ padding: 1.5em;
99
+ }
100
+
101
+ .section-branching {
102
+ background: linear-gradient(
103
+ 135deg,
104
+ rgba(170, 170, 170, 0.12),
105
+ rgba(170, 170, 170, 0.08)
106
+ );
107
+ padding: 1.5em;
108
+ margin: 0 -1.5em;
109
+ padding-left: 3em;
110
+ padding-right: 3em;
111
+ }
112
+
113
+ .section-header {
114
+ margin-bottom: 1.5em;
115
+ padding-top: 1em;
116
+ }
117
+
118
+ .section-title {
119
+ font-weight: 700;
120
+ font-size: 1.1rem;
121
+ color: var(--color-text-dark);
122
+ margin-bottom: 0.35em;
123
+ display: flex;
124
+ align-items: center;
125
+ }
126
+
127
+ .section-title::before {
128
+ content: '';
129
+ display: inline-block;
130
+ height: 1.2em;
131
+ background: linear-gradient(
132
+ 135deg,
133
+ var(--color-primary-dark),
134
+ var(--color-primary)
135
+ );
136
+ border-radius: 2px;
137
+ }
138
+
139
+ .section-description {
140
+ font-size: 0.9rem;
141
+ color: var(--color-text);
142
+ opacity: 0.7;
143
+ margin-left: 0em;
144
+ padding-bottom: 1em;
145
+ }
146
+
147
+ .category {
148
+ margin-bottom: 2em;
149
+ }
150
+
151
+ .category:last-child {
152
+ margin-bottom: 0;
153
+ }
154
+
155
+ .category-title {
156
+ font-weight: 600;
157
+ color: var(--color-text-dark);
158
+ margin-bottom: 0.5em;
159
+ text-transform: uppercase;
160
+ letter-spacing: 0.05em;
161
+ font-size: 0.9rem;
162
+ opacity: 0.7;
163
+ }
164
+
165
+ .category-description {
166
+ font-size: 0.85rem;
167
+ color: var(--color-text);
168
+ opacity: 0.6;
169
+ margin-bottom: 0.75em;
170
+ line-height: 1.4;
171
+ }
172
+
173
+ .items-grid {
174
+ display: grid;
175
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
176
+ gap: 0.75em;
177
+ }
178
+
179
+ .node-item {
180
+ padding: 1em;
181
+ border: 1px solid rgba(0, 0, 0, 0.1);
182
+ border-radius: calc(var(--curvature) * 0.75);
183
+ cursor: pointer;
184
+ transition: all 0.15s ease;
185
+ background: white;
186
+ position: relative;
187
+ overflow: hidden;
188
+ }
189
+
190
+ .node-item::before {
191
+ content: '';
192
+ position: absolute;
193
+ top: 0;
194
+ left: 0;
195
+ width: 4px;
196
+ height: 100%;
197
+ background: var(--item-color, rgba(0, 0, 0, 0.1));
198
+ }
199
+
200
+ .node-item:hover {
201
+ border-color: var(--item-color, var(--color-primary));
202
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
203
+ transform: translateY(-1px);
204
+ }
205
+
206
+ .node-item:hover::before {
207
+ width: 6px;
208
+ }
209
+
210
+ .node-item-title {
211
+ font-weight: 500;
212
+ font-size: 1rem;
213
+ color: var(--color-text-dark);
214
+ margin-bottom: 0.25em;
215
+ }
216
+
217
+ .node-item-type {
218
+ font-size: 0.75rem;
219
+ color: var(--color-text);
220
+ opacity: 0.6;
221
+ font-family: monospace;
222
+ }
223
+
224
+ .footer {
225
+ padding: 1em 1.5em;
226
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
227
+ display: flex;
228
+ justify-content: flex-end;
229
+ }
230
+
231
+ temba-button {
232
+ --button-y: 0.5em;
233
+ --button-x: 1.25em;
234
+ }
235
+ `;
236
+ }
237
+
238
+ @property({ type: Boolean, reflect: true })
239
+ public open = false;
240
+
241
+ @property({ type: String })
242
+ public mode: 'action' | 'split' | 'action-no-branching' = 'action';
243
+
244
+ @property({ type: String })
245
+ public flowType: string = 'message';
246
+
247
+ @property({ type: Array })
248
+ public features: string[] = [];
249
+
250
+ @state()
251
+ private clickPosition = { x: 0, y: 0 };
252
+
253
+ public show(
254
+ mode: 'action' | 'split' | 'action-no-branching',
255
+ position: { x: number; y: number }
256
+ ) {
257
+ this.mode = mode;
258
+ this.clickPosition = position;
259
+ this.open = true;
260
+ }
261
+
262
+ public close() {
263
+ this.open = false;
264
+ }
265
+
266
+ /**
267
+ * Check if a config is available for the current flow type and features
268
+ */
269
+ private isConfigAvailable(config: NodeConfig | ActionConfig): boolean {
270
+ // Check flow type filter
271
+ if (config.flowTypes !== undefined) {
272
+ // Empty array means not available for any flow type in selector
273
+ if (config.flowTypes.length === 0) {
274
+ return false;
275
+ }
276
+ // Non-empty array means check if current flow type is included
277
+ if (!config.flowTypes.includes(this.flowType as any)) {
278
+ return false;
279
+ }
280
+ }
281
+ // undefined/null flowTypes means available for all flow types
282
+
283
+ // Check features filter - all required features must be present
284
+ if (config.features && config.features.length > 0) {
285
+ for (const requiredFeature of config.features) {
286
+ if (!this.features.includes(requiredFeature)) {
287
+ return false;
288
+ }
289
+ }
290
+ }
291
+
292
+ return true;
293
+ }
294
+
295
+ private handleNodeTypeClick(nodeType: string) {
296
+ this.fireCustomEvent(CustomEventType.Selection, {
297
+ nodeType,
298
+ position: this.clickPosition
299
+ } as NodeTypeSelection);
300
+ this.close();
301
+ }
302
+
303
+ private handleOverlayClick() {
304
+ this.close();
305
+ }
306
+
307
+ private getCategories(): NodeCategory[] {
308
+ if (this.mode === 'action' || this.mode === 'action-no-branching') {
309
+ // Group actions by group
310
+ const actionsByGroup = new Map<
311
+ string,
312
+ Array<{ type: string; config: ActionConfig }>
313
+ >();
314
+ const splitsByGroup = new Map<
315
+ string,
316
+ Array<{ type: string; config: NodeConfig }>
317
+ >();
318
+
319
+ // Collect regular actions (from ACTION_CONFIG, unless hideFromActions is true)
320
+ Object.entries(ACTION_CONFIG)
321
+ .filter(([_, config]) => {
322
+ return (
323
+ config.name &&
324
+ !config.hideFromActions &&
325
+ config.group &&
326
+ this.isConfigAvailable(config)
327
+ );
328
+ })
329
+ .forEach(([type, config]) => {
330
+ const group = config.group;
331
+ if (!actionsByGroup.has(group)) {
332
+ actionsByGroup.set(group, []);
333
+ }
334
+ actionsByGroup.get(group)!.push({ type, config });
335
+ });
336
+
337
+ // Collect nodes that have showAsAction=true (these appear as "with split" actions)
338
+ // Only if we're not in 'action-no-branching' mode
339
+ if (this.mode === 'action') {
340
+ Object.entries(NODE_CONFIG)
341
+ .filter(([type, config]) => {
342
+ return (
343
+ type !== 'execute_actions' &&
344
+ config.name &&
345
+ config.showAsAction &&
346
+ config.group &&
347
+ this.isConfigAvailable(config)
348
+ );
349
+ })
350
+ .forEach(([type, config]) => {
351
+ const group = config.group!;
352
+ if (!splitsByGroup.has(group)) {
353
+ splitsByGroup.set(group, []);
354
+ }
355
+ splitsByGroup.get(group)!.push({ type, config });
356
+ });
357
+ }
358
+
359
+ // Build categories - first regular actions, then splitting actions
360
+ const categories: NodeCategory[] = [];
361
+
362
+ // Get the implicit order from ACTION_GROUPS object
363
+ const actionGroupOrder = Object.keys(ACTION_GROUPS);
364
+ // Get the implicit order of actions from ACTION_CONFIG
365
+ const actionConfigOrder = Object.keys(ACTION_CONFIG);
366
+
367
+ // Add regular action categories sorted by implicit order
368
+ const sortedActionCategories = Array.from(actionsByGroup.entries()).sort(
369
+ ([groupA], [groupB]) => {
370
+ const orderA = actionGroupOrder.indexOf(groupA);
371
+ const orderB = actionGroupOrder.indexOf(groupB);
372
+ return (
373
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
374
+ );
375
+ }
376
+ );
377
+
378
+ sortedActionCategories.forEach(([group, items]) => {
379
+ const metadata = ACTION_GROUP_METADATA[group];
380
+ // Sort items within the category by their order in ACTION_CONFIG
381
+ const sortedItems = items.sort((a, b) => {
382
+ const orderA = actionConfigOrder.indexOf(a.type);
383
+ const orderB = actionConfigOrder.indexOf(b.type);
384
+ return (
385
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
386
+ );
387
+ });
388
+ categories.push({
389
+ name: metadata.title,
390
+ description: metadata.description,
391
+ color: metadata.color,
392
+ items: sortedItems,
393
+ isBranching: false
394
+ });
395
+ });
396
+
397
+ // Add splitting action categories (with modified description to indicate they split)
398
+ // Also sorted by implicit order
399
+ // Get the implicit order of nodes from NODE_CONFIG
400
+ const nodeConfigOrder = Object.keys(NODE_CONFIG);
401
+
402
+ const sortedSplitCategories = Array.from(splitsByGroup.entries()).sort(
403
+ ([groupA], [groupB]) => {
404
+ const orderA = actionGroupOrder.indexOf(groupA);
405
+ const orderB = actionGroupOrder.indexOf(groupB);
406
+ return (
407
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
408
+ );
409
+ }
410
+ );
411
+
412
+ sortedSplitCategories.forEach(([group, items]) => {
413
+ const metadata = ACTION_GROUP_METADATA[group];
414
+ // Sort items within the category by their order in NODE_CONFIG
415
+ const sortedItems = items.sort((a, b) => {
416
+ const orderA = nodeConfigOrder.indexOf(a.type);
417
+ const orderB = nodeConfigOrder.indexOf(b.type);
418
+ return (
419
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
420
+ );
421
+ });
422
+ categories.push({
423
+ name: metadata.title,
424
+ description: metadata.description,
425
+ color: metadata.color,
426
+ items: sortedItems,
427
+ isBranching: true
428
+ });
429
+ });
430
+
431
+ return categories;
432
+ } else {
433
+ // Group splits by group
434
+ const itemsByGroup = new Map<
435
+ string,
436
+ Array<{ type: string; config: NodeConfig }>
437
+ >();
438
+
439
+ Object.entries(NODE_CONFIG)
440
+ .filter(([type, config]) => {
441
+ // exclude execute_actions (it's the default action-only node)
442
+ // exclude nodes that have showAsAction=true (they appear in action mode)
443
+ return (
444
+ type !== 'execute_actions' &&
445
+ config.name &&
446
+ !config.showAsAction &&
447
+ this.isConfigAvailable(config)
448
+ );
449
+ })
450
+ .forEach(([type, config]) => {
451
+ const group = config.group || SPLIT_GROUPS.split;
452
+ if (!itemsByGroup.has(group)) {
453
+ itemsByGroup.set(group, []);
454
+ }
455
+ itemsByGroup.get(group)!.push({ type, config });
456
+ });
457
+
458
+ // Convert to categories using group metadata, sorted by implicit order from SPLIT_GROUPS
459
+ const splitGroupOrder = Object.keys(SPLIT_GROUPS);
460
+ // Get the implicit order of nodes from NODE_CONFIG
461
+ const nodeConfigOrder = Object.keys(NODE_CONFIG);
462
+
463
+ return Array.from(itemsByGroup.entries())
464
+ .map(([group, items]) => {
465
+ const metadata =
466
+ SPLIT_GROUP_METADATA[group] || ACTION_GROUP_METADATA[group];
467
+ // Sort items within the category by their order in NODE_CONFIG
468
+ const sortedItems = items.sort((a, b) => {
469
+ const orderA = nodeConfigOrder.indexOf(a.type);
470
+ const orderB = nodeConfigOrder.indexOf(b.type);
471
+ return (
472
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
473
+ );
474
+ });
475
+ return {
476
+ name: metadata.title,
477
+ description: metadata.description,
478
+ color: metadata.color,
479
+ items: sortedItems
480
+ };
481
+ })
482
+ .sort((a, b) => {
483
+ // Find the group key by looking up metadata by title
484
+ const groupA = Object.keys(SPLIT_GROUP_METADATA).find(
485
+ (key) => SPLIT_GROUP_METADATA[key].title === a.name
486
+ )!;
487
+ const groupB = Object.keys(SPLIT_GROUP_METADATA).find(
488
+ (key) => SPLIT_GROUP_METADATA[key].title === b.name
489
+ )!;
490
+ const orderA = splitGroupOrder.indexOf(groupA);
491
+ const orderB = splitGroupOrder.indexOf(groupB);
492
+ return (
493
+ (orderA === -1 ? 999 : orderA) - (orderB === -1 ? 999 : orderB)
494
+ );
495
+ });
496
+ }
497
+ }
498
+
499
+ public render(): TemplateResult {
500
+ if (!this.open) {
501
+ return html``;
502
+ }
503
+
504
+ const categories = this.getCategories();
505
+ const title =
506
+ this.mode === 'split'
507
+ ? 'Select a Split'
508
+ : this.mode === 'action-no-branching'
509
+ ? 'Add Action'
510
+ : 'Select an Action';
511
+
512
+ // Separate regular and branching categories for action mode
513
+ const regularCategories = categories.filter((c) => !c.isBranching);
514
+ const branchingCategories = categories.filter((c) => c.isBranching);
515
+ const hasBranchingSection = branchingCategories.length > 0;
516
+
517
+ return html`
518
+ <div class="overlay" @click=${this.handleOverlayClick}></div>
519
+ <div class="dialog" @click=${(e: Event) => e.stopPropagation()}>
520
+ <div class="header">
521
+ <h2>${title}</h2>
522
+ </div>
523
+ <div class="content">
524
+ ${this.mode === 'action' || this.mode === 'action-no-branching'
525
+ ? html`
526
+ <div class="section-regular">
527
+ ${regularCategories.map(
528
+ (category) => html`
529
+ <div class="category">
530
+ <div class="category-title">${category.name}</div>
531
+ <div class="category-description">
532
+ ${category.description}
533
+ </div>
534
+ <div class="items-grid">
535
+ ${category.items.map(
536
+ (item) => html`
537
+ <div
538
+ class="node-item"
539
+ style="--item-color: ${category.color}"
540
+ @click=${() =>
541
+ this.handleNodeTypeClick(item.type)}
542
+ >
543
+ <div class="node-item-title">
544
+ ${item.config.name}
545
+ </div>
546
+ <div class="node-item-type">${item.type}</div>
547
+ </div>
548
+ `
549
+ )}
550
+ </div>
551
+ </div>
552
+ `
553
+ )}
554
+ </div>
555
+ ${hasBranchingSection
556
+ ? html`
557
+ <div class="section-branching">
558
+ <div class="section-header">
559
+ <div class="section-title">Actions that Branch</div>
560
+ <div class="section-description">
561
+ These actions also split the flow based on their
562
+ outcome
563
+ </div>
564
+ </div>
565
+ ${branchingCategories.map(
566
+ (category) => html`
567
+ <div class="category">
568
+ <div class="category-title">${category.name}</div>
569
+ <div class="category-description">
570
+ ${category.description}
571
+ </div>
572
+ <div class="items-grid">
573
+ ${category.items.map(
574
+ (item) => html`
575
+ <div
576
+ class="node-item"
577
+ style="--item-color: ${category.color}"
578
+ @click=${() =>
579
+ this.handleNodeTypeClick(item.type)}
580
+ >
581
+ <div class="node-item-title">
582
+ ${item.config.name}
583
+ </div>
584
+ <div class="node-item-type">
585
+ ${item.type}
586
+ </div>
587
+ </div>
588
+ `
589
+ )}
590
+ </div>
591
+ </div>
592
+ `
593
+ )}
594
+ </div>
595
+ `
596
+ : ''}
597
+ `
598
+ : html`
599
+ <div class="section-regular">
600
+ ${categories.map(
601
+ (category) => html`
602
+ <div class="category">
603
+ <div class="category-title">${category.name}</div>
604
+ <div class="category-description">
605
+ ${category.description}
606
+ </div>
607
+ <div class="items-grid">
608
+ ${category.items.map(
609
+ (item) => html`
610
+ <div
611
+ class="node-item"
612
+ style="--item-color: ${category.color}"
613
+ @click=${() =>
614
+ this.handleNodeTypeClick(item.type)}
615
+ >
616
+ <div class="node-item-title">
617
+ ${item.config.name}
618
+ </div>
619
+ <div class="node-item-type">${item.type}</div>
620
+ </div>
621
+ `
622
+ )}
623
+ </div>
624
+ </div>
625
+ `
626
+ )}
627
+ </div>
628
+ `}
629
+ </div>
630
+ <div class="footer">
631
+ <temba-button @click=${this.close} secondary>Cancel</temba-button>
632
+ </div>
633
+ </div>
634
+ `;
635
+ }
636
+ }
@@ -3,6 +3,7 @@ import { property } from 'lit/decorators.js';
3
3
  import { RapidElement } from '../RapidElement';
4
4
  import { StickyNote as StickyNoteData } from '../store/flow-definition';
5
5
  import { getStore } from '../store/Store';
6
+ import { AppState, fromStore, zustand } from '../store/AppState';
6
7
 
7
8
  export class StickyNote extends RapidElement {
8
9
  @property({ type: String })
@@ -20,6 +21,9 @@ export class StickyNote extends RapidElement {
20
21
  @property({ type: Boolean })
21
22
  private colorPickerExpanded = false;
22
23
 
24
+ @fromStore(zustand, (state: AppState) => state.isTranslating)
25
+ private isTranslating!: boolean;
26
+
23
27
  static get styles() {
24
28
  return css`
25
29
  :host {
@@ -119,6 +123,8 @@ export class StickyNote extends RapidElement {
119
123
  border-top-left-radius: var(--curvature);
120
124
  border-top-right-radius: var(--curvature);
121
125
  flex-grow: 1;
126
+ padding: 4px 8px !important;
127
+ margin: 2px;
122
128
  padding-left: 8px;
123
129
  }
124
130
  .sticky-title:empty::before {
@@ -139,6 +145,7 @@ export class StickyNote extends RapidElement {
139
145
  min-height: 48px;
140
146
  word-wrap: break-word;
141
147
  white-space: pre-wrap;
148
+ margin: 2px;
142
149
  }
143
150
  .sticky-body:empty::before {
144
151
  content: 'Click to add note';
@@ -377,7 +384,7 @@ export class StickyNote extends RapidElement {
377
384
  <temba-icon name="drag" class="drag-handle"></temba-icon>
378
385
  <div
379
386
  class="sticky-title"
380
- contenteditable="true"
387
+ contenteditable="${!this.isTranslating}"
381
388
  @blur="${this.handleTitleBlur}"
382
389
  @keydown="${this.handleKeyDown}"
383
390
  @mousedown="${this.handleContentMouseDown}"
@@ -387,13 +394,15 @@ export class StickyNote extends RapidElement {
387
394
  <div class="sticky-body-container">
388
395
  <div
389
396
  class="sticky-body"
390
- contenteditable="true"
397
+ contenteditable="${!this.isTranslating}"
391
398
  @blur="${this.handleBodyBlur}"
392
399
  @keydown="${this.handleKeyDown}"
393
400
  @mousedown="${this.handleContentMouseDown}"
394
401
  .textContent="${this.data.body}"
395
402
  ></div>
396
- <div class="edit-icon" title="Edit note"></div>
403
+ ${!this.isTranslating
404
+ ? html`<div class="edit-icon" title="Edit note"></div>`
405
+ : ''}
397
406
 
398
407
  <!-- Color picker -->
399
408
  <div