@nyaruka/temba-components 0.129.1 → 0.129.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 (583) hide show
  1. package/.github/workflows/build.yml +6 -5
  2. package/.github/workflows/coverage.yml +80 -0
  3. package/CHANGELOG.md +32 -0
  4. package/README.md +6 -0
  5. package/check-coverage.js +133 -0
  6. package/demo/components/alert/example.html +71 -0
  7. package/demo/components/button/example.html +167 -0
  8. package/demo/{chart → components/chart}/example.html +3 -3
  9. package/demo/components/chart/horizontal-demo.html +160 -0
  10. package/demo/components/checkbox/example.html +68 -0
  11. package/demo/components/compose/example.html +69 -0
  12. package/demo/components/datepicker/example.html +3 -3
  13. package/demo/components/datepicker/range-picker-demo.html +2 -2
  14. package/demo/{dialog → components/dialog}/example.html +3 -3
  15. package/demo/components/dropdown/example.html +95 -0
  16. package/demo/{flow → components/flow}/example.html +1 -1
  17. package/demo/{misc → components/misc}/example.html +3 -3
  18. package/demo/components/progress/example.html +62 -0
  19. package/demo/components/select/drag-and-drop.html +162 -0
  20. package/demo/components/select/example.html +76 -0
  21. package/demo/components/select/multi.html +72 -0
  22. package/demo/components/slider/example.html +55 -0
  23. package/demo/{sortable-list → components/sortable-list}/example.html +3 -3
  24. package/demo/components/tabs/example.html +91 -0
  25. package/demo/{textinput → components/textinput}/completion.html +3 -3
  26. package/demo/components/textinput/example.html +141 -0
  27. package/demo/{webchat → components/webchat}/example.html +3 -3
  28. package/demo/data/flows/sample-flow.json +107 -100
  29. package/demo/index.html +21 -21
  30. package/demo/static/css/styles.css +253 -0
  31. package/demo/sticky-note-demo.html +88 -85
  32. package/demo/styles.css +24 -0
  33. package/dist/locales/es.js +5 -5
  34. package/dist/locales/es.js.map +1 -1
  35. package/dist/locales/fr.js +5 -5
  36. package/dist/locales/fr.js.map +1 -1
  37. package/dist/locales/locale-codes.js +2 -11
  38. package/dist/locales/locale-codes.js.map +1 -1
  39. package/dist/locales/pt.js +5 -5
  40. package/dist/locales/pt.js.map +1 -1
  41. package/dist/temba-components.js +893 -476
  42. package/dist/temba-components.js.map +1 -1
  43. package/generate-coverage-badge.sh +69 -0
  44. package/out-tsc/src/{vectoricon/index.js → Icons.js} +1 -1
  45. package/out-tsc/src/Icons.js.map +1 -0
  46. package/out-tsc/src/display/Alert.js.map +1 -0
  47. package/out-tsc/src/display/Anchor.js.map +1 -0
  48. package/out-tsc/src/display/Button.js.map +1 -0
  49. package/out-tsc/src/{charcount → display}/CharCount.js +159 -2
  50. package/out-tsc/src/display/CharCount.js.map +1 -0
  51. package/out-tsc/src/display/Chat.js.map +1 -0
  52. package/out-tsc/src/display/ContactName.js.map +1 -0
  53. package/out-tsc/src/display/ContactUrn.js.map +1 -0
  54. package/out-tsc/src/display/Dropdown.js.map +1 -0
  55. package/out-tsc/src/{vectoricon/VectorIcon.js → display/Icon.js} +2 -2
  56. package/out-tsc/src/display/Icon.js.map +1 -0
  57. package/out-tsc/src/display/Label.js.map +1 -0
  58. package/out-tsc/src/{leafletmap → display}/LeafletMap.js +16 -1
  59. package/out-tsc/src/display/LeafletMap.js.map +1 -0
  60. package/out-tsc/src/display/Lightbox.js.map +1 -0
  61. package/out-tsc/src/{loading → display}/Loading.js.map +1 -1
  62. package/out-tsc/src/{options → display}/Options.js.map +1 -1
  63. package/out-tsc/src/display/ProgressBar.js.map +1 -0
  64. package/out-tsc/src/display/TembaDate.js.map +1 -0
  65. package/out-tsc/src/display/TembaUser.js.map +1 -0
  66. package/out-tsc/src/display/Thumbnail.js.map +1 -0
  67. package/out-tsc/src/{tip → display}/Tip.js +1 -2
  68. package/out-tsc/src/display/Tip.js.map +1 -0
  69. package/out-tsc/src/display/Toast.js.map +1 -0
  70. package/out-tsc/src/display/sms/gsmsplitter.js.map +1 -0
  71. package/out-tsc/src/display/sms/gsmvalidator.js.map +1 -0
  72. package/out-tsc/src/display/sms/index.js.map +1 -0
  73. package/out-tsc/src/display/sms/unicodesplitter.js.map +1 -0
  74. package/out-tsc/src/events.js +2 -0
  75. package/out-tsc/src/events.js.map +1 -0
  76. package/out-tsc/src/excellent/ExcellentParser.js.map +1 -0
  77. package/out-tsc/src/excellent/helpers.js.map +1 -0
  78. package/out-tsc/src/flow/Editor.js +533 -140
  79. package/out-tsc/src/flow/Editor.js.map +1 -1
  80. package/out-tsc/src/flow/EditorNode.js +287 -20
  81. package/out-tsc/src/flow/EditorNode.js.map +1 -1
  82. package/out-tsc/src/flow/Plumber.js +154 -74
  83. package/out-tsc/src/flow/Plumber.js.map +1 -1
  84. package/out-tsc/src/flow/StickyNote.js +153 -9
  85. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  86. package/out-tsc/src/flow/config.js +88 -18
  87. package/out-tsc/src/flow/config.js.map +1 -1
  88. package/out-tsc/src/flow/render.js +327 -10
  89. package/out-tsc/src/flow/render.js.map +1 -1
  90. package/out-tsc/src/{checkbox → form}/Checkbox.js +2 -2
  91. package/out-tsc/src/form/Checkbox.js.map +1 -0
  92. package/out-tsc/src/{colorpicker → form}/ColorPicker.js +1 -1
  93. package/out-tsc/src/form/ColorPicker.js.map +1 -0
  94. package/out-tsc/src/{completion → form}/Completion.js +2 -2
  95. package/out-tsc/src/form/Completion.js.map +1 -0
  96. package/out-tsc/src/{compose → form}/Compose.js +1 -1
  97. package/out-tsc/src/form/Compose.js.map +1 -0
  98. package/out-tsc/src/{contactsearch → form}/ContactSearch.js +2 -2
  99. package/out-tsc/src/form/ContactSearch.js.map +1 -0
  100. package/out-tsc/src/form/CroppieCSS.js.map +1 -0
  101. package/out-tsc/src/{datepicker → form}/DatePicker.js +1 -1
  102. package/out-tsc/src/form/DatePicker.js.map +1 -0
  103. package/out-tsc/src/{FormElement.js → form/FormElement.js} +1 -1
  104. package/out-tsc/src/form/FormElement.js.map +1 -0
  105. package/out-tsc/src/form/FormField.js.map +1 -0
  106. package/out-tsc/src/{imagepicker → form}/ImagePicker.js +2 -2
  107. package/out-tsc/src/form/ImagePicker.js.map +1 -0
  108. package/out-tsc/src/{mediapicker → form}/MediaPicker.js +1 -1
  109. package/out-tsc/src/form/MediaPicker.js.map +1 -0
  110. package/out-tsc/src/{datepicker → form}/RangePicker.js +3 -2
  111. package/out-tsc/src/form/RangePicker.js.map +1 -0
  112. package/out-tsc/src/{slider → form}/TembaSlider.js +1 -1
  113. package/out-tsc/src/form/TembaSlider.js.map +1 -0
  114. package/out-tsc/src/{templates → form}/TemplateEditor.js +1 -1
  115. package/out-tsc/src/form/TemplateEditor.js.map +1 -0
  116. package/out-tsc/src/{textinput → form}/TextInput.js +3 -3
  117. package/out-tsc/src/form/TextInput.js.map +1 -0
  118. package/out-tsc/src/{omnibox → form/select}/Omnibox.js +2 -2
  119. package/out-tsc/src/form/select/Omnibox.js.map +1 -0
  120. package/out-tsc/src/{select → form/select}/PopupSelect.js +1 -1
  121. package/out-tsc/src/form/select/PopupSelect.js.map +1 -0
  122. package/out-tsc/src/{select → form/select}/Select.js +86 -87
  123. package/out-tsc/src/form/select/Select.js.map +1 -0
  124. package/out-tsc/src/{select → form/select}/UserSelect.js +1 -1
  125. package/out-tsc/src/form/select/UserSelect.js.map +1 -0
  126. package/out-tsc/src/{select → form/select}/WorkspaceSelect.js +1 -1
  127. package/out-tsc/src/form/select/WorkspaceSelect.js.map +1 -0
  128. package/out-tsc/src/interfaces.js +1 -0
  129. package/out-tsc/src/interfaces.js.map +1 -1
  130. package/out-tsc/src/layout/Dialog.js.map +1 -0
  131. package/out-tsc/src/layout/Mask.js.map +1 -0
  132. package/out-tsc/src/{dialog → layout}/Modax.js.map +1 -1
  133. package/out-tsc/src/layout/Resizer.js.map +1 -0
  134. package/out-tsc/src/layout/Tab.js.map +1 -0
  135. package/out-tsc/src/layout/TabPane.js.map +1 -0
  136. package/out-tsc/src/list/NotificationList.js +1 -1
  137. package/out-tsc/src/list/NotificationList.js.map +1 -1
  138. package/out-tsc/src/list/RunList.js +1 -1
  139. package/out-tsc/src/list/RunList.js.map +1 -1
  140. package/out-tsc/src/list/ShortcutList.js.map +1 -1
  141. package/out-tsc/src/list/TembaMenu.js +1 -1
  142. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  143. package/out-tsc/src/list/TicketList.js +1 -1
  144. package/out-tsc/src/list/TicketList.js.map +1 -1
  145. package/out-tsc/src/{aliaseditor → live}/AliasEditor.js +1 -1
  146. package/out-tsc/src/live/AliasEditor.js.map +1 -0
  147. package/out-tsc/src/{contacts → live}/ContactBadges.js +1 -1
  148. package/out-tsc/src/live/ContactBadges.js.map +1 -0
  149. package/out-tsc/src/{contacts → live}/ContactChat.js +79 -3
  150. package/out-tsc/src/live/ContactChat.js.map +1 -0
  151. package/out-tsc/src/{contacts → live}/ContactDetails.js +1 -1
  152. package/out-tsc/src/live/ContactDetails.js.map +1 -0
  153. package/out-tsc/src/{contacts → live}/ContactFieldEditor.js +2 -2
  154. package/out-tsc/src/live/ContactFieldEditor.js.map +1 -0
  155. package/out-tsc/src/live/ContactFields.js.map +1 -0
  156. package/out-tsc/src/live/ContactNameFetch.js.map +1 -0
  157. package/out-tsc/src/{contacts → live}/ContactNotepad.js +1 -1
  158. package/out-tsc/src/{contacts → live}/ContactNotepad.js.map +1 -1
  159. package/out-tsc/src/{contacts → live}/ContactPending.js +1 -1
  160. package/out-tsc/src/live/ContactPending.js.map +1 -0
  161. package/out-tsc/src/live/ContactStoreElement.js.map +1 -0
  162. package/out-tsc/src/live/FieldManager.js.map +1 -0
  163. package/out-tsc/src/live/StartProgress.js.map +1 -0
  164. package/out-tsc/src/{chart → live}/TembaChart.js +5 -1
  165. package/out-tsc/src/live/TembaChart.js.map +1 -0
  166. package/out-tsc/src/locales/es.js +5 -5
  167. package/out-tsc/src/locales/es.js.map +1 -1
  168. package/out-tsc/src/locales/fr.js +5 -5
  169. package/out-tsc/src/locales/fr.js.map +1 -1
  170. package/out-tsc/src/locales/locale-codes.js +2 -11
  171. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  172. package/out-tsc/src/locales/pt.js +5 -5
  173. package/out-tsc/src/locales/pt.js.map +1 -1
  174. package/out-tsc/src/store/AppState.js +54 -24
  175. package/out-tsc/src/store/AppState.js.map +1 -1
  176. package/out-tsc/src/store/Store.js +1 -1
  177. package/out-tsc/src/store/Store.js.map +1 -1
  178. package/out-tsc/src/{utils/index.js → utils.js} +22 -1
  179. package/out-tsc/src/utils.js.map +1 -0
  180. package/out-tsc/src/webchat/WebChat.js +1 -1
  181. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  182. package/out-tsc/temba-components.js +2 -2
  183. package/out-tsc/temba-components.js.map +1 -1
  184. package/out-tsc/temba-modules.js +54 -54
  185. package/out-tsc/temba-modules.js.map +1 -1
  186. package/out-tsc/temba-webchat.js +2 -2
  187. package/out-tsc/temba-webchat.js.map +1 -1
  188. package/out-tsc/test/temba-alert.test.js +1 -1
  189. package/out-tsc/test/temba-alert.test.js.map +1 -1
  190. package/out-tsc/test/temba-appstate-language.test.js +90 -0
  191. package/out-tsc/test/temba-appstate-language.test.js.map +1 -1
  192. package/out-tsc/test/temba-charcount.test.js.map +1 -1
  193. package/out-tsc/test/temba-chart.test.js +1 -1
  194. package/out-tsc/test/temba-chart.test.js.map +1 -1
  195. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  196. package/out-tsc/test/temba-color-picker.test.js +1 -1
  197. package/out-tsc/test/temba-color-picker.test.js.map +1 -1
  198. package/out-tsc/test/temba-completion.test.js +1 -1
  199. package/out-tsc/test/temba-completion.test.js.map +1 -1
  200. package/out-tsc/test/temba-compose.test.js +1 -1
  201. package/out-tsc/test/temba-compose.test.js.map +1 -1
  202. package/out-tsc/test/temba-contact-badges.test.js +1 -1
  203. package/out-tsc/test/temba-contact-badges.test.js.map +1 -1
  204. package/out-tsc/test/temba-contact-chat.test.js +3 -1
  205. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  206. package/out-tsc/test/temba-contact-details.test.js +1 -1
  207. package/out-tsc/test/temba-contact-details.test.js.map +1 -1
  208. package/out-tsc/test/temba-contact-fields.test.js +1 -1
  209. package/out-tsc/test/temba-contact-fields.test.js.map +1 -1
  210. package/out-tsc/test/temba-contact-search.test.js +1 -1
  211. package/out-tsc/test/temba-contact-search.test.js.map +1 -1
  212. package/out-tsc/test/temba-date.test.js +5 -1
  213. package/out-tsc/test/temba-date.test.js.map +1 -1
  214. package/out-tsc/test/temba-datepicker.test.js +1 -1
  215. package/out-tsc/test/temba-datepicker.test.js.map +1 -1
  216. package/out-tsc/test/temba-dialog.test.js +1 -1
  217. package/out-tsc/test/temba-dialog.test.js.map +1 -1
  218. package/out-tsc/test/temba-dropdown.test.js +1 -1
  219. package/out-tsc/test/temba-dropdown.test.js.map +1 -1
  220. package/out-tsc/test/temba-excellent-helpers.test.js +316 -0
  221. package/out-tsc/test/temba-excellent-helpers.test.js.map +1 -0
  222. package/out-tsc/test/temba-field-manager.test.js.map +1 -1
  223. package/out-tsc/test/temba-flow-editor-node.test.js +414 -1
  224. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  225. package/out-tsc/test/temba-flow-editor.test.js +185 -0
  226. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  227. package/out-tsc/test/temba-flow-plumber-connections.test.js +113 -0
  228. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -0
  229. package/out-tsc/test/temba-flow-plumber.test.js +73 -93
  230. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  231. package/out-tsc/test/temba-flow-render.test.js +624 -1
  232. package/out-tsc/test/temba-flow-render.test.js.map +1 -1
  233. package/out-tsc/test/temba-flow-self-routing.test.js +172 -0
  234. package/out-tsc/test/temba-flow-self-routing.test.js.map +1 -0
  235. package/out-tsc/test/temba-formfield.test.js.map +1 -1
  236. package/out-tsc/test/temba-icon.test.js +1 -1
  237. package/out-tsc/test/temba-icon.test.js.map +1 -1
  238. package/out-tsc/test/temba-integration-markdown.test.js.map +1 -1
  239. package/out-tsc/test/temba-label.test.js +1 -1
  240. package/out-tsc/test/temba-label.test.js.map +1 -1
  241. package/out-tsc/test/temba-lightbox.test.js +1 -1
  242. package/out-tsc/test/temba-lightbox.test.js.map +1 -1
  243. package/out-tsc/test/temba-markdown.test.js +127 -0
  244. package/out-tsc/test/temba-markdown.test.js.map +1 -0
  245. package/out-tsc/test/temba-menu.test.js +1 -1
  246. package/out-tsc/test/temba-menu.test.js.map +1 -1
  247. package/out-tsc/test/temba-modax.test.js +1 -1
  248. package/out-tsc/test/temba-modax.test.js.map +1 -1
  249. package/out-tsc/test/temba-modules.test.js +47 -0
  250. package/out-tsc/test/temba-modules.test.js.map +1 -0
  251. package/out-tsc/test/temba-omnibox.test.js +1 -1
  252. package/out-tsc/test/temba-omnibox.test.js.map +1 -1
  253. package/out-tsc/test/temba-options.test.js.map +1 -1
  254. package/out-tsc/test/temba-range-picker.test.js +9 -2
  255. package/out-tsc/test/temba-range-picker.test.js.map +1 -1
  256. package/out-tsc/test/temba-rapid-element.test.js +273 -0
  257. package/out-tsc/test/temba-rapid-element.test.js.map +1 -0
  258. package/out-tsc/test/temba-resize-element.test.js +85 -0
  259. package/out-tsc/test/temba-resize-element.test.js.map +1 -0
  260. package/out-tsc/test/temba-select.test.js +2 -2
  261. package/out-tsc/test/temba-select.test.js.map +1 -1
  262. package/out-tsc/test/temba-slider.test.js.map +1 -1
  263. package/out-tsc/test/temba-sticky-note.test.js +194 -0
  264. package/out-tsc/test/temba-sticky-note.test.js.map +1 -0
  265. package/out-tsc/test/temba-template-editor.test.js.map +1 -1
  266. package/out-tsc/test/temba-textinput.test.js +1 -1
  267. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  268. package/out-tsc/test/temba-tip.test.js +1 -1
  269. package/out-tsc/test/temba-tip.test.js.map +1 -1
  270. package/out-tsc/test/temba-toast.test.js +1 -1
  271. package/out-tsc/test/temba-toast.test.js.map +1 -1
  272. package/out-tsc/test/temba-utils-index.test.js +1 -1
  273. package/out-tsc/test/temba-utils-index.test.js.map +1 -1
  274. package/out-tsc/test/temba-utils-uuid.test.js +38 -0
  275. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -0
  276. package/out-tsc/test/temba-webchat.test.js +28 -12
  277. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  278. package/out-tsc/test/utils.test.js +2 -6
  279. package/out-tsc/test/utils.test.js.map +1 -1
  280. package/package.json +18 -9
  281. package/rollup.components.mjs +1 -1
  282. package/screenshots/truth/datepicker/range-picker-all.png +0 -0
  283. package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
  284. package/screenshots/truth/datepicker/range-picker-default.png +0 -0
  285. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  286. package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
  287. package/screenshots/truth/datepicker/range-picker-week.png +0 -0
  288. package/screenshots/truth/datepicker/range-picker-year.png +0 -0
  289. package/screenshots/truth/sticky-note/blue-color.png +0 -0
  290. package/screenshots/truth/sticky-note/blue.png +0 -0
  291. package/screenshots/truth/sticky-note/color-picker-expanded.png +0 -0
  292. package/screenshots/truth/sticky-note/default.png +0 -0
  293. package/screenshots/truth/sticky-note/gray-color.png +0 -0
  294. package/screenshots/truth/sticky-note/gray.png +0 -0
  295. package/screenshots/truth/sticky-note/green-color.png +0 -0
  296. package/screenshots/truth/sticky-note/green.png +0 -0
  297. package/screenshots/truth/sticky-note/pink-color.png +0 -0
  298. package/screenshots/truth/sticky-note/pink.png +0 -0
  299. package/screenshots/truth/sticky-note/yellow-color.png +0 -0
  300. package/screenshots/truth/sticky-note/yellow.png +0 -0
  301. package/src/{charcount → display}/CharCount.ts +164 -2
  302. package/src/{vectoricon/VectorIcon.ts → display/Icon.ts} +1 -1
  303. package/src/{leafletmap → display}/LeafletMap.ts +19 -1
  304. package/src/{thumbnail → display}/Thumbnail.ts +1 -1
  305. package/src/{tip → display}/Tip.ts +1 -2
  306. package/src/{contacts/events.ts → events.ts} +1 -64
  307. package/src/flow/Editor.ts +655 -165
  308. package/src/flow/EditorNode.ts +337 -22
  309. package/src/flow/Plumber.ts +186 -79
  310. package/src/flow/StickyNote.ts +165 -9
  311. package/src/flow/config.ts +114 -18
  312. package/src/flow/render.ts +398 -11
  313. package/src/{checkbox → form}/Checkbox.ts +2 -2
  314. package/src/{colorpicker → form}/ColorPicker.ts +2 -2
  315. package/src/{completion → form}/Completion.ts +3 -3
  316. package/src/{compose → form}/Compose.ts +7 -7
  317. package/src/{contactsearch → form}/ContactSearch.ts +6 -6
  318. package/src/{datepicker → form}/DatePicker.ts +1 -1
  319. package/src/{FormElement.ts → form/FormElement.ts} +1 -1
  320. package/src/{imagepicker → form}/ImagePicker.ts +2 -2
  321. package/src/{mediapicker → form}/MediaPicker.ts +1 -1
  322. package/src/{datepicker → form}/RangePicker.ts +3 -2
  323. package/src/{slider → form}/TembaSlider.ts +1 -1
  324. package/src/{templates → form}/TemplateEditor.ts +2 -2
  325. package/src/{textinput → form}/TextInput.ts +5 -5
  326. package/src/{omnibox → form/select}/Omnibox.ts +2 -2
  327. package/src/{select → form/select}/PopupSelect.ts +1 -1
  328. package/src/{select → form/select}/Select.ts +124 -126
  329. package/src/{select → form/select}/UserSelect.ts +1 -1
  330. package/src/{select → form/select}/WorkspaceSelect.ts +1 -1
  331. package/src/interfaces.ts +2 -1
  332. package/src/{dialog → layout}/Dialog.ts +1 -1
  333. package/src/list/NotificationList.ts +2 -2
  334. package/src/list/RunList.ts +3 -3
  335. package/src/list/ShortcutList.ts +1 -1
  336. package/src/list/TembaMenu.ts +2 -2
  337. package/src/list/TicketList.ts +1 -1
  338. package/src/{aliaseditor → live}/AliasEditor.ts +3 -3
  339. package/src/{contacts → live}/ContactBadges.ts +1 -1
  340. package/src/{contacts → live}/ContactChat.ts +118 -8
  341. package/src/{contacts → live}/ContactDetails.ts +1 -1
  342. package/src/{contacts → live}/ContactFieldEditor.ts +4 -4
  343. package/src/{contacts → live}/ContactFields.ts +1 -1
  344. package/src/{contacts → live}/ContactNotepad.ts +1 -1
  345. package/src/{contacts → live}/ContactPending.ts +1 -1
  346. package/src/{chart → live}/TembaChart.ts +5 -2
  347. package/src/locales/es.ts +13 -18
  348. package/src/locales/fr.ts +13 -18
  349. package/src/locales/locale-codes.ts +2 -11
  350. package/src/locales/pt.ts +13 -18
  351. package/src/store/AppState.ts +75 -29
  352. package/src/store/Store.ts +1 -1
  353. package/src/store/flow-definition.d.ts +125 -0
  354. package/src/{utils/index.ts → utils.ts} +26 -10
  355. package/src/webchat/WebChat.ts +1 -1
  356. package/static/css/temba-components.css +1 -0
  357. package/svg.js +1 -4
  358. package/temba-components.ts +2 -2
  359. package/temba-modules.ts +54 -54
  360. package/temba-webchat.ts +2 -2
  361. package/test/temba-alert.test.ts +1 -1
  362. package/test/temba-appstate-language.test.ts +108 -0
  363. package/test/temba-charcount.test.ts +1 -1
  364. package/test/temba-chart.test.ts +1 -1
  365. package/test/temba-checkbox.test.ts +1 -1
  366. package/test/temba-color-picker.test.ts +1 -1
  367. package/test/temba-completion.test.ts +1 -1
  368. package/test/temba-compose.test.ts +1 -1
  369. package/test/temba-contact-badges.test.ts +1 -1
  370. package/test/temba-contact-chat.test.ts +6 -4
  371. package/test/temba-contact-details.test.ts +1 -1
  372. package/test/temba-contact-fields.test.ts +1 -1
  373. package/test/temba-contact-search.test.ts +2 -2
  374. package/test/temba-date.test.ts +8 -3
  375. package/test/temba-datepicker.test.ts +1 -1
  376. package/test/temba-dialog.test.ts +1 -1
  377. package/test/temba-dropdown.test.ts +1 -1
  378. package/test/temba-excellent-helpers.test.ts +417 -0
  379. package/test/temba-field-manager.test.ts +2 -2
  380. package/test/temba-flow-editor-node.test.ts +536 -1
  381. package/test/temba-flow-editor.test.ts +224 -0
  382. package/test/temba-flow-editor.test.ts.backup +563 -0
  383. package/test/temba-flow-plumber-connections.test.ts +142 -0
  384. package/test/temba-flow-plumber.test.ts +83 -120
  385. package/test/temba-flow-render.test.ts +787 -4
  386. package/test/temba-flow-self-routing.test.ts +215 -0
  387. package/test/temba-formfield.test.ts +1 -1
  388. package/test/temba-icon.test.ts +1 -1
  389. package/test/temba-integration-markdown.test.ts +1 -1
  390. package/test/temba-label.test.ts +1 -1
  391. package/test/temba-lightbox.test.ts +1 -1
  392. package/test/temba-markdown.test.ts +162 -0
  393. package/test/temba-menu.test.ts +1 -1
  394. package/test/temba-modax.test.ts +2 -2
  395. package/test/temba-modules.test.ts +56 -0
  396. package/test/temba-omnibox.test.ts +1 -1
  397. package/test/temba-options.test.ts +1 -1
  398. package/test/temba-range-picker.test.ts +17 -2
  399. package/test/temba-rapid-element.test.ts +341 -0
  400. package/test/temba-resize-element.test.ts +104 -0
  401. package/test/temba-select.test.ts +2 -2
  402. package/test/temba-slider.test.ts +1 -1
  403. package/test/temba-sticky-note.test.ts +281 -0
  404. package/test/temba-template-editor.test.ts +1 -1
  405. package/test/temba-textinput.test.ts +1 -1
  406. package/test/temba-tip.test.ts +1 -1
  407. package/test/temba-toast.test.ts +1 -1
  408. package/test/temba-utils-index.test.ts +1 -1
  409. package/test/temba-utils-index.test.ts.backup +1737 -0
  410. package/test/temba-utils-uuid.test.ts +48 -0
  411. package/test/temba-webchat.test.ts +30 -12
  412. package/test/utils.test.ts +5 -9
  413. package/web-dev-server.config.mjs +1 -1
  414. package/demo/alert/example.html +0 -65
  415. package/demo/button/example.html +0 -71
  416. package/demo/chart/horizontal-demo.html +0 -81
  417. package/demo/checkbox/example.html +0 -72
  418. package/demo/compose/example.html +0 -72
  419. package/demo/dropdown/example.html +0 -99
  420. package/demo/progress/example.html +0 -59
  421. package/demo/select/drag-and-drop.html +0 -142
  422. package/demo/select/example.html +0 -82
  423. package/demo/select/multi.html +0 -73
  424. package/demo/slider/example.html +0 -59
  425. package/demo/tabs/example.html +0 -91
  426. package/demo/textinput/example.html +0 -61
  427. package/out-tsc/src/FormElement.js.map +0 -1
  428. package/out-tsc/src/alert/Alert.js.map +0 -1
  429. package/out-tsc/src/aliaseditor/AliasEditor.js.map +0 -1
  430. package/out-tsc/src/anchor/Anchor.js.map +0 -1
  431. package/out-tsc/src/button/Button.js.map +0 -1
  432. package/out-tsc/src/charcount/CharCount.js.map +0 -1
  433. package/out-tsc/src/charcount/helpers.js +0 -159
  434. package/out-tsc/src/charcount/helpers.js.map +0 -1
  435. package/out-tsc/src/chart/TembaChart.js.map +0 -1
  436. package/out-tsc/src/chat/Chat.js.map +0 -1
  437. package/out-tsc/src/checkbox/Checkbox.js.map +0 -1
  438. package/out-tsc/src/colorpicker/ColorPicker.js.map +0 -1
  439. package/out-tsc/src/completion/Completion.js.map +0 -1
  440. package/out-tsc/src/completion/ExcellentParser.js.map +0 -1
  441. package/out-tsc/src/completion/helpers.js.map +0 -1
  442. package/out-tsc/src/compose/Compose.js.map +0 -1
  443. package/out-tsc/src/contacts/ContactBadges.js.map +0 -1
  444. package/out-tsc/src/contacts/ContactChat.js.map +0 -1
  445. package/out-tsc/src/contacts/ContactDetails.js.map +0 -1
  446. package/out-tsc/src/contacts/ContactFieldEditor.js.map +0 -1
  447. package/out-tsc/src/contacts/ContactFields.js.map +0 -1
  448. package/out-tsc/src/contacts/ContactName.js.map +0 -1
  449. package/out-tsc/src/contacts/ContactNameFetch.js.map +0 -1
  450. package/out-tsc/src/contacts/ContactPending.js.map +0 -1
  451. package/out-tsc/src/contacts/ContactStoreElement.js.map +0 -1
  452. package/out-tsc/src/contacts/ContactUrn.js.map +0 -1
  453. package/out-tsc/src/contacts/events.js +0 -65
  454. package/out-tsc/src/contacts/events.js.map +0 -1
  455. package/out-tsc/src/contacts/helpers.js +0 -77
  456. package/out-tsc/src/contacts/helpers.js.map +0 -1
  457. package/out-tsc/src/contactsearch/ContactSearch.js.map +0 -1
  458. package/out-tsc/src/date/TembaDate.js.map +0 -1
  459. package/out-tsc/src/datepicker/DatePicker.js.map +0 -1
  460. package/out-tsc/src/datepicker/RangePicker.js.map +0 -1
  461. package/out-tsc/src/dialog/Dialog.js.map +0 -1
  462. package/out-tsc/src/dropdown/Dropdown.js.map +0 -1
  463. package/out-tsc/src/fields/FieldManager.js.map +0 -1
  464. package/out-tsc/src/formfield/FormField.js.map +0 -1
  465. package/out-tsc/src/imagepicker/CroppieCSS.js.map +0 -1
  466. package/out-tsc/src/imagepicker/ImagePicker.js.map +0 -1
  467. package/out-tsc/src/label/Label.js.map +0 -1
  468. package/out-tsc/src/leafletmap/LeafletMap.js.map +0 -1
  469. package/out-tsc/src/leafletmap/helpers.js +0 -17
  470. package/out-tsc/src/leafletmap/helpers.js.map +0 -1
  471. package/out-tsc/src/lightbox/Lightbox.js.map +0 -1
  472. package/out-tsc/src/mask/Mask.js.map +0 -1
  473. package/out-tsc/src/mediapicker/MediaPicker.js.map +0 -1
  474. package/out-tsc/src/omnibox/Omnibox.js.map +0 -1
  475. package/out-tsc/src/options/helpers.js +0 -28
  476. package/out-tsc/src/options/helpers.js.map +0 -1
  477. package/out-tsc/src/progress/ProgressBar.js.map +0 -1
  478. package/out-tsc/src/progress/StartProgress.js.map +0 -1
  479. package/out-tsc/src/resizer/Resizer.js.map +0 -1
  480. package/out-tsc/src/select/PopupSelect.js.map +0 -1
  481. package/out-tsc/src/select/Select.js.map +0 -1
  482. package/out-tsc/src/select/UserSelect.js.map +0 -1
  483. package/out-tsc/src/select/WorkspaceSelect.js.map +0 -1
  484. package/out-tsc/src/select/helpers.js +0 -1
  485. package/out-tsc/src/select/helpers.js.map +0 -1
  486. package/out-tsc/src/shadowless/Shadowless.js +0 -33
  487. package/out-tsc/src/shadowless/Shadowless.js.map +0 -1
  488. package/out-tsc/src/slider/TembaSlider.js.map +0 -1
  489. package/out-tsc/src/sms/gsmsplitter.js.map +0 -1
  490. package/out-tsc/src/sms/gsmvalidator.js.map +0 -1
  491. package/out-tsc/src/sms/index.js.map +0 -1
  492. package/out-tsc/src/sms/unicodesplitter.js.map +0 -1
  493. package/out-tsc/src/tabpane/Tab.js.map +0 -1
  494. package/out-tsc/src/tabpane/TabPane.js.map +0 -1
  495. package/out-tsc/src/templates/TemplateEditor.js.map +0 -1
  496. package/out-tsc/src/textinput/TextInput.js.map +0 -1
  497. package/out-tsc/src/textinput/helpers.js +0 -12
  498. package/out-tsc/src/textinput/helpers.js.map +0 -1
  499. package/out-tsc/src/thumbnail/Thumbnail.js.map +0 -1
  500. package/out-tsc/src/tip/Tip.js.map +0 -1
  501. package/out-tsc/src/tip/helpers.js +0 -7
  502. package/out-tsc/src/tip/helpers.js.map +0 -1
  503. package/out-tsc/src/toast/Toast.js.map +0 -1
  504. package/out-tsc/src/user/TembaUser.js.map +0 -1
  505. package/out-tsc/src/utils/index.js.map +0 -1
  506. package/out-tsc/src/vectoricon/VectorIcon.js.map +0 -1
  507. package/out-tsc/src/vectoricon/index.js.map +0 -1
  508. package/src/charcount/helpers.ts +0 -162
  509. package/src/contacts/helpers.ts +0 -103
  510. package/src/leafletmap/helpers.ts +0 -18
  511. package/src/options/helpers.ts +0 -37
  512. package/src/select/helpers.ts +0 -0
  513. package/src/shadowless/Shadowless.ts +0 -32
  514. package/src/textinput/helpers.ts +0 -11
  515. package/src/tip/helpers.ts +0 -7
  516. /package/out-tsc/src/{alert → display}/Alert.js +0 -0
  517. /package/out-tsc/src/{anchor → display}/Anchor.js +0 -0
  518. /package/out-tsc/src/{button → display}/Button.js +0 -0
  519. /package/out-tsc/src/{chat → display}/Chat.js +0 -0
  520. /package/out-tsc/src/{contacts → display}/ContactName.js +0 -0
  521. /package/out-tsc/src/{contacts → display}/ContactUrn.js +0 -0
  522. /package/out-tsc/src/{dropdown → display}/Dropdown.js +0 -0
  523. /package/out-tsc/src/{label → display}/Label.js +0 -0
  524. /package/out-tsc/src/{lightbox → display}/Lightbox.js +0 -0
  525. /package/out-tsc/src/{loading → display}/Loading.js +0 -0
  526. /package/out-tsc/src/{options → display}/Options.js +0 -0
  527. /package/out-tsc/src/{progress → display}/ProgressBar.js +0 -0
  528. /package/out-tsc/src/{date → display}/TembaDate.js +0 -0
  529. /package/out-tsc/src/{user → display}/TembaUser.js +0 -0
  530. /package/out-tsc/src/{thumbnail → display}/Thumbnail.js +0 -0
  531. /package/out-tsc/src/{toast → display}/Toast.js +0 -0
  532. /package/out-tsc/src/{sms → display/sms}/gsmsplitter.js +0 -0
  533. /package/out-tsc/src/{sms → display/sms}/gsmvalidator.js +0 -0
  534. /package/out-tsc/src/{sms → display/sms}/index.js +0 -0
  535. /package/out-tsc/src/{sms → display/sms}/unicodesplitter.js +0 -0
  536. /package/out-tsc/src/{completion → excellent}/ExcellentParser.js +0 -0
  537. /package/out-tsc/src/{completion → excellent}/helpers.js +0 -0
  538. /package/out-tsc/src/{imagepicker → form}/CroppieCSS.js +0 -0
  539. /package/out-tsc/src/{formfield → form}/FormField.js +0 -0
  540. /package/out-tsc/src/{dialog → layout}/Dialog.js +0 -0
  541. /package/out-tsc/src/{mask → layout}/Mask.js +0 -0
  542. /package/out-tsc/src/{dialog → layout}/Modax.js +0 -0
  543. /package/out-tsc/src/{resizer → layout}/Resizer.js +0 -0
  544. /package/out-tsc/src/{tabpane → layout}/Tab.js +0 -0
  545. /package/out-tsc/src/{tabpane → layout}/TabPane.js +0 -0
  546. /package/out-tsc/src/{contacts → live}/ContactFields.js +0 -0
  547. /package/out-tsc/src/{contacts → live}/ContactNameFetch.js +0 -0
  548. /package/out-tsc/src/{contacts → live}/ContactStoreElement.js +0 -0
  549. /package/out-tsc/src/{fields → live}/FieldManager.js +0 -0
  550. /package/out-tsc/src/{progress → live}/StartProgress.js +0 -0
  551. /package/src/{vectoricon/index.ts → Icons.ts} +0 -0
  552. /package/src/{alert → display}/Alert.ts +0 -0
  553. /package/src/{anchor → display}/Anchor.ts +0 -0
  554. /package/src/{button → display}/Button.ts +0 -0
  555. /package/src/{chat → display}/Chat.ts +0 -0
  556. /package/src/{contacts → display}/ContactName.ts +0 -0
  557. /package/src/{contacts → display}/ContactUrn.ts +0 -0
  558. /package/src/{dropdown → display}/Dropdown.ts +0 -0
  559. /package/src/{label → display}/Label.ts +0 -0
  560. /package/src/{lightbox → display}/Lightbox.ts +0 -0
  561. /package/src/{loading → display}/Loading.ts +0 -0
  562. /package/src/{options → display}/Options.ts +0 -0
  563. /package/src/{progress → display}/ProgressBar.ts +0 -0
  564. /package/src/{date → display}/TembaDate.ts +0 -0
  565. /package/src/{user → display}/TembaUser.ts +0 -0
  566. /package/src/{toast → display}/Toast.ts +0 -0
  567. /package/src/{sms → display/sms}/gsmsplitter.ts +0 -0
  568. /package/src/{sms → display/sms}/gsmvalidator.ts +0 -0
  569. /package/src/{sms → display/sms}/index.ts +0 -0
  570. /package/src/{sms → display/sms}/unicodesplitter.ts +0 -0
  571. /package/src/{completion → excellent}/ExcellentParser.ts +0 -0
  572. /package/src/{completion → excellent}/helpers.ts +0 -0
  573. /package/src/{imagepicker → form}/CroppieCSS.ts +0 -0
  574. /package/src/{formfield → form}/FormField.ts +0 -0
  575. /package/src/{mask → layout}/Mask.ts +0 -0
  576. /package/src/{dialog → layout}/Modax.ts +0 -0
  577. /package/src/{resizer → layout}/Resizer.ts +0 -0
  578. /package/src/{tabpane → layout}/Tab.ts +0 -0
  579. /package/src/{tabpane → layout}/TabPane.ts +0 -0
  580. /package/src/{contacts → live}/ContactNameFetch.ts +0 -0
  581. /package/src/{contacts → live}/ContactStoreElement.ts +0 -0
  582. /package/src/{fields → live}/FieldManager.ts +0 -0
  583. /package/src/{progress → live}/StartProgress.ts +0 -0
