@nyaruka/temba-components 0.129.10 → 0.129.11

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 (243) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/demo/data/flows/sample-flow.json +96 -56
  3. package/dist/temba-components.js +278 -268
  4. package/dist/temba-components.js.map +1 -1
  5. package/out-tsc/src/events.js.map +1 -1
  6. package/out-tsc/src/flow/Editor.js +9 -6
  7. package/out-tsc/src/flow/Editor.js.map +1 -1
  8. package/out-tsc/src/flow/actions/set_contact_channel.js +1 -1
  9. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  10. package/out-tsc/src/flow/actions/set_contact_field.js +1 -1
  11. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  12. package/out-tsc/src/flow/actions/set_contact_language.js +1 -1
  13. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  14. package/out-tsc/src/flow/actions/set_contact_status.js +1 -1
  15. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  16. package/out-tsc/src/flow/config.js +2 -8
  17. package/out-tsc/src/flow/config.js.map +1 -1
  18. package/out-tsc/src/flow/nodes/split_by_llm.js +101 -0
  19. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -0
  20. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +4 -89
  21. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  22. package/out-tsc/src/flow/nodes/split_by_subflow.js +123 -3
  23. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  24. package/out-tsc/src/flow/nodes/split_by_ticket.js +115 -13
  25. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  26. package/out-tsc/src/flow/nodes/split_by_webhook.js +160 -12
  27. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  28. package/out-tsc/src/live/ContactChat.js +48 -66
  29. package/out-tsc/src/live/ContactChat.js.map +1 -1
  30. package/out-tsc/src/utils.js +115 -0
  31. package/out-tsc/src/utils.js.map +1 -1
  32. package/out-tsc/test/nodes/split_by_llm.test.js +174 -0
  33. package/out-tsc/test/nodes/split_by_llm.test.js.map +1 -0
  34. package/package.json +1 -1
  35. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  36. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  37. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  38. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  39. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  40. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  41. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  42. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  43. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  44. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  45. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  46. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  47. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  48. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  49. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  50. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  51. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  52. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  53. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  54. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  55. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  56. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  57. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  58. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  59. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  60. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  61. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  62. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  63. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  64. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  65. package/screenshots/truth/checkbox/checkbox-label-background-hover.png +0 -0
  66. package/screenshots/truth/checkbox/checkbox-no-label-no-background-hover.png +0 -0
  67. package/screenshots/truth/checkbox/checkbox-whitespace-label-no-background-hover.png +0 -0
  68. package/screenshots/truth/checkbox/checkbox-with-help-text.png +0 -0
  69. package/screenshots/truth/checkbox/checked.png +0 -0
  70. package/screenshots/truth/checkbox/default.png +0 -0
  71. package/screenshots/truth/colorpicker/default.png +0 -0
  72. package/screenshots/truth/colorpicker/focused.png +0 -0
  73. package/screenshots/truth/colorpicker/initialized.png +0 -0
  74. package/screenshots/truth/colorpicker/selected.png +0 -0
  75. package/screenshots/truth/compose/attachments-tab.png +0 -0
  76. package/screenshots/truth/compose/attachments-with-files.png +0 -0
  77. package/screenshots/truth/compose/intial-text.png +0 -0
  78. package/screenshots/truth/compose/no-counter.png +0 -0
  79. package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
  80. package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
  81. package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
  82. package/screenshots/truth/contacts/chat-failure.png +0 -0
  83. package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
  84. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  85. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  86. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  87. package/screenshots/truth/counter/summary.png +0 -0
  88. package/screenshots/truth/counter/text.png +0 -0
  89. package/screenshots/truth/counter/unicode-variables.png +0 -0
  90. package/screenshots/truth/counter/unicode.png +0 -0
  91. package/screenshots/truth/counter/variable.png +0 -0
  92. package/screenshots/truth/datepicker/date-truncated-time.png +0 -0
  93. package/screenshots/truth/datepicker/date.png +0 -0
  94. package/screenshots/truth/datepicker/initial-timezone.png +0 -0
  95. package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
  96. package/screenshots/truth/datepicker/updated-keyboard-date.png +0 -0
  97. package/screenshots/truth/dialog/focused.png +0 -0
  98. package/screenshots/truth/dropdown/right-edge-collision.png +0 -0
  99. package/screenshots/truth/editor/router.png +0 -0
  100. package/screenshots/truth/editor/send_msg.png +0 -0
  101. package/screenshots/truth/editor/set_contact_language.png +0 -0
  102. package/screenshots/truth/editor/set_contact_name.png +0 -0
  103. package/screenshots/truth/editor/set_run_result.png +0 -0
  104. package/screenshots/truth/editor/wait.png +0 -0
  105. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  106. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  107. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  108. package/screenshots/truth/field-renderer/context-comparison.png +0 -0
  109. package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
  110. package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
  111. package/screenshots/truth/field-renderer/select-multi.png +0 -0
  112. package/screenshots/truth/field-renderer/select-no-label.png +0 -0
  113. package/screenshots/truth/field-renderer/select-with-label.png +0 -0
  114. package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
  115. package/screenshots/truth/field-renderer/text-no-label.png +0 -0
  116. package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
  117. package/screenshots/truth/field-renderer/text-with-label.png +0 -0
  118. package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
  119. package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
  120. package/screenshots/truth/integration/checkbox-markdown-errors.png +0 -0
  121. package/screenshots/truth/list/fields-dragging.png +0 -0
  122. package/screenshots/truth/list/fields-filtered.png +0 -0
  123. package/screenshots/truth/list/fields-hovered.png +0 -0
  124. package/screenshots/truth/list/fields.png +0 -0
  125. package/screenshots/truth/list/items-selected.png +0 -0
  126. package/screenshots/truth/list/items-updated.png +0 -0
  127. package/screenshots/truth/list/items.png +0 -0
  128. package/screenshots/truth/menu/menu-focused-with items.png +0 -0
  129. package/screenshots/truth/menu/menu-refresh-1.png +0 -0
  130. package/screenshots/truth/menu/menu-refresh-2.png +0 -0
  131. package/screenshots/truth/menu/menu-submenu.png +0 -0
  132. package/screenshots/truth/menu/menu-tasks-nextup.png +0 -0
  133. package/screenshots/truth/menu/menu-tasks.png +0 -0
  134. package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
  135. package/screenshots/truth/message-editor/default.png +0 -0
  136. package/screenshots/truth/message-editor/drag-highlight.png +0 -0
  137. package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
  138. package/screenshots/truth/message-editor/with-completion.png +0 -0
  139. package/screenshots/truth/message-editor/with-properties.png +0 -0
  140. package/screenshots/truth/modax/form.png +0 -0
  141. package/screenshots/truth/modax/simple.png +0 -0
  142. package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
  143. package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
  144. package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
  145. package/screenshots/truth/nodes/split_by_llm/editor/translation-task.png +0 -0
  146. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  147. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  148. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  149. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  150. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  151. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  152. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  153. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  154. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  155. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  156. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  157. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  158. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  159. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  160. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  161. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  162. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  163. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  164. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  165. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  166. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  167. package/screenshots/truth/omnibox/selected.png +0 -0
  168. package/screenshots/truth/options/block.png +0 -0
  169. package/screenshots/truth/run-list/basic.png +0 -0
  170. package/screenshots/truth/select/disabled-multi-selection.png +0 -0
  171. package/screenshots/truth/select/disabled-selection.png +0 -0
  172. package/screenshots/truth/select/disabled.png +0 -0
  173. package/screenshots/truth/select/embedded.png +0 -0
  174. package/screenshots/truth/select/empty-options.png +0 -0
  175. package/screenshots/truth/select/expression-selected.png +0 -0
  176. package/screenshots/truth/select/expressions.png +0 -0
  177. package/screenshots/truth/select/functions.png +0 -0
  178. package/screenshots/truth/select/local-options.png +0 -0
  179. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  180. package/screenshots/truth/select/multiple-initial-values.png +0 -0
  181. package/screenshots/truth/select/remote-options.png +0 -0
  182. package/screenshots/truth/select/search-enabled.png +0 -0
  183. package/screenshots/truth/select/search-multi-no-matches.png +0 -0
  184. package/screenshots/truth/select/search-selected-focus.png +0 -0
  185. package/screenshots/truth/select/search-selected.png +0 -0
  186. package/screenshots/truth/select/search-with-selected.png +0 -0
  187. package/screenshots/truth/select/searching.png +0 -0
  188. package/screenshots/truth/select/selected-multi-maxitems-reached.png +0 -0
  189. package/screenshots/truth/select/selected-multi.png +0 -0
  190. package/screenshots/truth/select/selected-single.png +0 -0
  191. package/screenshots/truth/select/selection-clearable.png +0 -0
  192. package/screenshots/truth/select/static-initial-value.png +0 -0
  193. package/screenshots/truth/select/static-initial-via-selected.png +0 -0
  194. package/screenshots/truth/select/truncated-selection.png +0 -0
  195. package/screenshots/truth/select/with-placeholder.png +0 -0
  196. package/screenshots/truth/select/without-placeholder.png +0 -0
  197. package/screenshots/truth/slider/update-slider-on-circle-dragged.png +0 -0
  198. package/screenshots/truth/templates/default.png +0 -0
  199. package/screenshots/truth/templates/unapproved.png +0 -0
  200. package/screenshots/truth/textinput/autogrow-initial.png +0 -0
  201. package/screenshots/truth/textinput/input-disabled.png +0 -0
  202. package/screenshots/truth/textinput/input-focused.png +0 -0
  203. package/screenshots/truth/textinput/input-form.png +0 -0
  204. package/screenshots/truth/textinput/input-inserted.png +0 -0
  205. package/screenshots/truth/textinput/input-placeholder.png +0 -0
  206. package/screenshots/truth/textinput/input-updated.png +0 -0
  207. package/screenshots/truth/textinput/input.png +0 -0
  208. package/screenshots/truth/textinput/textarea-focused.png +0 -0
  209. package/screenshots/truth/textinput/textarea.png +0 -0
  210. package/src/events.ts +4 -2
  211. package/src/flow/Editor.ts +6 -3
  212. package/src/flow/actions/set_contact_channel.ts +1 -1
  213. package/src/flow/actions/set_contact_field.ts +1 -1
  214. package/src/flow/actions/set_contact_language.ts +1 -1
  215. package/src/flow/actions/set_contact_status.ts +1 -1
  216. package/src/flow/config.ts +2 -8
  217. package/src/flow/nodes/split_by_llm.ts +119 -0
  218. package/src/flow/nodes/split_by_llm_categorize.ts +13 -116
  219. package/src/flow/nodes/split_by_subflow.ts +153 -3
  220. package/src/flow/nodes/split_by_ticket.ts +135 -12
  221. package/src/flow/nodes/split_by_webhook.ts +187 -12
  222. package/src/live/ContactChat.ts +56 -58
  223. package/src/store/flow-definition.d.ts +2 -1
  224. package/src/utils.ts +192 -0
  225. package/test/nodes/split_by_llm.test.ts +232 -0
  226. package/test-assets/style.css +36 -234
  227. package/web-dev-server.config.mjs +26 -0
  228. package/web-test-runner.config.mjs +1 -1
  229. package/out-tsc/src/flow/actions/call_llm.js +0 -64
  230. package/out-tsc/src/flow/actions/call_llm.js.map +0 -1
  231. package/out-tsc/src/flow/actions/call_webhook.js +0 -131
  232. package/out-tsc/src/flow/actions/call_webhook.js.map +0 -1
  233. package/out-tsc/src/flow/actions/enter_flow.js +0 -14
  234. package/out-tsc/src/flow/actions/enter_flow.js.map +0 -1
  235. package/out-tsc/src/flow/actions/open_ticket.js +0 -73
  236. package/out-tsc/src/flow/actions/open_ticket.js.map +0 -1
  237. package/out-tsc/test/actions/call_llm.test.js +0 -103
  238. package/out-tsc/test/actions/call_llm.test.js.map +0 -1
  239. package/src/flow/actions/call_llm.ts +0 -66
  240. package/src/flow/actions/call_webhook.ts +0 -143
  241. package/src/flow/actions/enter_flow.ts +0 -15
  242. package/src/flow/actions/open_ticket.ts +0 -83
  243. package/test/actions/call_llm.test.ts +0 -137
