@nyaruka/temba-components 0.131.2 → 0.132.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/demo/components/floating-tabs/example.html +400 -0
  3. package/demo/components/flow/index.html +1 -1
  4. package/demo/data/flows/sample-flow.json +41 -2
  5. package/demo/data/flows/voicemail.json +613 -0
  6. package/demo/index.html +6 -0
  7. package/dist/locales/es.js +5 -5
  8. package/dist/locales/es.js.map +1 -1
  9. package/dist/locales/fr.js +5 -5
  10. package/dist/locales/fr.js.map +1 -1
  11. package/dist/locales/locale-codes.js +11 -2
  12. package/dist/locales/locale-codes.js.map +1 -1
  13. package/dist/locales/pt.js +5 -5
  14. package/dist/locales/pt.js.map +1 -1
  15. package/dist/temba-components.js +1122 -548
  16. package/dist/temba-components.js.map +1 -1
  17. package/out-tsc/src/display/FloatingTab.js +167 -0
  18. package/out-tsc/src/display/FloatingTab.js.map +1 -0
  19. package/out-tsc/src/display/ProgressBar.js +22 -2
  20. package/out-tsc/src/display/ProgressBar.js.map +1 -1
  21. package/out-tsc/src/events.js.map +1 -1
  22. package/out-tsc/src/flow/CanvasNode.js +165 -31
  23. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  24. package/out-tsc/src/flow/Editor.js +870 -3
  25. package/out-tsc/src/flow/Editor.js.map +1 -1
  26. package/out-tsc/src/flow/NodeEditor.js +239 -19
  27. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  28. package/out-tsc/src/flow/NodeTypeSelector.js +51 -4
  29. package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
  30. package/out-tsc/src/flow/StickyNote.js +12 -3
  31. package/out-tsc/src/flow/StickyNote.js.map +1 -1
  32. package/out-tsc/src/flow/actions/add_contact_groups.js +2 -1
  33. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  34. package/out-tsc/src/flow/actions/add_contact_urn.js +2 -1
  35. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
  36. package/out-tsc/src/flow/actions/add_input_labels.js +2 -1
  37. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  38. package/out-tsc/src/flow/actions/play_audio.js +2 -1
  39. package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
  40. package/out-tsc/src/flow/actions/remove_contact_groups.js +2 -1
  41. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  42. package/out-tsc/src/flow/actions/request_optin.js +1 -0
  43. package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
  44. package/out-tsc/src/flow/actions/say_msg.js +2 -1
  45. package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
  46. package/out-tsc/src/flow/actions/send_broadcast.js +2 -1
  47. package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
  48. package/out-tsc/src/flow/actions/send_email.js +2 -1
  49. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  50. package/out-tsc/src/flow/actions/send_msg.js +93 -3
  51. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  52. package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
  53. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  54. package/out-tsc/src/flow/actions/set_contact_field.js +2 -1
  55. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  56. package/out-tsc/src/flow/actions/set_contact_language.js +2 -1
  57. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  58. package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
  59. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
  60. package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
  61. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  62. package/out-tsc/src/flow/actions/set_run_result.js +2 -1
  63. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  64. package/out-tsc/src/flow/actions/start_session.js +2 -1
  65. package/out-tsc/src/flow/actions/start_session.js.map +1 -1
  66. package/out-tsc/src/flow/config.js +19 -14
  67. package/out-tsc/src/flow/config.js.map +1 -1
  68. package/out-tsc/src/flow/nodes/shared.js +54 -0
  69. package/out-tsc/src/flow/nodes/shared.js.map +1 -1
  70. package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -3
  71. package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -1
  72. package/out-tsc/src/flow/nodes/split_by_contact_field.js +8 -3
  73. package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
  74. package/out-tsc/src/flow/nodes/split_by_expression.js +8 -3
  75. package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
  76. package/out-tsc/src/flow/nodes/split_by_groups.js +8 -3
  77. package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
  78. package/out-tsc/src/flow/nodes/split_by_intent.js +3 -2
  79. package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -1
  80. package/out-tsc/src/flow/nodes/split_by_llm.js +9 -2
  81. package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
  82. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +9 -2
  83. package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
  84. package/out-tsc/src/flow/nodes/split_by_random.js +8 -2
  85. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  86. package/out-tsc/src/flow/nodes/split_by_resthook.js +8 -3
  87. package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
  88. package/out-tsc/src/flow/nodes/split_by_run_result.js +14 -3
  89. package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
  90. package/out-tsc/src/flow/nodes/split_by_scheme.js +8 -3
  91. package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
  92. package/out-tsc/src/flow/nodes/split_by_subflow.js +8 -2
  93. package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
  94. package/out-tsc/src/flow/nodes/split_by_ticket.js +8 -2
  95. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  96. package/out-tsc/src/flow/nodes/split_by_webhook.js +8 -2
  97. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  98. package/out-tsc/src/flow/nodes/wait_for_digits.js +3 -2
  99. package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
  100. package/out-tsc/src/flow/nodes/wait_for_menu.js +3 -2
  101. package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
  102. package/out-tsc/src/flow/nodes/wait_for_response.js +8 -3
  103. package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
  104. package/out-tsc/src/flow/types.js +15 -0
  105. package/out-tsc/src/flow/types.js.map +1 -1
  106. package/out-tsc/src/layout/FloatingWindow.js +346 -0
  107. package/out-tsc/src/layout/FloatingWindow.js.map +1 -0
  108. package/out-tsc/src/live/ContactChat.js +41 -49
  109. package/out-tsc/src/live/ContactChat.js.map +1 -1
  110. package/out-tsc/src/locales/es.js +5 -5
  111. package/out-tsc/src/locales/es.js.map +1 -1
  112. package/out-tsc/src/locales/fr.js +5 -5
  113. package/out-tsc/src/locales/fr.js.map +1 -1
  114. package/out-tsc/src/locales/locale-codes.js +11 -2
  115. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  116. package/out-tsc/src/locales/pt.js +5 -5
  117. package/out-tsc/src/locales/pt.js.map +1 -1
  118. package/out-tsc/src/store/AppState.js +75 -1
  119. package/out-tsc/src/store/AppState.js.map +1 -1
  120. package/out-tsc/temba-modules.js +4 -0
  121. package/out-tsc/temba-modules.js.map +1 -1
  122. package/out-tsc/test/nodes/split_by_run_result.test.js +83 -0
  123. package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
  124. package/out-tsc/test/temba-backwards-compatibility.test.js +30 -0
  125. package/out-tsc/test/temba-backwards-compatibility.test.js.map +1 -0
  126. package/out-tsc/test/temba-contact-chat.test.js +27 -12
  127. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  128. package/out-tsc/test/temba-floating-tab.test.js +91 -0
  129. package/out-tsc/test/temba-floating-tab.test.js.map +1 -0
  130. package/out-tsc/test/temba-floating-window.test.js +301 -0
  131. package/out-tsc/test/temba-floating-window.test.js.map +1 -0
  132. package/out-tsc/test/temba-flow-editor-node.test.js +117 -0
  133. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  134. package/out-tsc/test/temba-localization.test.js +490 -0
  135. package/out-tsc/test/temba-localization.test.js.map +1 -0
  136. package/out-tsc/test/temba-node-type-selector.test.js +217 -0
  137. package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
  138. package/out-tsc/test/utils.test.js +18 -0
  139. package/out-tsc/test/utils.test.js.map +1 -1
  140. package/package.json +1 -1
  141. package/screenshots/truth/floating-tab/default.png +0 -0
  142. package/screenshots/truth/floating-tab/gray.png +0 -0
  143. package/screenshots/truth/floating-tab/green.png +0 -0
  144. package/screenshots/truth/floating-tab/hidden.png +0 -0
  145. package/screenshots/truth/floating-tab/hover.png +0 -0
  146. package/screenshots/truth/floating-tab/purple.png +0 -0
  147. package/screenshots/truth/floating-window/chromeless.png +0 -0
  148. package/screenshots/truth/floating-window/custom-size.png +0 -0
  149. package/screenshots/truth/floating-window/default.png +0 -0
  150. package/screenshots/truth/floating-window/with-header.png +0 -0
  151. package/screenshots/truth/node-type-selector/action-mode.png +0 -0
  152. package/screenshots/truth/node-type-selector/split-mode.png +0 -0
  153. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  154. package/src/display/FloatingTab.ts +174 -0
  155. package/src/display/ProgressBar.ts +22 -2
  156. package/src/events.ts +2 -4
  157. package/src/flow/CanvasNode.ts +190 -32
  158. package/src/flow/Editor.ts +1054 -4
  159. package/src/flow/NodeEditor.ts +317 -19
  160. package/src/flow/NodeTypeSelector.ts +54 -4
  161. package/src/flow/StickyNote.ts +12 -3
  162. package/src/flow/actions/add_contact_groups.ts +2 -1
  163. package/src/flow/actions/add_contact_urn.ts +3 -1
  164. package/src/flow/actions/add_input_labels.ts +2 -1
  165. package/src/flow/actions/play_audio.ts +2 -1
  166. package/src/flow/actions/remove_contact_groups.ts +3 -1
  167. package/src/flow/actions/request_optin.ts +1 -0
  168. package/src/flow/actions/say_msg.ts +2 -1
  169. package/src/flow/actions/send_broadcast.ts +2 -1
  170. package/src/flow/actions/send_email.ts +3 -1
  171. package/src/flow/actions/send_msg.ts +134 -3
  172. package/src/flow/actions/set_contact_channel.ts +2 -1
  173. package/src/flow/actions/set_contact_field.ts +2 -1
  174. package/src/flow/actions/set_contact_language.ts +3 -1
  175. package/src/flow/actions/set_contact_name.ts +2 -1
  176. package/src/flow/actions/set_contact_status.ts +2 -1
  177. package/src/flow/actions/set_run_result.ts +2 -1
  178. package/src/flow/actions/start_session.ts +3 -1
  179. package/src/flow/config.ts +24 -16
  180. package/src/flow/nodes/shared.ts +70 -1
  181. package/src/flow/nodes/split_by_airtime.ts +20 -3
  182. package/src/flow/nodes/split_by_contact_field.ts +13 -3
  183. package/src/flow/nodes/split_by_expression.ts +13 -3
  184. package/src/flow/nodes/split_by_groups.ts +13 -3
  185. package/src/flow/nodes/split_by_intent.ts +3 -2
  186. package/src/flow/nodes/split_by_llm.ts +19 -2
  187. package/src/flow/nodes/split_by_llm_categorize.ts +13 -2
  188. package/src/flow/nodes/split_by_random.ts +12 -2
  189. package/src/flow/nodes/split_by_resthook.ts +13 -3
  190. package/src/flow/nodes/split_by_run_result.ts +20 -3
  191. package/src/flow/nodes/split_by_scheme.ts +13 -3
  192. package/src/flow/nodes/split_by_subflow.ts +12 -2
  193. package/src/flow/nodes/split_by_ticket.ts +12 -2
  194. package/src/flow/nodes/split_by_webhook.ts +12 -2
  195. package/src/flow/nodes/wait_for_digits.ts +3 -2
  196. package/src/flow/nodes/wait_for_menu.ts +3 -2
  197. package/src/flow/nodes/wait_for_response.ts +13 -3
  198. package/src/flow/types.ts +49 -0
  199. package/src/layout/FloatingWindow.ts +386 -0
  200. package/src/live/ContactChat.ts +42 -49
  201. package/src/locales/es.ts +18 -13
  202. package/src/locales/fr.ts +18 -13
  203. package/src/locales/locale-codes.ts +11 -2
  204. package/src/locales/pt.ts +18 -13
  205. package/src/store/AppState.ts +116 -1
  206. package/static/api/llms.json +18 -0
  207. package/temba-modules.ts +4 -0
  208. package/test/nodes/split_by_run_result.test.ts +99 -0
  209. package/test/temba-backwards-compatibility.test.ts +37 -0
  210. package/test/temba-contact-chat.test.ts +27 -12
  211. package/test/temba-floating-tab.test.ts +110 -0
  212. package/test/temba-floating-window.test.ts +477 -0
  213. package/test/temba-flow-editor-node.test.ts +144 -0
  214. package/test/temba-localization.test.ts +635 -0
  215. package/test/temba-node-type-selector.test.ts +289 -0
  216. package/test/utils.test.ts +20 -0
  217. package/test-assets/contacts/history.json +5 -6
  218. package/test-assets/select/llms.json +2 -2
  219. package/web-dev-server.config.mjs +47 -1
  220. package/web-test-runner.config.mjs +0 -1
  221. package/out-tsc/src/flow/nodes/wait_for_audio.js +0 -7
  222. package/out-tsc/src/flow/nodes/wait_for_audio.js.map +0 -1
  223. package/out-tsc/src/flow/nodes/wait_for_image.js +0 -7
  224. package/out-tsc/src/flow/nodes/wait_for_image.js.map +0 -1
  225. package/out-tsc/src/flow/nodes/wait_for_location.js +0 -7
  226. package/out-tsc/src/flow/nodes/wait_for_location.js.map +0 -1
  227. package/out-tsc/src/flow/nodes/wait_for_video.js +0 -7
  228. package/out-tsc/src/flow/nodes/wait_for_video.js.map +0 -1
  229. package/src/flow/nodes/wait_for_audio.ts +0 -7
  230. package/src/flow/nodes/wait_for_image.ts +0 -7
  231. package/src/flow/nodes/wait_for_location.ts +0 -7
  232. package/src/flow/nodes/wait_for_video.ts +0 -7
