@nyaruka/temba-components 0.131.2 → 0.131.3
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 +14 -0
- package/demo/components/floating-tabs/example.html +400 -0
- package/demo/components/flow/index.html +1 -1
- package/demo/data/flows/sample-flow.json +41 -2
- package/demo/data/flows/voicemail.json +613 -0
- package/demo/index.html +6 -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 +11 -2
- 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 +1109 -535
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +167 -0
- package/out-tsc/src/display/FloatingTab.js.map +1 -0
- package/out-tsc/src/display/ProgressBar.js +22 -2
- package/out-tsc/src/display/ProgressBar.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +165 -31
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +857 -3
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +239 -19
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +44 -3
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -1
- package/out-tsc/src/flow/StickyNote.js +12 -3
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +2 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +2 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +2 -1
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/play_audio.js +2 -1
- package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js +2 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/request_optin.js +1 -0
- package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +2 -1
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +2 -1
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +2 -1
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +93 -3
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +2 -1
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +2 -1
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +2 -1
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/config.js +2 -10
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/shared.js +54 -0
- package/out-tsc/src/flow/nodes/shared.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_airtime.js +9 -3
- package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_contact_field.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_groups.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_intent.js +3 -2
- package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm.js +9 -2
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +9 -2
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +8 -2
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_run_result.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_scheme.js +8 -3
- package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +8 -2
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_ticket.js +8 -2
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +8 -2
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js +3 -2
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_menu.js +3 -2
- package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +8 -3
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js +15 -0
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/layout/FloatingWindow.js +346 -0
- package/out-tsc/src/layout/FloatingWindow.js.map +1 -0
- package/out-tsc/src/live/ContactChat.js +3 -19
- 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 +11 -2
- 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 +67 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/temba-modules.js +4 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-floating-tab.test.js +91 -0
- package/out-tsc/test/temba-floating-tab.test.js.map +1 -0
- package/out-tsc/test/temba-floating-window.test.js +301 -0
- package/out-tsc/test/temba-floating-window.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor-node.test.js +117 -0
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-localization.test.js +471 -0
- package/out-tsc/test/temba-localization.test.js.map +1 -0
- package/out-tsc/test/temba-node-type-selector.test.js +150 -0
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +18 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- 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/hidden.png +0 -0
- package/screenshots/truth/floating-tab/hover.png +0 -0
- package/screenshots/truth/floating-tab/purple.png +0 -0
- package/screenshots/truth/floating-window/chromeless.png +0 -0
- package/screenshots/truth/floating-window/custom-size.png +0 -0
- package/screenshots/truth/floating-window/default.png +0 -0
- package/screenshots/truth/floating-window/with-header.png +0 -0
- package/screenshots/truth/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/src/display/FloatingTab.ts +174 -0
- package/src/display/ProgressBar.ts +22 -2
- package/src/events.ts +2 -4
- package/src/flow/CanvasNode.ts +190 -32
- package/src/flow/Editor.ts +1040 -3
- package/src/flow/NodeEditor.ts +317 -19
- package/src/flow/NodeTypeSelector.ts +47 -3
- package/src/flow/StickyNote.ts +12 -3
- package/src/flow/actions/add_contact_groups.ts +2 -1
- package/src/flow/actions/add_contact_urn.ts +3 -1
- package/src/flow/actions/add_input_labels.ts +2 -1
- package/src/flow/actions/play_audio.ts +2 -1
- package/src/flow/actions/remove_contact_groups.ts +3 -1
- package/src/flow/actions/request_optin.ts +1 -0
- package/src/flow/actions/say_msg.ts +2 -1
- package/src/flow/actions/send_broadcast.ts +2 -1
- package/src/flow/actions/send_email.ts +3 -1
- package/src/flow/actions/send_msg.ts +134 -3
- package/src/flow/actions/set_contact_channel.ts +2 -1
- package/src/flow/actions/set_contact_field.ts +2 -1
- package/src/flow/actions/set_contact_language.ts +3 -1
- package/src/flow/actions/set_contact_name.ts +2 -1
- package/src/flow/actions/set_contact_status.ts +2 -1
- package/src/flow/actions/set_run_result.ts +2 -1
- package/src/flow/actions/start_session.ts +3 -1
- package/src/flow/config.ts +2 -12
- package/src/flow/nodes/shared.ts +70 -1
- package/src/flow/nodes/split_by_airtime.ts +20 -3
- package/src/flow/nodes/split_by_contact_field.ts +13 -3
- package/src/flow/nodes/split_by_expression.ts +13 -3
- package/src/flow/nodes/split_by_groups.ts +13 -3
- package/src/flow/nodes/split_by_intent.ts +3 -2
- package/src/flow/nodes/split_by_llm.ts +19 -2
- package/src/flow/nodes/split_by_llm_categorize.ts +19 -2
- package/src/flow/nodes/split_by_random.ts +12 -2
- package/src/flow/nodes/split_by_resthook.ts +13 -3
- package/src/flow/nodes/split_by_run_result.ts +13 -3
- package/src/flow/nodes/split_by_scheme.ts +13 -3
- package/src/flow/nodes/split_by_subflow.ts +12 -2
- package/src/flow/nodes/split_by_ticket.ts +12 -2
- package/src/flow/nodes/split_by_webhook.ts +12 -2
- package/src/flow/nodes/wait_for_digits.ts +3 -2
- package/src/flow/nodes/wait_for_menu.ts +3 -2
- package/src/flow/nodes/wait_for_response.ts +13 -3
- package/src/flow/types.ts +47 -0
- package/src/layout/FloatingWindow.ts +386 -0
- package/src/live/ContactChat.ts +4 -19
- package/src/locales/es.ts +18 -13
- package/src/locales/fr.ts +18 -13
- package/src/locales/locale-codes.ts +11 -2
- package/src/locales/pt.ts +18 -13
- package/src/store/AppState.ts +104 -0
- package/static/api/llms.json +18 -0
- package/temba-modules.ts +4 -0
- package/test/temba-floating-tab.test.ts +110 -0
- package/test/temba-floating-window.test.ts +477 -0
- package/test/temba-flow-editor-node.test.ts +144 -0
- package/test/temba-localization.test.ts +611 -0
- package/test/temba-node-type-selector.test.ts +203 -0
- package/test/utils.test.ts +20 -0
- package/test-assets/contacts/history.json +5 -6
- package/test-assets/select/llms.json +2 -2
- package/web-dev-server.config.mjs +47 -1
- package/web-test-runner.config.mjs +0 -1
- package/out-tsc/src/flow/nodes/wait_for_audio.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_image.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_image.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_location.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_location.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_video.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_video.js.map +0 -1
- package/src/flow/nodes/wait_for_audio.ts +0 -7
- package/src/flow/nodes/wait_for_image.ts +0 -7
- package/src/flow/nodes/wait_for_location.ts +0 -7
- package/src/flow/nodes/wait_for_video.ts +0 -7
|
@@ -77,6 +77,15 @@ export class ProgressBar extends RapidElement {
|
|
|
77
77
|
display: none;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
.meter.static > span:after {
|
|
81
|
+
display: none;
|
|
82
|
+
animation: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.meter.static > span {
|
|
86
|
+
background-image: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
80
89
|
@keyframes move {
|
|
81
90
|
0% {
|
|
82
91
|
background-position: 0 0;
|
|
@@ -154,6 +163,9 @@ export class ProgressBar extends RapidElement {
|
|
|
154
163
|
@property({ type: String })
|
|
155
164
|
message: string;
|
|
156
165
|
|
|
166
|
+
@property({ type: Boolean })
|
|
167
|
+
animated = true;
|
|
168
|
+
|
|
157
169
|
public updated(
|
|
158
170
|
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
159
171
|
): void {
|
|
@@ -162,7 +174,7 @@ export class ProgressBar extends RapidElement {
|
|
|
162
174
|
this.showEstimatedCompletion = this.estimatedCompletionDate > new Date();
|
|
163
175
|
}
|
|
164
176
|
|
|
165
|
-
if (changes.has('current')) {
|
|
177
|
+
if (changes.has('current') || changes.has('total')) {
|
|
166
178
|
const pct = Math.floor(Math.min((this.current / this.total) * 100, 100));
|
|
167
179
|
if (Number.isNaN(pct)) {
|
|
168
180
|
this.showPercentage = false;
|
|
@@ -176,8 +188,16 @@ export class ProgressBar extends RapidElement {
|
|
|
176
188
|
}
|
|
177
189
|
|
|
178
190
|
public render(): TemplateResult {
|
|
191
|
+
const meterClasses = [
|
|
192
|
+
'meter',
|
|
193
|
+
this.done ? 'done' : '',
|
|
194
|
+
this.animated ? '' : 'static'
|
|
195
|
+
]
|
|
196
|
+
.filter(Boolean)
|
|
197
|
+
.join(' ');
|
|
198
|
+
|
|
179
199
|
return html`<div class="wrapper ${this.done ? 'complete' : ''}">
|
|
180
|
-
<div class="
|
|
200
|
+
<div class="${meterClasses}">
|
|
181
201
|
${this.message
|
|
182
202
|
? html`<div class="message">${this.message}</div>`
|
|
183
203
|
: null}
|
package/src/events.ts
CHANGED
|
@@ -57,8 +57,7 @@ export interface ChatStartedEvent extends ContactEvent {
|
|
|
57
57
|
export interface MsgEvent extends ContactEvent {
|
|
58
58
|
msg: Msg;
|
|
59
59
|
optin?: ObjectReference;
|
|
60
|
-
_status?:
|
|
61
|
-
_failed_reason?: string; // deprecated
|
|
60
|
+
_status?: { created_on: string; status: string; reason: string };
|
|
62
61
|
_logs_url?: string;
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -107,10 +106,9 @@ export interface AirtimeTransferredEvent extends ContactEvent {
|
|
|
107
106
|
export type CallStartedEvent = ContactEvent;
|
|
108
107
|
|
|
109
108
|
export interface ContactHistoryPage {
|
|
109
|
+
events: ContactEvent[];
|
|
110
110
|
has_older: boolean;
|
|
111
111
|
recent_only: boolean;
|
|
112
112
|
next_before: number;
|
|
113
113
|
next_after: number;
|
|
114
|
-
start_date: Date;
|
|
115
|
-
events: ContactEvent[];
|
|
116
114
|
}
|
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { getClasses } from '../utils';
|
|
|
9
9
|
import { Plumber } from './Plumber';
|
|
10
10
|
import { getStore } from '../store/Store';
|
|
11
11
|
import { CustomEventType } from '../interfaces';
|
|
12
|
+
import { AppState, fromStore, zustand } from '../store/AppState';
|
|
12
13
|
|
|
13
14
|
const DRAG_THRESHOLD = 5;
|
|
14
15
|
|
|
@@ -26,6 +27,22 @@ export class CanvasNode extends RapidElement {
|
|
|
26
27
|
@property({ type: Object })
|
|
27
28
|
private ui: NodeUI;
|
|
28
29
|
|
|
30
|
+
@fromStore(zustand, (state: AppState) => state.isTranslating)
|
|
31
|
+
private isTranslating!: boolean;
|
|
32
|
+
|
|
33
|
+
@fromStore(zustand, (state: AppState) => state.languageCode)
|
|
34
|
+
private languageCode!: string;
|
|
35
|
+
|
|
36
|
+
@fromStore(zustand, (state: AppState) => state.flowDefinition)
|
|
37
|
+
private flowDefinition!: any;
|
|
38
|
+
|
|
39
|
+
@fromStore(
|
|
40
|
+
zustand,
|
|
41
|
+
(state: AppState) =>
|
|
42
|
+
state.flowDefinition?._ui?.translation_filters?.categories || false
|
|
43
|
+
)
|
|
44
|
+
private includeCategoriesInTranslation!: boolean;
|
|
45
|
+
|
|
29
46
|
// Track exits that are in "removing" state
|
|
30
47
|
private exitRemovalTimeouts: Map<string, number> = new Map();
|
|
31
48
|
|
|
@@ -160,6 +177,20 @@ export class CanvasNode extends RapidElement {
|
|
|
160
177
|
|
|
161
178
|
.node.execute-actions temba-sortable-list .action:last-child .body {
|
|
162
179
|
padding-bottom: 1.5em;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Localization indicators */
|
|
183
|
+
.action.localizable:not(.has-localization) .action-content {
|
|
184
|
+
background: #fff8dc !important; /* Light yellow background for localizable but not yet localized */
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.non-localizable {
|
|
188
|
+
opacity: 0.25;
|
|
189
|
+
pointer-events: none;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.action.non-localizable .action-content {
|
|
193
|
+
cursor: not-allowed;
|
|
163
194
|
}
|
|
164
195
|
|
|
165
196
|
.action .drag-handle {
|
|
@@ -228,6 +259,10 @@ export class CanvasNode extends RapidElement {
|
|
|
228
259
|
margin: 0.2em;
|
|
229
260
|
}
|
|
230
261
|
|
|
262
|
+
.router-section {
|
|
263
|
+
/* Container for router and categories */
|
|
264
|
+
}
|
|
265
|
+
|
|
231
266
|
.categories {
|
|
232
267
|
display: flex;
|
|
233
268
|
flex-direction: row;
|
|
@@ -244,6 +279,11 @@ export class CanvasNode extends RapidElement {
|
|
|
244
279
|
flex-direction: column;
|
|
245
280
|
}
|
|
246
281
|
|
|
282
|
+
/* Localizable category - yellow background */
|
|
283
|
+
.category.localizable {
|
|
284
|
+
background-color: #fff8dc;
|
|
285
|
+
}
|
|
286
|
+
|
|
247
287
|
.action-exits {
|
|
248
288
|
padding-bottom: 0.7em;
|
|
249
289
|
margin-top: -0.7em;
|
|
@@ -1153,19 +1193,21 @@ export class CanvasNode extends RapidElement {
|
|
|
1153
1193
|
? ACTION_GROUP_METADATA[config.group]?.color
|
|
1154
1194
|
: '#aaaaaa';
|
|
1155
1195
|
return html`<div class="cn-title" style="background:${color}">
|
|
1156
|
-
${this.node?.actions?.length > 1
|
|
1196
|
+
${!this.isTranslating && this.node?.actions?.length > 1
|
|
1157
1197
|
? html`<temba-icon class="drag-handle" name="sort"></temba-icon>`
|
|
1158
1198
|
: html`<div class="title-spacer"></div>`}
|
|
1159
1199
|
|
|
1160
1200
|
<div class="name">${isRemoving ? 'Remove?' : config.name}</div>
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1201
|
+
${!this.isTranslating
|
|
1202
|
+
? html`<div
|
|
1203
|
+
class="remove-button"
|
|
1204
|
+
@click=${(e: MouseEvent) =>
|
|
1205
|
+
this.handleActionRemoveClick(e, action, index)}
|
|
1206
|
+
title="Remove action"
|
|
1207
|
+
>
|
|
1208
|
+
✕
|
|
1209
|
+
</div>`
|
|
1210
|
+
: html`<div class="title-spacer"></div>`}
|
|
1169
1211
|
</div>`;
|
|
1170
1212
|
}
|
|
1171
1213
|
|
|
@@ -1192,13 +1234,15 @@ export class CanvasNode extends RapidElement {
|
|
|
1192
1234
|
? config.renderTitle(node, ui)
|
|
1193
1235
|
: html`${config.name}`}
|
|
1194
1236
|
</div>
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1237
|
+
${!this.isTranslating
|
|
1238
|
+
? html`<div
|
|
1239
|
+
class="remove-button"
|
|
1240
|
+
@click=${(e: MouseEvent) => this.handleNodeRemoveClick(e)}
|
|
1241
|
+
title="Remove node"
|
|
1242
|
+
>
|
|
1243
|
+
✕
|
|
1244
|
+
</div>`
|
|
1245
|
+
: html`<div class="title-spacer"></div>`}
|
|
1202
1246
|
</div>`;
|
|
1203
1247
|
}
|
|
1204
1248
|
|
|
@@ -1210,25 +1254,93 @@ export class CanvasNode extends RapidElement {
|
|
|
1210
1254
|
></div>`;
|
|
1211
1255
|
}
|
|
1212
1256
|
|
|
1257
|
+
/**
|
|
1258
|
+
* Get the localized version of an action if translating, otherwise return the original action.
|
|
1259
|
+
* Falls back to base language values if no localization exists for a field.
|
|
1260
|
+
*/
|
|
1261
|
+
private getLocalizedAction(action: Action): Action {
|
|
1262
|
+
// If not translating or no flow definition, return original action
|
|
1263
|
+
if (
|
|
1264
|
+
!this.isTranslating ||
|
|
1265
|
+
!this.flowDefinition ||
|
|
1266
|
+
!this.languageCode ||
|
|
1267
|
+
this.languageCode === this.flowDefinition.language
|
|
1268
|
+
) {
|
|
1269
|
+
return action;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// Check if there's localization for this action
|
|
1273
|
+
const localization =
|
|
1274
|
+
this.flowDefinition?.localization?.[this.languageCode]?.[action.uuid];
|
|
1275
|
+
|
|
1276
|
+
if (!localization) {
|
|
1277
|
+
// No localization available, return original action
|
|
1278
|
+
return action;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// Create a new action with localized values, falling back to base language
|
|
1282
|
+
const localizedAction = { ...action };
|
|
1283
|
+
|
|
1284
|
+
// Apply localized values for each field
|
|
1285
|
+
Object.keys(localization).forEach((field) => {
|
|
1286
|
+
const localizedValue = localization[field];
|
|
1287
|
+
if (Array.isArray(localizedValue)) {
|
|
1288
|
+
// Localized values are stored as arrays
|
|
1289
|
+
if (localizedValue.length > 0) {
|
|
1290
|
+
// For single-value fields like 'text', take the first element
|
|
1291
|
+
// For array fields like 'quick_replies', use the whole array
|
|
1292
|
+
if (Array.isArray(action[field])) {
|
|
1293
|
+
localizedAction[field] = localizedValue;
|
|
1294
|
+
} else {
|
|
1295
|
+
localizedAction[field] = localizedValue[0];
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
return localizedAction;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1213
1304
|
private renderAction(node: Node, action: Action, index: number) {
|
|
1214
1305
|
const config = ACTION_CONFIG[action.type];
|
|
1215
1306
|
const isRemoving = this.actionRemovingState.has(action.uuid);
|
|
1307
|
+
const isLocalizable = config?.localizable && config.localizable.length > 0;
|
|
1308
|
+
const isDisabled = this.isTranslating && !isLocalizable;
|
|
1309
|
+
|
|
1310
|
+
// Check if this action has localization data
|
|
1311
|
+
const hasLocalization =
|
|
1312
|
+
this.isTranslating &&
|
|
1313
|
+
this.flowDefinition?.localization?.[this.languageCode]?.[action.uuid];
|
|
1314
|
+
|
|
1315
|
+
// Get the localized action if translating
|
|
1316
|
+
const displayAction = this.getLocalizedAction(action);
|
|
1216
1317
|
|
|
1217
1318
|
if (config) {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1319
|
+
const classes = [
|
|
1320
|
+
'action',
|
|
1321
|
+
'sortable',
|
|
1322
|
+
action.type,
|
|
1323
|
+
isRemoving ? 'removing' : '',
|
|
1324
|
+
isLocalizable && this.isTranslating ? 'localizable' : '',
|
|
1325
|
+
hasLocalization ? 'has-localization' : '',
|
|
1326
|
+
isDisabled ? 'non-localizable' : ''
|
|
1327
|
+
]
|
|
1328
|
+
.filter(Boolean)
|
|
1329
|
+
.join(' ');
|
|
1330
|
+
|
|
1331
|
+
return html`<div class="${classes}" id="action-${index}">
|
|
1222
1332
|
<div
|
|
1223
1333
|
class="action-content"
|
|
1224
|
-
@mousedown=${(e: MouseEvent) =>
|
|
1225
|
-
|
|
1226
|
-
|
|
1334
|
+
@mousedown=${(e: MouseEvent) =>
|
|
1335
|
+
!isDisabled && this.handleActionMouseDown(e, action)}
|
|
1336
|
+
@mouseup=${(e: MouseEvent) =>
|
|
1337
|
+
!isDisabled && this.handleActionMouseUp(e, action)}
|
|
1338
|
+
style="cursor: ${isDisabled ? 'not-allowed' : 'pointer'}"
|
|
1227
1339
|
>
|
|
1228
1340
|
${this.renderTitle(config, action, index, isRemoving)}
|
|
1229
1341
|
<div class="body">
|
|
1230
1342
|
${config.render
|
|
1231
|
-
? config.render(node,
|
|
1343
|
+
? config.render(node, displayAction)
|
|
1232
1344
|
: html`<pre>${action.type}</pre>`}
|
|
1233
1345
|
</div>
|
|
1234
1346
|
</div>
|
|
@@ -1299,6 +1411,10 @@ export class CanvasNode extends RapidElement {
|
|
|
1299
1411
|
return null;
|
|
1300
1412
|
}
|
|
1301
1413
|
|
|
1414
|
+
// Check if this node type supports category localization
|
|
1415
|
+
const nodeConfig = NODE_CONFIG[this.ui?.type];
|
|
1416
|
+
const supportsLocalization = nodeConfig?.localizable === 'categories';
|
|
1417
|
+
|
|
1302
1418
|
return html`<div class="categories">
|
|
1303
1419
|
${repeat(
|
|
1304
1420
|
node.router.categories,
|
|
@@ -1308,13 +1424,44 @@ export class CanvasNode extends RapidElement {
|
|
|
1308
1424
|
(exit: Exit) => exit.uuid == category.exit_uuid
|
|
1309
1425
|
);
|
|
1310
1426
|
|
|
1427
|
+
// Get localized category name if translating
|
|
1428
|
+
let displayName = category.name;
|
|
1429
|
+
let isLocalized = false;
|
|
1430
|
+
|
|
1431
|
+
if (
|
|
1432
|
+
this.isTranslating &&
|
|
1433
|
+
this.languageCode !== 'eng' &&
|
|
1434
|
+
supportsLocalization
|
|
1435
|
+
) {
|
|
1436
|
+
const localization =
|
|
1437
|
+
this.flowDefinition?.localization?.[this.languageCode];
|
|
1438
|
+
if (localization && localization[category.uuid]) {
|
|
1439
|
+
const categoryLocalization = localization[category.uuid];
|
|
1440
|
+
if (categoryLocalization.name && categoryLocalization.name[0]) {
|
|
1441
|
+
displayName = categoryLocalization.name[0];
|
|
1442
|
+
isLocalized = true;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// Category is localizable if: translating, supports localization, categories enabled, and not base language
|
|
1448
|
+
const isLocalizable =
|
|
1449
|
+
this.isTranslating &&
|
|
1450
|
+
this.languageCode !== 'eng' &&
|
|
1451
|
+
supportsLocalization &&
|
|
1452
|
+
this.includeCategoriesInTranslation &&
|
|
1453
|
+
!isLocalized;
|
|
1454
|
+
|
|
1311
1455
|
return html`<div
|
|
1312
|
-
class
|
|
1456
|
+
class=${getClasses({
|
|
1457
|
+
category: true,
|
|
1458
|
+
localizable: isLocalizable
|
|
1459
|
+
})}
|
|
1313
1460
|
@mousedown=${(e: MouseEvent) => this.handleNodeMouseDown(e)}
|
|
1314
1461
|
@mouseup=${(e: MouseEvent) => this.handleNodeMouseUp(e)}
|
|
1315
1462
|
style="cursor: pointer;"
|
|
1316
1463
|
>
|
|
1317
|
-
<div class="cn-title">${
|
|
1464
|
+
<div class="cn-title">${displayName}</div>
|
|
1318
1465
|
${this.renderExit(exit)}
|
|
1319
1466
|
</div>`;
|
|
1320
1467
|
}
|
|
@@ -1343,12 +1490,21 @@ export class CanvasNode extends RapidElement {
|
|
|
1343
1490
|
|
|
1344
1491
|
const nodeConfig = NODE_CONFIG[this.ui.type];
|
|
1345
1492
|
|
|
1493
|
+
// Check if this node should be disabled (grayed out)
|
|
1494
|
+
const supportsLocalization = nodeConfig?.localizable === 'categories';
|
|
1495
|
+
const isNodeDisabled =
|
|
1496
|
+
this.isTranslating &&
|
|
1497
|
+
supportsLocalization &&
|
|
1498
|
+
!this.includeCategoriesInTranslation;
|
|
1499
|
+
|
|
1346
1500
|
return html`
|
|
1347
1501
|
<div
|
|
1348
1502
|
id="${this.node.uuid}"
|
|
1349
|
-
class
|
|
1350
|
-
|
|
1351
|
-
: ''
|
|
1503
|
+
class=${getClasses({
|
|
1504
|
+
node: true,
|
|
1505
|
+
'execute-actions': this.ui.type === 'execute_actions',
|
|
1506
|
+
'non-localizable': isNodeDisabled
|
|
1507
|
+
})}
|
|
1352
1508
|
style="left:${this.ui.position.left}px;top:${this.ui.position.top}px"
|
|
1353
1509
|
>
|
|
1354
1510
|
${nodeConfig && nodeConfig.type !== 'execute_actions'
|
|
@@ -1387,8 +1543,10 @@ export class CanvasNode extends RapidElement {
|
|
|
1387
1543
|
)}`
|
|
1388
1544
|
: ''}
|
|
1389
1545
|
${this.node.router
|
|
1390
|
-
? html
|
|
1391
|
-
|
|
1546
|
+
? html`<div class="router-section">
|
|
1547
|
+
${this.renderRouter(this.node.router, this.ui)}
|
|
1548
|
+
${this.renderCategories(this.node)}
|
|
1549
|
+
</div>`
|
|
1392
1550
|
: html`<div class="action-exits">
|
|
1393
1551
|
${repeat(
|
|
1394
1552
|
this.node.exits,
|
|
@@ -1396,7 +1554,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1396
1554
|
(exit) => this.renderExit(exit)
|
|
1397
1555
|
)}
|
|
1398
1556
|
</div>`}
|
|
1399
|
-
${this.ui.type === 'execute_actions'
|
|
1557
|
+
${this.ui.type === 'execute_actions' && !this.isTranslating
|
|
1400
1558
|
? html`<div
|
|
1401
1559
|
class="add-action-button"
|
|
1402
1560
|
@click=${(e: MouseEvent) => this.handleAddActionClick(e)}
|