@@ -0,0 +1,101 @@
1
+ import { COLORS } from '../types';
2
+ import { generateUUID, createSuccessFailureRouter } from '../../utils';
3
+ import { html } from 'lit';
4
+ export const split_by_llm = {
5
+ type: 'split_by_llm',
6
+ name: 'Call AI',
7
+ color: COLORS.call,
8
+ form: {
9
+ llm: {
10
+ type: 'select',
11
+ label: 'LLM',
12
+ required: true,
13
+ options: [],
14
+ endpoint: '/test-assets/select/llms.json',
15
+ searchable: true,
16
+ valueKey: 'uuid',
17
+ nameKey: 'name',
18
+ placeholder: 'Select an LLM...'
19
+ },
20
+ input: {
21
+ type: 'text',
22
+ label: 'Input',
23
+ helpText: 'The input the AI will process',
24
+ required: true,
25
+ evaluated: true,
26
+ placeholder: '@input'
27
+ },
28
+ instructions: {
29
+ type: 'textarea',
30
+ label: 'Instructions',
31
+ helpText: 'Tell the AI what to do with the input. The result can be referenced as **`@locals._llm_output`**',
32
+ required: true,
33
+ evaluated: true,
34
+ placeholder: 'Enter instructions for the AI model...',
35
+ minHeight: 130
36
+ }
37
+ },
38
+ layout: ['llm', 'input', 'instructions'],
39
+ render: (node) => {
40
+ var _a;
41
+ const callLlmAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
42
+ return html `
43
+ <div
44
+ class="body"
45
+ style="word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; max-width: 180px; max-height: 90px; margin-bottom:10px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;"
46
+ >
47
+ ${(callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.instructions) || 'Configure AI instructions'}
48
+ </div>
49
+ `;
50
+ },
51
+ toFormData: (node) => {
52
+ var _a;
53
+ // Extract data from the existing node structure
54
+ const callLlmAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
55
+ return {
56
+ uuid: node.uuid,
57
+ llm: (callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.llm)
58
+ ? [{ value: callLlmAction.llm.uuid, name: callLlmAction.llm.name }]
59
+ : [],
60
+ input: (callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.input) || '@input',
61
+ instructions: (callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.instructions) || ''
62
+ };
63
+ },
64
+ fromFormData: (formData, originalNode) => {
65
+ var _a, _b, _c;
66
+ // Get LLM selection
67
+ const llmSelection = Array.isArray(formData.llm) && formData.llm.length > 0
68
+ ? formData.llm[0]
69
+ : null;
70
+ // Find existing call_llm action to preserve its UUID
71
+ const existingCallLlmAction = (_a = originalNode.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
72
+ const callLlmUuid = (existingCallLlmAction === null || existingCallLlmAction === void 0 ? void 0 : existingCallLlmAction.uuid) || generateUUID();
73
+ // Create call_llm action
74
+ const callLlmAction = {
75
+ type: 'call_llm',
76
+ uuid: callLlmUuid,
77
+ llm: llmSelection
78
+ ? { uuid: llmSelection.value, name: llmSelection.name }
79
+ : { uuid: '', name: '' },
80
+ input: formData.input || '@input',
81
+ instructions: formData.instructions || '',
82
+ output_local: '_llm_output'
83
+ };
84
+ // Create categories and exits for Success and Failure
85
+ const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
86
+ const existingExits = originalNode.exits || [];
87
+ const existingCases = ((_c = originalNode.router) === null || _c === void 0 ? void 0 : _c.cases) || [];
88
+ const { router, exits } = createSuccessFailureRouter('@locals._llm_output', {
89
+ type: 'has_text',
90
+ arguments: []
91
+ }, existingCategories, existingExits, existingCases);
92
+ // Return the complete node
93
+ return {
94
+ uuid: originalNode.uuid,
95
+ actions: [callLlmAction],
96
+ router: router,
97
+ exits: exits
98
+ };
99
+ }
100
+ };
101
+ //# sourceMappingURL=split_by_llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split_by_llm.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_llm.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { CallLLM, Node } from '../../store/flow-definition';\nimport { generateUUID, createSuccessFailureRouter } from '../../utils';\nimport { html } from 'lit';\n\nexport const split_by_llm: NodeConfig = {\n type: 'split_by_llm',\n name: 'Call AI',\n color: COLORS.call,\n form: {\n llm: {\n type: 'select',\n label: 'LLM',\n required: true,\n options: [],\n endpoint: '/test-assets/select/llms.json',\n searchable: true,\n valueKey: 'uuid',\n nameKey: 'name',\n placeholder: 'Select an LLM...'\n },\n input: {\n type: 'text',\n label: 'Input',\n helpText: 'The input the AI will process',\n required: true,\n evaluated: true,\n placeholder: '@input'\n },\n instructions: {\n type: 'textarea',\n label: 'Instructions',\n helpText:\n 'Tell the AI what to do with the input. The result can be referenced as **`@locals._llm_output`**',\n required: true,\n evaluated: true,\n placeholder: 'Enter instructions for the AI model...',\n minHeight: 130\n }\n },\n layout: ['llm', 'input', 'instructions'],\n render: (node: Node) => {\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as CallLLM;\n return html`\n <div\n class=\"body\"\n style=\"word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; max-width: 180px; max-height: 90px; margin-bottom:10px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;\"\n >\n ${callLlmAction?.instructions || 'Configure AI instructions'}\n </div>\n `;\n },\n toFormData: (node: Node) => {\n // Extract data from the existing node structure\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as CallLLM;\n\n return {\n uuid: node.uuid,\n llm: callLlmAction?.llm\n ? [{ value: callLlmAction.llm.uuid, name: callLlmAction.llm.name }]\n : [],\n input: callLlmAction?.input || '@input',\n instructions: callLlmAction?.instructions || ''\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get LLM selection\n const llmSelection =\n Array.isArray(formData.llm) && formData.llm.length > 0\n ? formData.llm[0]\n : null;\n\n // Find existing call_llm action to preserve its UUID\n const existingCallLlmAction = originalNode.actions?.find(\n (action) => action.type === 'call_llm'\n );\n const callLlmUuid = existingCallLlmAction?.uuid || generateUUID();\n\n // Create call_llm action\n const callLlmAction: CallLLM = {\n type: 'call_llm',\n uuid: callLlmUuid,\n llm: llmSelection\n ? { uuid: llmSelection.value, name: llmSelection.name }\n : { uuid: '', name: '' },\n input: formData.input || '@input',\n instructions: formData.instructions || '',\n output_local: '_llm_output'\n };\n\n // Create categories and exits for Success and Failure\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n const { router, exits } = createSuccessFailureRouter(\n '@locals._llm_output',\n {\n type: 'has_text',\n arguments: []\n },\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: [callLlmAction],\n router: router,\n exits: exits\n };\n }\n};\n"]}
@@ -1,5 +1,5 @@
1
1
  import { COLORS } from '../types';
2
- import { generateUUID } from '../../utils';
2
+ import { generateUUID, createMultiCategoryRouter } from '../../utils';
3
3
  import { html } from 'lit';
4
4
  export const split_by_llm_categorize = {
5
5
  type: 'split_by_llm_categorize',
@@ -123,98 +123,13 @@ export const split_by_llm_categorize = {
123
123
  output_local: '_llm_output'
124
124
  };
125
125
  // Create categories and exits
126
- const categories = [];
127
- const exits = [];
128
- const cases = [];
129
- // Get existing categories from original node for UUID preservation
130
126
  const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
131
127
  const existingExits = originalNode.exits || [];
132
128
  const existingCases = ((_c = originalNode.router) === null || _c === void 0 ? void 0 : _c.cases) || [];
133
- // Add user categories
134
- userCategories.forEach((categoryName) => {
135
- // Check if this category already exists
136
- const existingCategory = existingCategories.find((cat) => cat.name === categoryName);
137
- const existingExit = existingCategory
138
- ? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
139
- : null;
140
- const existingCase = existingCategory
141
- ? existingCases.find((case_) => case_.category_uuid === existingCategory.uuid)
142
- : null;
143
- // Use existing UUIDs if category name hasn't changed, otherwise generate new ones
144
- const categoryUuid = (existingCategory === null || existingCategory === void 0 ? void 0 : existingCategory.uuid) || generateUUID();
145
- const exitUuid = (existingExit === null || existingExit === void 0 ? void 0 : existingExit.uuid) || generateUUID();
146
- const caseUuid = (existingCase === null || existingCase === void 0 ? void 0 : existingCase.uuid) || generateUUID();
147
- categories.push({
148
- uuid: categoryUuid,
149
- name: categoryName,
150
- exit_uuid: exitUuid
151
- });
152
- exits.push({
153
- uuid: exitUuid,
154
- destination_uuid: (existingExit === null || existingExit === void 0 ? void 0 : existingExit.destination_uuid) || null
155
- });
156
- cases.push({
157
- uuid: caseUuid,
158
- type: 'has_only_text',
159
- arguments: [categoryName],
160
- category_uuid: categoryUuid
161
- });
162
- });
163
- // Add "Other" category (default)
164
- const existingOtherCategory = existingCategories.find((cat) => cat.name === 'Other');
165
- const existingOtherExit = existingOtherCategory
166
- ? existingExits.find((exit) => exit.uuid === existingOtherCategory.exit_uuid)
167
- : null;
168
- const otherCategoryUuid = (existingOtherCategory === null || existingOtherCategory === void 0 ? void 0 : existingOtherCategory.uuid) || generateUUID();
169
- const otherExitUuid = (existingOtherExit === null || existingOtherExit === void 0 ? void 0 : existingOtherExit.uuid) || generateUUID();
170
- categories.push({
171
- uuid: otherCategoryUuid,
172
- name: 'Other',
173
- exit_uuid: otherExitUuid
174
- });
175
- exits.push({
176
- uuid: otherExitUuid,
177
- destination_uuid: (existingOtherExit === null || existingOtherExit === void 0 ? void 0 : existingOtherExit.destination_uuid) || null
178
- });
179
- // Add "Failure" category
180
- const existingFailureCategory = existingCategories.find((cat) => cat.name === 'Failure');
181
- const existingFailureExit = existingFailureCategory
182
- ? existingExits.find((exit) => exit.uuid === existingFailureCategory.exit_uuid)
183
- : null;
184
- const existingFailureCase = existingFailureCategory
185
- ? existingCases.find((case_) => {
186
- var _a;
187
- return case_.category_uuid === existingFailureCategory.uuid &&
188
- ((_a = case_.arguments) === null || _a === void 0 ? void 0 : _a[0]) === '<ERROR>';
189
- })
190
- : null;
191
- const failureCategoryUuid = (existingFailureCategory === null || existingFailureCategory === void 0 ? void 0 : existingFailureCategory.uuid) || generateUUID();
192
- const failureExitUuid = (existingFailureExit === null || existingFailureExit === void 0 ? void 0 : existingFailureExit.uuid) || generateUUID();
193
- const failureCaseUuid = (existingFailureCase === null || existingFailureCase === void 0 ? void 0 : existingFailureCase.uuid) || generateUUID();
194
- categories.push({
195
- uuid: failureCategoryUuid,
196
- name: 'Failure',
197
- exit_uuid: failureExitUuid
198
- });
199
- exits.push({
200
- uuid: failureExitUuid,
201
- destination_uuid: (existingFailureExit === null || existingFailureExit === void 0 ? void 0 : existingFailureExit.destination_uuid) || null
202
- });
203
- // Add failure case for <ERROR>
204
- cases.push({
205
- uuid: failureCaseUuid,
129
+ const { router, exits } = createMultiCategoryRouter('@locals._llm_output', userCategories, (categoryName) => ({
206
130
  type: 'has_only_text',
207
- arguments: ['<ERROR>'],
208
- category_uuid: failureCategoryUuid
209
- });
210
- // Create the router
211
- const router = {
212
- type: 'switch',
213
- categories: categories,
214
- default_category_uuid: otherCategoryUuid,
215
- operand: '@locals._llm_output',
216
- cases: cases
217
- };
131
+ arguments: [categoryName]
132
+ }), existingCategories, existingExits, existingCases);
218
133
  // Return the complete node
219
134
  return {
220
135
  uuid: originalNode.uuid,
@@ -1 +1 @@
1
- {"version":3,"file":"split_by_llm_categorize.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_llm_categorize.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node } from '../../store/flow-definition';\nimport { generateUUID } from '../../utils';\nimport { html } from 'lit';\n\nexport const split_by_llm_categorize: NodeConfig = {\n type: 'split_by_llm_categorize',\n name: 'Split by AI',\n color: COLORS.call,\n form: {\n llm: {\n type: 'select',\n label: 'LLM',\n helpText: 'Select the LLM to use for categorization',\n required: true,\n endpoint: '/test-assets/select/llms.json',\n valueKey: 'uuid',\n nameKey: 'name',\n placeholder: 'Select an LLM...'\n },\n input: {\n type: 'text',\n label: 'Input',\n helpText: 'The input to categorize (usually @input)',\n required: true,\n evaluated: true,\n placeholder: '@input'\n },\n categories: {\n type: 'array',\n label: 'Categories',\n helpText: 'Define the categories for classification',\n required: true,\n itemLabel: 'Category',\n minItems: 1,\n maxItems: 10,\n isEmptyItem: (item: any) => {\n return !item.name || item.name.trim() === '';\n },\n itemConfig: {\n name: {\n type: 'text',\n placeholder: 'Category name',\n required: true\n }\n }\n }\n },\n layout: ['llm', 'input', 'categories'],\n validate: (formData: any) => {\n const errors: { [key: string]: string } = {};\n\n // Check for duplicate category names\n if (formData.categories && Array.isArray(formData.categories)) {\n const categories = formData.categories.filter(\n (item: any) => item?.name && item.name.trim() !== ''\n );\n\n // Find all categories that have duplicates (case-insensitive)\n const duplicateCategories = [];\n const lowerCaseMap = new Map();\n\n // First pass: map lowercase names to all original cases\n categories.forEach((category) => {\n const lowerName = category.name.trim().toLowerCase();\n if (!lowerCaseMap.has(lowerName)) {\n lowerCaseMap.set(lowerName, []);\n }\n lowerCaseMap.get(lowerName).push(category.name.trim());\n });\n\n // Second pass: collect all names that appear more than once\n lowerCaseMap.forEach((originalNames) => {\n if (originalNames.length > 1) {\n duplicateCategories.push(...originalNames);\n }\n });\n\n if (duplicateCategories.length > 0) {\n const uniqueDuplicates = [...new Set(duplicateCategories)];\n errors.categories = `Duplicate category names found: ${uniqueDuplicates.join(\n ', '\n )}`;\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n render: (node: Node) => {\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as any;\n return html`\n <div class=\"body\">Categorize with ${callLlmAction.llm.name}</div>\n `;\n },\n toFormData: (node: Node) => {\n // Extract data from the existing node structure\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as any;\n const categories =\n node.router?.categories\n ?.filter((cat) => cat.name !== 'Other' && cat.name !== 'Failure')\n .map((cat) => ({ name: cat.name })) || [];\n\n return {\n uuid: node.uuid,\n llm: callLlmAction?.llm\n ? [{ value: callLlmAction.llm.uuid, name: callLlmAction.llm.name }]\n : [],\n input: callLlmAction?.input || '@input',\n categories: categories\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get LLM selection\n const llmSelection =\n Array.isArray(formData.llm) && formData.llm.length > 0\n ? formData.llm[0]\n : null;\n\n // Get user categories\n const userCategories = (formData.categories || [])\n .filter((item: any) => item?.name?.trim())\n .map((item: any) => item.name.trim());\n\n // Find existing call_llm action to preserve its UUID\n const existingCallLlmAction = originalNode.actions?.find(\n (action) => action.type === 'call_llm'\n );\n const callLlmUuid = existingCallLlmAction?.uuid || generateUUID();\n\n // Create call_llm action (using any type to match the example format)\n const callLlmAction: any = {\n type: 'call_llm',\n uuid: callLlmUuid,\n llm: llmSelection\n ? { uuid: llmSelection.value, name: llmSelection.name }\n : { uuid: '', name: '' },\n instructions: `@(prompt(\"categorize\", slice(node.categories, 0, -2)))`,\n input: formData.input || '@input',\n output_local: '_llm_output'\n };\n\n // Create categories and exits\n const categories = [];\n const exits = [];\n const cases = [];\n\n // Get existing categories from original node for UUID preservation\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n // Add user categories\n userCategories.forEach((categoryName: string) => {\n // Check if this category already exists\n const existingCategory = existingCategories.find(\n (cat) => cat.name === categoryName\n );\n const existingExit = existingCategory\n ? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)\n : null;\n const existingCase = existingCategory\n ? existingCases.find(\n (case_) => case_.category_uuid === existingCategory.uuid\n )\n : null;\n\n // Use existing UUIDs if category name hasn't changed, otherwise generate new ones\n const categoryUuid = existingCategory?.uuid || generateUUID();\n const exitUuid = existingExit?.uuid || generateUUID();\n const caseUuid = existingCase?.uuid || generateUUID();\n\n categories.push({\n uuid: categoryUuid,\n name: categoryName,\n exit_uuid: exitUuid\n });\n\n exits.push({\n uuid: exitUuid,\n destination_uuid: existingExit?.destination_uuid || null\n });\n\n cases.push({\n uuid: caseUuid,\n type: 'has_only_text',\n arguments: [categoryName],\n category_uuid: categoryUuid\n });\n });\n\n // Add \"Other\" category (default)\n const existingOtherCategory = existingCategories.find(\n (cat) => cat.name === 'Other'\n );\n const existingOtherExit = existingOtherCategory\n ? existingExits.find(\n (exit) => exit.uuid === existingOtherCategory.exit_uuid\n )\n : null;\n\n const otherCategoryUuid = existingOtherCategory?.uuid || generateUUID();\n const otherExitUuid = existingOtherExit?.uuid || generateUUID();\n\n categories.push({\n uuid: otherCategoryUuid,\n name: 'Other',\n exit_uuid: otherExitUuid\n });\n exits.push({\n uuid: otherExitUuid,\n destination_uuid: existingOtherExit?.destination_uuid || null\n });\n\n // Add \"Failure\" category\n const existingFailureCategory = existingCategories.find(\n (cat) => cat.name === 'Failure'\n );\n const existingFailureExit = existingFailureCategory\n ? existingExits.find(\n (exit) => exit.uuid === existingFailureCategory.exit_uuid\n )\n : null;\n const existingFailureCase = existingFailureCategory\n ? existingCases.find(\n (case_) =>\n case_.category_uuid === existingFailureCategory.uuid &&\n case_.arguments?.[0] === '<ERROR>'\n )\n : null;\n\n const failureCategoryUuid = existingFailureCategory?.uuid || generateUUID();\n const failureExitUuid = existingFailureExit?.uuid || generateUUID();\n const failureCaseUuid = existingFailureCase?.uuid || generateUUID();\n\n categories.push({\n uuid: failureCategoryUuid,\n name: 'Failure',\n exit_uuid: failureExitUuid\n });\n exits.push({\n uuid: failureExitUuid,\n destination_uuid: existingFailureExit?.destination_uuid || null\n });\n\n // Add failure case for <ERROR>\n cases.push({\n uuid: failureCaseUuid,\n type: 'has_only_text',\n arguments: ['<ERROR>'],\n category_uuid: failureCategoryUuid\n });\n\n // Create the router\n const router = {\n type: 'switch' as const,\n categories: categories,\n default_category_uuid: otherCategoryUuid,\n operand: '@locals._llm_output',\n cases: cases\n };\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: [callLlmAction],\n router: router,\n exits: exits\n };\n }\n};\n"]}
1
+ {"version":3,"file":"split_by_llm_categorize.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_llm_categorize.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { CallLLM, Node } from '../../store/flow-definition';\nimport { generateUUID, createMultiCategoryRouter } from '../../utils';\nimport { html } from 'lit';\n\nexport const split_by_llm_categorize: NodeConfig = {\n type: 'split_by_llm_categorize',\n name: 'Split by AI',\n color: COLORS.call,\n form: {\n llm: {\n type: 'select',\n label: 'LLM',\n helpText: 'Select the LLM to use for categorization',\n required: true,\n endpoint: '/test-assets/select/llms.json',\n valueKey: 'uuid',\n nameKey: 'name',\n placeholder: 'Select an LLM...'\n },\n input: {\n type: 'text',\n label: 'Input',\n helpText: 'The input to categorize (usually @input)',\n required: true,\n evaluated: true,\n placeholder: '@input'\n },\n categories: {\n type: 'array',\n label: 'Categories',\n helpText: 'Define the categories for classification',\n required: true,\n itemLabel: 'Category',\n minItems: 1,\n maxItems: 10,\n isEmptyItem: (item: any) => {\n return !item.name || item.name.trim() === '';\n },\n itemConfig: {\n name: {\n type: 'text',\n placeholder: 'Category name',\n required: true\n }\n }\n }\n },\n layout: ['llm', 'input', 'categories'],\n validate: (formData: any) => {\n const errors: { [key: string]: string } = {};\n\n // Check for duplicate category names\n if (formData.categories && Array.isArray(formData.categories)) {\n const categories = formData.categories.filter(\n (item: any) => item?.name && item.name.trim() !== ''\n );\n\n // Find all categories that have duplicates (case-insensitive)\n const duplicateCategories = [];\n const lowerCaseMap = new Map();\n\n // First pass: map lowercase names to all original cases\n categories.forEach((category) => {\n const lowerName = category.name.trim().toLowerCase();\n if (!lowerCaseMap.has(lowerName)) {\n lowerCaseMap.set(lowerName, []);\n }\n lowerCaseMap.get(lowerName).push(category.name.trim());\n });\n\n // Second pass: collect all names that appear more than once\n lowerCaseMap.forEach((originalNames) => {\n if (originalNames.length > 1) {\n duplicateCategories.push(...originalNames);\n }\n });\n\n if (duplicateCategories.length > 0) {\n const uniqueDuplicates = [...new Set(duplicateCategories)];\n errors.categories = `Duplicate category names found: ${uniqueDuplicates.join(\n ', '\n )}`;\n }\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors\n };\n },\n render: (node: Node) => {\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as CallLLM;\n return html`\n <div class=\"body\">Categorize with ${callLlmAction.llm.name}</div>\n `;\n },\n toFormData: (node: Node) => {\n // Extract data from the existing node structure\n const callLlmAction = node.actions?.find(\n (action) => action.type === 'call_llm'\n ) as any;\n const categories =\n node.router?.categories\n ?.filter((cat) => cat.name !== 'Other' && cat.name !== 'Failure')\n .map((cat) => ({ name: cat.name })) || [];\n\n return {\n uuid: node.uuid,\n llm: callLlmAction?.llm\n ? [{ value: callLlmAction.llm.uuid, name: callLlmAction.llm.name }]\n : [],\n input: callLlmAction?.input || '@input',\n categories: categories\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get LLM selection\n const llmSelection =\n Array.isArray(formData.llm) && formData.llm.length > 0\n ? formData.llm[0]\n : null;\n\n // Get user categories\n const userCategories = (formData.categories || [])\n .filter((item: any) => item?.name?.trim())\n .map((item: any) => item.name.trim());\n\n // Find existing call_llm action to preserve its UUID\n const existingCallLlmAction = originalNode.actions?.find(\n (action) => action.type === 'call_llm'\n );\n const callLlmUuid = existingCallLlmAction?.uuid || generateUUID();\n\n // Create call_llm action (using any type to match the example format)\n const callLlmAction: CallLLM = {\n type: 'call_llm',\n uuid: callLlmUuid,\n llm: llmSelection\n ? { uuid: llmSelection.value, name: llmSelection.name }\n : { uuid: '', name: '' },\n instructions: `@(prompt(\"categorize\", slice(node.categories, 0, -2)))`,\n input: formData.input || '@input',\n output_local: '_llm_output'\n };\n\n // Create categories and exits\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n const { router, exits } = createMultiCategoryRouter(\n '@locals._llm_output',\n userCategories,\n (categoryName) => ({\n type: 'has_only_text',\n arguments: [categoryName]\n }),\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: [callLlmAction],\n router: router,\n exits: exits\n };\n }\n};\n"]}
@@ -1,9 +1,129 @@
1
- import { enter_flow } from '../actions/enter_flow';
2
1
  import { COLORS } from '../types';
2
+ import { generateUUID } from '../../utils';
3
+ import { html } from 'lit';
3
4
  export const split_by_subflow = {
4
5
  type: 'split_by_subflow',
5
- name: 'Split by Subflow',
6
+ name: 'Enter a Flow',
6
7
  color: COLORS.execute,
7
- action: enter_flow
8
+ form: {
9
+ flow: {
10
+ type: 'select',
11
+ required: true,
12
+ placeholder: 'Select a flow...',
13
+ helpText: 'Once the subflow is complete or expires, the contact will return here',
14
+ endpoint: '/api/v2/flows.json',
15
+ valueKey: 'uuid',
16
+ nameKey: 'name'
17
+ }
18
+ },
19
+ layout: ['flow'],
20
+ render: (node) => {
21
+ var _a, _b;
22
+ const enterFlowAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'enter_flow');
23
+ return html `
24
+ <div class="body">
25
+ ${((_b = enterFlowAction === null || enterFlowAction === void 0 ? void 0 : enterFlowAction.flow) === null || _b === void 0 ? void 0 : _b.name) || 'Configure subflow'}
26
+ </div>
27
+ `;
28
+ },
29
+ toFormData: (node) => {
30
+ var _a;
31
+ // Extract data from the existing node structure
32
+ const enterFlowAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'enter_flow');
33
+ return {
34
+ uuid: node.uuid,
35
+ flow: (enterFlowAction === null || enterFlowAction === void 0 ? void 0 : enterFlowAction.flow)
36
+ ? [{ uuid: enterFlowAction.flow.uuid, name: enterFlowAction.flow.name }]
37
+ : []
38
+ };
39
+ },
40
+ fromFormData: (formData, originalNode) => {
41
+ var _a, _b, _c;
42
+ // Get flow selection
43
+ const flowSelection = Array.isArray(formData.flow) && formData.flow.length > 0
44
+ ? formData.flow[0]
45
+ : null;
46
+ // Find existing enter_flow action to preserve its UUID
47
+ const existingEnterFlowAction = (_a = originalNode.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'enter_flow');
48
+ const enterFlowUuid = (existingEnterFlowAction === null || existingEnterFlowAction === void 0 ? void 0 : existingEnterFlowAction.uuid) || generateUUID();
49
+ // Create enter_flow action
50
+ const enterFlowAction = {
51
+ type: 'enter_flow',
52
+ uuid: enterFlowUuid,
53
+ flow: flowSelection
54
+ ? {
55
+ uuid: flowSelection.uuid || flowSelection.value,
56
+ name: flowSelection.name
57
+ }
58
+ : { uuid: '', name: '' }
59
+ };
60
+ // Create categories and exits for Complete and Expired
61
+ const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
62
+ const existingExits = originalNode.exits || [];
63
+ const existingCases = ((_c = originalNode.router) === null || _c === void 0 ? void 0 : _c.cases) || [];
64
+ // Find existing Complete category
65
+ const existingCompleteCategory = existingCategories.find((cat) => cat.name === 'Complete');
66
+ const existingCompleteExit = existingCompleteCategory
67
+ ? existingExits.find((exit) => exit.uuid === existingCompleteCategory.exit_uuid)
68
+ : null;
69
+ const existingCompleteCase = existingCompleteCategory
70
+ ? existingCases.find((case_) => case_.category_uuid === existingCompleteCategory.uuid)
71
+ : null;
72
+ const completeCategoryUuid = (existingCompleteCategory === null || existingCompleteCategory === void 0 ? void 0 : existingCompleteCategory.uuid) || generateUUID();
73
+ const completeExitUuid = (existingCompleteExit === null || existingCompleteExit === void 0 ? void 0 : existingCompleteExit.uuid) || generateUUID();
74
+ const completeCaseUuid = (existingCompleteCase === null || existingCompleteCase === void 0 ? void 0 : existingCompleteCase.uuid) || generateUUID();
75
+ // Find existing Expired category
76
+ const existingExpiredCategory = existingCategories.find((cat) => cat.name === 'Expired');
77
+ const existingExpiredExit = existingExpiredCategory
78
+ ? existingExits.find((exit) => exit.uuid === existingExpiredCategory.exit_uuid)
79
+ : null;
80
+ const expiredCategoryUuid = (existingExpiredCategory === null || existingExpiredCategory === void 0 ? void 0 : existingExpiredCategory.uuid) || generateUUID();
81
+ const expiredExitUuid = (existingExpiredExit === null || existingExpiredExit === void 0 ? void 0 : existingExpiredExit.uuid) || generateUUID();
82
+ const categories = [
83
+ {
84
+ uuid: completeCategoryUuid,
85
+ name: 'Complete',
86
+ exit_uuid: completeExitUuid
87
+ },
88
+ {
89
+ uuid: expiredCategoryUuid,
90
+ name: 'Expired',
91
+ exit_uuid: expiredExitUuid
92
+ }
93
+ ];
94
+ const exits = [
95
+ {
96
+ uuid: completeExitUuid,
97
+ destination_uuid: (existingCompleteExit === null || existingCompleteExit === void 0 ? void 0 : existingCompleteExit.destination_uuid) || null
98
+ },
99
+ {
100
+ uuid: expiredExitUuid,
101
+ destination_uuid: (existingExpiredExit === null || existingExpiredExit === void 0 ? void 0 : existingExpiredExit.destination_uuid) || null
102
+ }
103
+ ];
104
+ const cases = [
105
+ {
106
+ uuid: completeCaseUuid,
107
+ type: 'has_only_text',
108
+ arguments: ['completed'],
109
+ category_uuid: completeCategoryUuid
110
+ }
111
+ ];
112
+ // Create the router
113
+ const router = {
114
+ type: 'switch',
115
+ categories: categories,
116
+ default_category_uuid: expiredCategoryUuid,
117
+ operand: '@child.status',
118
+ cases: cases
119
+ };
120
+ // Return the complete node
121
+ return {
122
+ uuid: originalNode.uuid,
123
+ actions: [enterFlowAction],
124
+ router: router,
125
+ exits: exits
126
+ };
127
+ }
8
128
  };
