@nyaruka/temba-components 0.129.9 → 0.129.11

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 (323) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/demo/data/flows/sample-flow.json +96 -56
  3. package/demo/test-colorpicker.html +30 -0
  4. package/dist/temba-components.js +896 -934
  5. package/dist/temba-components.js.map +1 -1
  6. package/out-tsc/src/events.js.map +1 -1
  7. package/out-tsc/src/flow/Editor.js +9 -6
  8. package/out-tsc/src/flow/Editor.js.map +1 -1
  9. package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
  10. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  11. package/out-tsc/src/flow/actions/set_contact_field.js +1 -1
  12. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  13. package/out-tsc/src/flow/actions/set_contact_language.js +1 -1
  14. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  15. package/out-tsc/src/flow/actions/set_contact_status.js +1 -1
  16. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  17. package/out-tsc/src/flow/config.js +2 -8
  18. package/out-tsc/src/flow/config.js.map +1 -1
  19. package/out-tsc/src/flow/nodes/split_by_llm.js +101 -0
  20. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -0
  21. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +4 -89
  22. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  23. package/out-tsc/src/flow/nodes/split_by_subflow.js +123 -3
  24. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  25. package/out-tsc/src/flow/nodes/split_by_ticket.js +115 -13
  26. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  27. package/out-tsc/src/flow/nodes/split_by_webhook.js +160 -12
  28. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  29. package/out-tsc/src/form/ArrayEditor.js +45 -56
  30. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  31. package/out-tsc/src/form/BaseListEditor.js +4 -3
  32. package/out-tsc/src/form/BaseListEditor.js.map +1 -1
  33. package/out-tsc/src/form/Checkbox.js +77 -24
  34. package/out-tsc/src/form/Checkbox.js.map +1 -1
  35. package/out-tsc/src/form/ColorPicker.js +28 -40
  36. package/out-tsc/src/form/ColorPicker.js.map +1 -1
  37. package/out-tsc/src/form/Completion.js +44 -53
  38. package/out-tsc/src/form/Completion.js.map +1 -1
  39. package/out-tsc/src/form/Compose.js +7 -8
  40. package/out-tsc/src/form/Compose.js.map +1 -1
  41. package/out-tsc/src/form/ContactSearch.js +3 -4
  42. package/out-tsc/src/form/ContactSearch.js.map +1 -1
  43. package/out-tsc/src/form/DatePicker.js +29 -36
  44. package/out-tsc/src/form/DatePicker.js.map +1 -1
  45. package/out-tsc/src/form/{FormField.js → FieldElement.js} +78 -50
  46. package/out-tsc/src/form/FieldElement.js.map +1 -0
  47. package/out-tsc/src/form/FieldRenderer.js +2 -1
  48. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  49. package/out-tsc/src/form/ImagePicker.js +122 -126
  50. package/out-tsc/src/form/ImagePicker.js.map +1 -1
  51. package/out-tsc/src/form/KeyValueEditor.js +41 -37
  52. package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
  53. package/out-tsc/src/form/MessageEditor.js +55 -63
  54. package/out-tsc/src/form/MessageEditor.js.map +1 -1
  55. package/out-tsc/src/form/TembaSlider.js +3 -3
  56. package/out-tsc/src/form/TembaSlider.js.map +1 -1
  57. package/out-tsc/src/form/TemplateEditor.js +3 -3
  58. package/out-tsc/src/form/TemplateEditor.js.map +1 -1
  59. package/out-tsc/src/form/TextInput.js +22 -26
  60. package/out-tsc/src/form/TextInput.js.map +1 -1
  61. package/out-tsc/src/form/select/Select.js +9 -15
  62. package/out-tsc/src/form/select/Select.js.map +1 -1
  63. package/out-tsc/src/form/select/UserSelect.js +8 -9
  64. package/out-tsc/src/form/select/UserSelect.js.map +1 -1
  65. package/out-tsc/src/form/select/WorkspaceSelect.js +7 -8
  66. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -1
  67. package/out-tsc/src/live/ContactChat.js +73 -99
  68. package/out-tsc/src/live/ContactChat.js.map +1 -1
  69. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -1
  70. package/out-tsc/src/utils.js +115 -0
  71. package/out-tsc/src/utils.js.map +1 -1
  72. package/out-tsc/temba-modules.js +3 -2
  73. package/out-tsc/temba-modules.js.map +1 -1
  74. package/out-tsc/test/nodes/split_by_llm.test.js +174 -0
  75. package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -0
  76. package/out-tsc/test/temba-checkbox.test.js +16 -0
  77. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  78. package/out-tsc/test/temba-integration-markdown.test.js +2 -4
  79. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  80. package/out-tsc/test/temba-slider.test.js +0 -1
  81. package/out-tsc/test/temba-slider.test.js.map +1 -1
  82. package/package.json +1 -1
  83. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  84. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  85. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  86. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  87. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  88. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  89. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  90. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  91. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  92. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  93. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  94. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  95. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  96. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  97. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  98. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  99. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  100. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  101. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  102. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  103. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  104. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  105. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  106. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  107. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  108. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  109. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  110. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  111. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  112. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  113. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  114. package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
  115. package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
  116. package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
  117. package/screenshots/truth/checkbox/checked.png +0 -0
  118. package/screenshots/truth/checkbox/default.png +0 -0
  119. package/screenshots/truth/colorpicker/default.png +0 -0
  120. package/screenshots/truth/colorpicker/focused.png +0 -0
  121. package/screenshots/truth/colorpicker/initialized.png +0 -0
  122. package/screenshots/truth/colorpicker/selected.png +0 -0
  123. package/screenshots/truth/compose/attachments-tab.png +0 -0
  124. package/screenshots/truth/compose/attachments-with-files.png +0 -0
  125. package/screenshots/truth/compose/intial-text.png +0 -0
  126. package/screenshots/truth/compose/no-counter.png +0 -0
  127. package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
  128. package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
  129. package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
  130. package/screenshots/truth/contacts/chat-failure.png +0 -0
  131. package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
  132. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  133. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  134. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  135. package/screenshots/truth/counter/summary.png +0 -0
  136. package/screenshots/truth/counter/text.png +0 -0
  137. package/screenshots/truth/counter/unicode-variables.png +0 -0
  138. package/screenshots/truth/counter/unicode.png +0 -0
  139. package/screenshots/truth/counter/variable.png +0 -0
  140. package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
  141. package/screenshots/truth/datepicker/date.png +0 -0
  142. package/screenshots/truth/datepicker/initial-timezone.png +0 -0
  143. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  144. package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
  145. package/screenshots/truth/dialog/focused.png +0 -0
  146. package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
  147. package/screenshots/truth/editor/router.png +0 -0
  148. package/screenshots/truth/editor/send_msg.png +0 -0
  149. package/screenshots/truth/editor/set_contact_language.png +0 -0
  150. package/screenshots/truth/editor/set_contact_name.png +0 -0
  151. package/screenshots/truth/editor/set_run_result.png +0 -0
  152. package/screenshots/truth/editor/wait.png +0 -0
  153. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  154. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  155. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  156. package/screenshots/truth/field-renderer/context-comparison.png +0 -0
  157. package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
  158. package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
  159. package/screenshots/truth/field-renderer/select-multi.png +0 -0
  160. package/screenshots/truth/field-renderer/select-no-label.png +0 -0
  161. package/screenshots/truth/field-renderer/select-with-label.png +0 -0
  162. package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
  163. package/screenshots/truth/field-renderer/text-no-label.png +0 -0
  164. package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
  165. package/screenshots/truth/field-renderer/text-with-label.png +0 -0
  166. package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
  167. package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
  168. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  169. package/screenshots/truth/list/fields-dragging.png +0 -0
  170. package/screenshots/truth/list/fields-filtered.png +0 -0
  171. package/screenshots/truth/list/fields-hovered.png +0 -0
  172. package/screenshots/truth/list/fields.png +0 -0
  173. package/screenshots/truth/list/items-selected.png +0 -0
  174. package/screenshots/truth/list/items-updated.png +0 -0
  175. package/screenshots/truth/list/items.png +0 -0
  176. package/screenshots/truth/menu/menu-focused-with items.png +0 -0
  177. package/screenshots/truth/menu/menu-refresh-1.png +0 -0
  178. package/screenshots/truth/menu/menu-refresh-2.png +0 -0
  179. package/screenshots/truth/menu/menu-submenu.png +0 -0
  180. package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
  181. package/screenshots/truth/menu/menu-tasks.png +0 -0
  182. package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
  183. package/screenshots/truth/message-editor/default.png +0 -0
  184. package/screenshots/truth/message-editor/drag-highlight.png +0 -0
  185. package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
  186. package/screenshots/truth/message-editor/with-completion.png +0 -0
  187. package/screenshots/truth/message-editor/with-properties.png +0 -0
  188. package/screenshots/truth/modax/form.png +0 -0
  189. package/screenshots/truth/modax/simple.png +0 -0
  190. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  191. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  192. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  193. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  194. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  195. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  196. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  197. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  198. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  199. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  200. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  201. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  202. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  203. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  204. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  205. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  206. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  207. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  208. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  209. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  210. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  211. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  212. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  213. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  214. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  215. package/screenshots/truth/omnibox/selected.png +0 -0
  216. package/screenshots/truth/options/block.png +0 -0
  217. package/screenshots/truth/run-list/basic.png +0 -0
  218. package/screenshots/truth/select/disabled-multi-selection.png +0 -0
  219. package/screenshots/truth/select/disabled-selection.png +0 -0
  220. package/screenshots/truth/select/disabled.png +0 -0
  221. package/screenshots/truth/select/embedded.png +0 -0
  222. package/screenshots/truth/select/empty-options.png +0 -0
  223. package/screenshots/truth/select/expression-selected.png +0 -0
  224. package/screenshots/truth/select/expressions.png +0 -0
  225. package/screenshots/truth/select/functions.png +0 -0
  226. package/screenshots/truth/select/local-options.png +0 -0
  227. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  228. package/screenshots/truth/select/multiple-initial-values.png +0 -0
  229. package/screenshots/truth/select/remote-options.png +0 -0
  230. package/screenshots/truth/select/search-enabled.png +0 -0
  231. package/screenshots/truth/select/search-multi-no-matches.png +0 -0
  232. package/screenshots/truth/select/search-selected-focus.png +0 -0
  233. package/screenshots/truth/select/search-selected.png +0 -0
  234. package/screenshots/truth/select/search-with-selected.png +0 -0
  235. package/screenshots/truth/select/searching.png +0 -0
  236. package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
  237. package/screenshots/truth/select/selected-multi.png +0 -0
  238. package/screenshots/truth/select/selected-single.png +0 -0
  239. package/screenshots/truth/select/selection-clearable.png +0 -0
  240. package/screenshots/truth/select/static-initial-value.png +0 -0
  241. package/screenshots/truth/select/static-initial-via-selected.png +0 -0
  242. package/screenshots/truth/select/truncated-selection.png +0 -0
  243. package/screenshots/truth/select/with-placeholder.png +0 -0
  244. package/screenshots/truth/select/without-placeholder.png +0 -0
  245. package/screenshots/truth/slider/update-slider-on-circle-dragged.png +0 -0
  246. package/screenshots/truth/templates/default.png +0 -0
  247. package/screenshots/truth/templates/unapproved.png +0 -0
  248. package/screenshots/truth/textinput/autogrow-initial.png +0 -0
  249. package/screenshots/truth/textinput/input-disabled.png +0 -0
  250. package/screenshots/truth/textinput/input-focused.png +0 -0
  251. package/screenshots/truth/textinput/input-form.png +0 -0
  252. package/screenshots/truth/textinput/input-inserted.png +0 -0
  253. package/screenshots/truth/textinput/input-placeholder.png +0 -0
  254. package/screenshots/truth/textinput/input-updated.png +0 -0
  255. package/screenshots/truth/textinput/input.png +0 -0
  256. package/screenshots/truth/textinput/textarea-focused.png +0 -0
  257. package/screenshots/truth/textinput/textarea.png +0 -0
  258. package/src/events.ts +9 -8
  259. package/src/flow/Editor.ts +6 -3
  260. package/src/flow/actions/set_contact_channel.ts +1 -1
  261. package/src/flow/actions/set_contact_field.ts +1 -1
  262. package/src/flow/actions/set_contact_language.ts +1 -1
  263. package/src/flow/actions/set_contact_status.ts +1 -1
  264. package/src/flow/config.ts +2 -8
  265. package/src/flow/nodes/split_by_llm.ts +119 -0
  266. package/src/flow/nodes/split_by_llm_categorize.ts +13 -116
  267. package/src/flow/nodes/split_by_subflow.ts +153 -3
  268. package/src/flow/nodes/split_by_ticket.ts +135 -12
  269. package/src/flow/nodes/split_by_webhook.ts +187 -12
  270. package/src/form/ArrayEditor.ts +45 -57
  271. package/src/form/BaseListEditor.ts +4 -4
  272. package/src/form/Checkbox.ts +81 -24
  273. package/src/form/ColorPicker.ts +31 -43
  274. package/src/form/Completion.ts +49 -56
  275. package/src/form/Compose.ts +8 -8
  276. package/src/form/ContactSearch.ts +3 -4
  277. package/src/form/DatePicker.ts +32 -38
  278. package/src/form/{FormField.ts → FieldElement.ts} +105 -52
  279. package/src/form/FieldRenderer.ts +2 -1
  280. package/src/form/ImagePicker.ts +107 -110
  281. package/src/form/KeyValueEditor.ts +43 -39
  282. package/src/form/MessageEditor.ts +61 -67
  283. package/src/form/TembaSlider.ts +3 -3
  284. package/src/form/TemplateEditor.ts +3 -3
  285. package/src/form/TextInput.ts +25 -28
  286. package/src/form/select/Select.ts +12 -17
  287. package/src/form/select/UserSelect.ts +10 -11
  288. package/src/form/select/WorkspaceSelect.ts +9 -10
  289. package/src/live/ContactChat.ts +81 -92
  290. package/src/live/ContactFieldEditor.ts +2 -2
  291. package/src/store/flow-definition.d.ts +2 -1
  292. package/src/utils.ts +192 -0
  293. package/temba-modules.ts +3 -2
  294. package/test/nodes/split_by_llm.test.ts +232 -0
  295. package/test/temba-checkbox.test.ts +26 -0
  296. package/test/temba-integration-markdown.test.ts +2 -4
  297. package/test/temba-slider.test.ts +0 -1
  298. package/test-assets/contacts/history.json +7 -20
  299. package/test-assets/style.css +36 -234
  300. package/web-dev-server.config.mjs +26 -0
  301. package/web-test-runner.config.mjs +1 -1
  302. package/out-tsc/src/flow/actions/call_llm.js +0 -64
  303. package/out-tsc/src/flow/actions/call_llm.js.map +0 -1
  304. package/out-tsc/src/flow/actions/call_webhook.js +0 -131
  305. package/out-tsc/src/flow/actions/call_webhook.js.map +0 -1
  306. package/out-tsc/src/flow/actions/enter_flow.js +0 -14
  307. package/out-tsc/src/flow/actions/enter_flow.js.map +0 -1
  308. package/out-tsc/src/flow/actions/open_ticket.js +0 -73
  309. package/out-tsc/src/flow/actions/open_ticket.js.map +0 -1
  310. package/out-tsc/src/form/FormElement.js +0 -67
  311. package/out-tsc/src/form/FormElement.js.map +0 -1
  312. package/out-tsc/src/form/FormField.js.map +0 -1
  313. package/out-tsc/test/actions/call_llm.test.js +0 -103
  314. package/out-tsc/test/actions/call_llm.test.js.map +0 -1
  315. package/out-tsc/test/temba-formfield.test.js +0 -94
  316. package/out-tsc/test/temba-formfield.test.js.map +0 -1
  317. package/src/flow/actions/call_llm.ts +0 -66
  318. package/src/flow/actions/call_webhook.ts +0 -143
  319. package/src/flow/actions/enter_flow.ts +0 -15
  320. package/src/flow/actions/open_ticket.ts +0 -83
  321. package/src/form/FormElement.ts +0 -69
  322. package/test/actions/call_llm.test.ts +0 -137
  323. package/test/temba-formfield.test.ts +0 -121