@@ -1,18 +1,70 @@
1
1
  import { html, fixture, expect } from '@open-wc/testing';
2
2
  import {
3
+ renderAddContactUrn,
4
+ renderAddInputLabels,
5
+ renderAddToGroups,
6
+ renderCallClassifier,
7
+ renderCallLLM,
8
+ renderCallResthook,
9
+ renderCallWebhook,
10
+ renderEnterFlow,
11
+ renderOpenTicket,
12
+ renderPlayAudio,
13
+ renderRemoveFromGroups,
14
+ renderRequestOptin,
15
+ renderSayMsg,
16
+ renderSendBroadcast,
17
+ renderSendEmail,
3
18
  renderSendMsg,
19
+ renderSetContactChannel,
20
+ renderSetContactField,
21
+ renderSetContactLanguage,
4
22
  renderSetContactName,
23
+ renderSetContactStatus,
5
24
  renderSetRunResult,
6
- renderCallWebhook,
7
- renderAddToGroups
25
+ renderStartSession,
26
+ renderTransferAirtime,
27
+ renderWaitForAudio,
28
+ renderWaitForDigits,
29
+ renderWaitForImage,
30
+ renderWaitForLocation,
31
+ renderWaitForMenu,
32
+ renderWaitForResponse,
33
+ renderWaitForVideo
8
34
  } from '../src/flow/render';
