@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
@@ -45,11 +45,10 @@
45
45
  }
46
46
  },
47
47
  {
48
+ "uuid": "01988a70-075b-74e4-b738-3be521174d83",
48
49
  "type": "msg_created",
49
50
  "created_on": "2021-03-31T00:30:00.585471+00:00",
50
51
  "msg": {
51
- "uuid": "70e2e0bb-418a-410c-b90f-10374a0c8caf",
52
- "id": 1485,
53
52
  "urn": "tel:+250788123123",
54
53
  "text": "Hey John, just checking in on you",
55
54
  "channel": {
@@ -72,21 +71,20 @@
72
71
  "status": "C"
73
72
  },
74
73
  {
74
+ "uuid": "01988a70-3e8f-7890-b1d2-7418db7a575e",
75
75
  "type": "airtime_transferred",
76
76
  "created_on": "2021-03-30T22:20:35.573511+00:00",
77
77
  "sender": "tel:123456",
78
78
  "recipient": "tel:+250788123123?channel=8a81e9e0-10a0-4319-9b00-ce723cfa8303&id=9951&priority=1000",
79
79
  "currency": null,
80
80
  "desired_amount": "0.00",
81
- "actual_amount": "0.00",
82
- "logs_url": "/airtimetransfer/read/2/"
81
+ "actual_amount": "0.00"
83
82
  },
84
83
  {
84
+ "uuid": "01988a70-6cd1-738d-b5d6-ef9f9a0c529f",
85
85
  "type": "msg_created",
86
86
  "created_on": "2021-03-30T22:20:33.924847+00:00",
87
87
  "msg": {
88
- "uuid": "37507bdd-9087-4782-828d-ad5c17c14f72",
89
- "id": 1484,
90
88
  "urn": "tel:+250788123123",
91
89
  "text": "No problem, we are all done then!",
92
90
  "channel": {
@@ -98,11 +96,10 @@
98
96
  "logs_url": "/channels/channellog/read/1478/"
99
97
  },
100
98
  {
99
+ "uuid": "01988a71-045a-7902-8734-84311a7569de",
101
100
  "type": "msg_received",
102
101
  "created_on": "2021-03-30T22:20:33.801814+00:00",
103
102
  "msg": {
104
- "uuid": "b872ae96-28b1-4858-95c5-b7b662ccd08c",
105
- "id": 1483,
106
103
  "urn": "tel:+250788123123",
107
104
  "text": "no",
108
105
  "channel": {
@@ -114,11 +111,10 @@
114
111
  "logs_url": "/channels/channellog/read/1477/"
115
112
  },
116
113
  {
114
+ "uuid": "01988a71-6736-7948-9517-32971fcba1cb",
117
115
  "type": "msg_created",
118
116
  "created_on": "2021-03-30T22:20:31.933653+00:00",
119
117
  "msg": {
120
- "uuid": "c095a764-590a-4359-ba2a-c626f4e9baeb",
121
- "id": 1482,
122
118
  "urn": "tel:+250788123123",
123
119
  "text": "Mmmmm... delicious Primus. If only they made blue Primus! Do you want to set your name?",
124
120
  "channel": {
@@ -130,11 +126,10 @@
130
126
  "logs_url": "/channels/channellog/read/1476/"
131
127
  },
132
128
  {
129
+ "uuid": "01988a75-60cc-7681-bf4b-2b0b42347fc4",
133
130
  "type": "msg_received",
134
131
  "created_on": "2021-03-30T22:20:31.656303+00:00",
135
132
  "msg": {
136
- "uuid": "925995ad-fa5f-4f01-b8f1-050703f333e0",
137
- "id": 1481,
138
133
  "urn": "tel:+250788123123",
139
134
  "text": "primus",
140
135
  "channel": {
@@ -146,11 +141,10 @@
146
141
  "logs_url": "/channels/channellog/read/1475/"
147
142
  },
148
143
  {
144
+ "uuid": "01988a76-58fb-7252-9fac-3c6a385e8af1",
149
145
  "type": "msg_created",
150
146
  "created_on": "2021-03-30T22:20:29.397529+00:00",
151
147
  "msg": {
152
- "uuid": "9f0b200a-6e24-451d-a7cb-06ef2518d1e5",
153
- "id": 1480,
154
148
  "urn": "tel:+250788123123",
155
149
  "text": "Good choice, I like Blue too! What is your favorite beer?",
156
150
  "channel": {
@@ -162,11 +156,10 @@
162
156
  "logs_url": "/channels/channellog/read/1474/"
163
157
  },
164
158
  {
159
+ "uuid": "01988a76-afe4-7958-bea8-51683d99f665",
165
160
  "type": "msg_received",
166
161
  "created_on": "2021-03-30T22:20:29.277186+00:00",
167
162
  "msg": {
168
- "uuid": "a702b6a6-3035-433b-9029-1a8dfa0c0194",
169
- "id": 1479,
170
163
  "urn": "tel:+250788123123",
171
164
  "text": "blue",
172
165
  "channel": {
@@ -202,24 +195,10 @@
202
195
  "session_uuid": "885a9736-88fd-4676-b124-2577e1eaabd9"
203
196
  },
204
197
  {
205
- "type": "input_labels_added",
206
- "created_on": "2021-03-30T15:20:26.704494-07:00",
207
- "step_uuid": "83cbe193-29d8-40ce-a820-0b06d719932a",
208
- "input_uuid": "89109a8c-2895-46b7-aa44-170570de7d6a",
209
- "labels": [
210
- {
211
- "uuid": "825e2cef-2465-4467-a315-f10a83b6d8aa",
212
- "name": "A label"
213
- }
214
- ],
215
- "session_uuid": "885a9736-88fd-4676-b124-2577e1eaabd9"
216
- },
217
- {
198
+ "uuid": "01988a76-febd-7157-b2cd-4bc0c1663173",
218
199
  "type": "msg_created",
219
200
  "created_on": "2021-03-30T22:20:26.704491+00:00",
220
201
  "msg": {
221
- "uuid": "eef09c0f-24dc-426c-8050-50795dca8e8b",
222
- "id": 1478,
223
202
  "urn": "tel:+250788123123",
224
203
  "text": "What is your favorite color?",
225
204
  "channel": {
@@ -240,11 +219,10 @@
240
219
  "logs_url": null
241
220
  },
242
221
  {
222
+ "uuid": "01988a77-979e-7768-a940-8d9c348e24fe",
243
223
  "type": "msg_received",
244
224
  "created_on": "2021-03-30T22:20:26.557388+00:00",
245
225
  "msg": {
246
- "uuid": "89109a8c-2895-46b7-aa44-170570de7d6a",
247
- "id": 1477,
248
226
  "urn": "tel:+250788123123",
249
227
  "text": "fav",
250
228
  "channel": {
@@ -12,6 +12,40 @@ export default {
12
12
  preventAssignment: true,
13
13
  'process.env.NODE_ENV': JSON.stringify('development'),
14
14
  }),
15
+ {
16
+ name: 'api-mock-server',
17
+ serve(context) {
18
+ // Handle API endpoints by serving static files
19
+ if (context.request.method === 'GET' && context.path.startsWith('/api/')) {
20
+ // Map API endpoints to static files
21
+ const apiMappings = {
22
+ '/api/v2/groups.json': './static/api/groups.json',
23
+ '/api/v2/fields.json': './static/api/fields.json',
24
+ '/api/v2/globals.json': './static/api/globals.json',
25
+ '/api/v2/completion.json': './static/api/completion.json',
26
+ '/api/v2/functions.json': './static/api/functions.json',
27
+ '/api/internal/templates.json': './static/api/templates.json',
28
+ '/api/v2/media.json': './static/api/media.json',
29
+ '/api/v2/users.json': './static/api/users.json',
30
+ '/api/v2/contacts.json': './static/api/contacts.json',
31
+ '/api/v2/optins.json': './static/api/optins.json',
32
+ '/api/v2/topics.json': './static/api/topics.json',
33
+ '/api/internal/locations.json': './static/api/locations.json',
34
+ '/api/internal/orgs.json': './static/api/orgs.json'
35
+ };
36
+
37
+ // Handle base path without query parameters
38
+ const basePath = context.path.split('?')[0];
39
+ const staticFile = apiMappings[basePath];
40
+
41
+ if (staticFile && fs.existsSync(path.resolve(staticFile))) {
42
+ context.contentType = 'application/json';
43
+ context.body = fs.readFileSync(path.resolve(staticFile), 'utf-8');
44
+ return;
45
+ }
46
+ }
47
+ }
48
+ },
15
49
  {
16
50
  name: 'flow-files',
17
51
  serve(context) {
@@ -1,80 +0,0 @@
1
- name: 'Update Coverage Reports'
2
-
3
- on:
4
- push:
5
- branches: [main]
6
-
7
- permissions:
8
- contents: write
9
-
10
- jobs:
11
- coverage:
12
- runs-on: ubuntu-latest
13
- steps:
14
- - name: Set Timezone
15
- uses: szenius/set-timezone@v2.0
16
- with:
17
- timezoneLinux: 'UTC'
18
-
19
- - name: Checkout (GitHub)
20
- uses: actions/checkout@v4
21
- with:
22
- token: ${{ secrets.GITHUB_TOKEN }}
23
- fetch-depth: 0
24
-
25
- - run: docker network create --driver bridge textit_default
26
-
27
- - name: Build and run tests with coverage
28
- uses: devcontainers/ci@v0.3
29
- with:
30
- runCmd: yarn validate && ./generate-coverage-badge.sh
31
- push: never
32
- env: |
33
- CI=true
34
-
35
- - name: Copy coverage to temp
36
- run: |
37
- mkdir -p /tmp/coverage-copy
38
- cp -r coverage /tmp/coverage-copy/
39
-
40
- - name: Deploy coverage to coverage branch
41
- run: |
42
- git config --local user.email "action@github.com"
43
- git config --local user.name "GitHub Action"
44
-
45
- # Remove any coverage directory to avoid ambiguity with branch name
46
- rm -rf coverage
47
-
48
- # Create or checkout coverage branch
49
- if git show-ref --verify --quiet refs/remotes/origin/coverage; then
50
- git fetch origin coverage
51
- git checkout coverage
52
- else
53
- git checkout --orphan coverage
54
- git rm -rf . || true
55
- fi
56
-
57
- # Copy coverage report files from temp directly to root
58
- cp -r /tmp/coverage-copy/coverage/lcov-report/* ./
59
- rm -rf /tmp/coverage-copy
60
-
61
- # Create .nojekyll for GitHub Pages
62
- touch .nojekyll
63
-
64
- # Create .gitignore to exclude build byproducts from coverage branch
65
- echo "# Ignore build artifacts and local byproducts in coverage branch" > .gitignore
66
- echo "dist/" >> .gitignore
67
- echo "node_modules/" >> .gitignore
68
- echo "out-tsc/" >> .gitignore
69
- echo "screenshots/test/" >> .gitignore
70
- echo "static/svg/work/" >> .gitignore
71
- echo "# Add more patterns as needed" >> .gitignore
72
-
73
- # Add all files
74
- git add .
75
-
76
- # Commit if there are changes
77
- if ! git diff --staged --quiet; then
78
- git commit -m "Update coverage reports [skip ci] - $(date)"
79
- git push origin coverage
80
- fi
@@ -1,155 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en-GB">
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>Sticky Note Example</title>
6
- <link
7
- href="/static/css/temba-components.css"
8
- rel="stylesheet"
9
- type="text/css"
10
- />
11
- <link
12
- href="https://fonts.googleapis.com/css?family=Roboto+Mono:300|Roboto:300,400,500"
13
- rel="stylesheet"
14
- />
15
- <link href="../styles.css" rel="stylesheet" type="text/css" />
16
- <script type="module" src="../src/flow/StickyNote.ts"></script>
17
- <link href="/demo/static/css/prism.css" rel="stylesheet" />
18
- <script type="module" src="/demo/static/js/prism-loader.js"></script>
19
- </head>
20
- <body>
21
- <h1>Sticky Note Example</h1>
22
- <p><a href="../index.html">← Back to main demo</a></p>
23
-
24
- <table class="attr-table">
25
- <thead>
26
- <tr>
27
- <th>Attribute</th>
28
- <th>Description</th>
29
- <th>Default</th>
30
- </tr>
31
- </thead>
32
- <tbody>
33
- <tr>
34
- <td>uuid</td>
35
- <td>Unique identifier for the sticky note</td>
36
- <td>None (required)</td>
37
- </tr>
38
- <tr>
39
- <td>data</td>
40
- <td>
41
- Object containing position, title, body, and color properties.
42
- Position: {left: number, top: number}, color: 'yellow' | 'blue' | 'pink' | 'green' | 'gray'
43
- </td>
44
- <td>None (required)</td>
45
- </tr>
46
- </tbody>
47
- </table>
48
-
49
- <section class="doc-section">
50
- <h2>Events</h2>
51
- <p>
52
- The sticky note component fires events when its content is updated through the flow store system.
53
- Updates to title and body content are automatically synchronized with the flow state.
54
- </p>
55
- </section>
56
-
57
- <div class="example">
58
- <h3>Basic Sticky Note</h3>
59
- <p>A simple yellow sticky note with default positioning</p>
60
- <pre class="example-html"><code class="language-markup">&lt;temba-sticky-note uuid="basic-note"&gt;&lt;/temba-sticky-note&gt;</code></pre>
61
- <div class="demo-container">
62
- <temba-sticky-note id="basic-note"></temba-sticky-note>
63
- </div>
64
- </div>
65
-
66
- <div class="example">
67
- <h3>Colored Sticky Notes</h3>
68
- <p>Sticky notes with different color themes - click to edit the text, drag to move them around</p>
69
- <pre class="example-html"><code class="language-markup">&lt;!-- Multiple colored sticky notes --&gt;
70
- &lt;temba-sticky-note uuid="yellow-note"&gt;&lt;/temba-sticky-note&gt;
71
- &lt;temba-sticky-note uuid="blue-note"&gt;&lt;/temba-sticky-note&gt;
72
- &lt;temba-sticky-note uuid="pink-note"&gt;&lt;/temba-sticky-note&gt;
73
- &lt;temba-sticky-note uuid="green-note"&gt;&lt;/temba-sticky-note&gt;
74
- &lt;temba-sticky-note uuid="gray-note"&gt;&lt;/temba-sticky-note&gt;</code></pre>
75
- <div class="demo-container">
76
- <temba-sticky-note id="yellow-note"></temba-sticky-note>
77
- <temba-sticky-note id="blue-note"></temba-sticky-note>
78
- <temba-sticky-note id="pink-note"></temba-sticky-note>
79
- <temba-sticky-note id="green-note"></temba-sticky-note>
80
- <temba-sticky-note id="gray-note"></temba-sticky-note>
81
- </div>
82
- <div class="expected">
83
- <strong>How to use:</strong>
84
- <ul>
85
- <li>Click and drag the sticky notes to move them around</li>
86
- <li>Click on the title or body text to edit it inline</li>
87
- <li>Press Enter or Escape to finish editing</li>
88
- <li>Notes snap to a 20px grid when you finish dragging</li>
89
- <li>Each color has its own visual theme</li>
90
- </ul>
91
- </div>
92
- </div>
93
-
94
- <script type="module">
95
- import '/out-tsc/temba-modules.js';
96
-
97
- // Configure the sticky notes with sample data
98
- document.addEventListener('DOMContentLoaded', () => {
99
- const basicNote = document.getElementById('basic-note');
100
- basicNote.uuid = 'basic-uuid';
101
- basicNote.data = {
102
- position: { left: 50, top: 50 },
103
- title: 'Basic Note',
104
- body: 'This is a basic sticky note example.',
105
- color: 'yellow'
106
- };
107
-
108
- const yellowNote = document.getElementById('yellow-note');
109
- yellowNote.uuid = 'yellow-uuid';
110
- yellowNote.data = {
111
- position: { left: 50, top: 50 },
112
- title: 'Yellow Note',
113
- body: 'This is a yellow sticky note! Click to edit me.',
114
- color: 'yellow'
115
- };
116
-
117
- const blueNote = document.getElementById('blue-note');
118
- blueNote.uuid = 'blue-uuid';
119
- blueNote.data = {
120
- position: { left: 300, top: 120 },
121
- title: 'Blue Note',
122
- body: 'Blue notes are cool and calm. Drag me around!',
123
- color: 'blue'
124
- };
125
-
126
- const pinkNote = document.getElementById('pink-note');
127
- pinkNote.uuid = 'pink-uuid';
128
- pinkNote.data = {
129
- position: { left: 550, top: 80 },
130
- title: 'Pink Note',
131
- body: 'Pink is vibrant and fun. Try editing my text!',
132
- color: 'pink'
133
- };
134
-
135
- const greenNote = document.getElementById('green-note');
136
- greenNote.uuid = 'green-uuid';
137
- greenNote.data = {
138
- position: { left: 100, top: 250 },
139
- title: 'Green Note',
140
- body: 'Green represents nature and growth. I can grow in height as you type more content in my body!',
141
- color: 'green'
142
- };
143
-
144
- const grayNote = document.getElementById('gray-note');
145
- grayNote.uuid = 'gray-uuid';
146
- grayNote.data = {
147
- position: { left: 400, top: 300 },
148
- title: 'Gray Note',
149
- body: 'Gray is neutral and professional.',
150
- color: 'gray'
151
- };
152
- });
153
- </script>
154
- </body>
155
- </html>
@@ -1 +0,0 @@
1
- {"version":3,"file":"EditorNode.js","sourceRoot":"","sources":["../../../src/flow/EditorNode.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, PropertyValueMap, TemplateResult } from 'lit';\nimport { EDITOR_CONFIG, UIConfig } from './config';\nimport { Action, Exit, Node, NodeUI, Router } from '../store/flow-definition';\nimport { property } from 'lit/decorators.js';\nimport { RapidElement } from '../RapidElement';\nimport { getClasses } from '../utils';\nimport { Plumber } from './Plumber';\nimport { getStore } from '../store/Store';\nimport { CustomEventType } from '../interfaces';\n\nexport class EditorNode extends RapidElement {\n createRenderRoot() {\n return this;\n }\n\n @property({ type: Object })\n private plumber: Plumber;\n\n @property({ type: Object })\n private node: Node;\n\n @property({ type: Object })\n private ui: NodeUI;\n\n // Track exits that are in \"removing\" state\n private exitRemovalTimeouts: Map<string, number> = new Map();\n\n // Set of exit UUIDs that are in the removing state\n private exitRemovingState: Set<string> = new Set();\n\n // Track actions that are in \"removing\" state\n private actionRemovalTimeouts: Map<string, number> = new Map();\n\n // Set of action UUIDs that are in the removing state\n private actionRemovingState: Set<string> = new Set();\n\n static get styles() {\n return css`\n\n .node {\n background-color: #fff;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);\n min-width: 200px;\n border-radius: var(--curvature);\n \n color: #333;\n cursor: move;\n user-select: none;\n\n }\n\n .node:hover {\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);\n }\n\n .node.dragging {\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.4);\n transform: scale(1.02);\n z-index: 1000;\n }\n\n .action {\n max-width: 200px;\n position: relative;\n }\n\n .action .remove-button {\n position: absolute;\n top: 5px;\n right: 5px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--color-error, #dc3545);\n color: white;\n border: none;\n cursor: pointer;\n display: none;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n line-height: 1;\n z-index: 10;\n }\n\n .action:hover .remove-button {\n display: flex;\n }\n\n .action.removing .title {\n background-color: var(--color-error, #dc3545) !important;\n }\n\n .action.removing .title .name {\n color: white;\n }\n\n .action.sortable {\n display: flex;\n align-items: stretch;\n }\n\n .action .action-content {\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n }\n\n .action .body {\n padding: 1em;\n }\n\n .action .drag-handle {\n opacity: 0;\n transition: all 200ms ease-in-out;\n cursor: move;\n background: rgba(0, 0, 0, 0.02);\n max-width:0px;\n position: absolute;\n }\n\n .action:hover .drag-handle {\n opacity: 0.5;\n padding: 0.25em;\n max-width: 20px;\n }\n\n .action .drag-handle:hover {\n opacity: 1;\n \n }\n\n .action .title,\n .router .title {\n display: flex;\n color: #fff;\n padding: 5px 1px;\n text-align: center;\n font-size: 1em;\n font-weight: normal;\n\n }\n\n .title .name {\n flex-grow: 1;\n }\n\n .quick-replies {\n margin-top: 0.5em;\n }\n\n .quick-reply {\n background-color: #f0f0f0;\n border: 1px solid #e0e0e0;\n border-radius: calc(var(--curvature) * 1.5);\n padding: 0.2em 1em;\n display: inline-block;\n font-size: 0.8em;\n margin: 0.2em;\n }\n\n .categories {\n display: flex;\n flex-direction: row;\n\n }\n\n .category {\n margin:-1px -0.5px;\n border: 1px solid #f3f3f3;\n padding: 0.75em;\n flex-grow:1;\n text-align: center;\n display: flex;\n flex-direction: column;\n }\n\n .action-exits {\n padding-bottom: 0.6em;\n margin-top: -0.8em;\n }\n\n .category .title {\n font-weight: normal;\n font-size: 1em;\n }\n\n .router .body {\n padding: 0.75em;\n }\n\n .result-name {\n font-weight: bold;\n display: inline-block;\n }\n \n .exit-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n position: relative;\n margin-bottom: -1.2em;\n padding-top:0.2em;\n }\n\n .exit {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background-color: tomato;\n position: relative;\n box-shadow: 0 2px 2px rgba(0, 0, 0, .1);\n cursor: pointer;\n pointer-events: none;\n }\n\n .exit.jtk-connected {\n background: var(--color-connectors, #e6e6e6);\n }\n\n .exit.connected {\n background-color: #fff;\n pointer-events: all;\n }\n\n .exit.connected:hover {\n background-color: var(--color-connectors, #e6e6e6);\n }\n \n .exit.removing, .exit.removing:hover {\n background-color: var(--color-error);\n pointer-events: all;\n }\n \n .exit.removing::before {\n content: '✕';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 8px;\n color: white;\n line-height: 1;\n }\n \n /* Connector in removing state */\n :host {\n --color-connector-removing: var(--color-error);\n }\n \n body svg.plumb-connector.removing path {\n stroke: var(--color-connector-removing, tomato) !important;\n stroke-width: 3px;\n }\n \n body .plumb-connector.removing .plumb-arrow {\n fill: var(--color-connector-removing, tomato) !important;\n stroke: var(--color-connector-removing, transparent) !important;\n }\n\n .category:first-child {\n border-bottom-left-radius: var(--curvature);\n }\n\n .category:last-child {\n border-bottom-right-radius: var(--curvature);\n }\n\n .router .title {\n border-top-left-radius: var(--curvature);\n border-top-right-radius: var(--curvature);\n }\n\n .action{\n overflow: hidden;\n }\n\n .action:first-child .title {\n border-top-left-radius: var(--curvature);\n border-top-right-radius: var(--curvature);\n }\n }`;\n }\n\n constructor() {\n super();\n this.handleActionOrderChanged = this.handleActionOrderChanged.bind(this);\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('node')) {\n // make our initial connections\n if (changes.get('node') === undefined) {\n for (const exit of this.node.exits) {\n if (!exit.destination_uuid) {\n this.plumber.makeSource(exit.uuid);\n } else {\n this.plumber.connectIds(\n this.node.uuid,\n exit.uuid,\n exit.destination_uuid\n );\n }\n }\n }\n\n const ele = this.parentElement;\n const rect = ele.getBoundingClientRect();\n\n getStore()\n ?.getState()\n .expandCanvas(\n this.ui.position.left + rect.width,\n this.ui.position.top + rect.height\n );\n }\n }\n\n disconnectedCallback() {\n // Remove the event listener when the component is removed\n super.disconnectedCallback();\n\n // Clear any pending exit removal timeouts\n this.exitRemovalTimeouts.forEach((timeoutId) => {\n clearTimeout(timeoutId);\n });\n this.exitRemovalTimeouts.clear();\n\n // Clear any pending action removal timeouts\n this.actionRemovalTimeouts.forEach((timeoutId) => {\n clearTimeout(timeoutId);\n });\n this.actionRemovalTimeouts.clear();\n\n // Clear the removing state\n this.exitRemovingState.clear();\n this.actionRemovingState.clear();\n }\n\n private handleExitClick(event: MouseEvent, exit: Exit) {\n event.preventDefault();\n event.stopPropagation();\n\n const exitId = exit.uuid;\n\n // If exit is not connected, do nothing\n if (!exit.destination_uuid) return;\n\n // If the exit is already in removing state, perform the disconnect\n if (this.exitRemovingState.has(exitId)) {\n this.disconnectExit(exit);\n return;\n }\n\n // Start removal UI state\n this.exitRemovingState.add(exitId);\n this.requestUpdate();\n\n // Set the connection to removing state\n this.plumber.setConnectionRemovingState(exitId, true);\n\n // Clear any existing timeout for this exit\n if (this.exitRemovalTimeouts.has(exitId)) {\n clearTimeout(this.exitRemovalTimeouts.get(exitId));\n }\n\n // Set timeout to reset UI if user doesn't click\n const timeoutId = window.setTimeout(() => {\n this.exitRemovingState.delete(exitId);\n this.exitRemovalTimeouts.delete(exitId);\n\n // Reset the connection to normal state\n this.plumber.setConnectionRemovingState(exitId, false);\n\n this.requestUpdate();\n }, 1500);\n\n this.exitRemovalTimeouts.set(exitId, timeoutId);\n }\n\n private disconnectExit(exit: Exit) {\n const exitId = exit.uuid;\n\n // Clear the UI state\n this.exitRemovingState.delete(exitId);\n\n // Reset the connection to normal state (this will be redundant as we're about to remove it,\n // but it's safer to do this in case there's any timing issue)\n this.plumber.setConnectionRemovingState(exitId, false);\n\n // Clear any timeout\n if (this.exitRemovalTimeouts.has(exitId)) {\n clearTimeout(this.exitRemovalTimeouts.get(exitId));\n this.exitRemovalTimeouts.delete(exitId);\n }\n\n // Remove the JSPlumb connection\n this.plumber.removeExitConnection(exitId);\n\n // Update the flow definition\n const updatedExit = { ...exit, destination_uuid: null };\n const updatedExits = this.node.exits.map((e) =>\n e.uuid === exitId ? updatedExit : e\n );\n\n // Update the node\n const updatedNode = { ...this.node, exits: updatedExits };\n getStore()?.getState().updateNode(this.node.uuid, updatedNode);\n\n // Request update to reflect changes\n this.requestUpdate();\n }\n\n private handleActionRemoveClick(\n event: MouseEvent,\n action: Action,\n index: number\n ) {\n event.preventDefault();\n event.stopPropagation();\n\n const actionId = action.uuid;\n\n // If the action is already in removing state, perform the removal\n if (this.actionRemovingState.has(actionId)) {\n this.removeAction(action, index);\n return;\n }\n\n // Start removal UI state\n this.actionRemovingState.add(actionId);\n this.requestUpdate();\n\n // Clear any existing timeout for this action\n if (this.actionRemovalTimeouts.has(actionId)) {\n clearTimeout(this.actionRemovalTimeouts.get(actionId));\n }\n\n // Set timeout to reset UI if user doesn't click\n const timeoutId = window.setTimeout(() => {\n this.actionRemovingState.delete(actionId);\n this.actionRemovalTimeouts.delete(actionId);\n this.requestUpdate();\n }, 1000); // 1 second as per requirements\n\n this.actionRemovalTimeouts.set(actionId, timeoutId);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n private removeAction(action: Action, _index: number) {\n const actionId = action.uuid;\n\n // Clear the UI state\n this.actionRemovingState.delete(actionId);\n\n // Clear any timeout\n if (this.actionRemovalTimeouts.has(actionId)) {\n clearTimeout(this.actionRemovalTimeouts.get(actionId));\n this.actionRemovalTimeouts.delete(actionId);\n }\n\n // Remove the action from the node\n const updatedActions = this.node.actions.filter((a) => a.uuid !== actionId);\n\n // If no actions remain, remove the entire node\n if (updatedActions.length === 0) {\n this.fireCustomEvent(CustomEventType.NodeDeleted, {\n uuid: this.node.uuid\n });\n } else {\n // Update the node with remaining actions\n const updatedNode = { ...this.node, actions: updatedActions };\n getStore()?.getState().updateNode(this.node.uuid, updatedNode);\n\n // Request update to reflect changes\n this.requestUpdate();\n }\n }\n\n private handleActionOrderChanged(event: CustomEvent) {\n const [fromIdx, toIdx] = event.detail.swap;\n\n // swap our actions\n const newActions = [...this.node.actions];\n const movedAction = newActions.splice(fromIdx, 1)[0];\n newActions.splice(toIdx, 0, movedAction);\n\n // udate our internal reprensentation, this isn't strictly necessary\n // since the editor will update us from it's definition subscription\n // but it makes testing a lot easier\n this.node = { ...this.node, actions: newActions };\n\n getStore()\n ?.getState()\n .updateNode(this.node.uuid, { ...this.node, actions: newActions });\n }\n\n private renderTitle(config: UIConfig, isRemoving: boolean = false) {\n return html`<div class=\"title\" style=\"background:${config.color}\">\n ${this.node?.actions?.length > 1\n ? html`<temba-icon class=\"drag-handle\" name=\"sort\"></temba-icon>`\n : null}\n\n <div class=\"name\">${isRemoving ? 'Remove?' : config.name}</div>\n </div>`;\n }\n\n private renderAction(node: Node, action: Action, index: number) {\n const config = EDITOR_CONFIG[action.type];\n const isRemoving = this.actionRemovingState.has(action.uuid);\n\n if (config) {\n return html`<div\n class=\"action sortable ${action.type} ${isRemoving ? 'removing' : ''}\"\n id=\"action-${index}\"\n >\n <button\n class=\"remove-button\"\n @click=${(e: MouseEvent) =>\n this.handleActionRemoveClick(e, action, index)}\n title=\"Remove action\"\n >\n ✕\n </button>\n <div class=\"action-content\">\n ${this.renderTitle(config, isRemoving)}\n <div class=\"body\">\n ${config.render\n ? config.render(node, action)\n : html`<pre>${action.type}</pre>`}\n </div>\n </div>\n </div>`;\n }\n return html`<div\n class=\"action sortable ${isRemoving ? 'removing' : ''}\"\n id=\"action-${index}\"\n >\n <button\n class=\"remove-button\"\n @click=${(e: MouseEvent) =>\n this.handleActionRemoveClick(e, action, index)}\n title=\"Remove action\"\n >\n ✕\n </button>\n ${action.type}\n </div>`;\n }\n\n private renderRouter(router: Router, ui: NodeUI) {\n const config = EDITOR_CONFIG[ui.type];\n if (config) {\n return html`<div class=\"router\">\n ${this.renderTitle(config, false)}\n ${router.result_name\n ? html`<div class=\"body\">\n Save as\n <div class=\"result-name\">${router.result_name}</div>\n </div>`\n : null}\n </div>`;\n }\n }\n\n private renderCategories(node: Node) {\n if (!node.router || !node.router.categories) {\n return null;\n }\n const categories = node.router.categories.map((category) => {\n const exit = node.exits.find(\n (exit: Exit) => exit.uuid == category.exit_uuid\n );\n\n return html`<div class=\"category\">\n <div class=\"title\">${category.name}</div>\n ${this.renderExit(exit)}\n </div>`;\n });\n\n return html`<div class=\"categories\">${categories}</div>`;\n }\n\n private renderExit(exit: Exit): TemplateResult {\n return html`<div class=\"exit-wrapper\">\n <div\n id=\"${exit.uuid}\"\n class=${getClasses({\n exit: true,\n connected: !!exit.destination_uuid,\n removing: this.exitRemovingState.has(exit.uuid)\n })}\n @click=${(e: MouseEvent) => this.handleExitClick(e, exit)}\n ></div>\n </div>`;\n }\n\n public render() {\n if (!this.node || !this.ui) {\n return html`<div class=\"node\">Loading...</div>`;\n }\n\n return html`\n <div\n id=\"${this.node.uuid}\"\n class=\"node\"\n style=\"left:${this.ui.position.left}px;top:${this.ui.position.top}px\"\n >\n ${this.node.actions.length > 0\n ? html`<temba-sortable-list\n dragHandle=\"drag-handle\"\n @temba-order-changed=\"${this.handleActionOrderChanged}\"\n >\n ${this.node.actions.map((actionSpec, index) => {\n return this.renderAction(this.node, actionSpec, index);\n })}\n </temba-sortable-list>`\n : ''}\n ${this.node.router\n ? html` ${this.renderRouter(this.node.router, this.ui)}\n ${this.renderCategories(this.node)}`\n : html`<div class=\"action-exits\">\n ${this.node.exits.map((exit) => {\n return this.renderExit(exit);\n })}\n </div>`}\n </div>\n `;\n }\n}\n"]}