@@ -22,11 +22,12 @@ import {
22
22
  AirtimeTransferredEvent,
23
23
  CallEvent,
24
24
  ChannelEvent,
25
+ ChatStartedEvent,
25
26
  ContactEvent,
26
27
  ContactGroupsEvent,
27
28
  ContactHistoryPage,
28
29
  ContactLanguageChangedEvent,
29
- FlowEvent,
30
+ ContactStatusChangedEvent,
30
31
  MsgEvent,
31
32
  NameChangedEvent,
32
33
  OptInEvent,
@@ -51,36 +52,36 @@ export const BODY_SNIPPET_LENGTH = 250;
51
52
  */
52
53
 
53
54
  export enum Events {
54
- MESSAGE_CREATED = 'msg_created',
55
- MESSAGE_RECEIVED = 'msg_received',
55
+ AIRTIME_TRANSFERRED = 'airtime_transferred',
56
56
  BROADCAST_CREATED = 'broadcast_created',
57
- IVR_CREATED = 'ivr_created',
58
57
  CALL_CREATED = 'call_created',
58
+ CALL_MISSED = 'call_missed',
59
59
  CALL_RECEIVED = 'call_received',
60
+ CHAT_STARTED = 'chat_started',
60
61
  CONTACT_FIELD_CHANGED = 'contact_field_changed',
61
62
  CONTACT_GROUPS_CHANGED = 'contact_groups_changed',
63
+ CONTACT_LANGUAGE_CHANGED = 'contact_language_changed',
62
64
  CONTACT_NAME_CHANGED = 'contact_name_changed',
65
+ CONTACT_STATUS_CHANGED = 'contact_status_changed',
63
66
  CONTACT_URNS_CHANGED = 'contact_urns_changed',
64
- CHANNEL_EVENT = 'channel_event',
65
- CONTACT_LANGUAGE_CHANGED = 'contact_language_changed',
66
- AIRTIME_TRANSFERRED = 'airtime_transferred',
67
+ IVR_CREATED = 'ivr_created',
68
+ MSG_CREATED = 'msg_created',
69
+ MSG_RECEIVED = 'msg_received',
67
70
  NOTE_CREATED = 'note_created',
71
+ OPTIN_REQUESTED = 'optin_requested',
72
+ OPTIN_STARTED = 'optin_started',
73
+ OPTIN_STOPPED = 'optin_stopped',
74
+ RUN_ENDED = 'run_ended',
75
+ RUN_STARTED = 'run_started',
68
76
  TICKET_ASSIGNED = 'ticket_assigned',
69
- TICKET_NOTE_ADDED = 'ticket_note_added',
70
77
  TICKET_CLOSED = 'ticket_closed',
78
+ TICKET_NOTE_ADDED = 'ticket_note_added',
71
79
  TICKET_OPENED = 'ticket_opened',
72
80
  TICKET_REOPENED = 'ticket_reopened',
73
81
  TICKET_TOPIC_CHANGED = 'ticket_topic_changed',
74
- OPTIN_STARTED = 'optin_started',
75
- OPTIN_STOPPED = 'optin_stopped',
76
- OPTIN_REQUESTED = 'optin_requested',
77
- RUN_STARTED = 'run_started',
78
- RUN_ENDED = 'run_ended',
79
82
 
80
83
  // deprecated
81
- CALL_STARTED = 'call_started',
82
- FLOW_ENTERED = 'flow_entered',
83
- FLOW_EXITED = 'flow_exited'
84
+ CHANNEL_EVENT = 'channel_event'
84
85
  }
85
86
 
86
87
  const renderInfoList = (singular: string, plural: string, items: any[]) => {
@@ -98,43 +99,13 @@ const renderInfoList = (singular: string, plural: string, items: any[]) => {
98
99
  };
99
100
 
100
101
  const renderChannelEvent = (event: ChannelEvent): string => {
101
- if (event.event.type === 'mt_miss') {
102
- return 'Missed outgoing call';
103
- } else if (event.event.type === 'mo_miss') {
104
- return 'Missed incoming call';
105
- } else if (event.event.type === 'new_conversation') {
106
- return 'Started conversation';
107
- } else if (event.channel_event_type === 'welcome_message') {
108
- return 'Welcome Message Sent';
109
- } else if (event.event.type === 'referral') {
110
- return 'Referred';
111
- } else if (event.event.type === 'follow') {
112
- return 'Followed';
102
+ if (event.channel_event_type === 'welcome_message') {
103
+ return 'Welcome message sent';
113
104
  } else if (event.event.type === 'stop_contact') {
114
105
  return 'Stopped';
115
- } else if (event.event.type === 'mt_call') {
116
- return 'Outgoing Phone Call'; // deprecated
117
- } else if (event.event.type == 'mo_call') {
118
- return 'Incoming Phone call'; // deprecated
119
- } else if (event.event.type == 'optin') {
120
- return `Opted in to **${event.event.optin?.name}**`; // deprecated
121
- } else if (event.event.type == 'optout') {
122
- return `Opted out of **${event.event.optin?.name}**`; // deprecated
123
106
  }
124
107
  };
125
108
 
126
- const renderFlowEvent = (event: FlowEvent): string => {
127
- let verb = 'Interrupted';
128
- if (event.status !== 'I') {
129
- if (event.type === Events.FLOW_ENTERED) {
130
- verb = 'Started';
131
- } else {
132
- verb = 'Completed';
133
- }
134
- }
135
- return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
136
- };
137
-
138
109
  const renderRunEvent = (event: RunEvent): string => {
139
110
  let verb = 'Started';
140
111
  if (event.type === Events.RUN_ENDED) {
@@ -150,6 +121,14 @@ const renderRunEvent = (event: RunEvent): string => {
150
121
  return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
151
122
  };
152
123
 
124
+ const renderChatStartedEvent = (event: ChatStartedEvent): string => {
125
+ if (event.params) {
126
+ return `Chat referral`;
127
+ } else {
128
+ return `Chat started`;
129
+ }
130
+ };
131
+
153
132
  const renderUpdateEvent = (event: UpdateFieldEvent): string => {
154
133
  return event.value
155
134
  ? `Updated **${event.field.name}** to **${event.value.text}**`
@@ -225,17 +204,25 @@ export const renderContactLanguageChangedEvent = (
225
204
  return `Language updated to **${event.language}**`;
226
205
  };
227
206
 
207
+ export const renderContactStatusChangedEvent = (
208
+ event: ContactStatusChangedEvent
209
+ ): string => {
210
+ return `Status updated to **${event.status}**`;
211
+ };
212
+
228
213
  export const renderCallEvent = (event: CallEvent): string => {
229
214
  if (event.type === Events.CALL_CREATED) {
230
- return `Call Started`;
215
+ return `Call started`;
216
+ } else if (event.type === Events.CALL_MISSED) {
217
+ return `Call missed`;
231
218
  } else if (event.type === Events.CALL_RECEIVED) {
232
- return `Call Answered`;
219
+ return `Call answered`;
233
220
  }
234
221
  };
235
222
 
236
223
  export const renderOptInEvent = (event: OptInEvent): string => {
237
224
  if (event.type === Events.OPTIN_REQUESTED) {
238
- return `Requested opt-in for ${event.optin.name}`;
225
+ return `Requested opt-in for **${event.optin.name}**`;
239
226
  } else if (event.type === Events.OPTIN_STARTED) {
240
227
  return `Opted in to **${event.optin.name}**`;
241
228
  } else if (event.type === Events.OPTIN_STOPPED) {
@@ -635,113 +622,115 @@ export class ContactChat extends ContactStoreElement {
635
622
  public getEventMessage(event: ContactEvent): ChatEvent {
636
623
  let message = null;
637
624
  switch (event.type) {
638
- case Events.TICKET_OPENED:
625
+ case Events.AIRTIME_TRANSFERRED:
639
626
  message = {
640
627
  type: MessageType.Inline,
641
- text: renderTicketAction(event as TicketEvent, 'opened')
628
+ text: renderAirtimeTransferredEvent(event as AirtimeTransferredEvent)
642
629
  };
643
630
  break;
644
- case Events.TICKET_ASSIGNED:
631
+ case Events.CALL_CREATED:
632
+ case Events.CALL_MISSED:
633
+ case Events.CALL_RECEIVED:
645
634
  message = {
646
635
  type: MessageType.Inline,
647
- text: renderTicketAssigned(event as TicketEvent)
636
+ text: renderCallEvent(event as CallEvent)
648
637
  };
649
638
  break;
650
- case Events.TICKET_REOPENED:
639
+ case Events.CHAT_STARTED:
651
640
  message = {
652
641
  type: MessageType.Inline,
653
- text: renderTicketAction(event as TicketEvent, 'reopened')
642
+ text: renderChatStartedEvent(event as ChatStartedEvent)
654
643
  };
655
644
  break;
656
- case Events.TICKET_CLOSED:
645
+ case Events.CONTACT_FIELD_CHANGED:
657
646
  message = {
658
647
  type: MessageType.Inline,
659
- text: renderTicketAction(event as TicketEvent, 'closed')
648
+ text: renderUpdateEvent(event as UpdateFieldEvent)
660
649
  };
661
650
  break;
662
- case Events.TICKET_TOPIC_CHANGED:
651
+ case Events.CONTACT_GROUPS_CHANGED:
663
652
  message = {
664
653
  type: MessageType.Inline,
665
- text: `Topic changed to **${(event as TicketEvent).topic.name}**`
654
+ text: renderContactGroupsEvent(event as ContactGroupsEvent)
666
655
  };
667
656
  break;
668
- case Events.FLOW_ENTERED:
669
- case Events.FLOW_EXITED:
657
+ case Events.CONTACT_LANGUAGE_CHANGED:
670
658
  message = {
671
659
  type: MessageType.Inline,
672
- text: renderFlowEvent(event as FlowEvent)
660
+ text: renderContactLanguageChangedEvent(
661
+ event as ContactLanguageChangedEvent
662
+ )
673
663
  };
674
664
  break;
675
- case Events.RUN_STARTED:
676
- case Events.RUN_ENDED:
665
+ case Events.CONTACT_NAME_CHANGED:
677
666
  message = {
678
667
  type: MessageType.Inline,
679
- text: renderRunEvent(event as RunEvent)
668
+ text: renderNameChanged(event as NameChangedEvent)
680
669
  };
681
670
  break;
682
- case Events.CONTACT_FIELD_CHANGED:
671
+ case Events.CONTACT_STATUS_CHANGED:
683
672
  message = {
684
673
  type: MessageType.Inline,
685
- text: renderUpdateEvent(event as UpdateFieldEvent)
674
+ text: renderContactStatusChangedEvent(
675
+ event as ContactStatusChangedEvent
676
+ )
686
677
  };
687
678
  break;
688
- case Events.CONTACT_NAME_CHANGED:
679
+ case Events.CONTACT_URNS_CHANGED:
689
680
  message = {
690
681
  type: MessageType.Inline,
691
- text: renderNameChanged(event as NameChangedEvent)
682
+ text: renderContactURNsChanged(event as URNsChangedEvent)
692
683
  };
693
684
  break;
694
- case Events.CONTACT_URNS_CHANGED:
685
+ case Events.OPTIN_REQUESTED:
686
+ case Events.OPTIN_STARTED:
687
+ case Events.OPTIN_STOPPED:
695
688
  message = {
696
689
  type: MessageType.Inline,
697
- text: renderContactURNsChanged(event as URNsChangedEvent)
690
+ text: renderOptInEvent(event as OptInEvent)
698
691
  };
699
692
  break;
700
- case Events.CONTACT_GROUPS_CHANGED:
693
+ case Events.RUN_STARTED:
694
+ case Events.RUN_ENDED:
701
695
  message = {
702
696
  type: MessageType.Inline,
703
- text: renderContactGroupsEvent(event as ContactGroupsEvent)
697
+ text: renderRunEvent(event as RunEvent)
704
698
  };
705
699
  break;
706
- case Events.AIRTIME_TRANSFERRED:
700
+ case Events.TICKET_ASSIGNED:
707
701
  message = {
708
702
  type: MessageType.Inline,
709
- text: renderAirtimeTransferredEvent(event as AirtimeTransferredEvent)
703
+ text: renderTicketAssigned(event as TicketEvent)
710
704
  };
711
705
  break;
712
- case Events.CALL_CREATED:
713
- case Events.CALL_RECEIVED:
706
+ case Events.TICKET_CLOSED:
714
707
  message = {
715
708
  type: MessageType.Inline,
716
- text: renderCallEvent(event as CallEvent)
709
+ text: renderTicketAction(event as TicketEvent, 'closed')
717
710
  };
718
711
  break;
719
- case Events.CALL_STARTED: // deprecated
712
+ case Events.TICKET_OPENED:
720
713
  message = {
721
714
  type: MessageType.Inline,
722
- text: `Started Call`
715
+ text: renderTicketAction(event as TicketEvent, 'opened')
723
716
  };
724
717
  break;
725
- case Events.CHANNEL_EVENT:
718
+ case Events.TICKET_REOPENED:
726
719
  message = {
727
720
  type: MessageType.Inline,
728
- text: renderChannelEvent(event as ChannelEvent)
721
+ text: renderTicketAction(event as TicketEvent, 'reopened')
729
722
  };
730
723
  break;
731
- case Events.CONTACT_LANGUAGE_CHANGED:
724
+ case Events.TICKET_TOPIC_CHANGED:
732
725
  message = {
733
726
  type: MessageType.Inline,
734
- text: renderContactLanguageChangedEvent(
735
- event as ContactLanguageChangedEvent
736
- )
727
+ text: `Topic changed to **${(event as TicketEvent).topic.name}**`
737
728
  };
738
729
  break;
739
- case Events.OPTIN_REQUESTED:
740
- case Events.OPTIN_STARTED:
741
- case Events.OPTIN_STOPPED:
730
+ case Events.CHANNEL_EVENT: // deprecated
742
731
  message = {
743
732
  type: MessageType.Inline,
744
- text: renderOptInEvent(event as OptInEvent)
733
+ text: renderChannelEvent(event as ChannelEvent)
745
734
  };
746
735
  break;
747
736
  }
@@ -1,12 +1,12 @@
1
1
  import { css, html, TemplateResult } from 'lit';
2
2
  import { property } from 'lit/decorators.js';
3
- import { FormElement } from '../form/FormElement';
4
3
  import { CustomEventType } from '../interfaces';
5
4
  import { RapidElement } from '../RapidElement';
6
5
  import { InputType, TextInput } from '../form/TextInput';
7
6
  import { Icon } from '../Icons';
8
7
  import { getClasses, WebResponse } from '../utils';
9
8
  import { Select } from '../form/select/Select';
9
+ import { FieldElement } from '../form/FieldElement';
10
10
 
11
11
  enum Status {
12
12
  Success = 'success',
@@ -380,7 +380,7 @@ export class ContactFieldEditor extends RapidElement {
380
380
  public handleSubmit() {
381
381
  const input = this.shadowRoot.querySelector(
382
382
  'temba-textinput, temba-datepicker'
383
- ) as FormElement;
383
+ ) as FieldElement;
384
384
 
385
385
  if (input.value !== this.value) {
386
386
  this.dirty = true;
@@ -175,7 +175,8 @@ export interface CallLLM extends Action {
175
175
  llm: NamedObject;
176
176
  instructions: string;
177
177
  input: string;
178
- result_name: string;
178
+ result_name?: string;
179
+ output_local?: string;
179
180
  }
180
181
 
181
182
  export interface OpenTicket extends Action {
package/src/utils.ts CHANGED
@@ -932,3 +932,195 @@ export const getMiddle = (a: DOMRect, b: DOMRect) => {
932
932
 
933
933
  // Export the UUID function from the uuid package
934
934
  export { generateUUID };
935
+
936
+ // Helper types for router creation
937
+ export interface RouterCategory {
938
+ uuid: string;
939
+ name: string;
940
+ exit_uuid: string;
941
+ }
942
+
943
+ export interface RouterExit {
944
+ uuid: string;
945
+ destination_uuid: string | null;
946
+ }
947
+
948
+ export interface RouterCase {
949
+ uuid: string;
950
+ type: string;
951
+ arguments: string[];
952
+ category_uuid: string;
953
+ }
954
+
955
+ export interface CreateCategoryParams {
956
+ name: string;
957
+ existingCategories: any[];
958
+ existingExits: any[];
959
+ existingCases?: any[];
960
+ caseConfig?: {
961
+ type: string;
962
+ arguments: string[];
963
+ };
964
+ }
965
+
966
+ // Helper function to create or preserve a category with its exit and case
967
+ export const createOrPreserveCategory = (
968
+ params: CreateCategoryParams
969
+ ): {
970
+ category: RouterCategory;
971
+ exit: RouterExit;
972
+ case?: RouterCase;
973
+ } => {
974
+ const { name, existingCategories, existingExits, existingCases, caseConfig } =
975
+ params;
976
+
977
+ // Find existing category
978
+ const existingCategory = existingCategories.find((cat) => cat.name === name);
979
+ const existingExit = existingCategory
980
+ ? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
981
+ : null;
982
+ const existingCase =
983
+ existingCategory && existingCases
984
+ ? existingCases.find(
985
+ (case_) => case_.category_uuid === existingCategory.uuid
986
+ )
987
+ : null;
988
+
989
+ // Use existing UUIDs or generate new ones
990
+ const categoryUuid = existingCategory?.uuid || generateUUID();
991
+ const exitUuid = existingExit?.uuid || generateUUID();
992
+ const caseUuid = existingCase?.uuid || generateUUID();
993
+
994
+ const category: RouterCategory = {
995
+ uuid: categoryUuid,
996
+ name: name,
997
+ exit_uuid: exitUuid
998
+ };
999
+
1000
+ const exit: RouterExit = {
1001
+ uuid: exitUuid,
1002
+ destination_uuid: existingExit?.destination_uuid || null
1003
+ };
1004
+
1005
+ const result: {
1006
+ category: RouterCategory;
1007
+ exit: RouterExit;
1008
+ case?: RouterCase;
1009
+ } = { category, exit };
1010
+
1011
+ if (caseConfig) {
1012
+ result.case = {
1013
+ uuid: caseUuid,
1014
+ type: caseConfig.type,
1015
+ arguments: caseConfig.arguments,
1016
+ category_uuid: categoryUuid
1017
+ };
1018
+ }
1019
+
1020
+ return result;
1021
+ };
1022
+
1023
+ // Helper function to create a complete router with standard Success/Failure categories
1024
+ export const createSuccessFailureRouter = (
1025
+ operand: string,
1026
+ successCaseConfig: { type: string; arguments: string[] },
1027
+ existingCategories: any[] = [],
1028
+ existingExits: any[] = [],
1029
+ existingCases: any[] = []
1030
+ ) => {
1031
+ const success = createOrPreserveCategory({
1032
+ name: 'Success',
1033
+ existingCategories,
1034
+ existingExits,
1035
+ existingCases,
1036
+ caseConfig: successCaseConfig
1037
+ });
1038
+
1039
+ const failure = createOrPreserveCategory({
1040
+ name: 'Failure',
1041
+ existingCategories,
1042
+ existingExits
1043
+ });
1044
+
1045
+ return {
1046
+ router: {
1047
+ type: 'switch' as const,
1048
+ categories: [success.category, failure.category],
1049
+ default_category_uuid: failure.category.uuid,
1050
+ operand: operand,
1051
+ cases: success.case ? [success.case] : []
1052
+ },
1053
+ exits: [success.exit, failure.exit]
1054
+ };
1055
+ };
1056
+
1057
+ // Helper function to create a multi-category router with Other/Failure defaults
1058
+ export const createMultiCategoryRouter = (
1059
+ operand: string,
1060
+ userCategories: string[],
1061
+ categoryToCaseMap: (categoryName: string) => {
1062
+ type: string;
1063
+ arguments: string[];
1064
+ },
1065
+ existingCategories: any[] = [],
1066
+ existingExits: any[] = [],
1067
+ existingCases: any[] = []
1068
+ ) => {
1069
+ const categories: RouterCategory[] = [];
1070
+ const exits: RouterExit[] = [];
1071
+ const cases: RouterCase[] = [];
1072
+
1073
+ // Add user categories
1074
+ userCategories.forEach((categoryName) => {
1075
+ const result = createOrPreserveCategory({
1076
+ name: categoryName,
1077
+ existingCategories,
1078
+ existingExits,
1079
+ existingCases,
1080
+ caseConfig: categoryToCaseMap(categoryName)
1081
+ });
1082
+
1083
+ categories.push(result.category);
1084
+ exits.push(result.exit);
1085
+ if (result.case) {
1086
+ cases.push(result.case);
1087
+ }
1088
+ });
1089
+
1090
+ // Add "Other" category (default)
1091
+ const other = createOrPreserveCategory({
1092
+ name: 'Other',
1093
+ existingCategories,
1094
+ existingExits
1095
+ });
1096
+ categories.push(other.category);
1097
+ exits.push(other.exit);
1098
+
1099
+ // Add "Failure" category
1100
+ const failure = createOrPreserveCategory({
1101
+ name: 'Failure',
1102
+ existingCategories,
1103
+ existingExits,
1104
+ existingCases,
1105
+ caseConfig: {
1106
+ type: 'has_only_text',
1107
+ arguments: ['<ERROR>']
1108
+ }
1109
+ });
1110
+ categories.push(failure.category);
1111
+ exits.push(failure.exit);
1112
+ if (failure.case) {
1113
+ cases.push(failure.case);
1114
+ }
1115
+
1116
+ return {
1117
+ router: {
1118
+ type: 'switch' as const,
1119
+ categories: categories,
1120
+ default_category_uuid: other.category.uuid,
1121
+ operand: operand,
1122
+ cases: cases
1123
+ },
1124
+ exits: exits
1125
+ };
1126
+ };
package/temba-modules.ts CHANGED
@@ -6,7 +6,7 @@ import { Completion } from './src/form/Completion';
6
6
  import { Modax } from './src/layout/Modax';
7
7
  import { Dialog } from './src/layout/Dialog';
8
8
  import { Button } from './src/display/Button';
9
- import { FormField } from './src/form/FormField';
9
+ import { FieldElement } from './src/form/FieldElement';
10
10
  import { Loading } from './src/display/Loading';
11
11
  import { CharCount } from './src/display/CharCount';
12
12
  import { Options } from './src/display/Options';
@@ -103,7 +103,8 @@ addCustomElement('temba-field-manager', FieldManager);
103
103
  addCustomElement('temba-urn', ContactUrn);
104
104
  addCustomElement('temba-content-menu', ContentMenu);
105
105
 
106
- addCustomElement('temba-field', FormField);
106
+ // Note: FieldElement is a base class and not directly instantiated as a custom element
107
+ export { FieldElement };
107
108
  addCustomElement('temba-dialog', Dialog);
108
109
  addCustomElement('temba-modax', Modax);
109
110
  addCustomElement('temba-charcount', CharCount);