9
35
  import {
36
+ AddContactUrn,
37
+ AddInputLabels,
38
+ AddToGroup,
39
+ CallClassifier,
40
+ CallLLM,
41
+ CallResthook,
42
+ CallWebhook,
43
+ EnterFlow,
10
44
  Node,
45
+ OpenTicket,
46
+ PlayAudio,
47
+ RemoveFromGroup,
48
+ RequestOptin,
49
+ SayMsg,
50
+ SendBroadcast,
51
+ SendEmail,
11
52
  SendMsg,
53
+ SetContactChannel,
54
+ SetContactField,
55
+ SetContactLanguage,
12
56
  SetContactName,
57
+ SetContactStatus,
13
58
  SetRunResult,
14
- CallWebhook,
15
- AddToGroup
59
+ StartSession,
60
+ TransferAirtime,
61
+ WaitForAudio,
62
+ WaitForDigits,
63
+ WaitForImage,
64
+ WaitForLocation,
65
+ WaitForMenu,
66
+ WaitForResponse,
67
+ WaitForVideo
16
68
  } from '../src/store/flow-definition.d';
17
69
 
18
70
  describe('Flow Render Functions', () => {
@@ -216,5 +268,736 @@ describe('Flow Render Functions', () => {
216
268
  expect(container.innerHTML).to.contain('Test Group');
217
269
  expect(container.querySelectorAll('temba-icon')).to.have.length(0);
218
270
  });
271
+
272
+ it('renders groups with limit - shows +X more for 5+ items', async () => {
273
+ const action: AddToGroup = {
274
+ type: 'add_contact_groups',
275
+ uuid: 'action-uuid-9b',
276
+ groups: [
277
+ {
278
+ uuid: 'group1',
279
+ name: 'Group 1',
280
+ status: 'active',
281
+ system: false,
282
+ query: '',
283
+ count: 1
284
+ },
285
+ {
286
+ uuid: 'group2',
287
+ name: 'Group 2',
288
+ status: 'active',
289
+ system: false,
290
+ query: '',
291
+ count: 1
292
+ },
293
+ {
294
+ uuid: 'group3',
295
+ name: 'Group 3',
296
+ status: 'active',
297
+ system: false,
298
+ query: '',
299
+ count: 1
300
+ },
301
+ {
302
+ uuid: 'group4',
303
+ name: 'Group 4',
304
+ status: 'active',
305
+ system: false,
306
+ query: '',
307
+ count: 1
308
+ },
309
+ {
310
+ uuid: 'group5',
311
+ name: 'Group 5',
312
+ status: 'active',
313
+ system: false,
314
+ query: '',
315
+ count: 1
316
+ }
317
+ ]
318
+ };
319
+
320
+ const result = renderAddToGroups(mockNode, action);
321
+ const container = await fixture(html`<div>${result}</div>`);
322
+
323
+ expect(container.textContent).to.contain('Group 1');
324
+ expect(container.textContent).to.contain('Group 2');
325
+ expect(container.textContent).to.contain('Group 3');
326
+ expect(container.textContent).to.contain('+2 more');
327
+ expect(container.textContent).to.not.contain('Group 4');
328
+ expect(container.textContent).to.not.contain('Group 5');
329
+ });
330
+
331
+ it('renders all 4 groups when exactly 4 items', async () => {
332
+ const action: AddToGroup = {
333
+ type: 'add_contact_groups',
334
+ uuid: 'action-uuid-9c',
335
+ groups: [
336
+ {
337
+ uuid: 'group1',
338
+ name: 'Group 1',
339
+ status: 'active',
340
+ system: false,
341
+ query: '',
342
+ count: 1
343
+ },
344
+ {
345
+ uuid: 'group2',
346
+ name: 'Group 2',
347
+ status: 'active',
348
+ system: false,
349
+ query: '',
350
+ count: 1
351
+ },
352
+ {
353
+ uuid: 'group3',
354
+ name: 'Group 3',
355
+ status: 'active',
356
+ system: false,
357
+ query: '',
358
+ count: 1
359
+ },
360
+ {
361
+ uuid: 'group4',
362
+ name: 'Group 4',
363
+ status: 'active',
364
+ system: false,
365
+ query: '',
366
+ count: 1
367
+ }
368
+ ]
369
+ };
370
+
371
+ const result = renderAddToGroups(mockNode, action);
372
+ const container = await fixture(html`<div>${result}</div>`);
373
+
374
+ expect(container.textContent).to.contain('Group 1');
375
+ expect(container.textContent).to.contain('Group 2');
376
+ expect(container.textContent).to.contain('Group 3');
377
+ expect(container.textContent).to.contain('Group 4');
378
+ expect(container.textContent).to.not.contain('+');
379
+ });
380
+ });
381
+
382
+ describe('renderRemoveFromGroups', () => {
383
+ it('renders groups with icons for removal', async () => {
384
+ const action: RemoveFromGroup = {
385
+ type: 'remove_contact_groups',
386
+ uuid: 'action-uuid-10',
387
+ groups: [
388
+ {
389
+ uuid: 'group1',
390
+ name: 'VIP Customers',
391
+ status: 'active',
392
+ system: false,
393
+ query: '',
394
+ count: 10
395
+ }
396
+ ]
397
+ };
398
+
399
+ const result = renderRemoveFromGroups(mockNode, action);
400
+ const container = await fixture(html`<div>${result}</div>`);
401
+
402
+ expect(container.innerHTML).to.contain('VIP Customers');
403
+ expect(container.querySelectorAll('temba-icon')).to.have.length(1);
404
+ const icon = container.querySelector('temba-icon');
405
+ expect(icon?.getAttribute('name')).to.equal('group');
406
+ });
407
+ });
408
+
409
+ describe('renderSetContactField', () => {
410
+ it('renders contact field setting', async () => {
411
+ const action: SetContactField = {
412
+ type: 'set_contact_field',
413
+ uuid: 'action-uuid-11',
414
+ field: { uuid: 'field1', name: 'Favorite Color' },
415
+ value: 'Blue'
416
+ };
417
+
418
+ const result = renderSetContactField(mockNode, action);
419
+ const container = await fixture(html`<div>${result}</div>`);
420
+
421
+ expect(container.textContent).to.contain('Set');
422
+ expect(container.textContent).to.contain('Favorite Color');
423
+ expect(container.textContent).to.contain('to');
424
+ expect(container.textContent).to.contain('Blue');
425
+ expect(container.querySelectorAll('b')).to.have.length(2);
426
+ });
427
+ });
428
+
429
+ describe('renderSetContactLanguage', () => {
430
+ it('renders contact language setting', async () => {
431
+ const action: SetContactLanguage = {
432
+ type: 'set_contact_language',
433
+ uuid: 'action-uuid-12',
434
+ language: 'Spanish'
435
+ };
436
+
437
+ const result = renderSetContactLanguage(mockNode, action);
438
+ const container = await fixture(html`<div>${result}</div>`);
439
+
440
+ expect(container.textContent).to.contain('Set contact language to');
441
+ expect(container.textContent).to.contain('Spanish');
442
+ expect(container.querySelector('b')).to.exist;
443
+ });
444
+ });
445
+
446
+ describe('renderSetContactStatus', () => {
447
+ it('renders contact status setting', async () => {
448
+ const action: SetContactStatus = {
449
+ type: 'set_contact_status',
450
+ uuid: 'action-uuid-13',
451
+ status: 'blocked'
452
+ };
453
+
454
+ const result = renderSetContactStatus(mockNode, action);
455
+ const container = await fixture(html`<div>${result}</div>`);
456
+
457
+ expect(container.textContent).to.contain('Set contact status to');
458
+ expect(container.textContent).to.contain('blocked');
459
+ expect(container.querySelector('b')).to.exist;
460
+ });
461
+ });
462
+
463
+ describe('renderAddContactUrn', () => {
464
+ it('renders URN addition with friendly scheme names', async () => {
465
+ const action: AddContactUrn = {
466
+ type: 'add_contact_urn',
467
+ uuid: 'action-uuid-14',
468
+ scheme: 'tel',
469
+ path: '+1234567890'
470
+ };
471
+
472
+ const result = renderAddContactUrn(mockNode, action);
473
+ const container = await fixture(html`<div>${result}</div>`);
474
+
475
+ expect(container.textContent).to.contain('Add');
476
+ expect(container.textContent).to.contain('Phone Number');
477
+ expect(container.textContent).to.contain('+1234567890');
478
+ // Only the phone number should be bold, not the scheme
479
+ expect(container.querySelectorAll('b')).to.have.length(1);
480
+ expect(container.querySelector('b')?.textContent).to.equal('+1234567890');
481
+ });
482
+
483
+ it('renders URN addition with unmapped scheme', async () => {
484
+ const action: AddContactUrn = {
485
+ type: 'add_contact_urn',
486
+ uuid: 'action-uuid-14b',
487
+ scheme: 'unknown',
488
+ path: 'test123'
489
+ };
490
+
491
+ const result = renderAddContactUrn(mockNode, action);
492
+ const container = await fixture(html`<div>${result}</div>`);
493
+
494
+ expect(container.textContent).to.contain('Add');
495
+ expect(container.textContent).to.contain('unknown');
496
+ expect(container.textContent).to.contain('test123');
497
+ // Only the URN path should be bold
498
+ expect(container.querySelectorAll('b')).to.have.length(1);
499
+ expect(container.querySelector('b')?.textContent).to.equal('test123');
500
+ });
501
+ });
502
+
503
+ describe('renderSendEmail', () => {
504
+ it('renders email with subject and body', async () => {
505
+ const action: SendEmail = {
506
+ type: 'send_email',
507
+ uuid: 'action-uuid-15',
508
+ subject: 'Welcome!',
509
+ body: 'Thanks for signing up',
510
+ addresses: ['user@example.com', 'admin@example.com']
511
+ };
512
+
513
+ const result = renderSendEmail(mockNode, action);
514
+ const container = await fixture(html`<div>${result}</div>`);
515
+
516
+ // No longer expects "Send email to" prefix
517
+ expect(container.textContent).to.contain(
518
+ 'user@example.com, admin@example.com'
519
+ );
520
+ expect(container.textContent).to.contain('Welcome!');
521
+ });
522
+ });
523
+
524
+ describe('renderSendBroadcast', () => {
525
+ it('renders broadcast with groups and contacts', async () => {
526
+ const action: SendBroadcast = {
527
+ type: 'send_broadcast',
528
+ uuid: 'action-uuid-16',
529
+ text: 'Important announcement',
530
+ groups: [
531
+ {
532
+ uuid: 'group1',
533
+ name: 'VIP Customers',
534
+ status: 'active',
535
+ system: false,
536
+ query: '',
537
+ count: 10
538
+ }
539
+ ],
540
+ contacts: [{ uuid: 'contact1', name: 'John Doe' }]
541
+ };
542
+
543
+ const result = renderSendBroadcast(mockNode, action);
544
+ const container = await fixture(html`<div>${result}</div>`);
545
+
546
+ expect(container.textContent).to.contain('Important announcement');
547
+ expect(container.textContent).to.contain('Groups:');
548
+ expect(container.textContent).to.contain('VIP Customers');
549
+ expect(container.textContent).to.contain('Contacts:');
550
+ expect(container.textContent).to.contain('John Doe');
551
+ });
552
+
553
+ it('renders broadcast with text only', async () => {
554
+ const action: SendBroadcast = {
555
+ type: 'send_broadcast',
556
+ uuid: 'action-uuid-17',
557
+ text: 'Simple broadcast',
558
+ groups: [],
559
+ contacts: []
560
+ };
561
+
562
+ const result = renderSendBroadcast(mockNode, action);
563
+ const container = await fixture(html`<div>${result}</div>`);
564
+
565
+ expect(container.textContent).to.contain('Simple broadcast');
566
+ expect(container.textContent).to.not.contain('Groups:');
567
+ expect(container.textContent).to.not.contain('Contacts:');
568
+ });
569
+ });
570
+
571
+ describe('renderEnterFlow', () => {
572
+ it('renders flow entry', async () => {
573
+ const action: EnterFlow = {
574
+ type: 'enter_flow',
575
+ uuid: 'action-uuid-18',
576
+ flow: { uuid: 'flow1', name: 'Registration Flow' }
577
+ };
578
+
579
+ const result = renderEnterFlow(mockNode, action);
580
+ const container = await fixture(html`<div>${result}</div>`);
581
+
582
+ expect(container.textContent).to.contain('Enter flow');
583
+ expect(container.textContent).to.contain('Registration Flow');
584
+ expect(container.querySelector('b')).to.exist;
585
+ });
586
+ });
587
+
588
+ describe('renderStartSession', () => {
589
+ it('renders session start with groups and contacts', async () => {
590
+ const action: StartSession = {
591
+ type: 'start_session',
592
+ uuid: 'action-uuid-19',
593
+ flow: { uuid: 'flow1', name: 'Survey Flow' },
594
+ groups: [
595
+ {
596
+ uuid: 'group1',
597
+ name: 'Subscribers',
598
+ status: 'active',
599
+ system: false,
600
+ query: '',
601
+ count: 50
602
+ }
603
+ ],
604
+ contacts: [{ uuid: 'contact1', name: 'Jane Smith' }]
605
+ };
606
+
607
+ const result = renderStartSession(mockNode, action);
608
+ const container = await fixture(html`<div>${result}</div>`);
609
+
610
+ expect(container.textContent).to.contain('Subscribers');
611
+ expect(container.textContent).to.contain('Jane Smith');
612
+ expect(container.textContent).to.contain('Survey Flow');
613
+ });
614
+ });
615
+
616
+ describe('renderTransferAirtime', () => {
617
+ it('renders airtime transfer', async () => {
618
+ const action: TransferAirtime = {
619
+ type: 'transfer_airtime',
620
+ uuid: 'action-uuid-20',
621
+ amounts: [100, 200, 500],
622
+ result_name: 'airtime_result'
623
+ };
624
+
625
+ const result = renderTransferAirtime(mockNode, action);
626
+ const container = await fixture(html`<div>${result}</div>`);
627
+
628
+ expect(container.textContent).to.contain('Transfer airtime amounts:');
629
+ expect(container.textContent).to.contain('100, 200, 500');
630
+ expect(container.textContent).to.contain('Save result as');
631
+ expect(container.textContent).to.contain('airtime_result');
632
+ });
633
+ });
634
+
635
+ describe('renderCallClassifier', () => {
636
+ it('renders classifier call', async () => {
637
+ const action: CallClassifier = {
638
+ type: 'call_classifier',
639
+ uuid: 'action-uuid-21',
640
+ classifier: { uuid: 'classifier1', name: 'Intent Classifier' },
641
+ input: 'User message text',
642
+ result_name: 'intent_result'
643
+ };
644
+
645
+ const result = renderCallClassifier(mockNode, action);
646
+ const container = await fixture(html`<div>${result}</div>`);
647
+
648
+ expect(container.textContent).to.contain('Call classifier');
649
+ expect(container.textContent).to.contain('Intent Classifier');
650
+ expect(container.textContent).to.contain('Input:');
651
+ expect(container.textContent).to.contain('User message text');
652
+ expect(container.textContent).to.contain('Save result as');
653
+ expect(container.textContent).to.contain('intent_result');
654
+ });
655
+ });
656
+
657
+ describe('renderCallResthook', () => {
658
+ it('renders resthook call', async () => {
659
+ const action: CallResthook = {
660
+ type: 'call_resthook',
661
+ uuid: 'action-uuid-22',
662
+ resthook: 'survey-complete',
663
+ result_name: 'webhook_result'
664
+ };
665
+
666
+ const result = renderCallResthook(mockNode, action);
667
+ const container = await fixture(html`<div>${result}</div>`);
668
+
669
+ expect(container.textContent).to.contain('Call resthook');
670
+ expect(container.textContent).to.contain('survey-complete');
671
+ expect(container.textContent).to.contain('Save result as');
672
+ expect(container.textContent).to.contain('webhook_result');
673
+ });
674
+ });
675
+
676
+ describe('renderCallLLM', () => {
677
+ it('renders LLM call', async () => {
678
+ const action: CallLLM = {
679
+ type: 'call_llm',
680
+ uuid: 'action-uuid-23',
681
+ llm: { uuid: 'llm1', name: 'GPT-4' },
682
+ instructions: 'Analyze this text',
683
+ result_name: 'ai_result'
684
+ };
685
+
686
+ const result = renderCallLLM(mockNode, action);
687
+ const container = await fixture(html`<div>${result}</div>`);
688
+
689
+ // No longer expects "Call AI" prefix
690
+ expect(container.textContent).to.contain('GPT-4');
691
+ expect(container.textContent).to.contain('Analyze this text');
692
+ });
693
+ });
694
+
695
+ describe('renderOpenTicket', () => {
696
+ it('renders ticket with assignee and topic', async () => {
697
+ const action: OpenTicket = {
698
+ type: 'open_ticket',
699
+ uuid: 'action-uuid-24',
700
+ subject: 'Support Request',
701
+ body: 'Customer needs help',
702
+ assignee: { uuid: 'user1', name: 'Support Agent' },
703
+ topic: { uuid: 'topic1', name: 'Technical Support' }
704
+ };
705
+
706
+ const result = renderOpenTicket(mockNode, action);
707
+ const container = await fixture(html`<div>${result}</div>`);
708
+
709
+ // No longer expects subject
710
+ expect(container.textContent).to.contain('Customer needs help');
711
+ expect(container.textContent).to.contain('Support Agent');
712
+ expect(container.textContent).to.contain('Technical Support');
713
+ expect(container.querySelectorAll('temba-icon')).to.have.length(2);
714
+ });
715
+
716
+ it('renders ticket without assignee or topic', async () => {
717
+ const action: OpenTicket = {
718
+ type: 'open_ticket',
719
+ uuid: 'action-uuid-25',
720
+ subject: 'Basic Ticket',
721
+ body: 'Simple ticket content'
722
+ };
723
+
724
+ const result = renderOpenTicket(mockNode, action);
725
+ const container = await fixture(html`<div>${result}</div>`);
726
+
727
+ // No longer expects subject
728
+ expect(container.textContent).to.contain('Simple ticket content');
729
+ expect(container.querySelectorAll('temba-icon')).to.have.length(0);
730
+ });
731
+ });
732
+
733
+ describe('renderRequestOptin', () => {
734
+ it('renders optin request', async () => {
735
+ const action: RequestOptin = {
736
+ type: 'request_optin',
737
+ uuid: 'action-uuid-26',
738
+ optin: { uuid: 'optin1', name: 'Newsletter Subscription' }
739
+ };
740
+
741
+ const result = renderRequestOptin(mockNode, action);
742
+ const container = await fixture(html`<div>${result}</div>`);
743
+
744
+ expect(container.textContent).to.contain('Request opt-in for');
745
+ expect(container.textContent).to.contain('Newsletter Subscription');
746
+ expect(container.querySelector('b')).to.exist;
747
+ });
748
+ });
749
+
750
+ describe('renderAddInputLabels', () => {
751
+ it('renders input labels', async () => {
752
+ const action: AddInputLabels = {
753
+ type: 'add_input_labels',
754
+ uuid: 'action-uuid-27',
755
+ labels: [
756
+ { uuid: 'label1', name: 'Important' },
757
+ { uuid: 'label2', name: 'Customer Service' }
758
+ ]
759
+ };
760
+
761
+ const result = renderAddInputLabels(mockNode, action);
762
+ const container = await fixture(html`<div>${result}</div>`);
763
+
764
+ // No longer expects "Add labels to input:" prefix
765
+ expect(container.textContent).to.contain('Important');
766
+ expect(container.textContent).to.contain('Customer Service');
767
+ expect(container.querySelectorAll('temba-icon')).to.have.length(2);
768
+ });
769
+ });
770
+
771
+ describe('renderSayMsg', () => {
772
+ it('renders voice message with audio URL', async () => {
773
+ const action: SayMsg = {
774
+ type: 'say_msg',
775
+ uuid: 'action-uuid-28',
776
+ text: 'Welcome to our service',
777
+ audio_url: 'https://example.com/audio.mp3'
778
+ };
779
+
780
+ const result = renderSayMsg(mockNode, action);
781
+ const container = await fixture(html`<div>${result}</div>`);
782
+
783
+ expect(container.textContent).to.contain('Welcome to our service');
784
+ expect(container.innerHTML).to.contain('https://example.com/audio.mp3');
785
+ expect(container.querySelector('temba-icon')).to.exist;
786
+ expect(
787
+ container.querySelector('temba-icon')?.getAttribute('name')
788
+ ).to.equal('audio');
789
+ });
790
+
791
+ it('renders voice message without audio URL', async () => {
792
+ const action: SayMsg = {
793
+ type: 'say_msg',
794
+ uuid: 'action-uuid-29',
795
+ text: 'Text only message'
796
+ };
797
+
798
+ const result = renderSayMsg(mockNode, action);
799
+ const container = await fixture(html`<div>${result}</div>`);
800
+
801
+ expect(container.textContent).to.contain('Text only message');
802
+ expect(container.querySelector('temba-icon')).to.not.exist;
803
+ });
804
+ });
805
+
806
+ describe('renderPlayAudio', () => {
807
+ it('renders audio playback', async () => {
808
+ const action: PlayAudio = {
809
+ type: 'play_audio',
810
+ uuid: 'action-uuid-30',
811
+ audio_url: 'https://example.com/music.mp3'
812
+ };
813
+
814
+ const result = renderPlayAudio(mockNode, action);
815
+ const container = await fixture(html`<div>${result}</div>`);
816
+
817
+ expect(container.innerHTML).to.contain('https://example.com/music.mp3');
818
+ expect(container.querySelector('temba-icon')).to.exist;
819
+ expect(
820
+ container.querySelector('temba-icon')?.getAttribute('name')
821
+ ).to.equal('audio');
822
+ });
823
+ });
824
+
825
+ describe('renderSetContactChannel', () => {
826
+ it('renders contact channel setting', async () => {
827
+ const action: SetContactChannel = {
828
+ type: 'set_contact_channel',
829
+ uuid: 'action-uuid-31',
830
+ channel: { uuid: 'channel1', name: 'WhatsApp Channel' }
831
+ };
832
+
833
+ const result = renderSetContactChannel(mockNode, action);
834
+ const container = await fixture(html`<div>${result}</div>`);
835
+
836
+ expect(container.textContent).to.contain('Set contact channel to');
837
+ expect(container.textContent).to.contain('WhatsApp Channel');
838
+ expect(container.querySelector('b')).to.exist;
839
+ });
840
+ });
841
+
842
+ describe('renderWaitForResponse', () => {
843
+ it('renders wait for response with timeout', async () => {
844
+ const action: WaitForResponse = {
845
+ type: 'wait_for_response',
846
+ uuid: 'action-uuid-32',
847
+ timeout: 300
848
+ };
849
+
850
+ const result = renderWaitForResponse(mockNode, action);
851
+ const container = await fixture(html`<div>${result}</div>`);
852
+
853
+ expect(container.textContent).to.contain('Wait for message response');
854
+ expect(container.textContent).to.contain('Timeout after');
855
+ expect(container.textContent).to.contain('300');
856
+ expect(container.textContent).to.contain('seconds');
857
+ });
858
+
859
+ it('renders wait for response without timeout', async () => {
860
+ const action: WaitForResponse = {
861
+ type: 'wait_for_response',
862
+ uuid: 'action-uuid-33'
863
+ };
864
+
865
+ const result = renderWaitForResponse(mockNode, action);
866
+ const container = await fixture(html`<div>${result}</div>`);
867
+
868
+ expect(container.textContent).to.contain('Wait for message response');
869
+ expect(container.textContent).to.not.contain('Timeout');
870
+ });
871
+ });
872
+
873
+ describe('renderWaitForMenu', () => {
874
+ it('renders wait for menu with timeout', async () => {
875
+ const action: WaitForMenu = {
876
+ type: 'wait_for_menu',
877
+ uuid: 'action-uuid-34',
878
+ menu: { uuid: 'menu1', name: 'Main Menu' },
879
+ timeout: 120
880
+ };
881
+
882
+ const result = renderWaitForMenu(mockNode, action);
883
+ const container = await fixture(html`<div>${result}</div>`);
884
+
885
+ expect(container.textContent).to.contain('Wait for menu selection:');
886
+ expect(container.textContent).to.contain('Main Menu');
887
+ expect(container.textContent).to.contain('Timeout after');
888
+ expect(container.textContent).to.contain('120');
889
+ });
890
+ });
891
+
892
+ describe('renderWaitForDigits', () => {
893
+ it('renders wait for single digit', async () => {
894
+ const action: WaitForDigits = {
895
+ type: 'wait_for_digits',
896
+ uuid: 'action-uuid-35',
897
+ count: 1,
898
+ timeout: 60
899
+ };
900
+
901
+ const result = renderWaitForDigits(mockNode, action);
902
+ const container = await fixture(html`<div>${result}</div>`);
903
+
904
+ expect(container.textContent).to.contain('Wait for');
905
+ expect(container.textContent).to.contain('1');
906
+ expect(container.textContent).to.contain('digit');
907
+ expect(container.textContent).to.not.contain('digits');
908
+ expect(container.textContent).to.contain('Timeout after 60');
909
+ });
910
+
911
+ it('renders wait for multiple digits', async () => {
912
+ const action: WaitForDigits = {
913
+ type: 'wait_for_digits',
914
+ uuid: 'action-uuid-36',
915
+ count: 4
916
+ };
917
+
918
+ const result = renderWaitForDigits(mockNode, action);
919
+ const container = await fixture(html`<div>${result}</div>`);
920
+
921
+ expect(container.textContent).to.contain('Wait for');
922
+ expect(container.textContent).to.contain('4');
923
+ expect(container.textContent).to.contain('digits');
924
+ expect(container.textContent).to.not.contain('Timeout');
925
+ });
926
+ });
927
+
928
+ describe('renderWaitForAudio', () => {
929
+ it('renders wait for audio with icon', async () => {
930
+ const action: WaitForAudio = {
931
+ type: 'wait_for_audio',
932
+ uuid: 'action-uuid-37',
933
+ timeout: 180
934
+ };
935
+
936
+ const result = renderWaitForAudio(mockNode, action);
937
+ const container = await fixture(html`<div>${result}</div>`);
938
+
939
+ expect(container.textContent).to.contain('Wait for audio recording');
940
+ expect(container.textContent).to.contain('Timeout after 180');
941
+ expect(container.querySelector('temba-icon')).to.exist;
942
+ expect(
943
+ container.querySelector('temba-icon')?.getAttribute('name')
944
+ ).to.equal('audio');
945
+ });
946
+ });
947
+
948
+ describe('renderWaitForVideo', () => {
949
+ it('renders wait for video with icon', async () => {
950
+ const action: WaitForVideo = {
951
+ type: 'wait_for_video',
952
+ uuid: 'action-uuid-38'
953
+ };
954
+
955
+ const result = renderWaitForVideo(mockNode, action);
956
+ const container = await fixture(html`<div>${result}</div>`);
957
+
958
+ expect(container.textContent).to.contain('Wait for video recording');
959
+ expect(container.querySelector('temba-icon')).to.exist;
960
+ expect(
961
+ container.querySelector('temba-icon')?.getAttribute('name')
962
+ ).to.equal('video');
963
+ });
964
+ });
965
+
966
+ describe('renderWaitForImage', () => {
967
+ it('renders wait for image with icon', async () => {
968
+ const action: WaitForImage = {
969
+ type: 'wait_for_image',
970
+ uuid: 'action-uuid-39',
971
+ timeout: 240
972
+ };
973
+
974
+ const result = renderWaitForImage(mockNode, action);
975
+ const container = await fixture(html`<div>${result}</div>`);
976
+
977
+ expect(container.textContent).to.contain('Wait for image');
978
+ expect(container.textContent).to.contain('Timeout after 240');
979
+ expect(container.querySelector('temba-icon')).to.exist;
980
+ expect(
981
+ container.querySelector('temba-icon')?.getAttribute('name')
982
+ ).to.equal('image');
983
+ });
984
+ });
985
+
986
+ describe('renderWaitForLocation', () => {
987
+ it('renders wait for location with icon', async () => {
988
+ const action: WaitForLocation = {
989
+ type: 'wait_for_location',
990
+ uuid: 'action-uuid-40'
991
+ };
992
+
993
+ const result = renderWaitForLocation(mockNode, action);
994
+ const container = await fixture(html`<div>${result}</div>`);
995
+
996
+ expect(container.textContent).to.contain('Wait for location');
997
+ expect(container.querySelector('temba-icon')).to.exist;
998
+ expect(
999
+ container.querySelector('temba-icon')?.getAttribute('name')
1000
+ ).to.equal('location');
1001
+ });
219
1002
  });
220
1003
  });