@nyaruka/temba-components 0.129.3 → 0.129.5

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 (304) hide show
  1. package/.eslintrc.js +1 -0
  2. package/.github/workflows/build.yml +135 -3
  3. package/CHANGELOG.md +19 -0
  4. package/demo/data/flows/sample-flow.json +110 -87
  5. package/demo/field-config-demo.html +135 -0
  6. package/dist/temba-components.js +1257 -675
  7. package/dist/temba-components.js.map +1 -1
  8. package/docs/ActionEditor-Migration.md +118 -0
  9. package/out-tsc/src/events.js.map +1 -1
  10. package/out-tsc/src/flow/{EditorNode.js → CanvasNode.js} +345 -42
  11. package/out-tsc/src/flow/CanvasNode.js.map +1 -0
  12. package/out-tsc/src/flow/Editor.js +107 -3
  13. package/out-tsc/src/flow/Editor.js.map +1 -1
  14. package/out-tsc/src/flow/NodeEditor.js +1211 -0
  15. package/out-tsc/src/flow/NodeEditor.js.map +1 -0
  16. package/out-tsc/src/flow/Plumber.js +0 -6
  17. package/out-tsc/src/flow/Plumber.js.map +1 -1
  18. package/out-tsc/src/flow/actions/add_contact_groups.js +40 -0
  19. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -0
  20. package/out-tsc/src/flow/actions/add_contact_urn.js +16 -0
  21. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -0
  22. package/out-tsc/src/flow/actions/add_input_labels.js +11 -0
  23. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -0
  24. package/out-tsc/src/flow/actions/call_classifier.js +11 -0
  25. package/out-tsc/src/flow/actions/call_classifier.js.map +1 -0
  26. package/out-tsc/src/flow/actions/call_llm.js +11 -0
  27. package/out-tsc/src/flow/actions/call_llm.js.map +1 -0
  28. package/out-tsc/src/flow/actions/call_resthook.js +11 -0
  29. package/out-tsc/src/flow/actions/call_resthook.js.map +1 -0
  30. package/out-tsc/src/flow/actions/call_webhook.js +122 -0
  31. package/out-tsc/src/flow/actions/call_webhook.js.map +1 -0
  32. package/out-tsc/src/flow/actions/enter_flow.js +14 -0
  33. package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
  34. package/out-tsc/src/flow/actions/open_ticket.js +11 -0
  35. package/out-tsc/src/flow/actions/open_ticket.js.map +1 -0
  36. package/out-tsc/src/flow/actions/play_audio.js +11 -0
  37. package/out-tsc/src/flow/actions/play_audio.js.map +1 -0
  38. package/out-tsc/src/flow/actions/remove_contact_groups.js +62 -0
  39. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -0
  40. package/out-tsc/src/flow/actions/request_optin.js +11 -0
  41. package/out-tsc/src/flow/actions/request_optin.js.map +1 -0
  42. package/out-tsc/src/flow/actions/say_msg.js +11 -0
  43. package/out-tsc/src/flow/actions/say_msg.js.map +1 -0
  44. package/out-tsc/src/flow/actions/send_broadcast.js +33 -0
  45. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -0
  46. package/out-tsc/src/flow/actions/send_email.js +56 -0
  47. package/out-tsc/src/flow/actions/send_email.js.map +1 -0
  48. package/out-tsc/src/flow/actions/send_msg.js +55 -0
  49. package/out-tsc/src/flow/actions/send_msg.js.map +1 -0
  50. package/out-tsc/src/flow/actions/set_contact_channel.js +12 -0
  51. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -0
  52. package/out-tsc/src/flow/actions/set_contact_field.js +12 -0
  53. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -0
  54. package/out-tsc/src/flow/actions/set_contact_language.js +10 -0
  55. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -0
  56. package/out-tsc/src/flow/actions/set_contact_name.js +10 -0
  57. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -0
  58. package/out-tsc/src/flow/actions/set_contact_status.js +10 -0
  59. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -0
  60. package/out-tsc/src/flow/actions/set_run_result.js +10 -0
  61. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -0
  62. package/out-tsc/src/flow/actions/split_by_expression_example.js +77 -0
  63. package/out-tsc/src/flow/actions/split_by_expression_example.js.map +1 -0
  64. package/out-tsc/src/flow/actions/start_session.js +11 -0
  65. package/out-tsc/src/flow/actions/start_session.js.map +1 -0
  66. package/out-tsc/src/flow/actions/transfer_airtime.js +11 -0
  67. package/out-tsc/src/flow/actions/transfer_airtime.js.map +1 -0
  68. package/out-tsc/src/flow/config.js +88 -193
  69. package/out-tsc/src/flow/config.js.map +1 -1
  70. package/out-tsc/src/flow/nodes/execute_actions.js +4 -0
  71. package/out-tsc/src/flow/nodes/execute_actions.js.map +1 -0
  72. package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -0
  73. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -0
  74. package/out-tsc/src/flow/nodes/split_by_contact_field.js +7 -0
  75. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -0
  76. package/out-tsc/src/flow/nodes/split_by_expression.js +7 -0
  77. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -0
  78. package/out-tsc/src/flow/nodes/split_by_groups.js +7 -0
  79. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -0
  80. package/out-tsc/src/flow/nodes/split_by_random.js +10 -0
  81. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -0
  82. package/out-tsc/src/flow/nodes/split_by_run_result.js +7 -0
  83. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -0
  84. package/out-tsc/src/flow/nodes/split_by_scheme.js +7 -0
  85. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -0
  86. package/out-tsc/src/flow/nodes/split_by_subflow.js +9 -0
  87. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -0
  88. package/out-tsc/src/flow/nodes/split_by_webhook.js +18 -0
  89. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -0
  90. package/out-tsc/src/flow/nodes/wait_for_audio.js +7 -0
  91. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
  92. package/out-tsc/src/flow/nodes/wait_for_digits.js +7 -0
  93. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -0
  94. package/out-tsc/src/flow/nodes/wait_for_image.js +7 -0
  95. package/out-tsc/src/flow/nodes/wait_for_image.js.map +1 -0
  96. package/out-tsc/src/flow/nodes/wait_for_location.js +7 -0
  97. package/out-tsc/src/flow/nodes/wait_for_location.js.map +1 -0
  98. package/out-tsc/src/flow/nodes/wait_for_menu.js +7 -0
  99. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -0
  100. package/out-tsc/src/flow/nodes/wait_for_response.js +7 -0
  101. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -0
  102. package/out-tsc/src/flow/nodes/wait_for_video.js +7 -0
  103. package/out-tsc/src/flow/nodes/wait_for_video.js.map +1 -0
  104. package/out-tsc/src/flow/types.js +79 -0
  105. package/out-tsc/src/flow/types.js.map +1 -0
  106. package/out-tsc/src/flow/utils.js +65 -0
  107. package/out-tsc/src/flow/utils.js.map +1 -0
  108. package/out-tsc/src/form/ArrayEditor.js +199 -0
  109. package/out-tsc/src/form/ArrayEditor.js.map +1 -0
  110. package/out-tsc/src/form/BaseListEditor.js +128 -0
  111. package/out-tsc/src/form/BaseListEditor.js.map +1 -0
  112. package/out-tsc/src/form/Checkbox.js +17 -2
  113. package/out-tsc/src/form/Checkbox.js.map +1 -1
  114. package/out-tsc/src/form/Completion.js +6 -0
  115. package/out-tsc/src/form/Completion.js.map +1 -1
  116. package/out-tsc/src/form/FormField.js +110 -11
  117. package/out-tsc/src/form/FormField.js.map +1 -1
  118. package/out-tsc/src/form/KeyValueEditor.js +223 -0
  119. package/out-tsc/src/form/KeyValueEditor.js.map +1 -0
  120. package/out-tsc/src/form/select/Select.js +92 -32
  121. package/out-tsc/src/form/select/Select.js.map +1 -1
  122. package/out-tsc/src/interfaces.js +6 -0
  123. package/out-tsc/src/interfaces.js.map +1 -1
  124. package/out-tsc/src/live/ContactChat.js +2 -76
  125. package/out-tsc/src/live/ContactChat.js.map +1 -1
  126. package/out-tsc/temba-modules.js +9 -2
  127. package/out-tsc/temba-modules.js.map +1 -1
  128. package/out-tsc/test/ActionHelper.js +116 -0
  129. package/out-tsc/test/ActionHelper.js.map +1 -0
  130. package/out-tsc/test/actions/add_contact_groups.test.js +66 -0
  131. package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -0
  132. package/out-tsc/test/actions/remove_contact_groups.test.js +226 -0
  133. package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -0
  134. package/out-tsc/test/actions/send_email.test.js +160 -0
  135. package/out-tsc/test/actions/send_email.test.js.map +1 -0
  136. package/out-tsc/test/actions/send_msg.test.js +95 -0
  137. package/out-tsc/test/actions/send_msg.test.js.map +1 -0
  138. package/out-tsc/test/temba-action-editing-integration.test.js +183 -0
  139. package/out-tsc/test/temba-action-editing-integration.test.js.map +1 -0
  140. package/out-tsc/test/temba-checkbox.test.js +1 -1
  141. package/out-tsc/test/temba-checkbox.test.js.map +1 -1
  142. package/out-tsc/test/temba-field-config.test.js +133 -0
  143. package/out-tsc/test/temba-field-config.test.js.map +1 -0
  144. package/out-tsc/test/temba-flow-editor-node.test.js +14 -14
  145. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  146. package/out-tsc/test/temba-node-editor.test.js +283 -0
  147. package/out-tsc/test/temba-node-editor.test.js.map +1 -0
  148. package/out-tsc/test/temba-select.test.js +158 -0
  149. package/out-tsc/test/temba-select.test.js.map +1 -1
  150. package/package.json +1 -1
  151. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  152. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  153. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  154. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  155. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  156. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  157. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  158. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  159. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  160. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  161. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  162. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  163. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  164. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  165. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  166. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  167. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  168. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  169. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  170. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  171. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  172. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  173. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  174. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  175. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  176. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  177. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  178. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  179. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  180. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  181. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  182. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  183. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  184. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  185. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  186. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  187. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  188. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  189. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  190. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  191. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  192. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  193. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  194. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  195. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  196. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  197. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  198. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  199. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  200. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  201. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  202. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  203. package/screenshots/truth/editor/router.png +0 -0
  204. package/screenshots/truth/editor/send_msg.png +0 -0
  205. package/screenshots/truth/editor/set_contact_language.png +0 -0
  206. package/screenshots/truth/editor/set_contact_name.png +0 -0
  207. package/screenshots/truth/editor/set_run_result.png +0 -0
  208. package/screenshots/truth/editor/wait.png +0 -0
  209. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  210. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  211. package/screenshots/truth/formfield/widget-only-markdown-errors.png +0 -0
  212. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  213. package/src/events.ts +1 -40
  214. package/src/flow/{EditorNode.ts → CanvasNode.ts} +424 -48
  215. package/src/flow/Editor.ts +140 -4
  216. package/src/flow/NodeEditor.ts +1454 -0
  217. package/src/flow/Plumber.ts +0 -9
  218. package/src/flow/actions/add_contact_groups.ts +42 -0
  219. package/src/flow/actions/add_contact_urn.ts +17 -0
  220. package/src/flow/actions/add_input_labels.ts +12 -0
  221. package/src/flow/actions/call_classifier.ts +12 -0
  222. package/src/flow/actions/call_llm.ts +12 -0
  223. package/src/flow/actions/call_resthook.ts +12 -0
  224. package/src/flow/actions/call_webhook.ts +133 -0
  225. package/src/flow/actions/enter_flow.ts +15 -0
  226. package/src/flow/actions/open_ticket.ts +12 -0
  227. package/src/flow/actions/play_audio.ts +12 -0
  228. package/src/flow/actions/remove_contact_groups.ts +66 -0
  229. package/src/flow/actions/request_optin.ts +12 -0
  230. package/src/flow/actions/say_msg.ts +12 -0
  231. package/src/flow/actions/send_broadcast.ts +35 -0
  232. package/src/flow/actions/send_email.ts +60 -0
  233. package/src/flow/actions/send_msg.ts +58 -0
  234. package/src/flow/actions/set_contact_channel.ts +13 -0
  235. package/src/flow/actions/set_contact_field.ts +13 -0
  236. package/src/flow/actions/set_contact_language.ts +11 -0
  237. package/src/flow/actions/set_contact_name.ts +11 -0
  238. package/src/flow/actions/set_contact_status.ts +11 -0
  239. package/src/flow/actions/set_run_result.ts +11 -0
  240. package/src/flow/actions/split_by_expression_example.ts +88 -0
  241. package/src/flow/actions/start_session.ts +12 -0
  242. package/src/flow/actions/transfer_airtime.ts +12 -0
  243. package/src/flow/config.ts +93 -232
  244. package/src/flow/nodes/execute_actions.ts +5 -0
  245. package/src/flow/nodes/split_by_airtime.ts +9 -0
  246. package/src/flow/nodes/split_by_contact_field.ts +7 -0
  247. package/src/flow/nodes/split_by_expression.ts +7 -0
  248. package/src/flow/nodes/split_by_groups.ts +7 -0
  249. package/src/flow/nodes/split_by_random.ts +10 -0
  250. package/src/flow/nodes/split_by_run_result.ts +7 -0
  251. package/src/flow/nodes/split_by_scheme.ts +7 -0
  252. package/src/flow/nodes/split_by_subflow.ts +9 -0
  253. package/src/flow/nodes/split_by_webhook.ts +19 -0
  254. package/src/flow/nodes/wait_for_audio.ts +7 -0
  255. package/src/flow/nodes/wait_for_digits.ts +7 -0
  256. package/src/flow/nodes/wait_for_image.ts +7 -0
  257. package/src/flow/nodes/wait_for_location.ts +7 -0
  258. package/src/flow/nodes/wait_for_menu.ts +7 -0
  259. package/src/flow/nodes/wait_for_response.ts +7 -0
  260. package/src/flow/nodes/wait_for_video.ts +7 -0
  261. package/src/flow/types.ts +352 -0
  262. package/src/flow/utils.ts +76 -0
  263. package/src/form/ArrayEditor.ts +240 -0
  264. package/src/form/BaseListEditor.ts +177 -0
  265. package/src/form/Checkbox.ts +22 -3
  266. package/src/form/Completion.ts +6 -0
  267. package/src/form/FormField.ts +115 -11
  268. package/src/form/KeyValueEditor.ts +251 -0
  269. package/src/form/select/Select.ts +105 -32
  270. package/src/interfaces.ts +7 -2
  271. package/src/live/ContactChat.ts +3 -97
  272. package/src/store/flow-definition.d.ts +6 -1
  273. package/static/api/contacts.json +30 -0
  274. package/static/api/groups.json +4 -426
  275. package/static/api/locations.json +24 -0
  276. package/static/api/media.json +5 -0
  277. package/static/api/optins.json +16 -0
  278. package/static/api/orgs.json +13 -0
  279. package/static/api/topics.json +21 -0
  280. package/static/api/users.json +26 -0
  281. package/static/css/temba-components.css +3 -6
  282. package/temba-modules.ts +9 -2
  283. package/test/ActionHelper.ts +142 -0
  284. package/test/actions/add_contact_groups.test.ts +89 -0
  285. package/test/actions/remove_contact_groups.test.ts +265 -0
  286. package/test/actions/send_email.test.ts +214 -0
  287. package/test/actions/send_msg.test.ts +130 -0
  288. package/test/temba-action-editing-integration.test.ts +240 -0
  289. package/test/temba-checkbox.test.ts +1 -1
  290. package/test/temba-field-config.test.ts +152 -0
  291. package/test/temba-flow-editor-node.test.ts +18 -18
  292. package/test/temba-node-editor.test.ts +353 -0
  293. package/test/temba-select.test.ts +234 -0
  294. package/test-assets/contacts/history.json +11 -33
  295. package/web-dev-server.config.mjs +34 -0
  296. package/.github/workflows/coverage.yml +0 -80
  297. package/demo/sticky-note-demo.html +0 -155
  298. package/out-tsc/src/flow/EditorNode.js.map +0 -1
  299. package/out-tsc/src/flow/render.js +0 -358
  300. package/out-tsc/src/flow/render.js.map +0 -1
  301. package/out-tsc/test/temba-flow-render.test.js +0 -794
  302. package/out-tsc/test/temba-flow-render.test.js.map +0 -1
  303. package/src/flow/render.ts +0 -443
  304. package/test/temba-flow-render.test.ts +0 -1003
