@nyaruka/temba-components 0.129.7 → 0.129.9

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 (269) hide show
  1. package/.devcontainer/Dockerfile +11 -4
  2. package/.devcontainer/devcontainer.json +3 -2
  3. package/.github/workflows/build.yml +4 -14
  4. package/CHANGELOG.md +29 -0
  5. package/demo/components/flow/example.html +1 -1
  6. package/demo/components/message-editor/example.html +125 -0
  7. package/demo/components/textinput/completion.html +1 -0
  8. package/demo/data/flows/food-order.json +12 -21
  9. package/demo/data/flows/sample-flow.json +210 -104
  10. package/dist/temba-components.js +715 -364
  11. package/dist/temba-components.js.map +1 -1
  12. package/out-tsc/src/display/Thumbnail.js +2 -1
  13. package/out-tsc/src/display/Thumbnail.js.map +1 -1
  14. package/out-tsc/src/events.js.map +1 -1
  15. package/out-tsc/src/excellent/helpers.js +2 -2
  16. package/out-tsc/src/excellent/helpers.js.map +1 -1
  17. package/out-tsc/src/flow/CanvasNode.js +25 -7
  18. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  19. package/out-tsc/src/flow/Editor.js +11 -1
  20. package/out-tsc/src/flow/Editor.js.map +1 -1
  21. package/out-tsc/src/flow/NodeEditor.js +342 -276
  22. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  23. package/out-tsc/src/flow/actions/add_input_labels.js +40 -0
  24. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  25. package/out-tsc/src/flow/actions/call_llm.js +56 -3
  26. package/out-tsc/src/flow/actions/call_llm.js.map +1 -1
  27. package/out-tsc/src/flow/actions/call_webhook.js +26 -17
  28. package/out-tsc/src/flow/actions/call_webhook.js.map +1 -1
  29. package/out-tsc/src/flow/actions/open_ticket.js +65 -3
  30. package/out-tsc/src/flow/actions/open_ticket.js.map +1 -1
  31. package/out-tsc/src/flow/actions/send_msg.js +147 -6
  32. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  33. package/out-tsc/src/flow/actions/set_run_result.js +75 -0
  34. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  35. package/out-tsc/src/flow/config.js +4 -0
  36. package/out-tsc/src/flow/config.js.map +1 -1
  37. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +227 -0
  38. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -0
  39. package/out-tsc/src/flow/nodes/split_by_ticket.js +18 -0
  40. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -0
  41. package/out-tsc/src/flow/nodes/wait_for_response.js +27 -1
  42. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  43. package/out-tsc/src/flow/types.js +0 -65
  44. package/out-tsc/src/flow/types.js.map +1 -1
  45. package/out-tsc/src/form/ArrayEditor.js +87 -57
  46. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  47. package/out-tsc/src/form/BaseListEditor.js +19 -4
  48. package/out-tsc/src/form/BaseListEditor.js.map +1 -1
  49. package/out-tsc/src/form/FieldRenderer.js +305 -0
  50. package/out-tsc/src/form/FieldRenderer.js.map +1 -0
  51. package/out-tsc/src/form/FormField.js +4 -4
  52. package/out-tsc/src/form/FormField.js.map +1 -1
  53. package/out-tsc/src/form/KeyValueEditor.js +1 -1
  54. package/out-tsc/src/form/KeyValueEditor.js.map +1 -1
  55. package/out-tsc/src/form/MediaPicker.js +13 -1
  56. package/out-tsc/src/form/MediaPicker.js.map +1 -1
  57. package/out-tsc/src/form/MessageEditor.js +422 -0
  58. package/out-tsc/src/form/MessageEditor.js.map +1 -0
  59. package/out-tsc/src/form/TextInput.js +13 -6
  60. package/out-tsc/src/form/TextInput.js.map +1 -1
  61. package/out-tsc/src/form/select/Select.js +52 -24
  62. package/out-tsc/src/form/select/Select.js.map +1 -1
  63. package/out-tsc/src/live/ContactChat.js +66 -15
  64. package/out-tsc/src/live/ContactChat.js.map +1 -1
  65. package/out-tsc/src/markdown.js +13 -11
  66. package/out-tsc/src/markdown.js.map +1 -1
  67. package/out-tsc/temba-modules.js +2 -0
  68. package/out-tsc/temba-modules.js.map +1 -1
  69. package/out-tsc/test/ActionHelper.js +2 -0
  70. package/out-tsc/test/ActionHelper.js.map +1 -1
  71. package/out-tsc/test/NodeHelper.js +148 -0
  72. package/out-tsc/test/NodeHelper.js.map +1 -0
  73. package/out-tsc/test/actions/call_llm.test.js +103 -0
  74. package/out-tsc/test/actions/call_llm.test.js.map +1 -0
  75. package/out-tsc/test/nodes/split_by_llm_categorize.test.js +532 -0
  76. package/out-tsc/test/nodes/split_by_llm_categorize.test.js.map +1 -0
  77. package/out-tsc/test/nodes/split_by_random.test.js +150 -0
  78. package/out-tsc/test/nodes/split_by_random.test.js.map +1 -0
  79. package/out-tsc/test/nodes/wait_for_digits.test.js +150 -0
  80. package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -0
  81. package/out-tsc/test/nodes/wait_for_response.test.js +171 -0
  82. package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -0
  83. package/out-tsc/test/temba-add-input-labels.test.js +70 -0
  84. package/out-tsc/test/temba-add-input-labels.test.js.map +1 -0
  85. package/out-tsc/test/temba-field-config.test.js +4 -2
  86. package/out-tsc/test/temba-field-config.test.js.map +1 -1
  87. package/out-tsc/test/temba-field-renderer.test.js +296 -0
  88. package/out-tsc/test/temba-field-renderer.test.js.map +1 -0
  89. package/out-tsc/test/temba-markdown.test.js +1 -1
  90. package/out-tsc/test/temba-markdown.test.js.map +1 -1
  91. package/out-tsc/test/temba-message-editor.test.js +194 -0
  92. package/out-tsc/test/temba-message-editor.test.js.map +1 -0
  93. package/out-tsc/test/temba-node-editor.test.js +471 -0
  94. package/out-tsc/test/temba-node-editor.test.js.map +1 -1
  95. package/out-tsc/test/temba-select.test.js +7 -4
  96. package/out-tsc/test/temba-select.test.js.map +1 -1
  97. package/out-tsc/test/temba-textinput.test.js +16 -0
  98. package/out-tsc/test/temba-textinput.test.js.map +1 -1
  99. package/out-tsc/test/temba-webchat.test.js +5 -1
  100. package/out-tsc/test/temba-webchat.test.js.map +1 -1
  101. package/out-tsc/test/utils.test.js +2 -8
  102. package/out-tsc/test/utils.test.js.map +1 -1
  103. package/package.json +7 -4
  104. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  105. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  106. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  107. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  108. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  109. package/screenshots/truth/actions/call_llm/editor/information-extraction.png +0 -0
  110. package/screenshots/truth/actions/call_llm/editor/sentiment-analysis.png +0 -0
  111. package/screenshots/truth/actions/call_llm/editor/summarization.png +0 -0
  112. package/screenshots/truth/actions/call_llm/editor/translation-task.png +0 -0
  113. package/screenshots/truth/actions/call_llm/render/information-extraction.png +0 -0
  114. package/screenshots/truth/actions/call_llm/render/sentiment-analysis.png +0 -0
  115. package/screenshots/truth/actions/call_llm/render/summarization.png +0 -0
  116. package/screenshots/truth/actions/call_llm/render/translation-task.png +0 -0
  117. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  118. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  119. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  120. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  121. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  122. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  123. package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
  124. package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
  125. package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
  126. package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
  127. package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
  128. package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
  129. package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
  130. package/screenshots/truth/actions/send_email/editor/with-expressions.png +0 -0
  131. package/screenshots/truth/actions/send_msg/editor/long-quick-replies.png +0 -0
  132. package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
  133. package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
  134. package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
  135. package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
  136. package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
  137. package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
  138. package/screenshots/truth/editor/router.png +0 -0
  139. package/screenshots/truth/editor/send_msg.png +0 -0
  140. package/screenshots/truth/editor/set_contact_language.png +0 -0
  141. package/screenshots/truth/editor/set_contact_name.png +0 -0
  142. package/screenshots/truth/editor/set_run_result.png +0 -0
  143. package/screenshots/truth/editor/wait.png +0 -0
  144. package/screenshots/truth/field-renderer/checkbox-checked.png +0 -0
  145. package/screenshots/truth/field-renderer/checkbox-unchecked.png +0 -0
  146. package/screenshots/truth/field-renderer/checkbox-with-errors.png +0 -0
  147. package/screenshots/truth/field-renderer/context-comparison.png +0 -0
  148. package/screenshots/truth/field-renderer/key-value-with-label.png +0 -0
  149. package/screenshots/truth/field-renderer/message-editor-with-label.png +0 -0
  150. package/screenshots/truth/field-renderer/select-multi.png +0 -0
  151. package/screenshots/truth/field-renderer/select-no-label.png +0 -0
  152. package/screenshots/truth/field-renderer/select-with-label.png +0 -0
  153. package/screenshots/truth/field-renderer/text-evaluated.png +0 -0
  154. package/screenshots/truth/field-renderer/text-no-label.png +0 -0
  155. package/screenshots/truth/field-renderer/text-with-errors.png +0 -0
  156. package/screenshots/truth/field-renderer/text-with-label.png +0 -0
  157. package/screenshots/truth/field-renderer/textarea-evaluated.png +0 -0
  158. package/screenshots/truth/field-renderer/textarea-with-label.png +0 -0
  159. package/screenshots/truth/formfield/markdown-errors.png +0 -0
  160. package/screenshots/truth/formfield/no-errors.png +0 -0
  161. package/screenshots/truth/formfield/plain-text-errors.png +0 -0
  162. package/screenshots/truth/message-editor/autogrow-initial-content.png +0 -0
  163. package/screenshots/truth/message-editor/default.png +0 -0
  164. package/screenshots/truth/message-editor/drag-highlight.png +0 -0
  165. package/screenshots/truth/message-editor/filtered-attachments.png +0 -0
  166. package/screenshots/truth/message-editor/with-completion.png +0 -0
  167. package/screenshots/truth/message-editor/with-properties.png +0 -0
  168. package/screenshots/truth/nodes/split_by_llm_categorize/editor/basic-categorization.png +0 -0
  169. package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.png +0 -0
  170. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  171. package/screenshots/truth/nodes/split_by_llm_categorize/editor/many-categories.png +0 -0
  172. package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.png +0 -0
  173. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  174. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  175. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  176. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  177. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  178. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  179. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  180. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  181. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  182. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  183. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  184. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  185. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  186. package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
  187. package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
  188. package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
  189. package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
  190. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  191. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  192. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  193. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
  194. package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
  195. package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
  196. package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
  197. package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
  198. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  199. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  200. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  201. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  202. package/screenshots/truth/omnibox/selected.png +0 -0
  203. package/screenshots/truth/select/functions.png +0 -0
  204. package/screenshots/truth/select/multi-with-endpoint.png +0 -0
  205. package/screenshots/truth/select/search-enabled.png +0 -0
  206. package/screenshots/truth/textinput/autogrow-initial.png +0 -0
  207. package/screenshots/truth/textinput/input-form.png +0 -0
  208. package/src/display/Thumbnail.ts +2 -1
  209. package/src/events.ts +13 -1
  210. package/src/excellent/helpers.ts +2 -2
  211. package/src/flow/CanvasNode.ts +22 -1
  212. package/src/flow/Editor.ts +12 -1
  213. package/src/flow/NodeEditor.ts +412 -354
  214. package/src/flow/actions/add_input_labels.ts +45 -0
  215. package/src/flow/actions/call_llm.ts +57 -3
  216. package/src/flow/actions/call_webhook.ts +28 -18
  217. package/src/flow/actions/open_ticket.ts +74 -3
  218. package/src/flow/actions/send_msg.ts +170 -6
  219. package/src/flow/actions/set_run_result.ts +83 -0
  220. package/src/flow/config.ts +4 -0
  221. package/src/flow/nodes/split_by_llm_categorize.ts +277 -0
  222. package/src/flow/nodes/split_by_ticket.ts +19 -0
  223. package/src/flow/nodes/wait_for_response.ts +28 -1
  224. package/src/flow/types.ts +46 -128
  225. package/src/form/ArrayEditor.ts +96 -66
  226. package/src/form/BaseListEditor.ts +22 -6
  227. package/src/form/FieldRenderer.ts +465 -0
  228. package/src/form/FormField.ts +4 -4
  229. package/src/form/KeyValueEditor.ts +1 -1
  230. package/src/form/MediaPicker.ts +13 -1
  231. package/src/form/MessageEditor.ts +449 -0
  232. package/src/form/TextInput.ts +16 -8
  233. package/src/form/select/Select.ts +55 -24
  234. package/src/live/ContactChat.ts +69 -19
  235. package/src/markdown.ts +19 -11
  236. package/src/store/flow-definition.d.ts +5 -2
  237. package/static/api/labels.json +31 -0
  238. package/static/api/topics.json +24 -9
  239. package/static/api/users.json +35 -16
  240. package/static/css/temba-components.css +5 -3
  241. package/static/mr/docs/en-us/editor.json +2588 -0
  242. package/stress-test.js +143 -0
  243. package/temba-modules.ts +2 -0
  244. package/test/ActionHelper.ts +2 -0
  245. package/test/NodeHelper.ts +184 -0
  246. package/test/actions/call_llm.test.ts +137 -0
  247. package/test/nodes/README.md +78 -0
  248. package/test/nodes/split_by_llm_categorize.test.ts +698 -0
  249. package/test/nodes/split_by_random.test.ts +177 -0
  250. package/test/nodes/wait_for_digits.test.ts +176 -0
  251. package/test/nodes/wait_for_response.test.ts +206 -0
  252. package/test/temba-add-input-labels.test.ts +87 -0
  253. package/test/temba-field-config.test.ts +4 -2
  254. package/test/temba-field-renderer.test.ts +482 -0
  255. package/test/temba-markdown.test.ts +1 -1
  256. package/test/temba-message-editor.test.ts +300 -0
  257. package/test/temba-node-editor.test.ts +590 -0
  258. package/test/temba-select.test.ts +7 -7
  259. package/test/temba-textinput.test.ts +26 -0
  260. package/test/temba-webchat.test.ts +6 -1
  261. package/test/utils.test.ts +2 -13
  262. package/test-assets/contacts/history.json +19 -0
  263. package/test-assets/select/llms.json +18 -0
  264. package/test-assets/style.css +2 -0
  265. package/web-dev-mock.mjs +523 -0
  266. package/web-dev-server.config.mjs +74 -6
  267. package/web-test-runner.config.mjs +9 -4
  268. package/test/temba-flow-editor.test.ts.backup +0 -563
  269. package/test/temba-utils-index.test.ts.backup +0 -1737
