@nyaruka/temba-components 0.139.0 → 0.141.0

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 (385) hide show
  1. package/.github/workflows/cla.yml +1 -1
  2. package/.github/workflows/copilot-setup-steps.yml +6 -1
  3. package/.lintstagedrc.js +10 -0
  4. package/CHANGELOG.md +32 -0
  5. package/demo/data/flows/sample-flow.json +24 -0
  6. package/dist/locales/es.js +5 -5
  7. package/dist/locales/es.js.map +1 -1
  8. package/dist/locales/fr.js +5 -5
  9. package/dist/locales/fr.js.map +1 -1
  10. package/dist/locales/locale-codes.js +11 -2
  11. package/dist/locales/locale-codes.js.map +1 -1
  12. package/dist/locales/pt.js +5 -5
  13. package/dist/locales/pt.js.map +1 -1
  14. package/dist/temba-components.js +702 -338
  15. package/dist/temba-components.js.map +1 -1
  16. package/out-tsc/src/display/Chat.js +10 -7
  17. package/out-tsc/src/display/Chat.js.map +1 -1
  18. package/out-tsc/src/display/Dropdown.js +3 -1
  19. package/out-tsc/src/display/Dropdown.js.map +1 -1
  20. package/out-tsc/src/display/FloatingTab.js +4 -4
  21. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  22. package/out-tsc/src/display/Thumbnail.js +163 -5
  23. package/out-tsc/src/display/Thumbnail.js.map +1 -1
  24. package/out-tsc/src/flow/CanvasNode.js +65 -23
  25. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  26. package/out-tsc/src/flow/Editor.js +369 -49
  27. package/out-tsc/src/flow/Editor.js.map +1 -1
  28. package/out-tsc/src/flow/NodeEditor.js +118 -10
  29. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  30. package/out-tsc/src/flow/Plumber.js +61 -14
  31. package/out-tsc/src/flow/Plumber.js.map +1 -1
  32. package/out-tsc/src/flow/StickyNote.js +13 -4
  33. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  34. package/out-tsc/src/flow/actions/add_contact_groups.js +4 -1
  35. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  36. package/out-tsc/src/flow/actions/add_input_labels.js +4 -1
  37. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  38. package/out-tsc/src/flow/actions/audio-player.js +112 -0
  39. package/out-tsc/src/flow/actions/audio-player.js.map +1 -0
  40. package/out-tsc/src/flow/actions/enter_flow.js +43 -0
  41. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
  42. package/out-tsc/src/flow/actions/play_audio.js +57 -4
  43. package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
  44. package/out-tsc/src/flow/actions/remove_contact_groups.js +6 -1
  45. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  46. package/out-tsc/src/flow/actions/say_msg.js +86 -3
  47. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  48. package/out-tsc/src/flow/actions/send_broadcast.js +6 -2
  49. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  50. package/out-tsc/src/flow/actions/set_contact_channel.js +13 -0
  51. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  52. package/out-tsc/src/flow/actions/set_contact_status.js +7 -5
  53. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  54. package/out-tsc/src/flow/actions/start_session.js +10 -3
  55. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  56. package/out-tsc/src/flow/config.js +11 -3
  57. package/out-tsc/src/flow/config.js.map +1 -1
  58. package/out-tsc/src/flow/nodes/shared-rules.js +1 -1
  59. package/out-tsc/src/flow/nodes/shared-rules.js.map +1 -1
  60. package/out-tsc/src/flow/nodes/split_by_contact_field.js +18 -5
  61. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
  62. package/out-tsc/src/flow/nodes/split_by_expression.js +1 -1
  63. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
  64. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +0 -1
  65. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  66. package/out-tsc/src/flow/nodes/split_by_random.js +0 -1
  67. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  68. package/out-tsc/src/flow/nodes/split_by_run_result.js +10 -4
  69. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
  70. package/out-tsc/src/flow/nodes/terminal.js +7 -0
  71. package/out-tsc/src/flow/nodes/terminal.js.map +1 -0
  72. package/out-tsc/src/flow/nodes/wait_for_audio.js +77 -0
  73. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
  74. package/out-tsc/src/flow/nodes/wait_for_dial.js +151 -0
  75. package/out-tsc/src/flow/nodes/wait_for_dial.js.map +1 -0
  76. package/out-tsc/src/flow/nodes/wait_for_digits.js +61 -1
  77. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  78. package/out-tsc/src/flow/nodes/wait_for_menu.js +173 -2
  79. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
  80. package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
  81. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  82. package/out-tsc/src/flow/operators.js +21 -5
  83. package/out-tsc/src/flow/operators.js.map +1 -1
  84. package/out-tsc/src/flow/types.js.map +1 -1
  85. package/out-tsc/src/flow/utils.js +79 -3
  86. package/out-tsc/src/flow/utils.js.map +1 -1
  87. package/out-tsc/src/form/ArrayEditor.js +4 -2
  88. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  89. package/out-tsc/src/form/FieldRenderer.js +56 -0
  90. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  91. package/out-tsc/src/interfaces.js +1 -0
  92. package/out-tsc/src/interfaces.js.map +1 -1
  93. package/out-tsc/src/layout/Dialog.js +51 -7
  94. package/out-tsc/src/layout/Dialog.js.map +1 -1
  95. package/out-tsc/src/layout/Modax.js +20 -2
  96. package/out-tsc/src/layout/Modax.js.map +1 -1
  97. package/out-tsc/src/list/ContentMenu.js +14 -1
  98. package/out-tsc/src/list/ContentMenu.js.map +1 -1
  99. package/out-tsc/src/locales/es.js +5 -5
  100. package/out-tsc/src/locales/es.js.map +1 -1
  101. package/out-tsc/src/locales/fr.js +5 -5
  102. package/out-tsc/src/locales/fr.js.map +1 -1
  103. package/out-tsc/src/locales/locale-codes.js +11 -2
  104. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  105. package/out-tsc/src/locales/pt.js +5 -5
  106. package/out-tsc/src/locales/pt.js.map +1 -1
  107. package/out-tsc/src/simulator/Simulator.js +21 -4
  108. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  109. package/out-tsc/src/store/AppState.js +102 -3
  110. package/out-tsc/src/store/AppState.js.map +1 -1
  111. package/out-tsc/test/actions/add_contact_groups.test.js +35 -0
  112. package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -1
  113. package/out-tsc/test/actions/add_input_labels.test.js +53 -0
  114. package/out-tsc/test/actions/add_input_labels.test.js.map +1 -0
  115. package/out-tsc/test/actions/enter_flow.test.js +71 -0
  116. package/out-tsc/test/actions/enter_flow.test.js.map +1 -0
  117. package/out-tsc/test/actions/play_audio.test.js +118 -0
  118. package/out-tsc/test/actions/play_audio.test.js.map +1 -0
  119. package/out-tsc/test/actions/remove_contact_groups.test.js +24 -0
  120. package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -1
  121. package/out-tsc/test/actions/say_msg.test.js +158 -0
  122. package/out-tsc/test/actions/say_msg.test.js.map +1 -0
  123. package/out-tsc/test/actions/send_broadcast.test.js +41 -0
  124. package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
  125. package/out-tsc/test/actions/set_contact_channel.test.js +67 -0
  126. package/out-tsc/test/actions/set_contact_channel.test.js.map +1 -0
  127. package/out-tsc/test/actions/set_contact_field.test.js +52 -0
  128. package/out-tsc/test/actions/set_contact_field.test.js.map +1 -0
  129. package/out-tsc/test/actions/set_contact_language.test.js +39 -0
  130. package/out-tsc/test/actions/set_contact_language.test.js.map +1 -0
  131. package/out-tsc/test/actions/set_contact_name.test.js +28 -0
  132. package/out-tsc/test/actions/set_contact_name.test.js.map +1 -0
  133. package/out-tsc/test/actions/set_contact_status.test.js +44 -0
  134. package/out-tsc/test/actions/set_contact_status.test.js.map +1 -0
  135. package/out-tsc/test/actions/set_run_result.test.js +47 -0
  136. package/out-tsc/test/actions/set_run_result.test.js.map +1 -0
  137. package/out-tsc/test/actions/start_session.test.js +76 -0
  138. package/out-tsc/test/actions/start_session.test.js.map +1 -1
  139. package/out-tsc/test/nodes/split_by_contact_field.test.js +50 -0
  140. package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -1
  141. package/out-tsc/test/nodes/split_by_run_result.test.js +82 -0
  142. package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
  143. package/out-tsc/test/nodes/split_by_ticket.test.js +139 -0
  144. package/out-tsc/test/nodes/split_by_ticket.test.js.map +1 -0
  145. package/out-tsc/test/nodes/split_by_webhook.test.js +111 -0
  146. package/out-tsc/test/nodes/split_by_webhook.test.js.map +1 -0
  147. package/out-tsc/test/nodes/wait_for_audio.test.js +156 -0
  148. package/out-tsc/test/nodes/wait_for_audio.test.js.map +1 -0
  149. package/out-tsc/test/nodes/wait_for_dial.test.js +336 -0
  150. package/out-tsc/test/nodes/wait_for_dial.test.js.map +1 -0
  151. package/out-tsc/test/nodes/wait_for_digits.test.js +198 -84
  152. package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
  153. package/out-tsc/test/nodes/wait_for_menu.test.js +340 -0
  154. package/out-tsc/test/nodes/wait_for_menu.test.js.map +1 -0
  155. package/out-tsc/test/temba-flow-collision.test.js +261 -6
  156. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  157. package/out-tsc/test/temba-flow-editor.test.js +187 -0
  158. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  159. package/out-tsc/test/temba-flow-plumber.test.js +19 -0
  160. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  161. package/out-tsc/test/temba-node-type-selector.test.js +6 -6
  162. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
  163. package/out-tsc/test/temba-select.test.js +4 -1
  164. package/out-tsc/test/temba-select.test.js.map +1 -1
  165. package/out-tsc/test/utils.test.js +4 -2
  166. package/out-tsc/test/utils.test.js.map +1 -1
  167. package/package.json +3 -9
  168. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  169. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  170. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  171. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  172. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  173. package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
  174. package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
  175. package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
  176. package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
  177. package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
  178. package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
  179. package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
  180. package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
  181. package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
  182. package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
  183. package/screenshots/truth/actions/add_input_labels/editor/multiple-labels.png +0 -0
  184. package/screenshots/truth/actions/add_input_labels/editor/single-label.png +0 -0
  185. package/screenshots/truth/actions/add_input_labels/render/multiple-labels.png +0 -0
  186. package/screenshots/truth/actions/add_input_labels/render/single-label.png +0 -0
  187. package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
  188. package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
  189. package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
  190. package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
  191. package/screenshots/truth/actions/play_audio/editor/expression-url.png +0 -0
  192. package/screenshots/truth/actions/play_audio/editor/static-url.png +0 -0
  193. package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
  194. package/screenshots/truth/actions/play_audio/render/static-url.png +0 -0
  195. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  196. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  197. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  198. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  199. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  200. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  201. package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
  202. package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
  203. package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
  204. package/screenshots/truth/actions/say_msg/render/multiline-text.png +0 -0
  205. package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
  206. package/screenshots/truth/actions/say_msg/render/text-with-audio-url.png +0 -0
  207. package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
  208. package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
  209. package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
  210. package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
  211. package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
  212. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  213. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  214. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  215. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  216. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  217. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  218. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  219. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  220. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  221. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  222. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  223. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  224. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  225. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  226. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  227. package/screenshots/truth/actions/set_contact_channel/editor/sms-channel.png +0 -0
  228. package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
  229. package/screenshots/truth/actions/set_contact_channel/render/sms-channel.png +0 -0
  230. package/screenshots/truth/actions/set_contact_channel/render/whatsapp-channel.png +0 -0
  231. package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
  232. package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
  233. package/screenshots/truth/actions/set_contact_field/render/clear-value.png +0 -0
  234. package/screenshots/truth/actions/set_contact_field/render/set-value.png +0 -0
  235. package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
  236. package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
  237. package/screenshots/truth/actions/set_contact_language/render/english.png +0 -0
  238. package/screenshots/truth/actions/set_contact_language/render/french.png +0 -0
  239. package/screenshots/truth/actions/set_contact_name/editor/expression-name.png +0 -0
  240. package/screenshots/truth/actions/set_contact_name/editor/static-name.png +0 -0
  241. package/screenshots/truth/actions/set_contact_name/render/expression-name.png +0 -0
  242. package/screenshots/truth/actions/set_contact_name/render/static-name.png +0 -0
  243. package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
  244. package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
  245. package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
  246. package/screenshots/truth/actions/set_contact_status/render/active.png +0 -0
  247. package/screenshots/truth/actions/set_contact_status/render/archived.png +0 -0
  248. package/screenshots/truth/actions/set_contact_status/render/blocked.png +0 -0
  249. package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
  250. package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
  251. package/screenshots/truth/actions/set_run_result/render/expression-value.png +0 -0
  252. package/screenshots/truth/actions/set_run_result/render/with-category.png +0 -0
  253. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  254. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  255. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  256. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  257. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  258. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  259. package/screenshots/truth/editor/router.png +0 -0
  260. package/screenshots/truth/editor/wait.png +0 -0
  261. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  262. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  263. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  264. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  265. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  266. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  267. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  268. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  269. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  270. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  271. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  272. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  273. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  274. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  275. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  276. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  277. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  278. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  279. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  280. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  281. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  282. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  283. package/screenshots/truth/nodes/wait_for_audio/editor/basic-audio-wait.png +0 -0
  284. package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
  285. package/screenshots/truth/nodes/wait_for_dial/editor/basic-dial.png +0 -0
  286. package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
  287. package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
  288. package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
  289. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  290. package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
  291. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  292. package/screenshots/truth/nodes/wait_for_digits/render/digits-with-rules.png +0 -0
  293. package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
  294. package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
  295. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  296. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  297. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  298. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  299. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  300. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  301. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  302. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  303. package/src/display/Chat.ts +13 -7
  304. package/src/display/Dropdown.ts +3 -1
  305. package/src/display/FloatingTab.ts +4 -4
  306. package/src/display/Thumbnail.ts +162 -2
  307. package/src/flow/CanvasNode.ts +70 -24
  308. package/src/flow/Editor.ts +440 -99
  309. package/src/flow/NodeEditor.ts +137 -9
  310. package/src/flow/Plumber.ts +89 -14
  311. package/src/flow/StickyNote.ts +14 -4
  312. package/src/flow/actions/add_contact_groups.ts +4 -1
  313. package/src/flow/actions/add_input_labels.ts +4 -1
  314. package/src/flow/actions/audio-player.ts +127 -0
  315. package/src/flow/actions/enter_flow.ts +44 -0
  316. package/src/flow/actions/play_audio.ts +64 -5
  317. package/src/flow/actions/remove_contact_groups.ts +6 -1
  318. package/src/flow/actions/say_msg.ts +94 -4
  319. package/src/flow/actions/send_broadcast.ts +6 -2
  320. package/src/flow/actions/set_contact_channel.ts +13 -1
  321. package/src/flow/actions/set_contact_status.ts +7 -5
  322. package/src/flow/actions/start_session.ts +10 -3
  323. package/src/flow/config.ts +11 -3
  324. package/src/flow/nodes/shared-rules.ts +1 -1
  325. package/src/flow/nodes/split_by_contact_field.ts +16 -5
  326. package/src/flow/nodes/split_by_expression.ts +1 -1
  327. package/src/flow/nodes/split_by_llm_categorize.ts +0 -1
  328. package/src/flow/nodes/split_by_random.ts +0 -1
  329. package/src/flow/nodes/split_by_run_result.ts +10 -4
  330. package/src/flow/nodes/terminal.ts +9 -0
  331. package/src/flow/nodes/wait_for_audio.ts +88 -0
  332. package/src/flow/nodes/wait_for_dial.ts +176 -0
  333. package/src/flow/nodes/wait_for_digits.ts +87 -2
  334. package/src/flow/nodes/wait_for_menu.ts +209 -3
  335. package/src/flow/nodes/wait_for_response.ts +1 -1
  336. package/src/flow/operators.ts +23 -5
  337. package/src/flow/types.ts +23 -1
  338. package/src/flow/utils.ts +82 -3
  339. package/src/form/ArrayEditor.ts +4 -2
  340. package/src/form/FieldRenderer.ts +71 -1
  341. package/src/interfaces.ts +2 -1
  342. package/src/layout/Dialog.ts +52 -7
  343. package/src/layout/Modax.ts +19 -2
  344. package/src/list/ContentMenu.ts +15 -1
  345. package/src/locales/es.ts +18 -13
  346. package/src/locales/fr.ts +18 -13
  347. package/src/locales/locale-codes.ts +11 -2
  348. package/src/locales/pt.ts +18 -13
  349. package/src/simulator/Simulator.ts +25 -4
  350. package/src/store/AppState.ts +120 -1
  351. package/src/store/flow-definition.d.ts +2 -0
  352. package/test/actions/add_contact_groups.test.ts +38 -0
  353. package/test/actions/add_input_labels.test.ts +67 -0
  354. package/test/actions/enter_flow.test.ts +88 -0
  355. package/test/actions/play_audio.test.ts +155 -0
  356. package/test/actions/remove_contact_groups.test.ts +29 -0
  357. package/test/actions/say_msg.test.ts +196 -0
  358. package/test/actions/send_broadcast.test.ts +44 -0
  359. package/test/actions/set_contact_channel.test.ts +88 -0
  360. package/test/actions/set_contact_field.test.ts +68 -0
  361. package/test/actions/set_contact_language.test.ts +55 -0
  362. package/test/actions/set_contact_name.test.ts +39 -0
  363. package/test/actions/set_contact_status.test.ts +64 -0
  364. package/test/actions/set_run_result.test.ts +61 -0
  365. package/test/actions/start_session.test.ts +82 -0
  366. package/test/nodes/split_by_contact_field.test.ts +59 -0
  367. package/test/nodes/split_by_run_result.test.ts +100 -0
  368. package/test/nodes/split_by_ticket.test.ts +157 -0
  369. package/test/nodes/split_by_webhook.test.ts +131 -0
  370. package/test/nodes/wait_for_audio.test.ts +182 -0
  371. package/test/nodes/wait_for_dial.test.ts +382 -0
  372. package/test/nodes/wait_for_digits.test.ts +233 -109
  373. package/test/nodes/wait_for_menu.test.ts +383 -0
  374. package/test/temba-flow-collision.test.ts +286 -6
  375. package/test/temba-flow-editor.test.ts +240 -0
  376. package/test/temba-flow-plumber.test.ts +62 -0
  377. package/test/temba-node-type-selector.test.ts +6 -6
  378. package/test/temba-select.test.ts +6 -1
  379. package/test/utils.test.ts +4 -2
  380. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  381. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  382. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  383. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  384. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  385. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
