@nyaruka/temba-components 0.132.0 → 0.134.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 (181) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/demo/components/flow/example.html +1 -0
  3. package/demo/components/webchat/example.html +1 -1
  4. package/demo/static/css/tailwind.css +30019 -0
  5. package/dist/locales/es.js +5 -5
  6. package/dist/locales/es.js.map +1 -1
  7. package/dist/locales/fr.js +5 -5
  8. package/dist/locales/fr.js.map +1 -1
  9. package/dist/locales/locale-codes.js +2 -11
  10. package/dist/locales/locale-codes.js.map +1 -1
  11. package/dist/locales/pt.js +5 -5
  12. package/dist/locales/pt.js.map +1 -1
  13. package/dist/temba-components.js +555 -476
  14. package/dist/temba-components.js.map +1 -1
  15. package/out-tsc/src/display/Chat.js +248 -95
  16. package/out-tsc/src/display/Chat.js.map +1 -1
  17. package/out-tsc/src/display/FloatingTab.js +4 -4
  18. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  19. package/out-tsc/src/display/TembaUser.js +3 -3
  20. package/out-tsc/src/display/TembaUser.js.map +1 -1
  21. package/out-tsc/src/events.js.map +1 -1
  22. package/out-tsc/src/flow/CanvasNode.js +132 -58
  23. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  24. package/out-tsc/src/flow/Editor.js +183 -58
  25. package/out-tsc/src/flow/Editor.js.map +1 -1
  26. package/out-tsc/src/flow/utils.js +141 -0
  27. package/out-tsc/src/flow/utils.js.map +1 -1
  28. package/out-tsc/src/interfaces.js.map +1 -1
  29. package/out-tsc/src/layout/FloatingWindow.js +1 -2
  30. package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
  31. package/out-tsc/src/list/ContentMenu.js +1 -0
  32. package/out-tsc/src/list/ContentMenu.js.map +1 -1
  33. package/out-tsc/src/list/SortableList.js +3 -2
  34. package/out-tsc/src/list/SortableList.js.map +1 -1
  35. package/out-tsc/src/live/ContactChat.js +184 -205
  36. package/out-tsc/src/live/ContactChat.js.map +1 -1
  37. package/out-tsc/src/locales/es.js +5 -5
  38. package/out-tsc/src/locales/es.js.map +1 -1
  39. package/out-tsc/src/locales/fr.js +5 -5
  40. package/out-tsc/src/locales/fr.js.map +1 -1
  41. package/out-tsc/src/locales/locale-codes.js +2 -11
  42. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  43. package/out-tsc/src/locales/pt.js +5 -5
  44. package/out-tsc/src/locales/pt.js.map +1 -1
  45. package/out-tsc/src/store/AppState.js +34 -0
  46. package/out-tsc/src/store/AppState.js.map +1 -1
  47. package/out-tsc/src/store/Store.js +5 -5
  48. package/out-tsc/src/store/Store.js.map +1 -1
  49. package/out-tsc/src/utils.js +3 -3
  50. package/out-tsc/src/utils.js.map +1 -1
  51. package/out-tsc/src/webchat/WebChat.js +22 -9
  52. package/out-tsc/src/webchat/WebChat.js.map +1 -1
  53. package/out-tsc/test/ActionHelper.js +6 -5
  54. package/out-tsc/test/ActionHelper.js.map +1 -1
  55. package/out-tsc/test/actions/send_broadcast.test.js +9 -4
  56. package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
  57. package/out-tsc/test/temba-contact-chat.test.js +1 -1
  58. package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
  59. package/out-tsc/test/temba-floating-window.test.js +0 -2
  60. package/out-tsc/test/temba-floating-window.test.js.map +1 -1
  61. package/out-tsc/test/temba-flow-collision.test.js +673 -0
  62. package/out-tsc/test/temba-flow-collision.test.js.map +1 -0
  63. package/out-tsc/test/temba-flow-editor-node.test.js +195 -0
  64. package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
  65. package/out-tsc/test/temba-utils-uuid.test.js +45 -1
  66. package/out-tsc/test/temba-utils-uuid.test.js.map +1 -1
  67. package/out-tsc/test/utils.test.js +2 -2
  68. package/out-tsc/test/utils.test.js.map +1 -1
  69. package/package.json +1 -1
  70. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  71. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  72. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  73. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  74. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  75. package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
  76. package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
  77. package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
  78. package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
  79. package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
  80. package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
  81. package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
  82. package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
  83. package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
  84. package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
  85. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  86. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  87. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  88. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  89. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  90. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  91. package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
  92. package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
  93. package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
  94. package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
  95. package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
  96. package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
  97. package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
  98. package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
  99. package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
  100. package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
  101. package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
  102. package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
  103. package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
  104. package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
  105. package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
  106. package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
  107. package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
  108. package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
  109. package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
  110. package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
  111. package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
  112. package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
  113. package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
  114. package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
  115. package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
  116. package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
  117. package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
  118. package/screenshots/truth/contacts/chat-failure.png +0 -0
  119. package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
  120. package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
  121. package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
  122. package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
  123. package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
  124. package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
  125. package/screenshots/truth/floating-tab/default.png +0 -0
  126. package/screenshots/truth/floating-tab/gray.png +0 -0
  127. package/screenshots/truth/floating-tab/green.png +0 -0
  128. package/screenshots/truth/floating-tab/hover.png +0 -0
  129. package/screenshots/truth/floating-tab/purple.png +0 -0
  130. package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
  131. package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
  132. package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
  133. package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
  134. package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
  135. package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
  136. package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
  137. package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
  138. package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
  139. package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
  140. package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
  141. package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
  142. package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
  143. package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
  144. package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
  145. package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
  146. package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
  147. package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
  148. package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
  149. package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
  150. package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
  151. package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
  152. package/src/display/Chat.ts +331 -135
  153. package/src/display/FloatingTab.ts +4 -4
  154. package/src/display/TembaUser.ts +3 -2
  155. package/src/events.ts +12 -12
  156. package/src/flow/CanvasNode.ts +140 -57
  157. package/src/flow/Editor.ts +240 -58
  158. package/src/flow/utils.ts +207 -1
  159. package/src/interfaces.ts +7 -0
  160. package/src/layout/FloatingWindow.ts +1 -3
  161. package/src/list/ContentMenu.ts +1 -0
  162. package/src/list/SortableList.ts +3 -2
  163. package/src/live/ContactChat.ts +195 -221
  164. package/src/locales/es.ts +13 -18
  165. package/src/locales/fr.ts +13 -18
  166. package/src/locales/locale-codes.ts +2 -11
  167. package/src/locales/pt.ts +13 -18
  168. package/src/store/AppState.ts +43 -0
  169. package/src/store/Store.ts +5 -5
  170. package/src/utils.ts +3 -3
  171. package/src/webchat/WebChat.ts +24 -10
  172. package/test/ActionHelper.ts +13 -5
  173. package/test/actions/send_broadcast.test.ts +4 -2
  174. package/test/temba-contact-chat.test.ts +1 -1
  175. package/test/temba-floating-window.test.ts +0 -2
  176. package/test/temba-flow-collision.test.ts +833 -0
  177. package/test/temba-flow-editor-node.test.ts +224 -0
  178. package/test/temba-utils-uuid.test.ts +61 -1
  179. package/test/utils.test.ts +7 -2
  180. package/test-assets/contacts/history.json +22 -9
  181. package/web-test-runner.config.mjs +3 -3