@@ -0,0 +1,227 @@
1
+ import { COLORS } from '../types';
2
+ import { generateUUID } from '../../utils';
3
+ import { html } from 'lit';
4
+ export const split_by_llm_categorize = {
5
+ type: 'split_by_llm_categorize',
6
+ name: 'Split by AI',
7
+ color: COLORS.call,
8
+ form: {
9
+ llm: {
10
+ type: 'select',
11
+ label: 'LLM',
12
+ helpText: 'Select the LLM to use for categorization',
13
+ required: true,
14
+ endpoint: '/test-assets/select/llms.json',
15
+ valueKey: 'uuid',
16
+ nameKey: 'name',
17
+ placeholder: 'Select an LLM...'
18
+ },
19
+ input: {
20
+ type: 'text',
21
+ label: 'Input',
22
+ helpText: 'The input to categorize (usually @input)',
23
+ required: true,
24
+ evaluated: true,
25
+ placeholder: '@input'
26
+ },
27
+ categories: {
28
+ type: 'array',
29
+ label: 'Categories',
30
+ helpText: 'Define the categories for classification',
31
+ required: true,
32
+ itemLabel: 'Category',
33
+ minItems: 1,
34
+ maxItems: 10,
35
+ isEmptyItem: (item) => {
36
+ return !item.name || item.name.trim() === '';
37
+ },
38
+ itemConfig: {
39
+ name: {
40
+ type: 'text',
41
+ placeholder: 'Category name',
42
+ required: true
43
+ }
44
+ }
45
+ }
46
+ },
47
+ layout: ['llm', 'input', 'categories'],
48
+ validate: (formData) => {
49
+ const errors = {};
50
+ // Check for duplicate category names
51
+ if (formData.categories && Array.isArray(formData.categories)) {
52
+ const categories = formData.categories.filter((item) => (item === null || item === void 0 ? void 0 : item.name) && item.name.trim() !== '');
53
+ // Find all categories that have duplicates (case-insensitive)
54
+ const duplicateCategories = [];
55
+ const lowerCaseMap = new Map();
56
+ // First pass: map lowercase names to all original cases
57
+ categories.forEach((category) => {
58
+ const lowerName = category.name.trim().toLowerCase();
59
+ if (!lowerCaseMap.has(lowerName)) {
60
+ lowerCaseMap.set(lowerName, []);
61
+ }
62
+ lowerCaseMap.get(lowerName).push(category.name.trim());
63
+ });
64
+ // Second pass: collect all names that appear more than once
65
+ lowerCaseMap.forEach((originalNames) => {
66
+ if (originalNames.length > 1) {
67
+ duplicateCategories.push(...originalNames);
68
+ }
69
+ });
70
+ if (duplicateCategories.length > 0) {
71
+ const uniqueDuplicates = [...new Set(duplicateCategories)];
72
+ errors.categories = `Duplicate category names found: ${uniqueDuplicates.join(', ')}`;
73
+ }
74
+ }
75
+ return {
76
+ valid: Object.keys(errors).length === 0,
77
+ errors
78
+ };
79
+ },
80
+ render: (node) => {
81
+ var _a;
82
+ const callLlmAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
83
+ return html `
84
+ <div class="body">Categorize with ${callLlmAction.llm.name}</div>
85
+ `;
86
+ },
87
+ toFormData: (node) => {
88
+ var _a, _b, _c;
89
+ // Extract data from the existing node structure
90
+ const callLlmAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
91
+ const categories = ((_c = (_b = node.router) === null || _b === void 0 ? void 0 : _b.categories) === null || _c === void 0 ? void 0 : _c.filter((cat) => cat.name !== 'Other' && cat.name !== 'Failure').map((cat) => ({ name: cat.name }))) || [];
92
+ return {
93
+ uuid: node.uuid,
94
+ llm: (callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.llm)
95
+ ? [{ value: callLlmAction.llm.uuid, name: callLlmAction.llm.name }]
96
+ : [],
97
+ input: (callLlmAction === null || callLlmAction === void 0 ? void 0 : callLlmAction.input) || '@input',
98
+ categories: categories
99
+ };
100
+ },
101
+ fromFormData: (formData, originalNode) => {
102
+ var _a, _b, _c;
103
+ // Get LLM selection
104
+ const llmSelection = Array.isArray(formData.llm) && formData.llm.length > 0
105
+ ? formData.llm[0]
106
+ : null;
107
+ // Get user categories
108
+ const userCategories = (formData.categories || [])
109
+ .filter((item) => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.name) === null || _a === void 0 ? void 0 : _a.trim(); })
110
+ .map((item) => item.name.trim());
111
+ // Find existing call_llm action to preserve its UUID
112
+ const existingCallLlmAction = (_a = originalNode.actions) === null || _a === void 0 ? void 0 : _a.find((action) => action.type === 'call_llm');
113
+ const callLlmUuid = (existingCallLlmAction === null || existingCallLlmAction === void 0 ? void 0 : existingCallLlmAction.uuid) || generateUUID();
114
+ // Create call_llm action (using any type to match the example format)
115
+ const callLlmAction = {
116
+ type: 'call_llm',
117
+ uuid: callLlmUuid,
118
+ llm: llmSelection
119
+ ? { uuid: llmSelection.value, name: llmSelection.name }
120
+ : { uuid: '', name: '' },
121
+ instructions: `@(prompt("categorize", slice(node.categories, 0, -2)))`,
122
+ input: formData.input || '@input',
123
+ output_local: '_llm_output'
124
+ };
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
+ const existingCategories = ((_b = originalNode.router) === null || _b === void 0 ? void 0 : _b.categories) || [];
131
+ const existingExits = originalNode.exits || [];
132
+ 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,
206
+ 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
+ };
218
+ // Return the complete node
219
+ return {
220
+ uuid: originalNode.uuid,
221
+ actions: [callLlmAction],
222
+ router: router,
223
+ exits: exits
224
+ };
225
+ }
226
+ };
227
+ //# sourceMappingURL=split_by_llm_categorize.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,18 @@
1
+ import { open_ticket } from '../actions/open_ticket';
2
+ export const split_by_ticket = {
3
+ 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
+ ]
16
+ }
17
+ };
18
+ //# sourceMappingURL=split_by_ticket.js.map
@@ -0,0 +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"]}
@@ -2,6 +2,32 @@ import { COLORS } from '../types';
2
2
  export const wait_for_response = {
3
3
  type: 'wait_for_response',
4
4
  name: 'Wait for Response',
5
- color: COLORS.wait
5
+ color: COLORS.wait,
6
+ form: {
7
+ result_name: {
8
+ type: 'text',
9
+ label: 'Result Name',
10
+ helpText: 'The name to save the response as',
11
+ placeholder: 'response'
12
+ }
13
+ },
14
+ layout: ['timeout', 'result_name'],
15
+ toFormData: (node) => {
16
+ var _a;
17
+ return {
18
+ uuid: node.uuid,
19
+ result_name: ((_a = node.router) === null || _a === void 0 ? void 0 : _a.result_name) || 'response'
20
+ };
21
+ },
22
+ fromFormData: (formData, originalNode) => {
23
+ const router = {
24
+ ...originalNode.router,
25
+ result_name: formData.result_name || 'response'
26
+ };
27
+ return {
28
+ ...originalNode,
29
+ router
30
+ };
31
+ }
6
32
  };
