@nyaruka/temba-components 0.140.0 → 0.141.1

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 (297) hide show
  1. package/.lintstagedrc.js +10 -0
  2. package/CHANGELOG.md +22 -0
  3. package/dist/locales/es.js +5 -5
  4. package/dist/locales/es.js.map +1 -1
  5. package/dist/locales/fr.js +5 -5
  6. package/dist/locales/fr.js.map +1 -1
  7. package/dist/locales/locale-codes.js +11 -2
  8. package/dist/locales/locale-codes.js.map +1 -1
  9. package/dist/locales/pt.js +5 -5
  10. package/dist/locales/pt.js.map +1 -1
  11. package/dist/temba-components.js +263 -156
  12. package/dist/temba-components.js.map +1 -1
  13. package/out-tsc/src/display/FloatingTab.js +1 -1
  14. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  15. package/out-tsc/src/flow/CanvasNode.js +1 -1
  16. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  17. package/out-tsc/src/flow/Editor.js +239 -43
  18. package/out-tsc/src/flow/Editor.js.map +1 -1
  19. package/out-tsc/src/flow/Plumber.js +61 -14
  20. package/out-tsc/src/flow/Plumber.js.map +1 -1
  21. package/out-tsc/src/flow/actions/add_contact_groups.js +4 -1
  22. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  23. package/out-tsc/src/flow/actions/add_input_labels.js +4 -1
  24. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  25. package/out-tsc/src/flow/actions/remove_contact_groups.js +6 -1
  26. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  27. package/out-tsc/src/flow/actions/send_broadcast.js +6 -2
  28. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  29. package/out-tsc/src/flow/actions/set_contact_channel.js +13 -0
  30. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  31. package/out-tsc/src/flow/actions/set_contact_status.js +7 -5
  32. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  33. package/out-tsc/src/flow/actions/start_session.js +10 -3
  34. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  35. package/out-tsc/src/flow/nodes/split_by_contact_field.js +18 -5
  36. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
  37. package/out-tsc/src/flow/nodes/split_by_expression.js +1 -1
  38. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
  39. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +0 -1
  40. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  41. package/out-tsc/src/flow/nodes/split_by_random.js +0 -1
  42. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  43. package/out-tsc/src/flow/nodes/split_by_run_result.js +10 -4
  44. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
  45. package/out-tsc/src/flow/nodes/wait_for_digits.js +1 -1
  46. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  47. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
  48. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  49. package/out-tsc/src/form/FieldRenderer.js +7 -0
  50. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  51. package/out-tsc/src/layout/Dialog.js +0 -1
  52. package/out-tsc/src/layout/Dialog.js.map +1 -1
  53. package/out-tsc/src/layout/Modax.js +20 -2
  54. package/out-tsc/src/layout/Modax.js.map +1 -1
  55. package/out-tsc/src/list/ContentMenu.js +14 -1
  56. package/out-tsc/src/list/ContentMenu.js.map +1 -1
  57. package/out-tsc/src/live/ContactChat.js +10 -1
  58. package/out-tsc/src/live/ContactChat.js.map +1 -1
  59. package/out-tsc/src/live/TembaChart.js.map +1 -1
  60. package/out-tsc/src/locales/es.js +5 -5
  61. package/out-tsc/src/locales/es.js.map +1 -1
  62. package/out-tsc/src/locales/fr.js +5 -5
  63. package/out-tsc/src/locales/fr.js.map +1 -1
  64. package/out-tsc/src/locales/locale-codes.js +11 -2
  65. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  66. package/out-tsc/src/locales/pt.js +5 -5
  67. package/out-tsc/src/locales/pt.js.map +1 -1
  68. package/out-tsc/src/simulator/Simulator.js +11 -0
  69. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  70. package/out-tsc/src/store/AppState.js +13 -0
  71. package/out-tsc/src/store/AppState.js.map +1 -1
  72. package/out-tsc/src/version.js +9 -0
  73. package/out-tsc/src/version.js.map +1 -0
  74. package/out-tsc/test/actions/add_contact_groups.test.js +35 -0
  75. package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -1
  76. package/out-tsc/test/actions/add_input_labels.test.js +53 -0
  77. package/out-tsc/test/actions/add_input_labels.test.js.map +1 -0
  78. package/out-tsc/test/actions/enter_flow.test.js +71 -0
  79. package/out-tsc/test/actions/enter_flow.test.js.map +1 -0
  80. package/out-tsc/test/actions/remove_contact_groups.test.js +24 -0
  81. package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -1
  82. package/out-tsc/test/actions/send_broadcast.test.js +41 -0
  83. package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
  84. package/out-tsc/test/actions/set_contact_channel.test.js +67 -0
  85. package/out-tsc/test/actions/set_contact_channel.test.js.map +1 -0
  86. package/out-tsc/test/actions/set_contact_field.test.js +52 -0
  87. package/out-tsc/test/actions/set_contact_field.test.js.map +1 -0
  88. package/out-tsc/test/actions/set_contact_language.test.js +39 -0
  89. package/out-tsc/test/actions/set_contact_language.test.js.map +1 -0
  90. package/out-tsc/test/actions/set_contact_name.test.js +28 -0
  91. package/out-tsc/test/actions/set_contact_name.test.js.map +1 -0
  92. package/out-tsc/test/actions/set_contact_status.test.js +44 -0
  93. package/out-tsc/test/actions/set_contact_status.test.js.map +1 -0
  94. package/out-tsc/test/actions/set_run_result.test.js +47 -0
  95. package/out-tsc/test/actions/set_run_result.test.js.map +1 -0
  96. package/out-tsc/test/actions/start_session.test.js +76 -0
  97. package/out-tsc/test/actions/start_session.test.js.map +1 -1
  98. package/out-tsc/test/nodes/split_by_contact_field.test.js +50 -0
  99. package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -1
  100. package/out-tsc/test/nodes/split_by_run_result.test.js +82 -0
  101. package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
  102. package/out-tsc/test/nodes/split_by_ticket.test.js +139 -0
  103. package/out-tsc/test/nodes/split_by_ticket.test.js.map +1 -0
  104. package/out-tsc/test/nodes/split_by_webhook.test.js +111 -0
  105. package/out-tsc/test/nodes/split_by_webhook.test.js.map +1 -0
  106. package/out-tsc/test/temba-contact-chat.test.js +12 -0
  107. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  108. package/out-tsc/test/temba-flow-editor.test.js +206 -0
  109. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  110. package/out-tsc/test/temba-flow-plumber.test.js +19 -0
  111. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  112. package/out-tsc/test/temba-select.test.js +4 -1
  113. package/out-tsc/test/temba-select.test.js.map +1 -1
  114. package/out-tsc/test/utils.test.js +4 -2
  115. package/out-tsc/test/utils.test.js.map +1 -1
  116. package/package.json +3 -9
  117. package/rollup.components.mjs +7 -1
  118. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  119. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  120. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  121. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  122. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  123. package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
  124. package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
  125. package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
  126. package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
  127. package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
  128. package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
  129. package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
  130. package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
  131. package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
  132. package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
  133. package/screenshots/truth/actions/add_input_labels/editor/multiple-labels.png +0 -0
  134. package/screenshots/truth/actions/add_input_labels/editor/single-label.png +0 -0
  135. package/screenshots/truth/actions/add_input_labels/render/multiple-labels.png +0 -0
  136. package/screenshots/truth/actions/add_input_labels/render/single-label.png +0 -0
  137. package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
  138. package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
  139. package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
  140. package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
  141. package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
  142. package/screenshots/truth/actions/play_audio/render/static-url.png +0 -0
  143. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  144. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  145. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  146. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  147. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  148. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  149. package/screenshots/truth/actions/say_msg/render/multiline-text.png +0 -0
  150. package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
  151. package/screenshots/truth/actions/say_msg/render/text-with-audio-url.png +0 -0
  152. package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
  153. package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
  154. package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
  155. package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
  156. package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
  157. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  158. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  159. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  160. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  161. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  162. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  163. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  164. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  165. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  166. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  167. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  168. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  169. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  170. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  171. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  172. package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
  173. package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
  174. package/screenshots/truth/actions/set_contact_channel/render/sms-channel.png +0 -0
  175. package/screenshots/truth/actions/set_contact_channel/render/whatsapp-channel.png +0 -0
  176. package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
  177. package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
  178. package/screenshots/truth/actions/set_contact_field/render/clear-value.png +0 -0
  179. package/screenshots/truth/actions/set_contact_field/render/set-value.png +0 -0
  180. package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
  181. package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
  182. package/screenshots/truth/actions/set_contact_language/render/english.png +0 -0
  183. package/screenshots/truth/actions/set_contact_language/render/french.png +0 -0
  184. package/screenshots/truth/actions/set_contact_name/editor/expression-name.png +0 -0
  185. package/screenshots/truth/actions/set_contact_name/editor/static-name.png +0 -0
  186. package/screenshots/truth/actions/set_contact_name/render/expression-name.png +0 -0
  187. package/screenshots/truth/actions/set_contact_name/render/static-name.png +0 -0
  188. package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
  189. package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
  190. package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
  191. package/screenshots/truth/actions/set_contact_status/render/active.png +0 -0
  192. package/screenshots/truth/actions/set_contact_status/render/archived.png +0 -0
  193. package/screenshots/truth/actions/set_contact_status/render/blocked.png +0 -0
  194. package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
  195. package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
  196. package/screenshots/truth/actions/set_run_result/render/expression-value.png +0 -0
  197. package/screenshots/truth/actions/set_run_result/render/with-category.png +0 -0
  198. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  199. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  200. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  201. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  202. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  203. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  204. package/screenshots/truth/editor/wait.png +0 -0
  205. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  206. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  207. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  208. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  209. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  210. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  211. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  212. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  213. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  214. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  215. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  216. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  217. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  218. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  219. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  220. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  221. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  222. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  223. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  224. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  225. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  226. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  227. package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
  228. package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
  229. package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
  230. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  231. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  232. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  233. package/screenshots/truth/nodes/wait_for_digits/render/digits-with-rules.png +0 -0
  234. package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
  235. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  236. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  237. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  238. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  239. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  240. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  241. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  242. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  243. package/src/display/FloatingTab.ts +1 -1
  244. package/src/flow/CanvasNode.ts +1 -1
  245. package/src/flow/Editor.ts +299 -88
  246. package/src/flow/Plumber.ts +89 -14
  247. package/src/flow/actions/add_contact_groups.ts +4 -1
  248. package/src/flow/actions/add_input_labels.ts +4 -1
  249. package/src/flow/actions/remove_contact_groups.ts +6 -1
  250. package/src/flow/actions/send_broadcast.ts +6 -2
  251. package/src/flow/actions/set_contact_channel.ts +13 -1
  252. package/src/flow/actions/set_contact_status.ts +7 -5
  253. package/src/flow/actions/start_session.ts +10 -3
  254. package/src/flow/nodes/split_by_contact_field.ts +16 -5
  255. package/src/flow/nodes/split_by_expression.ts +1 -1
  256. package/src/flow/nodes/split_by_llm_categorize.ts +0 -1
  257. package/src/flow/nodes/split_by_random.ts +0 -1
  258. package/src/flow/nodes/split_by_run_result.ts +10 -4
  259. package/src/flow/nodes/wait_for_digits.ts +2 -1
  260. package/src/flow/nodes/wait_for_response.ts +1 -1
  261. package/src/form/FieldRenderer.ts +7 -0
  262. package/src/layout/Dialog.ts +0 -1
  263. package/src/layout/Modax.ts +19 -2
  264. package/src/list/ContentMenu.ts +15 -1
  265. package/src/live/ContactChat.ts +10 -1
  266. package/src/live/TembaChart.ts +1 -1
  267. package/src/locales/es.ts +18 -13
  268. package/src/locales/fr.ts +18 -13
  269. package/src/locales/locale-codes.ts +11 -2
  270. package/src/locales/pt.ts +18 -13
  271. package/src/simulator/Simulator.ts +12 -0
  272. package/src/store/AppState.ts +15 -0
  273. package/src/store/flow-definition.d.ts +1 -0
  274. package/src/version.ts +10 -0
  275. package/test/actions/add_contact_groups.test.ts +38 -0
  276. package/test/actions/add_input_labels.test.ts +67 -0
  277. package/test/actions/enter_flow.test.ts +88 -0
  278. package/test/actions/remove_contact_groups.test.ts +29 -0
  279. package/test/actions/send_broadcast.test.ts +44 -0
  280. package/test/actions/set_contact_channel.test.ts +88 -0
  281. package/test/actions/set_contact_field.test.ts +68 -0
  282. package/test/actions/set_contact_language.test.ts +55 -0
  283. package/test/actions/set_contact_name.test.ts +39 -0
  284. package/test/actions/set_contact_status.test.ts +64 -0
  285. package/test/actions/set_run_result.test.ts +61 -0
  286. package/test/actions/start_session.test.ts +82 -0
  287. package/test/nodes/split_by_contact_field.test.ts +59 -0
  288. package/test/nodes/split_by_run_result.test.ts +100 -0
  289. package/test/nodes/split_by_ticket.test.ts +157 -0
  290. package/test/nodes/split_by_webhook.test.ts +131 -0
  291. package/test/temba-contact-chat.test.ts +17 -0
  292. package/test/temba-flow-editor.test.ts +264 -0
  293. package/test/temba-flow-plumber.test.ts +62 -0
  294. package/test/temba-select.test.ts +6 -1
  295. package/test/utils.test.ts +4 -2
  296. package/web-dev-server.config.mjs +5 -1
  297. package/web-test-runner.config.mjs +4 -1