@@ -55,6 +55,10 @@ export class Select<T extends SelectOption> extends FormElement {
55
55
  --temba-options-font-size: var(--temba-select-selected-font-size);
56
56
  --icon-color: var(--color-text-dark);
57
57
  --color-options-bg: #fff;
58
+ /* Always use normal border colors for options popup, even when select is in error state */
59
+ --color-widget-border: #ddd;
60
+ --color-focus: #007bff;
61
+ --widget-box-shadow-focused: 0 0 0 3px rgba(0, 123, 255, 0.25);
58
62
  }
59
63
 
60
64
  :host:focus {
@@ -448,6 +452,9 @@ export class Select<T extends SelectOption> extends FormElement {
448
452
  @property({ type: Boolean })
449
453
  tags = false;
450
454
 
455
+ @property({ type: Boolean })
456
+ emails = false;
457
+
451
458
  @property({ type: Boolean, attribute: 'space_select' })
452
459
  spaceSelect: boolean;
453
460
 
@@ -599,7 +606,7 @@ export class Select<T extends SelectOption> extends FormElement {
599
606
 
600
607
  this.staticOptions.push(option);
601
608
  if (selected) {
602
- if (this.multi) {
609
+ if (this.isMultiMode) {
603
610
  this.addValue(option);
604
611
  } else {
605
612
  this.setValues([option]);
@@ -735,9 +742,11 @@ export class Select<T extends SelectOption> extends FormElement {
735
742
  }
736
743
 
737
744
  // remove any arbitrary values
738
- this.values = this.values.filter((value) => {
739
- return !(value as any).arbitrary;
740
- });
745
+ for (let i = this.values.length - 1; i >= 0; i--) {
746
+ if ((this.values[i] as any).arbitrary) {
747
+ this.values.splice(i, 1);
748
+ }
749
+ }
741
750
 
742
751
  // reset our cache
743
752
  this.cacheKey = new Date().getTime().toString();
@@ -855,9 +864,14 @@ export class Select<T extends SelectOption> extends FormElement {
855
864
  const name = this.getAttribute('name');
856
865
 
857
866
  if (name) {
858
- if (!this.multi && this.values.length === 1) {
867
+ if (!this.isMultiMode && this.values.length === 1) {
859
868
  this.selection = this.values[0];
860
869
  this.value = this.serializeValue(this.values[0]);
870
+
871
+ // Ensure FormElement internals are updated
872
+ if (this.internals) {
873
+ this.internals.setFormValue(this.value);
874
+ }
861
875
  } else {
862
876
  if (this.inputRoot.parentElement) {
863
877
  this.values.forEach((value) => {
@@ -875,13 +889,13 @@ export class Select<T extends SelectOption> extends FormElement {
875
889
  }
876
890
 
877
891
  private setSelectedOption(option: any) {
878
- if (this.multi) {
892
+ if (this.isMultiMode) {
879
893
  this.addValue(option);
880
894
  } else {
881
895
  this.setValues([option]);
882
896
  }
883
897
 
884
- if (!this.multi || !this.searchable) {
898
+ if (!this.isMultiMode || !this.searchable) {
885
899
  this.blur();
886
900
  this.focused = false;
887
901
  }
@@ -904,7 +918,7 @@ export class Select<T extends SelectOption> extends FormElement {
904
918
 
905
919
  public handleOptionSelection(event: CustomEvent) {
906
920
  if (
907
- this.multi &&
921
+ this.isMultiMode &&
908
922
  this.maxItems > 0 &&
909
923
  this.values.length >= this.maxItems
910
924
  ) {
@@ -969,10 +983,27 @@ export class Select<T extends SelectOption> extends FormElement {
969
983
  this.visibleOptions = [];
970
984
  }
971
985
 
972
- private createArbitraryOptionDefault(): any {
986
+ private createArbitraryOptionDefault(input: string, _options: any[]): any {
987
+ if (this.emails && input && this.isValidEmail(input)) {
988
+ return { name: input, value: input };
989
+ }
990
+ if (this.tags && input) {
991
+ return { name: input, value: input };
992
+ }
973
993
  return null;
974
994
  }
975
995
 
996
+ private isValidEmail(email: string): boolean {
997
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
998
+ return emailRegex.test(email);
999
+ }
1000
+
1001
+ // Helper method to determine if this select should behave as multi-select
1002
+ // Returns true if multi is explicitly set OR if emails mode is enabled
1003
+ private get isMultiMode(): boolean {
1004
+ return this.multi || this.emails;
1005
+ }
1006
+
976
1007
  public open(): void {
977
1008
  (
978
1009
  this.shadowRoot.querySelector('.select-container') as HTMLDivElement
@@ -1042,7 +1073,7 @@ export class Select<T extends SelectOption> extends FormElement {
1042
1073
  // filter out any options already selected by id
1043
1074
  // TODO: should maybe be doing a deep equals here with option to optimize
1044
1075
  if (this.values.length > 0) {
1045
- if (this.multi) {
1076
+ if (this.isMultiMode) {
1046
1077
  options = options.filter(
1047
1078
  (option) =>
1048
1079
  !this.values.find(
@@ -1063,7 +1094,7 @@ export class Select<T extends SelectOption> extends FormElement {
1063
1094
  }
1064
1095
 
1065
1096
  if (
1066
- this.multi &&
1097
+ this.isMultiMode &&
1067
1098
  this.maxItems > 0 &&
1068
1099
  this.values.length >= this.maxItems
1069
1100
  ) {
@@ -1123,6 +1154,18 @@ export class Select<T extends SelectOption> extends FormElement {
1123
1154
  }
1124
1155
  }
1125
1156
 
1157
+ if (this.emails && q) {
1158
+ if (
1159
+ this.isValidEmail(q) &&
1160
+ !options.find(
1161
+ (option: any) =>
1162
+ this.getValue(option) && this.getValue(option).toLowerCase() === q
1163
+ )
1164
+ ) {
1165
+ options.splice(0, 0, { name: query, value: query });
1166
+ }
1167
+ }
1168
+
1126
1169
  if (this.endpoint) {
1127
1170
  let url = this.endpoint;
1128
1171
  if (next) {
@@ -1149,7 +1192,7 @@ export class Select<T extends SelectOption> extends FormElement {
1149
1192
  }
1150
1193
 
1151
1194
  const cache = this.lruCache.get(url);
1152
- if (this.cache && !this.tags && cache) {
1195
+ if (this.cache && !this.tags && !this.emails && cache) {
1153
1196
  if (page === 0 && !this.next) {
1154
1197
  this.cursorIndex = 0;
1155
1198
  this.setVisibleOptions([...options, ...cache.options]);
@@ -1168,7 +1211,7 @@ export class Select<T extends SelectOption> extends FormElement {
1168
1211
  fetchResults(url).then((results: any) => {
1169
1212
  results = this.prepareOptions(results);
1170
1213
 
1171
- if (this.cache && !this.tags) {
1214
+ if (this.cache && !this.tags && !this.emails) {
1172
1215
  this.lruCache.set(url, {
1173
1216
  options: results,
1174
1217
  complete: true,
@@ -1207,7 +1250,7 @@ export class Select<T extends SelectOption> extends FormElement {
1207
1250
  this.complete = this.isComplete(results, response);
1208
1251
  }
1209
1252
 
1210
- if (this.cache && !this.tags) {
1253
+ if (this.cache && !this.tags && !this.emails) {
1211
1254
  this.lruCache.set(url, {
1212
1255
  options: results,
1213
1256
  complete: this.complete,
@@ -1249,7 +1292,7 @@ export class Select<T extends SelectOption> extends FormElement {
1249
1292
  }
1250
1293
 
1251
1294
  if (
1252
- this.multi &&
1295
+ this.isMultiMode &&
1253
1296
  this.maxItems > 0 &&
1254
1297
  this.values.length >= this.maxItems
1255
1298
  ) {
@@ -1270,7 +1313,7 @@ export class Select<T extends SelectOption> extends FormElement {
1270
1313
  expression: true
1271
1314
  };
1272
1315
 
1273
- if (this.multi) {
1316
+ if (this.isMultiMode) {
1274
1317
  if (
1275
1318
  !this.values.find((option: T) => {
1276
1319
  return (
@@ -1289,7 +1332,7 @@ export class Select<T extends SelectOption> extends FormElement {
1289
1332
  }
1290
1333
 
1291
1334
  this.input = '';
1292
- if (!this.multi) {
1335
+ if (!this.isMultiMode) {
1293
1336
  this.blur();
1294
1337
  }
1295
1338
  }
@@ -1303,6 +1346,21 @@ export class Select<T extends SelectOption> extends FormElement {
1303
1346
  this.input.indexOf('@') > -1
1304
1347
  ) {
1305
1348
  this.addInputAsValue();
1349
+ return;
1350
+ }
1351
+
1352
+ // if we are in email mode and have a valid email, add it
1353
+ if (
1354
+ evt.key === 'Enter' &&
1355
+ this.emails &&
1356
+ this.input &&
1357
+ this.isValidEmail(this.input.trim()) &&
1358
+ this.visibleOptions.length === 0
1359
+ ) {
1360
+ evt.preventDefault();
1361
+ const emailOption = { name: this.input.trim(), value: this.input.trim() };
1362
+ this.setSelectedOption(emailOption);
1363
+ return;
1306
1364
  }
1307
1365
 
1308
1366
  // see if we should open our options on a key event
@@ -1323,7 +1381,7 @@ export class Select<T extends SelectOption> extends FormElement {
1323
1381
  }
1324
1382
 
1325
1383
  // focus our last item on delete
1326
- if (this.multi && evt.key === 'Backspace' && !this.input) {
1384
+ if (this.isMultiMode && evt.key === 'Backspace' && !this.input) {
1327
1385
  if (this.visibleOptions.length > 0) {
1328
1386
  this.visibleOptions = [];
1329
1387
  return;
@@ -1447,7 +1505,10 @@ export class Select<T extends SelectOption> extends FormElement {
1447
1505
 
1448
1506
  public serializeValue(value: any): string {
1449
1507
  // static options just use their value
1450
- if (!this.jsonValue && (this.staticOptions.length > 0 || this.tags)) {
1508
+ if (
1509
+ !this.jsonValue &&
1510
+ (this.staticOptions.length > 0 || this.isMultiMode)
1511
+ ) {
1451
1512
  return value.value;
1452
1513
  }
1453
1514
 
@@ -1481,14 +1542,18 @@ export class Select<T extends SelectOption> extends FormElement {
1481
1542
 
1482
1543
  public setValues(values: any[]) {
1483
1544
  const oldValues = this.values;
1484
- this.values = values;
1545
+ this.values.splice(0, this.values.length, ...values);
1485
1546
  this.requestUpdate('values', oldValues);
1547
+ this.updateInputs();
1548
+ this.fireEvent('change');
1486
1549
  }
1487
1550
 
1488
1551
  public addValue(value: any) {
1489
1552
  const oldValues = [...this.values];
1490
1553
  this.values.push(value);
1491
1554
  this.requestUpdate('values', oldValues);
1555
+ this.updateInputs();
1556
+ this.fireEvent('change');
1492
1557
  }
1493
1558
 
1494
1559
  public removeValue(valueToRemove: any) {
@@ -1511,6 +1576,8 @@ export class Select<T extends SelectOption> extends FormElement {
1511
1576
  }
1512
1577
  this.requestUpdate('values', oldValues);
1513
1578
  this.infoText = '';
1579
+ this.updateInputs();
1580
+ this.fireEvent('change');
1514
1581
  }
1515
1582
 
1516
1583
  public popValue() {
@@ -1518,12 +1585,16 @@ export class Select<T extends SelectOption> extends FormElement {
1518
1585
  this.values.pop();
1519
1586
  this.requestUpdate('values', oldValues);
1520
1587
  this.infoText = '';
1588
+ this.updateInputs();
1589
+ this.fireEvent('change');
1521
1590
  }
1522
1591
 
1523
1592
  public clear() {
1524
1593
  const oldValues = this.values;
1525
- this.values = [];
1594
+ this.values.splice(0, this.values.length);
1526
1595
  this.requestUpdate('values', oldValues);
1596
+ this.updateInputs();
1597
+ this.fireEvent('change');
1527
1598
  }
1528
1599
 
1529
1600
  private shouldShowEmptyMessage(): boolean {
@@ -1553,10 +1624,12 @@ export class Select<T extends SelectOption> extends FormElement {
1553
1624
  toIdx < this.values.length
1554
1625
  ) {
1555
1626
  const oldValues = [...this.values];
1556
- // Move the item from fromIdx to toIdx
1627
+ // Move the item using splice operations directly on this.values
1557
1628
  const movedItem = this.values.splice(fromIdx, 1)[0];
1558
1629
  this.values.splice(toIdx, 0, movedItem);
1559
1630
  this.requestUpdate('values', oldValues);
1631
+ this.updateInputs();
1632
+ this.fireEvent('change');
1560
1633
  }
1561
1634
  }
1562
1635
  }
@@ -1568,7 +1641,7 @@ export class Select<T extends SelectOption> extends FormElement {
1568
1641
  `;
1569
1642
 
1570
1643
  const clear =
1571
- this.clearable && this.values.length > 0 && !this.multi
1644
+ this.clearable && this.values.length > 0 && !this.isMultiMode
1572
1645
  ? html`<temba-icon
1573
1646
  name="${Icon.select_clear}"
1574
1647
  size="1.1"
@@ -1578,8 +1651,8 @@ export class Select<T extends SelectOption> extends FormElement {
1578
1651
  : null;
1579
1652
 
1580
1653
  const classes = getClasses({
1581
- multi: this.multi,
1582
- single: !this.multi,
1654
+ multi: this.isMultiMode,
1655
+ single: !this.isMultiMode,
1583
1656
  searchable: this.searchable,
1584
1657
  empty: this.values.length === 0,
1585
1658
  options: this.visibleOptions.length > 0,
@@ -1615,8 +1688,8 @@ export class Select<T extends SelectOption> extends FormElement {
1615
1688
  `
1616
1689
  : placeholderDiv;
1617
1690
 
1618
- const items = html`${!this.multi && !this.resolving ? input : null}
1619
- ${this.multi && this.values.length > 1
1691
+ const items = html`${!this.isMultiMode && !this.resolving ? input : null}
1692
+ ${this.isMultiMode && this.values.length > 1
1620
1693
  ? html`
1621
1694
  <temba-sortable-list
1622
1695
  horizontal
@@ -1657,7 +1730,7 @@ export class Select<T extends SelectOption> extends FormElement {
1657
1730
  : ''}
1658
1731
  "
1659
1732
  >
1660
- ${this.multi
1733
+ ${this.isMultiMode
1661
1734
  ? html`
1662
1735
  <div
1663
1736
  class="remove-item"
@@ -1706,7 +1779,7 @@ export class Select<T extends SelectOption> extends FormElement {
1706
1779
  : ''}
1707
1780
  "
1708
1781
  >
1709
- ${this.multi
1782
+ ${this.isMultiMode
1710
1783
  ? html`
1711
1784
  <div
1712
1785
  class="remove-item"
@@ -1732,13 +1805,13 @@ export class Select<T extends SelectOption> extends FormElement {
1732
1805
  </div>
1733
1806
  `
1734
1807
  : null}
1735
- ${!this.input || this.multi
1808
+ ${!this.input || this.isMultiMode
1736
1809
  ? this.renderSelectedItem(selected)
1737
1810
  : null}
1738
1811
  </div>
1739
1812
  `
1740
1813
  )}
1741
- ${this.multi ? input : null}`;
1814
+ ${this.isMultiMode ? input : null}`;
1742
1815
 
1743
1816
  return html`
1744
1817
 
@@ -1778,7 +1851,7 @@ export class Select<T extends SelectOption> extends FormElement {
1778
1851
 
1779
1852
  <slot name="right"></slot>
1780
1853
  ${
1781
- !this.tags
1854
+ !this.tags && !this.emails
1782
1855
  ? html`<div
1783
1856
  class="right-side arrow"
1784
1857
  style="display:block;margin-right:5px"
package/src/interfaces.ts CHANGED
@@ -100,7 +100,6 @@ export interface Msg {
100
100
  channel: ObjectReference;
101
101
  quick_replies: string[];
102
102
  urn: string;
103
- id: number;
104
103
  direction: string;
105
104
  type: string;
106
105
  attachments: string[];
@@ -287,5 +286,11 @@ export enum CustomEventType {
287
286
  TicketUpdated = 'temba-ticket-updated',
288
287
  Moved = 'temba-moved',
289
288
  DateRangeChanged = 'temba-date-range-changed',
290
- NodeDeleted = 'temba-node-deleted'
289
+ NodeDeleted = 'temba-node-deleted',
290
+ ActionEditRequested = 'temba-action-edit-requested',
291
+ ActionSaved = 'temba-action-saved',
292
+ ActionEditCanceled = 'temba-action-edit-canceled',
293
+ NodeEditRequested = 'temba-node-edit-requested',
294
+ NodeSaved = 'temba-node-saved',
295
+ NodeEditCancelled = 'temba-node-edit-cancelled'
291
296
  }
@@ -11,7 +11,6 @@ import {
11
11
  import {
12
12
  fetchResults,
13
13
  getUrl,
14
- oxford,
15
14
  oxfordFn,
16
15
  postJSON,
17
16
  postUrl,
@@ -21,24 +20,18 @@ import { ContactStoreElement } from './ContactStoreElement';
21
20
  import { Compose, ComposeValue } from '../form/Compose';
22
21
  import {
23
22
  AirtimeTransferredEvent,
24
- CampaignFiredEvent,
25
23
  ChannelEvent,
26
24
  ContactEvent,
27
25
  ContactGroupsEvent,
28
26
  ContactHistoryPage,
29
27
  ContactLanguageChangedEvent,
30
- EmailSentEvent,
31
- ErrorMessageEvent,
32
28
  FlowEvent,
33
- LabelsAddedEvent,
34
29
  MsgEvent,
35
30
  NameChangedEvent,
36
31
  OptinRequestedEvent,
37
32
  TicketEvent,
38
33
  UpdateFieldEvent,
39
- UpdateResultEvent,
40
- URNsChangedEvent,
41
- WebhookEvent
34
+ URNsChangedEvent
42
35
  } from '../events';
43
36
  import { Chat, ChatEvent, MessageType } from '../display/Chat';
44
37
  import { getUserDisplay } from '../webchat';
@@ -63,19 +56,14 @@ export enum Events {
63
56
  FLOW_ENTERED = 'flow_entered',
64
57
 
65
58
  FLOW_EXITED = 'flow_exited',
66
- RUN_RESULT_CHANGED = 'run_result_changed',
67
59
  CONTACT_FIELD_CHANGED = 'contact_field_changed',
68
60
  CONTACT_GROUPS_CHANGED = 'contact_groups_changed',
69
61
  CONTACT_NAME_CHANGED = 'contact_name_changed',
70
62
  CONTACT_URNS_CHANGED = 'contact_urns_changed',
71
- CAMPAIGN_FIRED = 'campaign_fired',
72
63
  CHANNEL_EVENT = 'channel_event',
73
64
  CONTACT_LANGUAGE_CHANGED = 'contact_language_changed',
74
- WEBHOOK_CALLED = 'webhook_called',
75
65
  AIRTIME_TRANSFERRED = 'airtime_transferred',
76
66
  CALL_STARTED = 'call_started',
77
- EMAIL_SENT = 'email_sent',
78
- INPUT_LABELS_ADDED = 'input_labels_added',
79
67
  NOTE_CREATED = 'note_created',
80
68
  TICKET_ASSIGNED = 'ticket_assigned',
81
69
  TICKET_NOTE_ADDED = 'ticket_note_added',
@@ -83,9 +71,7 @@ export enum Events {
83
71
  TICKET_OPENED = 'ticket_opened',
84
72
  TICKET_REOPENED = 'ticket_reopened',
85
73
  TICKET_TOPIC_CHANGED = 'ticket_topic_changed',
86
- OPTIN_REQUESTED = 'optin_requested',
87
- ERROR = 'error',
88
- FAILURE = 'failure'
74
+ OPTIN_REQUESTED = 'optin_requested'
89
75
  }
90
76
 
91
77
  const renderInfoList = (singular: string, plural: string, items: any[]) => {
@@ -102,10 +88,6 @@ const renderInfoList = (singular: string, plural: string, items: any[]) => {
102
88
  }
103
89
  };
104
90
 
105
- const toTitleCase = (str: string) => {
106
- return str.charAt(0).toUpperCase() + str.slice(1);
107
- };
108
-
109
91
  const renderChannelEvent = (event: ChannelEvent): string => {
110
92
  if (event.event.type === 'mt_miss') {
111
93
  return 'Missed outgoing call';
@@ -144,12 +126,6 @@ const renderFlowEvent = (event: FlowEvent): string => {
144
126
  return `${verb} [**${event.flow.name}**](/flow/editor/${event.flow.uuid}/)`;
145
127
  };
146
128
 
147
- const renderResultEvent = (event: UpdateResultEvent): string => {
148
- if (!event.name.startsWith('_') && event.value) {
149
- return `Updated flow result **${event.name}** to **${event.value}**`;
150
- }
151
- };
152
-
153
129
  const renderUpdateEvent = (event: UpdateFieldEvent): string => {
154
130
  return event.value
155
131
  ? `Updated **${event.field.name}** to **${event.value.text}**`
@@ -167,16 +143,6 @@ const renderContactURNsChanged = (event: URNsChangedEvent): string => {
167
143
  )}`;
168
144
  };
169
145
 
170
- const renderEmailSent = (event: EmailSentEvent): string => {
171
- return `Email sent to **${oxford(event.to, 'and')}** with subject **${
172
- event.subject
173
- }**`;
174
- };
175
-
176
- const renderLabelsAdded = (event: LabelsAddedEvent): string => {
177
- return `Applied ${renderInfoList('label', 'labels', event.labels)}`;
178
- };
179
-
180
146
  export const renderTicketAction = (
181
147
  event: TicketEvent,
182
148
  action: string
@@ -216,31 +182,10 @@ export const renderContactGroupsEvent = (event: ContactGroupsEvent): string => {
216
182
  }
217
183
  };
218
184
 
219
- export const renderCampaignFiredEvent = (event: CampaignFiredEvent): string => {
220
- return `Campaign ${event.campaign.name}
221
- ${event.fired_result === 'S' ? 'skipped' : 'triggered'}
222
- ${event.campaign_event.offset_display}
223
- ${event.campaign_event.relative_to.name}`;
224
- };
225
-
226
185
  export const renderTicketOpened = (event: TicketEvent): string => {
227
186
  return `${event.ticket.topic.name} ticket was opened`;
228
187
  };
229
188
 
230
- export const renderErrorMessage = (event: ErrorMessageEvent): string => {
231
- return `${event.text} ${
232
- event.type === Events.FAILURE
233
- ? `Run ended prematurely, check the flow design`
234
- : null
235
- }`;
236
- };
237
-
238
- export const renderWebhookEvent = (event: WebhookEvent): string => {
239
- return event.status === 'success'
240
- ? `Successfully called ${event.url}`
241
- : `Failed to call ${event.url}`;
242
- };
243
-
244
189
  export const renderAirtimeTransferredEvent = (
245
190
  event: AirtimeTransferredEvent
246
191
  ): string => {
@@ -656,15 +601,6 @@ export class ContactChat extends ContactStoreElement {
656
601
  public getEventMessage(event: ContactEvent): ChatEvent {
657
602
  let message = null;
658
603
  switch (event.type) {
659
- case Events.ERROR:
660
- case Events.FAILURE:
661
- message = {
662
- type: MessageType.Inline,
663
- text: `Error during flow: ${toTitleCase(
664
- (event as ErrorMessageEvent).text
665
- )}`
666
- };
667
- break;
668
604
  case Events.TICKET_OPENED:
669
605
  message = {
670
606
  type: MessageType.Inline,
@@ -702,12 +638,6 @@ export class ContactChat extends ContactStoreElement {
702
638
  text: renderFlowEvent(event as FlowEvent)
703
639
  };
704
640
  break;
705
- case Events.RUN_RESULT_CHANGED:
706
- message = {
707
- type: MessageType.Inline,
708
- text: renderResultEvent(event as UpdateResultEvent)
709
- };
710
- break;
711
641
  case Events.CONTACT_FIELD_CHANGED:
712
642
  message = {
713
643
  type: MessageType.Inline,
@@ -726,30 +656,12 @@ export class ContactChat extends ContactStoreElement {
726
656
  text: renderContactURNsChanged(event as URNsChangedEvent)
727
657
  };
728
658
  break;
729
- case Events.EMAIL_SENT:
730
- message = {
731
- type: MessageType.Inline,
732
- text: renderEmailSent(event as EmailSentEvent)
733
- };
734
- break;
735
- case Events.INPUT_LABELS_ADDED:
736
- message = {
737
- type: MessageType.Inline,
738
- text: renderLabelsAdded(event as LabelsAddedEvent)
739
- };
740
- break;
741
659
  case Events.CONTACT_GROUPS_CHANGED:
742
660
  message = {
743
661
  type: MessageType.Inline,
744
662
  text: renderContactGroupsEvent(event as ContactGroupsEvent)
745
663
  };
746
664
  break;
747
- case Events.WEBHOOK_CALLED:
748
- message = {
749
- type: MessageType.Inline,
750
- text: renderWebhookEvent(event as WebhookEvent)
751
- };
752
- break;
753
665
  case Events.AIRTIME_TRANSFERRED:
754
666
  message = {
755
667
  type: MessageType.Inline,
@@ -762,12 +674,6 @@ export class ContactChat extends ContactStoreElement {
762
674
  text: renderCallStartedEvent()
763
675
  };
764
676
  break;
765
- case Events.CAMPAIGN_FIRED:
766
- message = {
767
- type: MessageType.Inline,
768
- text: renderCampaignFiredEvent(event as CampaignFiredEvent)
769
- };
770
- break;
771
677
  case Events.CHANNEL_EVENT:
772
678
  message = {
773
679
  type: MessageType.Inline,
@@ -853,8 +759,8 @@ export class ContactChat extends ContactStoreElement {
853
759
  ) {
854
760
  const msgEvent = event as MsgEvent;
855
761
  messages.push({
762
+ uuid: event.uuid,
856
763
  type: msgEvent.type === 'msg_received' ? 'msg_in' : 'msg_out',
857
- id: msgEvent.msg.id + '',
858
764
  user: this.getUserForEvent(msgEvent),
859
765
  date: new Date(msgEvent.created_on),
860
766
  attachments: msgEvent.msg.attachments,
@@ -76,7 +76,7 @@ export interface Group extends NamedObject {
76
76
 
77
77
  export interface SendMsg extends Action {
78
78
  text: string;
79
- quick_replies: string[];
79
+ quick_replies?: string[];
80
80
  }
81
81
 
82
82
  export interface SetRunResult extends Action {
@@ -91,6 +91,10 @@ export interface SetContactName extends Action {
91
91
 
92
92
  export interface CallWebhook extends Action {
93
93
  url: string;
94
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
95
+ headers?: Record<string, string>;
96
+ body?: string;
97
+ result_name?: string;
94
98
  }
95
99
 
96
100
  export interface AddToGroup extends Action {
@@ -99,6 +103,7 @@ export interface AddToGroup extends Action {
99
103
 
100
104
  export interface RemoveFromGroup extends Action {
101
105
  groups: Group[];
106
+ all_groups?: boolean;
102
107
  }
103
108
 
104
109
  export interface SetContactField extends Action {
@@ -0,0 +1,30 @@
1
+ {
2
+ "next": null,
3
+ "previous": null,
4
+ "results": [
5
+ {
6
+ "uuid": "contact-1",
7
+ "name": "John Doe",
8
+ "language": "eng",
9
+ "urns": ["tel:+1234567890"],
10
+ "fields": {},
11
+ "groups": [],
12
+ "blocked": false,
13
+ "stopped": false,
14
+ "created_on": "2024-01-01T00:00:00Z",
15
+ "modified_on": "2024-01-01T00:00:00Z"
16
+ },
17
+ {
18
+ "uuid": "contact-2",
19
+ "name": "Jane Smith",
20
+ "language": "eng",
21
+ "urns": ["tel:+0987654321"],
22
+ "fields": {},
23
+ "groups": [],
24
+ "blocked": false,
25
+ "stopped": false,
26
+ "created_on": "2024-01-01T00:00:00Z",
27
+ "modified_on": "2024-01-01T00:00:00Z"
28
+ }
29
+ ]
30
+ }