7
33
  //# sourceMappingURL=wait_for_response.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wait_for_response.js","sourceRoot":"","sources":["../../../../src/flow/nodes/wait_for_response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,UAAU,CAAC;AAE9C,MAAM,CAAC,MAAM,iBAAiB,GAAe;IAC3C,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,MAAM,CAAC,IAAI;CACnB,CAAC","sourcesContent":["import { COLORS, NodeConfig } from '../types';\n\nexport const wait_for_response: NodeConfig = {\n type: 'wait_for_response',\n name: 'Wait for Response',\n color: COLORS.wait\n};\n"]}
1
+ {"version":3,"file":"wait_for_response.js","sourceRoot":"","sources":["../../../../src/flow/nodes/wait_for_response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,UAAU,CAAC;AAG9C,MAAM,CAAC,MAAM,iBAAiB,GAAe;IAC3C,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,MAAM,CAAC,IAAI;IAClB,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,kCAAkC;YAC5C,WAAW,EAAE,UAAU;SACxB;KACF;IACD,MAAM,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,UAAU,EAAE,CAAC,IAAU,EAAE,EAAE;;QACzB,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,CAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,WAAW,KAAI,UAAU;SACpD,CAAC;IACJ,CAAC;IACD,YAAY,EAAE,CAAC,QAAa,EAAE,YAAkB,EAAQ,EAAE;QACxD,MAAM,MAAM,GAAQ;YAClB,GAAG,YAAY,CAAC,MAAM;YACtB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,UAAU;SAChD,CAAC;QAEF,OAAO;YACL,GAAG,YAAY;YACf,MAAM;SACP,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { COLORS, NodeConfig } from '../types';\nimport { Node } from '../../store/flow-definition';\n\nexport const wait_for_response: NodeConfig = {\n type: 'wait_for_response',\n name: 'Wait for Response',\n color: COLORS.wait,\n form: {\n result_name: {\n type: 'text',\n label: 'Result Name',\n helpText: 'The name to save the response as',\n placeholder: 'response'\n }\n },\n layout: ['timeout', 'result_name'],\n toFormData: (node: Node) => {\n return {\n uuid: node.uuid,\n result_name: node.router?.result_name || 'response'\n };\n },\n fromFormData: (formData: any, originalNode: Node): Node => {\n const router: any = {\n ...originalNode.router,\n result_name: formData.result_name || 'response'\n };\n\n return {\n ...originalNode,\n router\n };\n }\n};\n"]}
@@ -11,69 +11,4 @@ export const COLORS = {
11
11
  add: '#309c42',
12
12
  remove: '#e74c3c'
13
13
  };