@@ -10,9 +10,18 @@ export const sourceLocale = `en`;
10
10
  * The other locale codes that this application is localized into. Sorted
11
11
  * lexicographically.
12
12
  */
13
- export const targetLocales = [`es`, `fr`, `pt`] as const;
13
+ export const targetLocales = [
14
+ `es`,
15
+ `fr`,
16
+ `pt`,
17
+ ] as const;
14
18
 
15
19
  /**
16
20
  * All valid project locale codes. Sorted lexicographically.
17
21
  */
18
- export const allLocales = [`en`, `es`, `fr`, `pt`] as const;
22
+ export const allLocales = [
23
+ `en`,
24
+ `es`,
25
+ `fr`,
26
+ `pt`,
27
+ ] as const;
package/src/locales/pt.ts CHANGED
@@ -1,13 +1,18 @@
1
- // Do not modify this file by hand!
2
- // Re-generate this file by running lit-localize
3
-
4
- /* eslint-disable no-irregular-whitespace */
5
- /* eslint-disable @typescript-eslint/no-explicit-any */
6
-
7
- export const templates = {
8
- s73b4d70c02f4b4e0: `No options`,
9
- scf1453991c986b25: `Tab to complete, enter to select`,
10
- s8f02e3a18ffc083a: `Are not currently in a flow`,
11
- s638236250662c6b3: `Have sent a message in the last`,
12
- s4788ee206c4570c7: `Have not started this flow in the last 90 days`
13
- };
1
+
2
+ // Do not modify this file by hand!
3
+ // Re-generate this file by running lit-localize
4
+
5
+
6
+
7
+
8
+ /* eslint-disable no-irregular-whitespace */
9
+ /* eslint-disable @typescript-eslint/no-explicit-any */
10
+
11
+ export const templates = {
12
+ 's73b4d70c02f4b4e0': `No options`,
13
+ 'scf1453991c986b25': `Tab to complete, enter to select`,
14
+ 's8f02e3a18ffc083a': `Are not currently in a flow`,
15
+ 's638236250662c6b3': `Have sent a message in the last`,
16
+ 's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
17
+ };
18
+
@@ -5,6 +5,8 @@ import { css, PropertyValueMap } from 'lit';
5
5
  import { property } from 'lit/decorators.js';