package/src/locales/es.ts CHANGED
@@ -1,18 +1,13 @@
1
-
2
- // Do not modify this file by hand!
3
- // Re-generate this file by running lit-localize
4
-
5
-
6
-
7
-
8
- /* eslint-disable no-irregular-whitespace */
9
- /* eslint-disable @typescript-eslint/no-explicit-any */
10
-
11
- export const templates = {
12
- 'scf1453991c986b25': `Tab para completar, enter para seleccionar`,
13
- 's73b4d70c02f4b4e0': `No options`,
14
- 's8f02e3a18ffc083a': `Are not currently in a flow`,
15
- 's638236250662c6b3': `Have sent a message in the last`,
16
- 's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
17
- };
18
-
1
+ // Do not modify this file by hand!
2
+ // Re-generate this file by running lit-localize
3
+
4
+ /* eslint-disable no-irregular-whitespace */
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+
7
+ export const templates = {
8
+ scf1453991c986b25: `Tab para completar, enter para seleccionar`,
9
+ s73b4d70c02f4b4e0: `No options`,
10
+ s8f02e3a18ffc083a: `Are not currently in a flow`,
11
+ s638236250662c6b3: `Have sent a message in the last`,
12
+ s4788ee206c4570c7: `Have not started this flow in the last 90 days`
13
+ };
package/src/locales/fr.ts CHANGED
@@ -1,18 +1,13 @@
1
-
2
- // Do not modify this file by hand!
3
- // Re-generate this file by running lit-localize
4
-
5
-
6
-
7
-
8
- /* eslint-disable no-irregular-whitespace */
9
- /* eslint-disable @typescript-eslint/no-explicit-any */
10
-
11
- export const templates = {
12
- 's73b4d70c02f4b4e0': `No options`,
13
- 'scf1453991c986b25': `Tab to complete, enter to select`,
14
- 's8f02e3a18ffc083a': `Are not currently in a flow`,
15
- 's638236250662c6b3': `Have sent a message in the last`,
16
- 's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
17
- };
18
-
1
+ // Do not modify this file by hand!
2
+ // Re-generate this file by running lit-localize
3
+
4
+ /* eslint-disable no-irregular-whitespace */
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+
7
+ export const templates = {
8
+ s73b4d70c02f4b4e0: `No options`,
9
+ scf1453991c986b25: `Tab to complete, enter to select`,
10
+ s8f02e3a18ffc083a: `Are not currently in a flow`,
11
+ s638236250662c6b3: `Have sent a message in the last`,
12
+ s4788ee206c4570c7: `Have not started this flow in the last 90 days`
13
+ };
@@ -10,18 +10,9 @@ export const sourceLocale = `en`;
10
10
  * The other locale codes that this application is localized into. Sorted