9
129
  //# sourceMappingURL=split_by_subflow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"split_by_subflow.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_subflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAc,MAAM,UAAU,CAAC;AAE9C,MAAM,CAAC,MAAM,gBAAgB,GAAe;IAC1C,IAAI,EAAE,kBAAkB;IACxB,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,MAAM,CAAC,OAAO;IACrB,MAAM,EAAE,UAAU;CACnB,CAAC","sourcesContent":["import { enter_flow } from '../actions/enter_flow';\nimport { COLORS, NodeConfig } from '../types';\n\nexport const split_by_subflow: NodeConfig = {\n type: 'split_by_subflow',\n name: 'Split by Subflow',\n color: COLORS.execute,\n action: enter_flow\n};\n"]}
1
+ {"version":3,"file":"split_by_subflow.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_subflow.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node } from '../../store/flow-definition';\nimport { generateUUID } from '../../utils';\nimport { html } from 'lit';\n\nexport const split_by_subflow: NodeConfig = {\n type: 'split_by_subflow',\n name: 'Enter a Flow',\n color: COLORS.execute,\n form: {\n flow: {\n type: 'select',\n required: true,\n placeholder: 'Select a flow...',\n helpText:\n 'Once the subflow is complete or expires, the contact will return here',\n endpoint: '/api/v2/flows.json',\n valueKey: 'uuid',\n nameKey: 'name'\n }\n },\n layout: ['flow'],\n render: (node: Node) => {\n const enterFlowAction = node.actions?.find(\n (action) => action.type === 'enter_flow'\n ) as any;\n return html`\n <div class=\"body\">\n ${enterFlowAction?.flow?.name || 'Configure subflow'}\n </div>\n `;\n },\n toFormData: (node: Node) => {\n // Extract data from the existing node structure\n const enterFlowAction = node.actions?.find(\n (action) => action.type === 'enter_flow'\n ) as any;\n\n return {\n uuid: node.uuid,\n flow: enterFlowAction?.flow\n ? [{ uuid: enterFlowAction.flow.uuid, name: enterFlowAction.flow.name }]\n : []\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Get flow selection\n const flowSelection =\n Array.isArray(formData.flow) && formData.flow.length > 0\n ? formData.flow[0]\n : null;\n\n // Find existing enter_flow action to preserve its UUID\n const existingEnterFlowAction = originalNode.actions?.find(\n (action) => action.type === 'enter_flow'\n );\n const enterFlowUuid = existingEnterFlowAction?.uuid || generateUUID();\n\n // Create enter_flow action\n const enterFlowAction: any = {\n type: 'enter_flow',\n uuid: enterFlowUuid,\n flow: flowSelection\n ? {\n uuid: flowSelection.uuid || flowSelection.value,\n name: flowSelection.name\n }\n : { uuid: '', name: '' }\n };\n\n // Create categories and exits for Complete and Expired\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n // Find existing Complete category\n const existingCompleteCategory = existingCategories.find(\n (cat) => cat.name === 'Complete'\n );\n const existingCompleteExit = existingCompleteCategory\n ? existingExits.find(\n (exit) => exit.uuid === existingCompleteCategory.exit_uuid\n )\n : null;\n const existingCompleteCase = existingCompleteCategory\n ? existingCases.find(\n (case_) => case_.category_uuid === existingCompleteCategory.uuid\n )\n : null;\n\n const completeCategoryUuid =\n existingCompleteCategory?.uuid || generateUUID();\n const completeExitUuid = existingCompleteExit?.uuid || generateUUID();\n const completeCaseUuid = existingCompleteCase?.uuid || generateUUID();\n\n // Find existing Expired category\n const existingExpiredCategory = existingCategories.find(\n (cat) => cat.name === 'Expired'\n );\n const existingExpiredExit = existingExpiredCategory\n ? existingExits.find(\n (exit) => exit.uuid === existingExpiredCategory.exit_uuid\n )\n : null;\n\n const expiredCategoryUuid = existingExpiredCategory?.uuid || generateUUID();\n const expiredExitUuid = existingExpiredExit?.uuid || generateUUID();\n\n const categories = [\n {\n uuid: completeCategoryUuid,\n name: 'Complete',\n exit_uuid: completeExitUuid\n },\n {\n uuid: expiredCategoryUuid,\n name: 'Expired',\n exit_uuid: expiredExitUuid\n }\n ];\n\n const exits = [\n {\n uuid: completeExitUuid,\n destination_uuid: existingCompleteExit?.destination_uuid || null\n },\n {\n uuid: expiredExitUuid,\n destination_uuid: existingExpiredExit?.destination_uuid || null\n }\n ];\n\n const cases = [\n {\n uuid: completeCaseUuid,\n type: 'has_only_text',\n arguments: ['completed'],\n category_uuid: completeCategoryUuid\n }\n ];\n\n // Create the router\n const router = {\n type: 'switch' as const,\n categories: categories,\n default_category_uuid: expiredCategoryUuid,\n operand: '@child.status',\n cases: cases\n };\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: [enterFlowAction],\n router: router,\n exits: exits\n };\n }\n};\n"]}
@@ -1,18 +1,120 @@
1
- import { open_ticket } from '../actions/open_ticket';
1
+ import { COLORS } from '../types';
2
+ import { generateUUID, createSuccessFailureRouter } from '../../utils';
3
+ import { html } from 'lit';
2
4
  export const split_by_ticket = {
3
5
  type: 'split_by_ticket',
4
- action: open_ticket,
5
- router: {
6
- type: 'switch',
7
- defaultCategory: 'Failure',
8
- operand: '@locals._new_ticket',
9
- rules: [
10
- {
11
- type: 'has_text',
12
- arguments: [],
13
- categoryName: 'Success'
14
- }
15
- ]
6
+ name: 'Open Ticket',
7
+ color: COLORS.create,
8
+ form: {
9
+ topic: {
10
+ type: 'select',
11
+ label: 'Topic',
12
+ required: true,
13
+ placeholder: 'Select a topic',
14
+ options: [],
15
+ endpoint: '/api/v2/topics.json',
16
+ valueKey: 'uuid',
17
+ nameKey: 'name',
18
+ maxWidth: '200px'
19
+ },
20
+ assignee: {
21
+ type: 'select',
22
+ label: 'Assignee',
23
+ required: false,
24
+ placeholder: 'Select an agent (optional)',
25
+ options: [],
26
+ endpoint: '/api/v2/users.json',
27
+ valueKey: 'uuid',
28
+ getName: (item) => {
29
+ return item.name || [item.first_name, item.last_name].join(' ');
30
+ },
31
+ clearable: true
32
+ },
33
+ note: {
34
+ type: 'textarea',
35
+ label: 'Note',
36
+ required: false,
37
+ placeholder: 'Enter a note for the ticket (optional)',
38
+ minHeight: 100
39
+ }
40
+ },
41
+ layout: [{ type: 'row', items: ['topic', 'assignee'] }, 'note'],
42
+ render: (node) => {
43
+ var _a, _b;
44
+ const openTicketAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'open_ticket');
45
+ return html `
46
+ <div class="body">
47
+ ${((_b = openTicketAction === null || openTicketAction === void 0 ? void 0 : openTicketAction.topic) === null || _b === void 0 ? void 0 : _b.name) || 'Configure ticket'}
48
+ </div>
49
+ `;
50
+ },
51
+ toFormData: (node) => {
52
+ var _a;
53
+ // Extract data from the existing node structure
54
+ const openTicketAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'open_ticket');
55
+ return {
56
+ uuid: node.uuid,
57
+ topic: (openTicketAction === null || openTicketAction === void 0 ? void 0 : openTicketAction.topic)
58
+ ? [
59
+ {
60
+ uuid: openTicketAction.topic.uuid,
61
+ name: openTicketAction.topic.name
62
+ }
63
+ ]
64
+ : [],
65
+ assignee: (openTicketAction === null || openTicketAction === void 0 ? void 0 : openTicketAction.assignee)
66
+ ? [
67
+ {
68
+ uuid: openTicketAction.assignee.uuid,
69
+ name: openTicketAction.assignee.name
70
+ }
71
+ ]
72
+ : [],
73
+ note: (openTicketAction === null || openTicketAction === void 0 ? void 0 : openTicketAction.note) || ''
74
+ };
75
+ },
76
+ fromFormData: (formData, originalNode) => {
77
+ var _a, _b, _c;
78
+ // Find existing open_ticket action to preserve its UUID
79
+ const existingOpenTicketAction = (_a = originalNode.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'open_ticket');
80
+ const openTicketUuid = (existingOpenTicketAction === null || existingOpenTicketAction === void 0 ? void 0 : existingOpenTicketAction.uuid) || generateUUID();
81
+ // Create open_ticket action
82
+ const openTicketAction = {
83
+ type: 'open_ticket',
84
+ uuid: openTicketUuid,
85
+ topic: formData.topic && formData.topic.length > 0
86
+ ? {
87
+ uuid: formData.topic[0].uuid,
88
+ name: formData.topic[0].name
89
+ }
90
+ : undefined,
91
+ assignee: formData.assignee && formData.assignee.length > 0
92
+ ? {
93
+ uuid: formData.assignee[0].uuid,
94
+ name: formData.assignee[0].name ||
95
+ [
96
+ formData.assignee[0].first_name,
97
+ formData.assignee[0].last_name
98
+ ].join(' ')
99
+ }
100
+ : undefined,
101
+ note: formData.note || ''
102
+ };
103
+ // Create categories and exits for Success and Failure
104
+ const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
105
+ const existingExits = originalNode.exits || [];
106
+ const existingCases = ((_c = originalNode.router) === null || _c === void 0 ? void 0 : _c.cases) || [];
107
+ const { router, exits } = createSuccessFailureRouter('@locals._new_ticket', {
108
+ type: 'has_text',
109
+ arguments: []
110
+ }, existingCategories, existingExits, existingCases);
111
+ // Return the complete node
112
+ return {
113
+ uuid: originalNode.uuid,
114
+ actions: [openTicketAction],
115
+ router: router,
116
+ exits: exits
117
+ };
16
118
  }