6
6
  import { postJSON, fromCookie, generateUUIDv7 } from '../utils';
7
7
  import { getStore } from '../store/Store';
8
+ import { AppState, fromStore, zustand } from '../store/AppState';
9
+ import { FlowDefinition } from '../store/flow-definition';
8
10
  import { CustomEventType } from '../interfaces';
9
11
  import { Chat, ContactEvent, MessageType } from '../display/Chat';
10
12
  import { Events, renderEvent } from '../events/eventRenderers';
@@ -692,6 +694,12 @@ export class Simulator extends RapidElement {
692
694
  `;
693
695
  }
694
696
 
697
+ @fromStore(zustand, (state: AppState) => state.flowDefinition)
698
+ private definition!: FlowDefinition;
699
+
700
+ @fromStore(zustand, (state: AppState) => state.viewingRevision)
701
+ private viewingRevision!: boolean;
702
+
695
703
  @property({ type: String })
696
704
  flow = '';
697
705
 
@@ -1726,6 +1734,10 @@ export class Simulator extends RapidElement {
1726
1734
  }
1727
1735
 
1728
1736
  protected render(): TemplateResult {
1737
+ if (this.viewingRevision || this.definition?.nodes.length === 0) {
1738
+ return html``;
1739
+ }
1740
+
1729
1741
  const config = this.sizeConfig;
1730
1742
 
1731
1743
  // set CSS custom properties dynamically based on size
@@ -245,6 +245,7 @@ export interface AppState {
245
245
  actionUuid: string,
246
246
  localizationData: Record<string, any>
247
247
  ): void;
248
+ clearFlowData: () => void;
248
249
  setTranslationFilters: (filters: { categories: boolean }) => void;
249
250
  markAutoTranslated: (
250
251
  languageCode: string,
@@ -380,6 +381,20 @@ export const zustand = createStore<AppState>()(
380
381
  return { name: languageNames[languageCode], code: languageCode };
381
382
  },
382
383
 
384
+ clearFlowData: () => {
385
+ set({
386
+ flowDefinition: null,
387
+ flowInfo: null,
388
+ issuesByNode: new Map(),
389
+ issuesByAction: new Map(),
390
+ activity: null,
391
+ simulatorActivity: null,
392
+ simulatorActive: false,
393
+ dirtyDate: null,
394
+ viewingRevision: false
395
+ });
396
+ },
397
+
383
398
  // todo: eventually we should be doing the fetching
384
399
  setFlowContents: (flow: FlowContents) => {
385
400
  set((state: AppState) => {
@@ -325,6 +325,7 @@ export interface FlowUI {
325
325
  languages: Record<string, string>[];
326
326
  translation_filters?: { categories: boolean };
327
327
  auto_translations?: Record<string, Record<string, string[]>>;
328
+ editor?: string;
328
329
  }
329
330
 
330
331
  export interface FlowDefinition {
package/src/version.ts ADDED
@@ -0,0 +1,10 @@
1
+ declare const __TEMBA_COMPONENTS_VERSION__: string;
2
+
3
+ let _version = 'dev';
4
+ try {
5
+ _version = __TEMBA_COMPONENTS_VERSION__;
6
+ } catch {
7
+ // not replaced by build tooling; keep default
8
+ }
9
+
10
+ export const TEMBA_COMPONENTS_VERSION = _version;
@@ -86,4 +86,42 @@ describe('add_contact_groups action config', () => {
86
86
  'descriptive-group-names'
87
87
  );
88
88
  });
89
+
90
+ describe('metadata stripping', () => {
91
+ it('should strip superfluous API metadata from groups', () => {
92
+ const formData = {
93
+ uuid: 'test-uuid',
94
+ groups: [
95
+ {
96
+ uuid: 'group-1',
97
+ name: 'VIP Customers',
98
+ query: 'status = vip',
99
+ status: 'ready',
100
+ count: 150,
101
+ system: false
102
+ },
103
+ {
104
+ uuid: 'group-2',
105
+ name: 'Beta Testers',
106
+ query: null,
107
+ status: 'ready',
108
+ count: 45,
109
+ system: false
110
+ }
111
+ ]
112
+ };
113
+
114
+ const action = add_contact_groups.fromFormData(formData) as AddToGroup;
115
+
116
+ expect(action.groups).to.have.lengthOf(2);
117
+ expect(action.groups[0]).to.deep.equal({
118
+ uuid: 'group-1',
119
+ name: 'VIP Customers'
120
+ });
121
+ expect(action.groups[1]).to.deep.equal({
122
+ uuid: 'group-2',
123
+ name: 'Beta Testers'
124
+ });
125
+ });
126
+ });
89
127
  });
@@ -0,0 +1,67 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { add_input_labels } from '../../src/flow/actions/add_input_labels';
3
+ import { AddInputLabels } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the add_input_labels action configuration.
8
+ */
9
+ describe('add_input_labels action config', () => {
10
+ const helper = new ActionTest(add_input_labels, 'add_input_labels');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(add_input_labels.name).to.equal('Add Input Labels');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'add_input_labels',
25
+ labels: [{ uuid: 'label-1', name: 'Important' }]
26
+ } as AddInputLabels,
27
+ 'single-label'
28
+ );
29
+
30
+ helper.testAction(
31
+ {
32
+ uuid: 'test-action-2',
33
+ type: 'add_input_labels',
34
+ labels: [
35
+ { uuid: 'label-1', name: 'Important' },
36
+ { uuid: 'label-2', name: 'Follow Up' },
37
+ { uuid: 'label-3', name: 'Spam' }
38
+ ]
39
+ } as AddInputLabels,
40
+ 'multiple-labels'
41
+ );
42
+ });
43
+
44
+ describe('metadata stripping', () => {
45
+ it('should strip superfluous API metadata from labels', () => {
46
+ const formData = {
47
+ uuid: 'test-uuid',
48
+ labels: [
49
+ { uuid: 'label-1', name: 'Important', count: 250 },
50
+ { uuid: 'label-2', name: 'Follow Up', count: 42 }
51
+ ]
52
+ };
53
+
54
+ const action = add_input_labels.fromFormData(formData) as AddInputLabels;
55
+
56
+ expect(action.labels).to.have.lengthOf(2);
57
+ expect(action.labels[0]).to.deep.equal({
58
+ uuid: 'label-1',
59
+ name: 'Important'
60
+ });
61
+ expect(action.labels[1]).to.deep.equal({
62
+ uuid: 'label-2',
63
+ name: 'Follow Up'
64
+ });
65
+ });
66
+ });
67
+ });
@@ -0,0 +1,88 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { enter_flow } from '../../src/flow/actions/enter_flow';
3
+ import { EnterFlow } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the enter_flow action configuration.
8
+ */
9
+ describe('enter_flow action config', () => {
10
+ const helper = new ActionTest(enter_flow, 'enter_flow');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(enter_flow.name).to.equal('Enter a Flow');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'enter_flow',
25
+ terminal: true,
26
+ flow: { uuid: 'flow-1', name: 'Registration Flow' }
27
+ } as EnterFlow,
28
+ 'basic-flow'
29
+ );
30
+
31
+ helper.testAction(
32
+ {
33
+ uuid: 'test-action-2',
34
+ type: 'enter_flow',
35
+ terminal: true,
36
+ flow: {
37
+ uuid: 'flow-2',
38
+ name: 'Very Long Flow Name That Tests Layout Wrapping'
39
+ }
40
+ } as EnterFlow,
41
+ 'long-flow-name'
42
+ );
43
+ });
44
+
45
+ describe('metadata stripping', () => {
46
+ it('should strip superfluous API metadata from flow', () => {
47
+ const formData = {
48
+ uuid: 'test-uuid',
49
+ flow: [
50
+ {
51
+ uuid: 'flow-1',
52
+ name: 'Registration Flow',
53
+ type: 'message',
54
+ archived: false,
55
+ labels: [],
56
+ expires: 720,
57
+ runs: { active: 0, waiting: 5, completed: 100 },
58
+ results: [],
59
+ parent_refs: [],
60
+ created_on: '2024-01-01T00:00:00.000Z',
61
+ modified_on: '2024-06-15T12:00:00.000Z'
62
+ }
63
+ ]
64
+ };
65
+
66
+ const action = enter_flow.fromFormData(formData) as EnterFlow;
67
+
68
+ expect(action.flow).to.deep.equal({
69
+ uuid: 'flow-1',
70
+ name: 'Registration Flow'
71
+ });
72
+ });
73
+
74
+ it('should handle flow selected via value key', () => {
75
+ const formData = {
76
+ uuid: 'test-uuid',
77
+ flow: [{ value: 'flow-1', name: 'Test Flow' }]
78
+ };
79
+
80
+ const action = enter_flow.fromFormData(formData) as EnterFlow;
81
+
82
+ expect(action.flow).to.deep.equal({
83
+ uuid: 'flow-1',
84
+ name: 'Test Flow'
85
+ });
86
+ });
87
+ });
88
+ });
@@ -262,4 +262,33 @@ describe('remove_contact_groups action config', () => {
262
262
  expect(Object.keys(result.errors)).to.have.length(0);
263
263
  });
264
264
  });
265
+
266
+ describe('metadata stripping', () => {
267
+ it('should strip superfluous API metadata from groups', () => {
268
+ const formData = {
269
+ uuid: 'test-uuid',
270
+ all_groups: false,
271
+ groups: [
272
+ {
273
+ uuid: 'group-1',
274
+ name: 'VIP Customers',
275
+ query: 'status = vip',
276
+ status: 'ready',
277
+ count: 150,
278
+ system: false
279
+ }
280
+ ]
281
+ };
282
+
283
+ const action = remove_contact_groups.fromFormData(
284
+ formData
285
+ ) as RemoveFromGroup;
286
+
287
+ expect(action.groups).to.have.lengthOf(1);
288
+ expect(action.groups[0]).to.deep.equal({
289
+ uuid: 'group-1',
290
+ name: 'VIP Customers'
291
+ });
292
+ });
293
+ });
265
294
  });
@@ -188,5 +188,49 @@ describe('send_broadcast action config', () => {
188
188
 
189
189
  expect(formData.text).to.equal('Test message');
190
190
  });
191
+
192
+ it('should strip superfluous API metadata from contacts and groups', () => {
193
+ const formData = {
194
+ uuid: 'test-uuid',
195
+ recipients: [
196
+ {
197
+ uuid: 'contact-1',
198
+ name: 'Alice',
199
+ status: 'active',
200
+ language: 'eng',
201
+ urns: ['tel:+250788123456'],
202
+ groups: [{ uuid: 'g-1', name: 'G1' }],
203
+ fields: { age: '30' },
204
+ created_on: '2024-01-01T00:00:00.000Z',
205
+ modified_on: '2024-06-15T12:00:00.000Z',
206
+ last_seen_on: '2024-06-14T10:00:00.000Z'
207
+ },
208
+ {
209
+ uuid: 'group-1',
210
+ name: 'Subscribers',
211
+ group: true,
212
+ query: null,
213
+ status: 'ready',
214
+ count: 500,
215
+ system: false
216
+ }
217
+ ],
218
+ text: 'Hello!',
219
+ attachments: []
220
+ };
221
+
222
+ const action = send_broadcast.fromFormData(formData) as SendBroadcast;
223
+
224
+ expect(action.contacts).to.have.lengthOf(1);
225
+ expect(action.contacts[0]).to.deep.equal({
226
+ uuid: 'contact-1',
227
+ name: 'Alice'
228
+ });
229
+ expect(action.groups).to.have.lengthOf(1);
230
+ expect(action.groups[0]).to.deep.equal({
231
+ uuid: 'group-1',
232
+ name: 'Subscribers'
233
+ });
234
+ });
191
235
  });
192
236
  });
@@ -0,0 +1,88 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_contact_channel } from '../../src/flow/actions/set_contact_channel';
3
+ import { SetContactChannel } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_contact_channel action configuration.
8
+ */
9
+ describe('set_contact_channel action config', () => {
10
+ const helper = new ActionTest(set_contact_channel, 'set_contact_channel');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_contact_channel.name).to.equal('Update Channel');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_contact_channel',
25
+ channel: { uuid: 'channel-1', name: 'WhatsApp Channel' }
26
+ } as SetContactChannel,
27
+ 'whatsapp-channel'
28
+ );
29
+
30
+ helper.testAction(
31
+ {
32
+ uuid: 'test-action-2',
33
+ type: 'set_contact_channel',
34
+ channel: { uuid: 'channel-2', name: 'Twilio SMS' }
35
+ } as SetContactChannel,
36
+ 'sms-channel'
37
+ );
38
+ });
39
+
40
+ describe('metadata stripping', () => {
41
+ it('should strip superfluous API metadata from channel', () => {
42
+ const formData = {
43
+ uuid: 'test-uuid',
44
+ channel: [
45
+ {
46
+ uuid: 'channel-1',
47
+ name: 'WhatsApp Channel',
48
+ address: '+250788123456',
49
+ country: 'RW',
50
+ schemes: ['whatsapp'],
51
+ roles: ['send', 'receive'],
52
+ created_on: '2024-01-01T00:00:00.000Z'
53
+ }
54
+ ]
55
+ };
56
+
57
+ const action = set_contact_channel.fromFormData(
58
+ formData
59
+ ) as SetContactChannel;
60
+
61
+ expect(action.channel).to.deep.equal({
62
+ uuid: 'channel-1',
63
+ name: 'WhatsApp Channel'
64
+ });
65
+ });
66
+
67
+ it('should handle channel selected via value key', () => {
68
+ const formData = {
69
+ uuid: 'test-uuid',
70
+ channel: [
71
+ {
72
+ value: 'channel-1',
73
+ name: 'WhatsApp Channel'
74
+ }
75
+ ]
76
+ };
77
+
78
+ const action = set_contact_channel.fromFormData(
79
+ formData
80
+ ) as SetContactChannel;
81
+
82
+ expect(action.channel).to.deep.equal({
83
+ uuid: 'channel-1',
84
+ name: 'WhatsApp Channel'
85
+ });
86
+ });
87
+ });
88
+ });
@@ -0,0 +1,68 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_contact_field } from '../../src/flow/actions/set_contact_field';
3
+ import { SetContactField } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_contact_field action configuration.
8
+ */
9
+ describe('set_contact_field action config', () => {
10
+ const helper = new ActionTest(set_contact_field, 'set_contact_field');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_contact_field.name).to.equal('Update Field');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_contact_field',
25
+ field: { key: 'favorite_color', name: 'Favorite Color' },
26
+ value: 'Blue'
27
+ } as SetContactField,
28
+ 'set-value'
29
+ );
30
+
31
+ helper.testAction(
32
+ {
33
+ uuid: 'test-action-2',
34
+ type: 'set_contact_field',
35
+ field: { key: 'age', name: 'Age' },
36
+ value: ''
37
+ } as SetContactField,
38
+ 'clear-value'
39
+ );
40
+ });
41
+
42
+ describe('metadata stripping', () => {
43
+ it('should strip superfluous API metadata from field', () => {
44
+ const formData = {
45
+ uuid: 'test-uuid',
46
+ field: [
47
+ {
48
+ key: 'favorite_color',
49
+ name: 'Favorite Color',
50
+ value_type: 'text',
51
+ featured: true,
52
+ usages: { campaign_events: 0, flows: 3, groups: 1 }
53
+ }
54
+ ],
55
+ value: 'Red'
56
+ };
57
+
58
+ const action = set_contact_field.fromFormData(
59
+ formData
60
+ ) as SetContactField;
61
+
62
+ expect(action.field).to.deep.equal({
63
+ key: 'favorite_color',
64
+ name: 'Favorite Color'
65
+ });
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,55 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_contact_language } from '../../src/flow/actions/set_contact_language';
3
+ import { SetContactLanguage } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_contact_language action configuration.
8
+ */
9
+ describe('set_contact_language action config', () => {
10
+ const helper = new ActionTest(set_contact_language, 'set_contact_language');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_contact_language.name).to.equal('Update Language');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_contact_language',
25
+ language: 'eng'
26
+ } as SetContactLanguage,
27
+ 'english'
28
+ );
29
+
30
+ helper.testAction(
31
+ {
32
+ uuid: 'test-action-2',
33
+ type: 'set_contact_language',
34
+ language: 'fra'
35
+ } as SetContactLanguage,
36
+ 'french'
37
+ );
38
+ });
39
+
40
+ describe('round-trip', () => {
41
+ it('should extract language code from select option', () => {
42
+ const formData = {
43
+ uuid: 'test-uuid',
44
+ language: [{ value: 'spa', name: 'Spanish' }]
45
+ };
46
+
47
+ const action = set_contact_language.fromFormData(
48
+ formData
49
+ ) as SetContactLanguage;
50
+
51
+ expect(action.language).to.equal('spa');
52
+ expect(action.type).to.equal('set_contact_language');
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,39 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_contact_name } from '../../src/flow/actions/set_contact_name';
3
+ import { SetContactName } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_contact_name action configuration.
8
+ */
9
+ describe('set_contact_name action config', () => {
10
+ const helper = new ActionTest(set_contact_name, 'set_contact_name');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_contact_name.name).to.equal('Update Name');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_contact_name',
25
+ name: 'Alice Johnson'
26
+ } as SetContactName,
27
+ 'static-name'
28
+ );
29
+
30
+ helper.testAction(
31
+ {
32
+ uuid: 'test-action-2',
33
+ type: 'set_contact_name',
34
+ name: '@(title(input))'
35
+ } as SetContactName,
36
+ 'expression-name'
37
+ );
38
+ });
39
+ });