@@ -1,12 +1,24 @@
1
- import { ACTION_GROUPS, FormData, NodeConfig } from '../types';
1
+ import {
2
+ ACTION_GROUPS,
3
+ FormData,
4
+ NodeConfig,
5
+ FlowTypes,
6
+ Features
7
+ } from '../types';
2
8
  import { CallLLM, Node } from '../../store/flow-definition';
3
9
  import { generateUUID, createSuccessFailureRouter } from '../../utils';
4
10
  import { html } from 'lit';
11
+ import {
12
+ categoriesToLocalizationFormData,
13
+ localizationFormDataToCategories
14
+ } from './shared';
5
15
 
6
16
  export const split_by_llm: NodeConfig = {
7
17
  type: 'split_by_llm',
8
18
  name: 'Call AI',
9
19
  group: ACTION_GROUPS.services,
20
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
21
+ features: [Features.AI],
10
22
  showAsAction: true,
11
23
  render: (node: Node) => {
12
24
  const callLlmAction = node.actions?.find(
@@ -117,5 +129,10 @@ export const split_by_llm: NodeConfig = {
117
129
  router: router,
118
130
  exits: exits
119
131
  };
120
- }
132
+ },
133
+
134
+ // Localization support for categories
135
+ localizable: 'categories',
136
+ toLocalizationFormData: categoriesToLocalizationFormData,
137
+ fromLocalizationFormData: localizationFormDataToCategories
121
138
  };