14
- // Default property type mappings
15
- export function getDefaultComponent(value) {
16
- if (typeof value === 'boolean') {
17
- return 'temba-checkbox';
18
- }
19
- if (typeof value === 'number') {
20
- return 'temba-textinput';
21
- }
22
- if (Array.isArray(value)) {
23
- return 'temba-select'; // For arrays, use multi-select
24
- }
25
- // Default to text input for strings and unknown types
26
- return 'temba-textinput';
27
- }
28
- // Get component properties for default mappings with proper typing
29
- export function getDefaultComponentProps(value) {
30
- if (typeof value === 'boolean') {
31
- return {
32
- widget: { type: 'temba-checkbox' }
33
- };
34
- }
35
- if (typeof value === 'number') {
36
- return {
37
- widget: {
38
- type: 'temba-textinput',
39
- attributes: { type: 'number' }
40
- }
41
- };
42
- }
43
- if (Array.isArray(value)) {
44
- if (value.length > 0 && typeof value[0] === 'string') {
45
- return {
46
- widget: {
47
- type: 'temba-select',
48
- attributes: { multi: true, tags: true }
49
- }
50
- };
51
- }
52
- return {
53
- widget: {
54
- type: 'temba-select',
55
- attributes: { multi: true }
56
- }
57
- };
58
- }
59
- return {
60
- widget: { type: 'temba-textinput' }
61
- };
62
- }
63
- // Type guard functions for working with WidgetConfig
64
- export function isTextInputWidget(config) {
65
- return config.type === 'temba-textinput';
66
- }
67
- export function isCompletionWidget(config) {
68
- return config.type === 'temba-completion';
69
- }
70
- export function isSelectWidget(config) {
71
- return config.type === 'temba-select';
72
- }
73
- export function isCheckboxWidget(config) {
74
- return config.type === 'temba-checkbox';
75
- }
76
- export function isSliderWidget(config) {
77
- return config.type === 'temba-slider';
78
- }
79
14
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/flow/types.ts"],"names":[],"mappings":"AAiQA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,iCAAiC;AACjC,MAAM,UAAU,mBAAmB,CAAC,KAAU;IAC5C,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,cAAc,CAAC,CAAC,+BAA+B;IACxD,CAAC;IACD,sDAAsD;IACtD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,wBAAwB,CAAC,KAAU;IACjD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;SACnC,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO;YACL,MAAM,EAAE;gBACN,IAAI,EAAE,iBAAiB;gBACvB,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC/B;SACF,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO;gBACL,MAAM,EAAE;oBACN,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;iBACxC;aACF,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE;gBACN,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;aAC5B;SACF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,MAAM,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,iBAAiB,CAC/B,MAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,KAAK,kBAAkB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,KAAK,gBAAgB,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,MAAoB;IAEpB,OAAO,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;AACxC,CAAC","sourcesContent":["import { TemplateResult } from 'lit-html';\nimport { Action } from '../store/flow-definition';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: { [key: string]: string };\n}\n\n// Component attribute interfaces - these define what's allowed for each component type\nexport interface TextInputAttributes {\n type?: 'text' | 'email' | 'number' | 'url' | 'tel';\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n submitOnEnter?: boolean;\n}\n\nexport interface CompletionAttributes {\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n expressions?: string;\n counter?: string;\n minHeight?: number;\n}\n\nexport interface SelectAttributes {\n placeholder?: string;\n multi?: boolean;\n searchable?: boolean;\n tags?: boolean;\n emails?: boolean;\n clearable?: boolean;\n endpoint?: string;\n valueKey?: string;\n nameKey?: string;\n queryParam?: string;\n maxItems?: number;\n maxItemsText?: string;\n expressions?: string;\n options?: Array<{ name: string; value: any }>;\n sorted?: boolean;\n allowCreate?: boolean;\n jsonValue?: boolean;\n spaceSelect?: boolean;\n infoText?: string;\n}\n\nexport interface CheckboxAttributes {\n label?: string;\n size?: number;\n disabled?: boolean;\n animateChange?: string;\n}\n\nexport interface SliderAttributes {\n min?: number;\n max?: number;\n range?: boolean;\n}\n\n// Widget configuration using discriminated union for type safety\nexport type WidgetConfig =\n | { type: 'temba-textinput'; attributes?: TextInputAttributes }\n | { type: 'temba-completion'; attributes?: CompletionAttributes }\n | { type: 'temba-select'; attributes?: SelectAttributes }\n | { type: 'temba-checkbox'; attributes?: CheckboxAttributes }\n | { type: 'temba-slider'; attributes?: SliderAttributes }\n | { type: string; attributes?: { [key: string]: any } }; // Generic fallback\n\n// Property configuration with the clean structure you want\nexport interface PropertyConfig {\n // Form field metadata\n label?: string;\n helpText?: string;\n required?: boolean;\n maxLength?: number;\n minLength?: number;\n pattern?: string;\n\n // Widget configuration\n widget: WidgetConfig;\n\n // Conditional behavior based on other field values\n conditions?: {\n // When to show this field\n visible?: (formData: any) => boolean;\n\n // When this field is disabled\n disabled?: (formData: any) => boolean;\n };\n}\n\nexport interface NodeConfig {\n type: string;\n name?: string;\n color?: string;\n action?: ActionConfig;\n router?: {\n type: 'switch' | 'random';\n defaultCategory?: string;\n operand?: string;\n configurable?: boolean; // can the rules be configured in the UI\n rules?: {\n type: 'has_number_between' | 'has_string' | 'has_value' | 'has_not_value';\n arguments: string[];\n categoryName: string;\n }[];\n };\n properties?: { [key: string]: PropertyConfig };\n toFormData?: (node: any) => any;\n fromFormData?: (formData: any, originalNode: any) => any;\n}\n\n// New field configuration system for generic form generation\nexport interface BaseFieldConfig {\n label?: string;\n required?: boolean;\n evaluated?: boolean; // if this field supports expression evaluation\n dependsOn?: string[]; // fields this field depends on\n computeValue?: (\n values: Record<string, any>,\n currentValue: any,\n originalValues?: Record<string, any>\n ) => any;\n\n // Validation properties\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n helpText?: string;\n\n // Layout properties\n maxWidth?: string; // CSS max-width value (e.g., '200px', '50%', '10rem')\n\n // Conditional rendering\n conditions?: {\n visible?: (formData: Record<string, any>) => boolean;\n disabled?: (formData: Record<string, any>) => boolean;\n };\n}\n\nexport interface TextFieldConfig extends BaseFieldConfig {\n type: 'text';\n placeholder?: string;\n}\n\nexport interface TextareaFieldConfig extends BaseFieldConfig {\n type: 'textarea';\n placeholder?: string;\n rows?: number;\n minHeight?: number;\n}\n\nexport interface SelectFieldConfig extends BaseFieldConfig {\n type: 'select';\n options: string[] | { value: string; label: string }[];\n multi?: boolean;\n searchable?: boolean;\n tags?: boolean;\n placeholder?: string;\n maxItems?: number;\n valueKey?: string;\n nameKey?: string;\n endpoint?: string;\n emails?: boolean;\n}\n\nexport interface KeyValueFieldConfig extends BaseFieldConfig {\n type: 'key-value';\n sortable?: boolean;\n keyPlaceholder?: string;\n valuePlaceholder?: string;\n minRows?: number;\n}\n\nexport interface ArrayFieldConfig extends BaseFieldConfig {\n type: 'array';\n itemConfig: Record<string, FieldConfig>;\n sortable?: boolean;\n minItems?: number;\n maxItems?: number;\n itemLabel?: string;\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n}\n\nexport interface CheckboxFieldConfig extends BaseFieldConfig {\n type: 'checkbox';\n size?: number;\n animateChange?: string;\n}\n\nexport type FieldConfig =\n | TextFieldConfig\n | TextareaFieldConfig\n | SelectFieldConfig\n | KeyValueFieldConfig\n | ArrayFieldConfig\n | CheckboxFieldConfig;\n\n// Layout configurations for better form organization\n// Recursive layout system - any layout item can contain other layout items\n\nexport interface FieldItemConfig {\n type: 'field';\n field: string; // field name to render\n}\n\nexport interface RowLayoutConfig {\n type: 'row';\n items: LayoutItem[]; // can contain fields, groups, or other rows\n gap?: string; // CSS gap value, defaults to '1rem'\n}\n\nexport interface GroupLayoutConfig {\n type: 'group';\n label: string;\n items: LayoutItem[]; // can contain fields, rows, or other groups\n collapsible?: boolean;\n collapsed?: boolean; // initial state if collapsible\n helpText?: string;\n}\n\nexport type LayoutItem =\n | FieldItemConfig\n | RowLayoutConfig\n | GroupLayoutConfig\n | string; // string is shorthand for field\n\nexport interface ActionConfig {\n name: string;\n color: string;\n evaluated?: string[];\n render?: (node: any, action: any) => TemplateResult;\n\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[]; // optional layout configuration - array of layout items\n\n // Action editor configuration (legacy)\n // Form-level transformations\n toFormData?: (action: Action) => any;\n fromFormData?: (formData: any) => Action;\n\n validate?: (action: Action) => ValidationResult;\n}\n\nexport const COLORS = {\n send: '#3498db',\n update: '#01c1af',\n broadcast: '#8e5ea7',\n call: '#e68628',\n create: '#df419f',\n save: '#1a777c',\n split: '#aaaaaa',\n execute: '#666666',\n wait: '#4d7dad',\n add: '#309c42',\n remove: '#e74c3c'\n};\n\n// Default property type mappings\nexport function getDefaultComponent(value: any): WidgetConfig['type'] {\n if (typeof value === 'boolean') {\n return 'temba-checkbox';\n }\n if (typeof value === 'number') {\n return 'temba-textinput';\n }\n if (Array.isArray(value)) {\n return 'temba-select'; // For arrays, use multi-select\n }\n // Default to text input for strings and unknown types\n return 'temba-textinput';\n}\n\n// Get component properties for default mappings with proper typing\nexport function getDefaultComponentProps(value: any): PropertyConfig {\n if (typeof value === 'boolean') {\n return {\n widget: { type: 'temba-checkbox' }\n };\n }\n if (typeof value === 'number') {\n return {\n widget: {\n type: 'temba-textinput',\n attributes: { type: 'number' }\n }\n };\n }\n if (Array.isArray(value)) {\n if (value.length > 0 && typeof value[0] === 'string') {\n return {\n widget: {\n type: 'temba-select',\n attributes: { multi: true, tags: true }\n }\n };\n }\n return {\n widget: {\n type: 'temba-select',\n attributes: { multi: true }\n }\n };\n }\n return {\n widget: { type: 'temba-textinput' }\n };\n}\n\n// Type guard functions for working with WidgetConfig\nexport function isTextInputWidget(\n config: WidgetConfig\n): config is { type: 'temba-textinput'; attributes?: TextInputAttributes } {\n return config.type === 'temba-textinput';\n}\n\nexport function isCompletionWidget(\n config: WidgetConfig\n): config is { type: 'temba-completion'; attributes?: CompletionAttributes } {\n return config.type === 'temba-completion';\n}\n\nexport function isSelectWidget(\n config: WidgetConfig\n): config is { type: 'temba-select'; attributes?: SelectAttributes } {\n return config.type === 'temba-select';\n}\n\nexport function isCheckboxWidget(\n config: WidgetConfig\n): config is { type: 'temba-checkbox'; attributes?: CheckboxAttributes } {\n return config.type === 'temba-checkbox';\n}\n\nexport function isSliderWidget(\n config: WidgetConfig\n): config is { type: 'slider'; attributes?: SliderAttributes } {\n return config.type === 'temba-slider';\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/flow/types.ts"],"names":[],"mappings":"AAiQA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,MAAM,EAAE,SAAS;CAClB,CAAC","sourcesContent":["import { TemplateResult } from 'lit-html';\nimport { Action, Node } from '../store/flow-definition';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: { [key: string]: string };\n}\n\n// Component attribute interfaces - these define what's allowed for each component type\nexport interface TextInputAttributes {\n type?: 'text' | 'email' | 'number' | 'url' | 'tel';\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n submitOnEnter?: boolean;\n}\n\nexport interface CompletionAttributes {\n placeholder?: string;\n clearable?: boolean;\n maxlength?: number;\n gsm?: boolean;\n autogrow?: boolean;\n textarea?: boolean;\n expressions?: string;\n counter?: string;\n minHeight?: number;\n}\n\nexport interface SelectAttributes {\n placeholder?: string;\n multi?: boolean;\n searchable?: boolean;\n tags?: boolean;\n emails?: boolean;\n clearable?: boolean;\n endpoint?: string;\n valueKey?: string;\n nameKey?: string;\n queryParam?: string;\n maxItems?: number;\n maxItemsText?: string;\n expressions?: string;\n options?: Array<{ name: string; value: any }>;\n sorted?: boolean;\n allowCreate?: boolean;\n jsonValue?: boolean;\n spaceSelect?: boolean;\n infoText?: string;\n}\n\nexport interface CheckboxAttributes {\n label?: string;\n size?: number;\n disabled?: boolean;\n animateChange?: string;\n}\n\nexport interface SliderAttributes {\n min?: number;\n max?: number;\n range?: boolean;\n}\n\nexport interface FormData extends Record<string, any> {}\n\nexport interface FormConfig {\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[];\n sanitize?: (formData: FormData) => void;\n validate?: (formData: FormData) => ValidationResult;\n}\n\nexport interface NodeConfig extends FormConfig {\n type: string;\n name?: string;\n color?: string;\n action?: ActionConfig;\n router?: {\n type: 'switch' | 'random';\n defaultCategory?: string;\n operand?: string;\n configurable?: boolean; // can the rules be configured in the UI\n rules?: {\n type:\n | 'has_number_between'\n | 'has_string'\n | 'has_value'\n | 'has_not_value'\n | 'has_text';\n arguments: string[];\n categoryName: string;\n }[];\n };\n\n toFormData?: (node: Node) => FormData;\n fromFormData?: (formData: FormData, originalNode: Node) => Node;\n render?: (node: Node) => TemplateResult;\n}\n\n// New field configuration system for generic form generation\nexport interface BaseFieldConfig {\n label?: string;\n required?: boolean;\n evaluated?: boolean;\n dependsOn?: string[];\n computeValue?: (\n values: Record<string, any>,\n currentValue: any,\n originalValues?: Record<string, any>\n ) => any;\n\n // Validation properties\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n helpText?: string;\n\n // Layout properties\n maxWidth?: string;\n\n // Conditional rendering\n conditions?: {\n visible?: (formData: Record<string, any>) => boolean;\n disabled?: (formData: Record<string, any>) => boolean;\n };\n}\n\nexport interface TextFieldConfig extends BaseFieldConfig {\n type: 'text';\n placeholder?: string;\n}\n\nexport interface TextareaFieldConfig extends BaseFieldConfig {\n type: 'textarea';\n placeholder?: string;\n rows?: number;\n minHeight?: number;\n}\n\nexport interface SelectFieldConfig extends BaseFieldConfig {\n type: 'select';\n options?: string[] | { value: string; label: string }[];\n multi?: boolean;\n clearable?: boolean;\n searchable?: boolean;\n tags?: boolean;\n placeholder?: string;\n maxItems?: number;\n valueKey?: string;\n nameKey?: string;\n endpoint?: string;\n emails?: boolean;\n getName?: (item: any) => string;\n flavor?: 'small' | 'large';\n createArbitraryOption?: (input: string, options: any[]) => any;\n allowCreate?: boolean;\n}\n\nexport interface KeyValueFieldConfig extends BaseFieldConfig {\n type: 'key-value';\n sortable?: boolean;\n keyPlaceholder?: string;\n valuePlaceholder?: string;\n minRows?: number;\n}\n\nexport interface ArrayFieldConfig extends BaseFieldConfig {\n type: 'array';\n itemConfig: Record<string, FieldConfig>;\n sortable?: boolean;\n minItems?: number;\n maxItems?: number;\n itemLabel?: string;\n onItemChange?: (\n itemIndex: number,\n field: string,\n value: any,\n allItems: any[]\n ) => any[];\n isEmptyItem?: (item: any) => boolean;\n}\n\nexport interface CheckboxFieldConfig extends BaseFieldConfig {\n type: 'checkbox';\n size?: number;\n animateChange?: string;\n}\n\nexport interface MessageEditorFieldConfig extends BaseFieldConfig {\n type: 'message-editor';\n placeholder?: string;\n minHeight?: number;\n maxAttachments?: number;\n accept?: string;\n endpoint?: string;\n counter?: string;\n gsm?: boolean;\n autogrow?: boolean;\n disableCompletion?: boolean;\n}\n\nexport type FieldConfig =\n | TextFieldConfig\n | TextareaFieldConfig\n | SelectFieldConfig\n | KeyValueFieldConfig\n | ArrayFieldConfig\n | CheckboxFieldConfig\n | MessageEditorFieldConfig;\n\n// Layout configurations for better form organization\n// Recursive layout system - any layout item can contain other layout items\n\nexport interface FieldItemConfig {\n type: 'field';\n field: string; // field name to render\n}\n\nexport interface RowLayoutConfig {\n type: 'row';\n items: LayoutItem[]; // can contain fields, groups, or other rows\n gap?: string; // CSS gap value, defaults to '1rem'\n}\n\nexport interface GroupLayoutConfig {\n type: 'group';\n label: string;\n items: LayoutItem[]; // can contain fields, rows, or other groups\n collapsible?: boolean;\n collapsed?: boolean | ((formData: any) => boolean); // initial state if collapsible - can be a function\n helpText?: string;\n getGroupValueCount?: (formData: any) => number; // optional function to get count for bubble display\n}\n\nexport type LayoutItem =\n | FieldItemConfig\n | RowLayoutConfig\n | GroupLayoutConfig\n | string; // string is shorthand for field\n\nexport interface ActionConfig extends FormConfig {\n name: string;\n color: string;\n evaluated?: string[];\n render?: (node: any, action: any) => TemplateResult;\n\n form?: Record<string, FieldConfig>;\n layout?: LayoutItem[]; // optional layout configuration - array of layout items\n\n toFormData?: (action: Action) => any;\n fromFormData?: (formData: any) => Action;\n}\n\nexport const COLORS = {\n send: '#3498db',\n update: '#01c1af',\n broadcast: '#8e5ea7',\n call: '#e68628',\n create: '#df419f',\n save: '#1a777c',\n split: '#aaaaaa',\n execute: '#666666',\n wait: '#4d7dad',\n add: '#309c42',\n remove: '#e74c3c'\n};\n"]}