@@ -0,0 +1,196 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { say_msg } from '../../src/flow/actions/say_msg';
3
+ import { SayMsg } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the say_msg action configuration.
8
+ */
9
+ describe('say_msg action config', () => {
10
+ const helper = new ActionTest(say_msg, 'say_msg');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(say_msg.name).to.equal('Say Message');
17
+ });
18
+
19
+ it('is voice-only', () => {
20
+ expect(say_msg.flowTypes).to.deep.equal(['voice']);
21
+ });
22
+ });
23
+
24
+ describe('action scenarios', () => {
25
+ helper.testAction(
26
+ {
27
+ uuid: 'test-say-1',
28
+ type: 'say_msg',
29
+ text: 'Hello, welcome to our service.'
30
+ } as SayMsg,
31
+ 'simple-text'
32
+ );
33
+
34
+ helper.testAction(
35
+ {
36
+ uuid: 'test-say-2',
37
+ type: 'say_msg',
38
+ text: 'Press 1 for sales.\nPress 2 for support.\nPress 3 to leave a message.'
39
+ } as SayMsg,
40
+ 'multiline-text'
41
+ );
42
+
43
+ helper.testAction(
44
+ {
45
+ uuid: 'test-say-3',
46
+ type: 'say_msg',
47
+ text: 'Please listen to the following recording.',
48
+ audio_url: 'https://example.com/greeting.mp3'
49
+ } as SayMsg,
50
+ 'text-with-audio-url'
51
+ );
52
+ });
53
+
54
+ describe('data transformation', () => {
55
+ it('converts action to form data', () => {
56
+ const action: SayMsg = {
57
+ uuid: 'test-action',
58
+ type: 'say_msg',
59
+ text: 'Hello world',
60
+ audio_url: 'https://example.com/audio.mp3'
61
+ };
62
+
63
+ const formData = say_msg.toFormData!(action);
64
+ expect(formData.uuid).to.equal('test-action');
65
+ expect(formData.text).to.equal('Hello world');
66
+ expect(formData.audio_url).to.equal('https://example.com/audio.mp3');
67
+ });
68
+
69
+ it('handles missing audio_url in toFormData', () => {
70
+ const action: SayMsg = {
71
+ uuid: 'test-action',
72
+ type: 'say_msg',
73
+ text: 'Hello'
74
+ } as SayMsg;
75
+
76
+ const formData = say_msg.toFormData!(action);
77
+ expect(formData.audio_url).to.equal('');
78
+ });
79
+
80
+ it('converts form data to action', () => {
81
+ const formData = {
82
+ uuid: 'test-action',
83
+ text: 'Hello world',
84
+ audio_url: 'https://example.com/audio.mp3'
85
+ };
86
+
87
+ const action = say_msg.fromFormData!(formData) as SayMsg;
88
+ expect(action.uuid).to.equal('test-action');
89
+ expect(action.type).to.equal('say_msg');
90
+ expect(action.text).to.equal('Hello world');
91
+ expect(action.audio_url).to.equal('https://example.com/audio.mp3');
92
+ });
93
+
94
+ it('omits empty audio_url in fromFormData', () => {
95
+ const formData = {
96
+ uuid: 'test-action',
97
+ text: 'Hello world',
98
+ audio_url: ''
99
+ };
100
+
101
+ const action = say_msg.fromFormData!(formData) as SayMsg;
102
+ expect(action.audio_url).to.be.undefined;
103
+ });
104
+
105
+ it('trims whitespace from audio_url', () => {
106
+ const formData = {
107
+ uuid: 'test-action',
108
+ text: 'Hello',
109
+ audio_url: ' https://example.com/audio.mp3 '
110
+ };
111
+
112
+ const action = say_msg.fromFormData!(formData) as SayMsg;
113
+ expect(action.audio_url).to.equal('https://example.com/audio.mp3');
114
+ });
115
+ });
116
+
117
+ describe('sanitize', () => {
118
+ it('trims text whitespace', () => {
119
+ const formData = { text: ' Hello world ' };
120
+ say_msg.sanitize!(formData);
121
+ expect(formData.text).to.equal('Hello world');
122
+ });
123
+ });
124
+
125
+ describe('localization', () => {
126
+ it('converts localization to form data', () => {
127
+ const action: SayMsg = {
128
+ uuid: 'test-action',
129
+ type: 'say_msg',
130
+ text: 'Hello',
131
+ audio_url: 'https://example.com/en.mp3'
132
+ };
133
+
134
+ const localization = {
135
+ text: ['Hola'],
136
+ audio_url: ['https://example.com/es.mp3']
137
+ };
138
+
139
+ const formData = say_msg.toLocalizationFormData!(action, localization);
140
+ expect(formData.text).to.equal('Hola');
141
+ expect(formData.audio_url).to.equal('https://example.com/es.mp3');
142
+ });
143
+
144
+ it('handles missing localization fields', () => {
145
+ const action: SayMsg = {
146
+ uuid: 'test-action',
147
+ type: 'say_msg',
148
+ text: 'Hello'
149
+ } as SayMsg;
150
+
151
+ const formData = say_msg.toLocalizationFormData!(action, {});
152
+ expect(formData.text).to.equal('');
153
+ expect(formData.audio_url).to.equal('');
154
+ });
155
+
156
+ it('converts form data to localization', () => {
157
+ const action: SayMsg = {
158
+ uuid: 'test-action',
159
+ type: 'say_msg',
160
+ text: 'Hello',
161
+ audio_url: 'https://example.com/en.mp3'
162
+ };
163
+
164
+ const formData = {
165
+ uuid: 'test-action',
166
+ text: 'Hola',
167
+ audio_url: 'https://example.com/es.mp3'
168
+ };
169
+
170
+ const localization = say_msg.fromLocalizationFormData!(formData, action);
171
+ expect(localization.text).to.deep.equal(['Hola']);
172
+ expect(localization.audio_url).to.deep.equal([
173
+ 'https://example.com/es.mp3'
174
+ ]);
175
+ });
176
+
177
+ it('omits unchanged localization fields', () => {
178
+ const action: SayMsg = {
179
+ uuid: 'test-action',
180
+ type: 'say_msg',
181
+ text: 'Hello',
182
+ audio_url: 'https://example.com/en.mp3'
183
+ };
184
+
185
+ const formData = {
186
+ uuid: 'test-action',
187
+ text: 'Hello', // same as original
188
+ audio_url: 'https://example.com/en.mp3' // same as original
189
+ };
190
+
191
+ const localization = say_msg.fromLocalizationFormData!(formData, action);
192
+ expect(localization.text).to.be.undefined;
193
+ expect(localization.audio_url).to.be.undefined;
194
+ });
195
+ });
196
+ });
@@ -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
+ });
@@ -0,0 +1,64 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_contact_status } from '../../src/flow/actions/set_contact_status';
3
+ import { SetContactStatus } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_contact_status action configuration.
8
+ */
9
+ describe('set_contact_status action config', () => {
10
+ const helper = new ActionTest(set_contact_status, 'set_contact_status');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_contact_status.name).to.equal('Update Status');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_contact_status',
25
+ status: 'active'
26
+ } as SetContactStatus,
27
+ 'active'
28
+ );
29
+
30
+ helper.testAction(
31
+ {
32
+ uuid: 'test-action-2',
33
+ type: 'set_contact_status',
34
+ status: 'blocked'
35
+ } as SetContactStatus,
36
+ 'blocked'
37
+ );
38
+
39
+ helper.testAction(
40
+ {
41
+ uuid: 'test-action-3',
42
+ type: 'set_contact_status',
43
+ status: 'archived'
44
+ } as SetContactStatus,
45
+ 'archived'
46
+ );
47
+ });
48
+
49
+ describe('round-trip', () => {
50
+ it('should extract status value from select option', () => {
51
+ const formData = {
52
+ uuid: 'test-uuid',
53
+ status: [{ value: 'stopped', name: 'Stopped' }]
54
+ };
55
+
56
+ const action = set_contact_status.fromFormData(
57
+ formData
58
+ ) as SetContactStatus;
59
+
60
+ expect(action.status).to.equal('stopped');
61
+ expect(action.type).to.equal('set_contact_status');
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,61 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { set_run_result } from '../../src/flow/actions/set_run_result';
3
+ import { SetRunResult } from '../../src/store/flow-definition';
4
+ import { ActionTest } from '../ActionHelper';
5
+
6
+ /**
7
+ * Test suite for the set_run_result action configuration.
8
+ */
9
+ describe('set_run_result action config', () => {
10
+ const helper = new ActionTest(set_run_result, 'set_run_result');
11
+
12
+ describe('basic properties', () => {
13
+ helper.testBasicProperties();
14
+
15
+ it('has correct name', () => {
16
+ expect(set_run_result.name).to.equal('Save Flow Result');
17
+ });
18
+ });
19
+
20
+ describe('action scenarios', () => {
21
+ helper.testAction(
22
+ {
23
+ uuid: 'test-action-1',
24
+ type: 'set_run_result',
25
+ name: 'Score',
26
+ value: '100',
27
+ category: 'High'
28
+ } as SetRunResult,
29
+ 'with-category'
30
+ );
31
+
32
+ helper.testAction(
33
+ {
34
+ uuid: 'test-action-2',
35
+ type: 'set_run_result',
36
+ name: 'Response',
37
+ value: '@input.text',
38
+ category: ''
39
+ } as SetRunResult,
40
+ 'expression-value'
41
+ );
42
+ });
43
+
44
+ describe('round-trip', () => {
45
+ it('should extract name from select option array', () => {
46
+ const formData = {
47
+ uuid: 'test-uuid',
48
+ name: [{ value: 'Score', name: 'Score' }],
49
+ value: '42',
50
+ category: 'Medium'
51
+ };
52
+
53
+ const action = set_run_result.fromFormData(formData) as SetRunResult;
54
+
55
+ expect(action.name).to.equal('Score');
56
+ expect(action.value).to.equal('42');
57
+ expect(action.category).to.equal('Medium');
58
+ expect(action.type).to.equal('set_run_result');
59
+ });
60
+ });
61
+ });