11
11
  * lexicographically.
12
12
  */
13
- export const targetLocales = [
14
- `es`,
15
- `fr`,
16
- `pt`,
17
- ] as const;
13
+ export const targetLocales = [`es`, `fr`, `pt`] as const;
18
14
 
19
15
  /**
20
16
  * All valid project locale codes. Sorted lexicographically.
21
17
  */
22
- export const allLocales = [
23
- `en`,
24
- `es`,
25
- `fr`,
26
- `pt`,
27
- ] as const;
18
+ export const allLocales = [`en`, `es`, `fr`, `pt`] as const;
package/src/locales/pt.ts CHANGED
@@ -1,18 +1,13 @@
1
-
2
- // Do not modify this file by hand!
3
- // Re-generate this file by running lit-localize
4
-
5
-
6
-
7
-
8
- /* eslint-disable no-irregular-whitespace */
9
- /* eslint-disable @typescript-eslint/no-explicit-any */
10
-
11
- export const templates = {
12
- 's73b4d70c02f4b4e0': `No options`,
13
- 'scf1453991c986b25': `Tab to complete, enter to select`,
14
- 's8f02e3a18ffc083a': `Are not currently in a flow`,
15
- 's638236250662c6b3': `Have sent a message in the last`,
16
- 's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
17
- };
18
-
1
+ // Do not modify this file by hand!
2
+ // Re-generate this file by running lit-localize
3
+
4
+ /* eslint-disable no-irregular-whitespace */
5
+ /* eslint-disable @typescript-eslint/no-explicit-any */
6
+
7
+ export const templates = {
8
+ s73b4d70c02f4b4e0: `No options`,
9
+ scf1453991c986b25: `Tab to complete, enter to select`,
10
+ s8f02e3a18ffc083a: `Are not currently in a flow`,
11
+ s638236250662c6b3: `Have sent a message in the last`,
12
+ s4788ee206c4570c7: `Have not started this flow in the last 90 days`
13
+ };
@@ -88,6 +88,7 @@ export interface AppState {
88
88
 
89
89
  setFlowContents: (flow: FlowContents) => void;
90
90
  setFlowInfo: (info: FlowInfo) => void;
91
+ setRevision: (revision: number) => void;
91
92
  setLanguageCode: (languageCode: string) => void;
92
93
  setDirtyDate: (date: Date) => void;
93
94
  expandCanvas: (width: number, height: number) => void;
@@ -216,6 +217,12 @@ export const zustand = createStore<AppState>()(
216
217
  });