17
119
  };
18
120
  //# sourceMappingURL=split_by_ticket.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"split_by_ticket.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_ticket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrD,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,eAAe,EAAE,SAAS;QAC1B,OAAO,EAAE,qBAAqB;QAC9B,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,UAAU;gBAChB,SAAS,EAAE,EAAE;gBACb,YAAY,EAAE,SAAS;aACxB;SACF;KACF;CACF,CAAC","sourcesContent":["import { open_ticket } from '../actions/open_ticket';\nimport { NodeConfig } from '../types';\n\nexport const split_by_ticket: NodeConfig = {\n type: 'split_by_ticket',\n action: open_ticket,\n router: {\n type: 'switch',\n defaultCategory: 'Failure',\n operand: '@locals._new_ticket',\n rules: [\n {\n type: 'has_text',\n arguments: [],\n categoryName: 'Success'\n }\n ]\n }\n};\n"]}
1
+ {"version":3,"file":"split_by_ticket.js","sourceRoot":"","sources":["../../../../src/flow/nodes/split_by_ticket.ts"],"names":[],"mappings":"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","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node, OpenTicket } from '../../store/flow-definition';\nimport { generateUUID, createSuccessFailureRouter } from '../../utils';\nimport { html } from 'lit';\n\nexport const split_by_ticket: NodeConfig = {\n type: 'split_by_ticket',\n name: 'Open Ticket',\n color: COLORS.create,\n form: {\n topic: {\n type: 'select',\n label: 'Topic',\n required: true,\n placeholder: 'Select a topic',\n options: [],\n endpoint: '/api/v2/topics.json',\n valueKey: 'uuid',\n nameKey: 'name',\n maxWidth: '200px'\n },\n assignee: {\n type: 'select',\n label: 'Assignee',\n required: false,\n placeholder: 'Select an agent (optional)',\n options: [],\n endpoint: '/api/v2/users.json',\n valueKey: 'uuid',\n getName: (item: {\n first_name?: string;\n last_name?: string;\n name?: string;\n }) => {\n return item.name || [item.first_name, item.last_name].join(' ');\n },\n clearable: true\n },\n note: {\n type: 'textarea',\n label: 'Note',\n required: false,\n placeholder: 'Enter a note for the ticket (optional)',\n minHeight: 100\n }\n },\n layout: [{ type: 'row', items: ['topic', 'assignee'] }, 'note'],\n render: (node: Node) => {\n const openTicketAction = node.actions?.find(\n (action) => action.type === 'open_ticket'\n ) as OpenTicket;\n return html`\n <div class=\"body\">\n ${openTicketAction?.topic?.name || 'Configure ticket'}\n </div>\n `;\n },\n toFormData: (node: Node) => {\n // Extract data from the existing node structure\n const openTicketAction = node.actions?.find(\n (action) => action.type === 'open_ticket'\n ) as any;\n\n return {\n uuid: node.uuid,\n topic: openTicketAction?.topic\n ? [\n {\n uuid: openTicketAction.topic.uuid,\n name: openTicketAction.topic.name\n }\n ]\n : [],\n assignee: openTicketAction?.assignee\n ? [\n {\n uuid: openTicketAction.assignee.uuid,\n name: openTicketAction.assignee.name\n }\n ]\n : [],\n note: openTicketAction?.note || ''\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n // Find existing open_ticket action to preserve its UUID\n const existingOpenTicketAction = originalNode.actions?.find(\n (action) => action.type === 'open_ticket'\n );\n const openTicketUuid = existingOpenTicketAction?.uuid || generateUUID();\n\n // Create open_ticket action\n const openTicketAction: OpenTicket = {\n type: 'open_ticket',\n uuid: openTicketUuid,\n topic:\n formData.topic && formData.topic.length > 0\n ? {\n uuid: formData.topic[0].uuid,\n name: formData.topic[0].name\n }\n : undefined,\n assignee:\n formData.assignee && formData.assignee.length > 0\n ? {\n uuid: formData.assignee[0].uuid,\n name:\n formData.assignee[0].name ||\n [\n formData.assignee[0].first_name,\n formData.assignee[0].last_name\n ].join(' ')\n }\n : undefined,\n note: formData.note || ''\n };\n\n // Create categories and exits for Success and Failure\n const existingCategories = originalNode.router?.categories || [];\n const existingExits = originalNode.exits || [];\n const existingCases = originalNode.router?.cases || [];\n\n const { router, exits } = createSuccessFailureRouter(\n '@locals._new_ticket',\n {\n type: 'has_text',\n arguments: []\n },\n existingCategories,\n existingExits,\n existingCases\n );\n\n // Return the complete node\n return {\n uuid: originalNode.uuid,\n actions: [openTicketAction],\n router: router,\n exits: exits\n };\n }\n};\n"]}