@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.
- package/CHANGELOG.md +31 -1
- package/demo/components/flow/example.html +1 -0
- package/demo/components/webchat/example.html +1 -1
- package/demo/static/css/tailwind.css +30019 -0
- package/dist/locales/es.js +5 -5
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +5 -5
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/locale-codes.js +2 -11
- package/dist/locales/locale-codes.js.map +1 -1
- package/dist/locales/pt.js +5 -5
- package/dist/locales/pt.js.map +1 -1
- package/dist/temba-components.js +555 -476
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +248 -95
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +4 -4
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/display/TembaUser.js +3 -3
- package/out-tsc/src/display/TembaUser.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +132 -58
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +183 -58
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/utils.js +141 -0
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/FloatingWindow.js +1 -2
- package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +1 -0
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +3 -2
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +184 -205
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/locales/es.js +5 -5
- package/out-tsc/src/locales/es.js.map +1 -1
- package/out-tsc/src/locales/fr.js +5 -5
- package/out-tsc/src/locales/fr.js.map +1 -1
- package/out-tsc/src/locales/locale-codes.js +2 -11
- package/out-tsc/src/locales/locale-codes.js.map +1 -1
- package/out-tsc/src/locales/pt.js +5 -5
- package/out-tsc/src/locales/pt.js.map +1 -1
- package/out-tsc/src/store/AppState.js +34 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/store/Store.js +5 -5
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/utils.js +3 -3
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/src/webchat/WebChat.js +22 -9
- package/out-tsc/src/webchat/WebChat.js.map +1 -1
- package/out-tsc/test/ActionHelper.js +6 -5
- package/out-tsc/test/ActionHelper.js.map +1 -1
- package/out-tsc/test/actions/send_broadcast.test.js +9 -4
- package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
- package/out-tsc/test/temba-contact-chat.test.js +1 -1
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-floating-window.test.js +0 -2
- package/out-tsc/test/temba-floating-window.test.js.map +1 -1
- package/out-tsc/test/temba-flow-collision.test.js +673 -0
- package/out-tsc/test/temba-flow-collision.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor-node.test.js +195 -0
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-utils-uuid.test.js +45 -1
- package/out-tsc/test/temba-utils-uuid.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -2
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
- package/screenshots/truth/actions/send_email/render/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/render/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/render/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/render/with-expressions.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/start_session/render/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/render/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/render/many-recipients.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/floating-tab/default.png +0 -0
- package/screenshots/truth/floating-tab/gray.png +0 -0
- package/screenshots/truth/floating-tab/green.png +0 -0
- package/screenshots/truth/floating-tab/hover.png +0 -0
- package/screenshots/truth/floating-tab/purple.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/render/translation-task.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/custom-input-and-result-name.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/feedback-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/render/minimal-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/render/two-bucket-split.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/src/display/Chat.ts +331 -135
- package/src/display/FloatingTab.ts +4 -4
- package/src/display/TembaUser.ts +3 -2
- package/src/events.ts +12 -12
- package/src/flow/CanvasNode.ts +140 -57
- package/src/flow/Editor.ts +240 -58
- package/src/flow/utils.ts +207 -1
- package/src/interfaces.ts +7 -0
- package/src/layout/FloatingWindow.ts +1 -3
- package/src/list/ContentMenu.ts +1 -0
- package/src/list/SortableList.ts +3 -2
- package/src/live/ContactChat.ts +195 -221
- package/src/locales/es.ts +13 -18
- package/src/locales/fr.ts +13 -18
- package/src/locales/locale-codes.ts +2 -11
- package/src/locales/pt.ts +13 -18
- package/src/store/AppState.ts +43 -0
- package/src/store/Store.ts +5 -5
- package/src/utils.ts +3 -3
- package/src/webchat/WebChat.ts +24 -10
- package/test/ActionHelper.ts +13 -5
- package/test/actions/send_broadcast.test.ts +4 -2
- package/test/temba-contact-chat.test.ts +1 -1
- package/test/temba-floating-window.test.ts +0 -2
- package/test/temba-flow-collision.test.ts +833 -0
- package/test/temba-flow-editor-node.test.ts +224 -0
- package/test/temba-utils-uuid.test.ts +61 -1
- package/test/utils.test.ts +7 -2
- package/test-assets/contacts/history.json +22 -9
- package/web-test-runner.config.mjs +3 -3
package/src/locales/es.ts
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
+
};
|
package/src/store/AppState.ts
CHANGED
|
@@ -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)) {
|
package/src/store/Store.ts
CHANGED
|
@@ -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
|
|
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.
|
|
523
|
-
|
|
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
|
-
|
|
530
|
+
uuids.forEach((uuid) => {
|
|
531
531
|
promises.push(
|
|
532
|
-
this.getUrl(`/api/v2/users.json?
|
|
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
|
|
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 {
|
package/src/webchat/WebChat.ts
CHANGED
|
@@ -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,
|
|
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):
|
|
87
|
-
const type = msg.msg_in ?
|
|
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
|
-
|
|
91
|
+
uuid: msgContent.id,
|
|
92
92
|
type,
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
[
|
|
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
|
);
|
package/test/ActionHelper.ts
CHANGED
|
@@ -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(
|
|
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
|
{
|
|
@@ -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 () => {
|