217
218
  },
218
219
 
220
+ setRevision: (revision: number) => {
221
+ set((state: AppState) => {
222
+ state.flowDefinition.revision = revision;
223
+ });
224
+ },
225
+
219
226
  setLanguageCode: (languageCode: string) => {
220
227
  set((state: AppState) => {
221
228
  state.languageCode = languageCode;
@@ -264,10 +271,46 @@ export const zustand = createStore<AppState>()(
264
271
  }
265
272
 
266
273
  state.flowDefinition = produce(state.flowDefinition, (draft) => {
274
+ // For each node being removed, check if we should reroute connections
275
+ uuids.forEach((removedUuid) => {
276
+ const removedNode = draft.nodes.find(
277
+ (n) => n.uuid === removedUuid
278
+ );
279
+
280
+ if (!removedNode || !removedNode.exits.length) return;
281
+
282
+ // Get all destinations (filter out null/undefined)
283
+ const destinations = removedNode.exits
284
+ .map((exit) => exit.destination_uuid)
285
+ .filter((dest) => dest);
286
+
287
+ // Only proceed if all exits have destinations and they all point to the same place
288
+ if (
289
+ destinations.length === removedNode.exits.length &&
290
+ destinations.every((dest) => dest === destinations[0])
291
+ ) {
292
+ const targetDestination = destinations[0];
293
+ // Don't reroute if the target is also being removed
294
+ if (uuids.includes(targetDestination)) return;
295
+
296
+ // Find all nodes with exits pointing to the node being removed
297
+ draft.nodes.forEach((node) => {
298
+ node.exits.forEach((exit) => {
299
+ if (exit.destination_uuid === removedUuid) {
300
+ // Reroute to the same destination the removed node was going to
301
+ exit.destination_uuid = targetDestination;
302
+ }
303
+ });
304
+ });
305
+ }
306
+ });
307
+
308
+ // Remove the nodes
267
309
  draft.nodes = draft.nodes.filter(
268
310
  (node) => !uuids.includes(node.uuid)
269
311
  );
270
312
 
313
+ // Clear any remaining connections to removed nodes that weren't rerouted
271
314
  draft.nodes.forEach((node) => {
272
315
  node.exits.forEach((exit) => {
273
316
  if (uuids.includes(exit.destination_uuid)) {
@@ -506,7 +506,7 @@ export class Store extends RapidElement {
506
506
 
507
507
  public resolveUsers(items: any, keys: string[]): Promise<void> {
508
508
  return new Promise<void>((resolve) => {
509
- const emails = new Set<string>();
509
+ const uuids = new Set<string>();
510
510
 
511
511
  // keys are dot notation paths to user fields
512
512
  items.forEach((item) => {
@@ -519,17 +519,17 @@ export class Store extends RapidElement {
519
519
  break;
520
520
  }
521
521
  }
522
- if (value && value.email) {
523
- emails.add(value.email);
522
+ if (value && value.uuid) {
523
+ uuids.add(value.uuid);
524
524
  }
525
525
  });
526
526
  });
527
527
 
528
528
  const promises = [];
529
529
  // we don't want to fetch all users at once so we can benefit from caching
530
- emails.forEach((email) => {
530
+ uuids.forEach((uuid) => {
531
531
  promises.push(
532
- this.getUrl(`/api/v2/users.json?email=${encodeURIComponent(email)}`, {
532
+ this.getUrl(`/api/v2/users.json?uuid=${encodeURIComponent(uuid)}`, {
533
533
  force: true
534
534
  })
535
535
  );
package/src/utils.ts CHANGED
@@ -5,7 +5,7 @@ import { Dialog } from './layout/Dialog';
5
5
  import { Attachment, ContactField, Shortcut, Ticket, User } from './interfaces';
6
6
  import ColorHash from 'color-hash';
7
7
  import { Toast } from './display/Toast';
8
- import { v4 as generateUUID } from 'uuid';
8
+ import { v4 as generateUUID, v7 as generateUUIDv7 } from 'uuid';
9
9
 
10
10
  export const DEFAULT_MEDIA_ENDPOINT = '/api/v2/media.json';
11
11
 
@@ -918,8 +918,8 @@ export const getMiddle = (a: DOMRect, b: DOMRect) => {
918
918
  return a.top + a.height / 2 - b.height / 2;
919
919
  };
920
920
 
921
- // Export the UUID function from the uuid package
922
- export { generateUUID };
921
+ // Export the UUID functions from the uuid package
922
+ export { generateUUID, generateUUIDv7 };
923
923
 
924
924
  // Helper types for router creation
925
925
  export interface RouterCategory {
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/no-this-alias */
2
2
  import { LitElement, TemplateResult, html, css, PropertyValueMap } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { getCookie, setCookie } from '../utils';
4
+ import { generateUUIDv7, getCookie, setCookie } from '../utils';
5
5
  import { DEFAULT_AVATAR } from './assets';
6
- import { Chat, ChatEvent, Message, MessageType } from '../display/Chat';
6
+ import { Chat, MsgEvent } from '../display/Chat';
7
7
 
8
8
  interface User {
9
9
  avatar?: string;
@@ -83,17 +83,24 @@ enum ChatStatus {
83
83
  CONNECTED = 'connected'
84
84
  }
85
85
 
86
- const sockToChat = function (msg: any): ChatEvent | Message {
87
- const type = msg.msg_in ? MessageType.MsgIn : MessageType.MsgOut;
86
+ const sockToChat = function (msg: any): MsgEvent {
87
+ const type = msg.msg_in ? 'msg_created' : 'msg_received';
88
88
  const msgContent = msg.msg_in || msg.msg_out;
89
89
 
90
90
  return {
91
- id: msgContent.id,
91
+ uuid: msgContent.id,
92
92
  type,
93
- text: msgContent.text,
94
- date: new Date(msgContent.time),
95
- user: msgContent.user,
96
- attachments: msgContent.attachments
93
+ created_on: new Date(msgContent.time),
94
+ _user: msgContent.user,
95
+ msg: {
96
+ text: msgContent.text,
97
+ channel: undefined,
98
+ quick_replies: [],
99
+ urn: '',
100
+ direction: '',
101
+ type: '',
102
+ attachments: msgContent.attachments
103
+ }
97
104
  };
98
105
  };
99
106
 
@@ -570,7 +577,14 @@ export class WebChat extends LitElement {
570
577
  const date = new Date();
571
578
 
572
579
  this.chat.addMessages(
573
- [{ type: MessageType.MsgIn, text, date }],
580
+ [
581
+ {
582
+ uuid: generateUUIDv7(),
583
+ type: 'msg_received',
584
+ msg: { text },
585
+ created_on: date
586
+ } as MsgEvent
587
+ ],
574
588
  date,
575
589
  true
576
590
  );
@@ -71,12 +71,13 @@ export class ActionTest<T extends Action> {
71
71
  */
72
72
  private async assertDialogScreenshot(
73
73
  el: HTMLElement,
74
- screenshotName: string
74
+ screenshotName: string,
75
+ waitForNetwork: boolean = false
75
76
  ) {
76
77
  const dialog = el.shadowRoot
77
78
  .querySelector('temba-dialog')
78
79
  .shadowRoot.querySelector('.dialog-container') as HTMLElement;
79
- await assertScreenshot(screenshotName, getClip(dialog));
80
+ await assertScreenshot(screenshotName, getClip(dialog), waitForNetwork);
80
81
  }
81
82
 
82
83
  /**
@@ -84,22 +85,29 @@ export class ActionTest<T extends Action> {
84
85
  * 1. Renders the action in a flow node (with screenshot)
85
86
  * 2. Opens the node editor (with screenshot)
86
87
  * 3. Simulates save and validates round-trip conversion
88
+ * @param waitForNetwork - If true, waits longer for network idle (useful for slow loading resources)
87
89
  */
88
- async testAction(action: T, testName: string) {
90
+ async testAction(
91
+ action: T,
92
+ testName: string,
93
+ waitForNetwork: boolean = false
94
+ ) {
89
95
  it(`${testName}`, async () => {
90
96
  // Step 1: Render action in flow node
91
97
  const flowNode = await this.renderAction(action);
92
98
  expect(flowNode.querySelector('.body')).to.exist;
93
99
  await assertScreenshot(
94
100
  `actions/${this.actionName}/render/${testName}`,
95
- getClip(flowNode)
101
+ getClip(flowNode),
102
+ waitForNetwork
96
103
  );
97
104
 
98
105
  // Step 2: Open node editor
99
106
  const nodeEditor = await this.openNodeEditor(action);
100
107
  await this.assertDialogScreenshot(
101
108
  nodeEditor,
102
- `actions/${this.actionName}/editor/${testName}`
109
+ `actions/${this.actionName}/editor/${testName}`,
110
+ waitForNetwork
103
111
  );
104
112
 
105
113
  // Step 3: Test round-trip conversion (simulates save workflow)
@@ -68,6 +68,7 @@ describe('send_broadcast action config', () => {
68
68
  'multiline-text'
69
69
  );
70
70
 
71
+ /* TODO: flaky test having to do with attachment render times
71
72
  helper.testAction(
72
73
  {
73
74
  uuid: 'test-action-5',
@@ -80,8 +81,9 @@ describe('send_broadcast action config', () => {
80
81
  'application/pdf:https://example.com/document.pdf'
81
82
  ]
82
83
  } as SendBroadcast,
83
- 'with-attachments'
84
- );
84
+ 'with-attachments',
85
+ true
86
+ );*/
85
87
 
86
88
  helper.testAction(
87
89
  {
@@ -55,7 +55,7 @@ describe('temba-contact-chat', () => {
55
55
  mockedNow = mockNow('2021-03-31T00:31:00.000-00:00');
56
56
  clearMockPosts();
57
57
  mockGET(
58
- /\/contact\/history\/contact-.*/,
58
+ /\/contact\/chat\/contact-.*/,
59
59
  '/test-assets/contacts/history.json'
60
60
  );
61
61
 
@@ -51,7 +51,6 @@ describe('temba-floating-window', () => {
51
51
  )) as FloatingWindow;
52
52
 
53
53
  expect(window.hidden).to.equal(true);
54
- expect(window.classList.contains('hidden')).to.equal(true);
55
54
  });
56
55
 
57
56
  it('can be shown and hidden', async () => {
@@ -74,7 +73,6 @@ describe('temba-floating-window', () => {
74
73
  window.hide();
75
74
  await window.updateComplete;
76
75
  expect(window.hidden).to.equal(true);
77
- expect(window.classList.contains('hidden')).to.equal(true);
78
76
  });
79
77
 
80
78
  it('fires close event when close button clicked', async () => {