@@ -1,12 +1,18 @@
1
- import { FormData, NodeConfig, ACTION_GROUPS } from '../types';
1
+ import { FormData, NodeConfig, ACTION_GROUPS, Features } from '../types';
2
2
  import { CallLLM, Node } from '../../store/flow-definition';
3
3
  import { generateUUID, createMultiCategoryRouter } from '../../utils';
4
4
  import { html } from 'lit';
5
+ import {
6
+ categoriesToLocalizationFormData,
7
+ localizationFormDataToCategories
8
+ } from './shared';
5
9
 
6
10
  export const split_by_llm_categorize: NodeConfig = {
7
11
  type: 'split_by_llm_categorize',
8
12
  name: 'Split by AI',
9
13
  group: ACTION_GROUPS.services,
14
+ flowTypes: [],
15
+ features: [Features.AI],
10
16
  form: {
11
17
  llm: {
12
18
  type: 'select',
@@ -171,5 +177,10 @@ export const split_by_llm_categorize: NodeConfig = {
171
177
  router: router,
172
178
  exits: exits
173
179
  };
174
- }
180
+ },
181
+
182
+ // Localization support for categories
183
+ localizable: 'categories',
184
+ toLocalizationFormData: categoriesToLocalizationFormData,
185
+ fromLocalizationFormData: localizationFormDataToCategories
175
186
  };
@@ -1,6 +1,10 @@
1
- import { SPLIT_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, Category, Exit } from '../../store/flow-definition.d';
3
3
  import { generateUUID } from '../../utils';
4
+ import {
5
+ categoriesToLocalizationFormData,
6
+ localizationFormDataToCategories
7
+ } from './shared';
4
8
 
5
9
  // Helper function to create a random router with categories
6
10
  const createRandomRouter = (
@@ -49,6 +53,7 @@ export const split_by_random: NodeConfig = {
49
53
  type: 'split_by_random',
50
54
  name: 'Random Split',
51
55
  group: SPLIT_GROUPS.split,
56
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
52
57
  form: {
53
58
  categories: {
54
59
  type: 'array',
@@ -155,5 +160,10 @@ export const split_by_random: NodeConfig = {
155
160
  },
156
161
  router: {
157
162
  type: 'random'
158
- }
163
+ },
164
+
165
+ // Localization support for categories
166
+ localizable: 'categories',
167
+ toLocalizationFormData: categoriesToLocalizationFormData,
168
+ fromLocalizationFormData: localizationFormDataToCategories
159
169
  };
@@ -1,13 +1,18 @@
1
- import { ACTION_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { ACTION_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { CallResthook, Node } from '../../store/flow-definition';
3
3
  import { generateUUID, createSuccessFailureRouter } from '../../utils';
4
4
  import { html } from 'lit';
5
- import { resultNameField } from './shared';
5
+ import {
6
+ resultNameField,
7
+ categoriesToLocalizationFormData,
8
+ localizationFormDataToCategories
9
+ } from './shared';
6
10
 
7
11
  export const split_by_resthook: NodeConfig = {
8
12
  type: 'split_by_resthook',
9
13
  name: 'Call Resthook',
10
14
  group: ACTION_GROUPS.services,
15
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
11
16
  showAsAction: true,
12
17
  form: {
13
18
  resthook: {
@@ -126,5 +131,10 @@ export const split_by_resthook: NodeConfig = {
126
131
  router: finalRouter,
127
132
  exits: exits
128
133
  };
129
- }
134
+ },
135
+
136
+ // Localization support for categories
137
+ localizable: 'categories',
138
+ toLocalizationFormData: categoriesToLocalizationFormData,
139
+ fromLocalizationFormData: localizationFormDataToCategories
130
140
  };
@@ -1,4 +1,4 @@
1
- import { SPLIT_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node } from '../../store/flow-definition';
3
3
  import { createRulesRouter } from '../../utils';
4
4
  import {
@@ -6,7 +6,11 @@ import {
6
6
  operatorsToSelectOptions,
7
7
  getOperatorConfig
8
8
  } from '../operators';
9
- import { resultNameField } from './shared';
9
+ import {
10
+ resultNameField,
11
+ categoriesToLocalizationFormData,
12
+ localizationFormDataToCategories
13
+ } from './shared';
10
14
  import {
11
15
  createRulesArrayConfig,
12
16
  extractUserRules,
@@ -49,7 +53,9 @@ const DELIMIT_BY_OPTIONS = [
49
53
  export const split_by_run_result: NodeConfig = {
50
54
  type: 'split_by_run_result',
51
55
  name: 'Split by Result',
56
+ aliases: ['split_by_run_result_delimited'], // backwards compatibility with old flow editor
52
57
  group: SPLIT_GROUPS.split,
58
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
53
59
  dialogSize: 'large',
54
60
  form: {
55
61
  result: {
@@ -248,6 +254,17 @@ export const split_by_run_result: NodeConfig = {
248
254
  config.delimiter = delimitBy;
249
255
  }
250
256
 
257
+ // Set the type based on whether delimiter is configured
258
+ // Use split_by_run_result_delimited for backward compatibility with old editor
259
+ config.type = hasDelimiter
260
+ ? 'split_by_run_result_delimited'
261
+ : 'split_by_run_result';
262
+
251
263
  return config;
252
- }
264
+ },
265
+
266
+ // Localization support for categories
267
+ localizable: 'categories',
268
+ toLocalizationFormData: categoriesToLocalizationFormData,
269
+ fromLocalizationFormData: localizationFormDataToCategories
253
270
  };
@@ -1,8 +1,12 @@
1
- import { SPLIT_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, Category, Exit, Case } from '../../store/flow-definition.d';
3
3
  import { generateUUID } from '../../utils';
4
4
  import { SCHEMES } from '../utils';
5
- import { resultNameField } from './shared';
5
+ import {
6
+ resultNameField,
7
+ categoriesToLocalizationFormData,
8
+ localizationFormDataToCategories
9
+ } from './shared';
6
10
 
7
11
  // Helper function to get scheme options for the select dropdown
8
12
  const getSchemeOptions = () => {
@@ -106,6 +110,7 @@ export const split_by_scheme: NodeConfig = {
106
110
  type: 'split_by_scheme',
107
111
  name: 'Split by URN Type',
108
112
  group: SPLIT_GROUPS.split,
113
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
109
114
  form: {
110
115
  schemes: {
111
116
  type: 'select',
@@ -193,5 +198,10 @@ export const split_by_scheme: NodeConfig = {
193
198
  router: {
194
199
  type: 'switch',
195
200
  operand: '@(urn_parts(contact.urn).scheme)'
196
- }
201
+ },
202
+
203
+ // Localization support for categories
204
+ localizable: 'categories',
205
+ toLocalizationFormData: categoriesToLocalizationFormData,
206
+ fromLocalizationFormData: localizationFormDataToCategories
197
207
  };
@@ -1,13 +1,18 @@
1
- import { ACTION_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { ACTION_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node } from '../../store/flow-definition';
3
3
  import { generateUUID } from '../../utils';
4
4
  import { html } from 'lit';
5
5
  import { renderNamedObjects } from '../utils';
6
+ import {
7
+ categoriesToLocalizationFormData,
8
+ localizationFormDataToCategories
9
+ } from './shared';
6
10
 
7
11
  export const split_by_subflow: NodeConfig = {
8
12
  type: 'split_by_subflow',
9
13
  name: 'Enter a Flow',
10
14
  group: ACTION_GROUPS.trigger,
15
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
11
16
  showAsAction: true,
12
17
  form: {
13
18
  flow: {
@@ -157,5 +162,10 @@ export const split_by_subflow: NodeConfig = {
157
162
  router: router,
158
163
  exits: exits
159
164
  };
160
- }
165
+ },
166
+
167
+ // Localization support for categories
168
+ localizable: 'categories',
169
+ toLocalizationFormData: categoriesToLocalizationFormData,
170
+ fromLocalizationFormData: localizationFormDataToCategories
161
171
  };
@@ -1,12 +1,17 @@
1
- import { ACTION_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { ACTION_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, OpenTicket } from '../../store/flow-definition';
3
3
  import { generateUUID, createSuccessFailureRouter } from '../../utils';
4
4
  import { html } from 'lit';
5
+ import {
6
+ categoriesToLocalizationFormData,
7
+ localizationFormDataToCategories
8
+ } from './shared';
5
9
 
6
10
  export const split_by_ticket: NodeConfig = {
7
11
  type: 'split_by_ticket',
8
12
  name: 'Open Ticket',
9
13
  group: ACTION_GROUPS.trigger,
14
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
10
15
  showAsAction: true,
11
16
  form: {
12
17
  topic: {
@@ -138,5 +143,10 @@ export const split_by_ticket: NodeConfig = {
138
143
  router: router,
139
144
  exits: exits
140
145
  };
141
- }
146
+ },
147
+
148
+ // Localization support for categories
149
+ localizable: 'categories',
150
+ toLocalizationFormData: categoriesToLocalizationFormData,
151
+ fromLocalizationFormData: localizationFormDataToCategories
142
152
  };
@@ -1,7 +1,11 @@
1
- import { ACTION_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { ACTION_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { CallWebhook, Node } from '../../store/flow-definition';
3
3
  import { generateUUID, createSuccessFailureRouter } from '../../utils';
4
4
  import { html } from 'lit';
5
+ import {
6
+ categoriesToLocalizationFormData,
7
+ localizationFormDataToCategories
8
+ } from './shared';
5
9
 
6
10
  const defaultPost = `@(json(object(
7
11
  "contact", object(
@@ -20,6 +24,7 @@ export const split_by_webhook: NodeConfig = {
20
24
  type: 'split_by_webhook',
21
25
  name: 'Call Webhook',
22
26
  group: ACTION_GROUPS.services,
27
+ flowTypes: [FlowTypes.VOICE, FlowTypes.MESSAGE, FlowTypes.BACKGROUND],
23
28
  showAsAction: true,
24
29
  form: {
25
30
  method: {
@@ -189,5 +194,10 @@ export const split_by_webhook: NodeConfig = {
189
194
  router: router,
190
195
  exits: exits
191
196
  };
192
- }
197
+ },
198
+
199
+ // Localization support for categories
200
+ localizable: 'categories',
201
+ toLocalizationFormData: categoriesToLocalizationFormData,
202
+ fromLocalizationFormData: localizationFormDataToCategories
193
203
  };
@@ -1,7 +1,8 @@
1
- import { SPLIT_GROUPS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, NodeConfig, FlowTypes } from '../types';
2
2
 
3
3
  export const wait_for_digits: NodeConfig = {
4
4
  type: 'wait_for_digits',
5
5
  name: 'Wait for Digits',
6
- group: SPLIT_GROUPS.wait
6
+ group: SPLIT_GROUPS.wait,
7
+ flowTypes: [FlowTypes.VOICE]
7
8
  };
@@ -1,7 +1,8 @@
1
- import { SPLIT_GROUPS, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, NodeConfig, FlowTypes } from '../types';
2
2
 
3
3
  export const wait_for_menu: NodeConfig = {
4
4
  type: 'wait_for_menu',
5
5
  name: 'Wait for Menu Selection',
6
- group: SPLIT_GROUPS.wait
6
+ group: SPLIT_GROUPS.wait,
7
+ flowTypes: [FlowTypes.VOICE]
7
8
  };
@@ -1,4 +1,4 @@
1
- import { SPLIT_GROUPS, FormData, NodeConfig } from '../types';
1
+ import { SPLIT_GROUPS, FormData, NodeConfig, FlowTypes } from '../types';
2
2
  import { Node, Category, Exit, Case } from '../../store/flow-definition';
3
3
  import { generateUUID, createRulesRouter } from '../../utils';
4
4
  import {
@@ -6,7 +6,11 @@ import {
6
6
  operatorsToSelectOptions,
7
7
  getOperatorConfig
8
8
  } from '../operators';
9
- import { resultNameField } from './shared';
9
+ import {
10
+ resultNameField,
11
+ categoriesToLocalizationFormData,
12
+ localizationFormDataToCategories
13
+ } from './shared';
10
14
  import {
11
15
  createRulesArrayConfig,
12
16
  extractUserRules,
@@ -77,6 +81,7 @@ export const wait_for_response: NodeConfig = {
77
81
  type: 'wait_for_response',
78
82
  name: 'Wait for Response',
79
83
  group: SPLIT_GROUPS.wait,
84
+ flowTypes: [FlowTypes.MESSAGE],
80
85
  dialogSize: 'large',
81
86
  form: {
82
87
  rules: createRulesArrayConfig(
@@ -390,5 +395,10 @@ export const wait_for_response: NodeConfig = {
390
395
  router: finalRouter,
391
396
  exits: exits
392
397
  };
393
- }
398
+ },
399
+
400
+ // Localization support for categories
401
+ localizable: 'categories',
402
+ toLocalizationFormData: categoriesToLocalizationFormData,
403
+ fromLocalizationFormData: localizationFormDataToCategories
394
404
  };
package/src/flow/types.ts CHANGED
@@ -6,6 +6,27 @@ export interface ValidationResult {
6
6
  errors: { [key: string]: string };
7
7
  }
8
8
 
9
+ /**
10
+ * Flow types - defines the type of flow being edited
11
+ */
12
+ export const FlowTypes = {
13
+ MESSAGE: 'message',
14
+ VOICE: 'voice',
15
+ BACKGROUND: 'background'
16
+ } as const;
17
+
18
+ export type FlowType = (typeof FlowTypes)[keyof typeof FlowTypes];
19
+
20
+ /**
21
+ * Features - defines the features available in the account
22
+ */
23
+ export const Features = {
24
+ AI: 'ai',
25
+ AIRTIME: 'airtime'
26
+ } as const;
27
+
28
+ export type Feature = (typeof Features)[keyof typeof Features];
29
+
9
30
  // Component attribute interfaces - these define what's allowed for each component type
10
31
  export interface TextInputAttributes {
11
32
  type?: 'text' | 'email' | 'number' | 'url' | 'tel';
@@ -78,10 +99,13 @@ export interface FormConfig {
78
99
  export interface NodeConfig extends FormConfig {
79
100
  type: string;
80
101
  name?: string;
102
+ aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)
81
103
  group?: ActionGroup | SplitGroup; // Nodes can use either when showAsAction is true
82
104
  dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';
83
105
  action?: ActionConfig;
84
106
  showAsAction?: boolean; // if true, show in action dialog instead of splits (default: false - nodes show in splits)
107
+ flowTypes?: FlowType[]; // which flow types this node is available for (defaults to all if not specified)
108
+ features?: Feature[]; // which features are required for this node (all must be present)
85
109
  router?: {
86
110
  type: 'switch' | 'random';
87
111
  defaultCategory?: string;
@@ -104,6 +128,17 @@ export interface NodeConfig extends FormConfig {
104
128
  toUIConfig?: (formData: FormData) => Record<string, any>;
105
129
  render?: (node: Node, nodeUI?: any) => TemplateResult;
106
130
  renderTitle?: (node: Node, nodeUI?: NodeUI) => TemplateResult;
131
+
132
+ // Localization support for router categories
133
+ localizable?: 'categories'; // Only categories are localizable for routers
134
+ toLocalizationFormData?: (
135
+ node: Node,
136
+ localization: Record<string, any>
137
+ ) => FormData;
138
+ fromLocalizationFormData?: (
139
+ formData: FormData,
140
+ node: Node
141
+ ) => Record<string, any>;
107
142
  }
108
143
 
109
144
  // New field configuration system for generic form generation
@@ -350,10 +385,13 @@ export const SPLIT_GROUP_METADATA: Record<SplitGroup, GroupMetadata> = {
350
385
 
351
386
  export interface ActionConfig extends FormConfig {
352
387
  name: string;
388
+ aliases?: string[]; // alternate type names for backwards compatibility (won't show in selector)
353
389
  group: ActionGroup;
354
390
  dialogSize?: 'small' | 'medium' | 'large' | 'xlarge';
355
391
  evaluated?: string[];
356
392
  hideFromActions?: boolean; // if true, don't show in action dialog (default: false - actions show in actions)
393
+ flowTypes?: FlowType[]; // which flow types this action is available for (defaults to all if not specified)
394
+ features?: Feature[]; // which features are required for this action (all must be present)
357
395
  render?: (node: any, action: any) => TemplateResult;
358
396
 
359
397
  form?: Record<string, FieldConfig>;
@@ -362,4 +400,15 @@ export interface ActionConfig extends FormConfig {
362
400
 
363
401
  toFormData?: (action: Action) => FormData;
364
402
  fromFormData?: (formData: FormData) => Action;
403
+
404
+ // Localization support
405
+ localizable?: string[]; // array of field names that can be localized
406
+ toLocalizationFormData?: (
407
+ action: Action,
408
+ localization: Record<string, any>
409
+ ) => FormData;
410
+ fromLocalizationFormData?: (
411
+ formData: FormData,
412
+ action: Action
413
+ ) => Record<string, any>;
365
414
  }