@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
|
@@ -8,6 +8,8 @@ import { CustomEventType } from '../interfaces';
|
|
|
8
8
|
import { generateUUID } from '../utils';
|
|
9
9
|
import { FieldRenderer } from '../form/FieldRenderer';
|
|
10
10
|
import { renderMarkdownInline } from '../markdown';
|
|
11
|
+
import { fromStore, zustand } from '../store/AppState';
|
|
12
|
+
import { getStore } from '../store/Store';
|
|
11
13
|
export class NodeEditor extends RapidElement {
|
|
12
14
|
constructor() {
|
|
13
15
|
super(...arguments);
|
|
@@ -314,6 +316,54 @@ export class NodeEditor extends RapidElement {
|
|
|
314
316
|
.optional-field-link a:hover {
|
|
315
317
|
text-decoration: underline;
|
|
316
318
|
}
|
|
319
|
+
|
|
320
|
+
.original-value {
|
|
321
|
+
background: #fff8dc;
|
|
322
|
+
padding: 10px;
|
|
323
|
+
border-radius: 4px;
|
|
324
|
+
font-size: 13px;
|
|
325
|
+
color: #666;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.original-value-content {
|
|
329
|
+
color: #333;
|
|
330
|
+
white-space: pre-wrap;
|
|
331
|
+
word-break: break-word;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.category-localization-table {
|
|
335
|
+
width: 100%;
|
|
336
|
+
display: flex;
|
|
337
|
+
flex-direction: column;
|
|
338
|
+
gap: 5px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.category-localization-row {
|
|
342
|
+
display: grid;
|
|
343
|
+
grid-template-columns: 40% 60%;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.category-localization-row:last-child {
|
|
347
|
+
border-bottom: none;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.original-name {
|
|
351
|
+
padding: 10px 20px;
|
|
352
|
+
background: #fff8dc;
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
border-radius: var(--curvature);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.localized-name {
|
|
359
|
+
padding: 10px;
|
|
360
|
+
display: flex;
|
|
361
|
+
align-items: center;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.localized-name temba-textinput {
|
|
365
|
+
width: 100%;
|
|
366
|
+
}
|
|
317
367
|
`;
|
|
318
368
|
}
|
|
319
369
|
connectedCallback() {
|
|
@@ -345,11 +395,20 @@ export class NodeEditor extends RapidElement {
|
|
|
345
395
|
this.isOpen = true;
|
|
346
396
|
}
|
|
347
397
|
initializeFormData() {
|
|
398
|
+
var _a, _b, _c, _d, _e;
|
|
348
399
|
const nodeConfig = this.getNodeConfig();
|
|
349
400
|
if ((!nodeConfig || nodeConfig.type === 'execute_actions') && this.action) {
|
|
350
401
|
// Action editing mode - use action config
|
|
351
402
|
const actionConfig = ACTION_CONFIG[this.action.type];
|
|
352
|
-
|
|
403
|
+
// Check if we're in localization mode
|
|
404
|
+
if (this.isTranslating &&
|
|
405
|
+
(actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.localizable) &&
|
|
406
|
+
actionConfig.toLocalizationFormData) {
|
|
407
|
+
// Get localized values for this action
|
|
408
|
+
const localization = ((_c = (_b = (_a = this.flowDefinition) === null || _a === void 0 ? void 0 : _a.localization) === null || _b === void 0 ? void 0 : _b[this.languageCode]) === null || _c === void 0 ? void 0 : _c[this.action.uuid]) || {};
|
|
409
|
+
this.formData = actionConfig.toLocalizationFormData(this.action, localization);
|
|
410
|
+
}
|
|
411
|
+
else if (actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.toFormData) {
|
|
353
412
|
this.formData = actionConfig.toFormData(this.action);
|
|
354
413
|
}
|
|
355
414
|
else {
|
|
@@ -363,7 +422,15 @@ export class NodeEditor extends RapidElement {
|
|
|
363
422
|
else if (this.node) {
|
|
364
423
|
// Node editing mode - use node config
|
|
365
424
|
const nodeConfig = this.getNodeConfig();
|
|
366
|
-
|
|
425
|
+
// Check if we're in localization mode for a node with localizable categories
|
|
426
|
+
if (this.isTranslating &&
|
|
427
|
+
(nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.localizable) === 'categories' &&
|
|
428
|
+
nodeConfig.toLocalizationFormData) {
|
|
429
|
+
// Get localized values for this node's categories
|
|
430
|
+
const localization = ((_e = (_d = this.flowDefinition) === null || _d === void 0 ? void 0 : _d.localization) === null || _e === void 0 ? void 0 : _e[this.languageCode]) || {};
|
|
431
|
+
this.formData = nodeConfig.toLocalizationFormData(this.node, localization);
|
|
432
|
+
}
|
|
433
|
+
else if (nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.toFormData) {
|
|
367
434
|
this.formData = nodeConfig.toFormData(this.node, this.nodeUI);
|
|
368
435
|
}
|
|
369
436
|
else {
|
|
@@ -488,16 +555,63 @@ export class NodeEditor extends RapidElement {
|
|
|
488
555
|
}
|
|
489
556
|
}
|
|
490
557
|
handleSave() {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (!validation.valid) {
|
|
494
|
-
this.errors = validation.errors;
|
|
495
|
-
// Expand any groups that contain validation errors
|
|
496
|
-
this.expandGroupsWithErrors(validation.errors);
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
// Process form data to convert key-value arrays to Records before saving
|
|
558
|
+
var _a, _b, _c, _d;
|
|
559
|
+
// Process form data first
|
|
500
560
|
const processedFormData = this.processFormDataForSave();
|
|
561
|
+
// Skip validation if we're in localization mode
|
|
562
|
+
// (localization only deals with translating text, not changing structure)
|
|
563
|
+
if (!this.isTranslating) {
|
|
564
|
+
// Validate the form
|
|
565
|
+
const validation = this.validateForm();
|
|
566
|
+
if (!validation.valid) {
|
|
567
|
+
this.errors = validation.errors;
|
|
568
|
+
// Expand any groups that contain validation errors
|
|
569
|
+
this.expandGroupsWithErrors(validation.errors);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// Check if we're in localization mode
|
|
574
|
+
if (this.isTranslating) {
|
|
575
|
+
// Handle action localization
|
|
576
|
+
if (this.action) {
|
|
577
|
+
const actionConfig = ACTION_CONFIG[this.action.type];
|
|
578
|
+
if ((actionConfig === null || actionConfig === void 0 ? void 0 : actionConfig.localizable) &&
|
|
579
|
+
actionConfig.fromLocalizationFormData) {
|
|
580
|
+
// Save to localization structure
|
|
581
|
+
const localizationData = actionConfig.fromLocalizationFormData(processedFormData, this.action);
|
|
582
|
+
// Update the flow definition's localization
|
|
583
|
+
this.updateLocalization(this.languageCode, this.action.uuid, localizationData);
|
|
584
|
+
// Close the dialog
|
|
585
|
+
this.fireCustomEvent(CustomEventType.NodeEditCancelled, {});
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// Handle node localization (for router categories)
|
|
590
|
+
if (this.node) {
|
|
591
|
+
const nodeConfig = this.getNodeConfig();
|
|
592
|
+
if ((nodeConfig === null || nodeConfig === void 0 ? void 0 : nodeConfig.localizable) === 'categories' &&
|
|
593
|
+
nodeConfig.fromLocalizationFormData) {
|
|
594
|
+
// Get localization data for all categories
|
|
595
|
+
const localizationData = nodeConfig.fromLocalizationFormData(processedFormData, this.node);
|
|
596
|
+
const languageLocalization = ((_b = (_a = this.flowDefinition) === null || _a === void 0 ? void 0 : _a.localization) === null || _b === void 0 ? void 0 : _b[this.languageCode]) || {};
|
|
597
|
+
const categories = ((_d = (_c = this.node) === null || _c === void 0 ? void 0 : _c.router) === null || _d === void 0 ? void 0 : _d.categories) || [];
|
|
598
|
+
categories.forEach((category) => {
|
|
599
|
+
const categoryUuid = category.uuid;
|
|
600
|
+
const nextLocalization = localizationData[categoryUuid];
|
|
601
|
+
if (nextLocalization) {
|
|
602
|
+
this.updateLocalization(this.languageCode, categoryUuid, nextLocalization);
|
|
603
|
+
}
|
|
604
|
+
else if (languageLocalization[categoryUuid]) {
|
|
605
|
+
// Remove existing localization when the translation was cleared
|
|
606
|
+
this.updateLocalization(this.languageCode, categoryUuid, {});
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
// Close the dialog
|
|
610
|
+
this.fireCustomEvent(CustomEventType.NodeEditCancelled, {});
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
501
615
|
// Determine whether to use node or action saving based on context
|
|
502
616
|
// If we have a node with a router, always use node saving (even if action is set)
|
|
503
617
|
// because router configuration is handled at the node level
|
|
@@ -535,6 +649,12 @@ export class NodeEditor extends RapidElement {
|
|
|
535
649
|
});
|
|
536
650
|
}
|
|
537
651
|
}
|
|
652
|
+
updateLocalization(languageCode, actionUuid, localizationData) {
|
|
653
|
+
// Use the store method to properly update localization with immer
|
|
654
|
+
zustand
|
|
655
|
+
.getState()
|
|
656
|
+
.updateLocalization(languageCode, actionUuid, localizationData);
|
|
657
|
+
}
|
|
538
658
|
processFormDataForSave() {
|
|
539
659
|
const processed = { ...this.formData };
|
|
540
660
|
// Convert key-value arrays to Records
|
|
@@ -586,8 +706,9 @@ export class NodeEditor extends RapidElement {
|
|
|
586
706
|
'There was an error creating' + ' "' + selected.name + '"';
|
|
587
707
|
}
|
|
588
708
|
}
|
|
589
|
-
// Check required fields
|
|
590
|
-
if (
|
|
709
|
+
// Check required fields (skip in localization mode since all fields are optional)
|
|
710
|
+
if (!this.isTranslating &&
|
|
711
|
+
fieldConfig.required &&
|
|
591
712
|
(!value || (Array.isArray(value) && value.length === 0))) {
|
|
592
713
|
errors[fieldName] = `${fieldConfig.label || fieldName} is required.`;
|
|
593
714
|
}
|
|
@@ -948,12 +1069,17 @@ export class NodeEditor extends RapidElement {
|
|
|
948
1069
|
const containerStyle = config.maxWidth
|
|
949
1070
|
? `max-width: ${config.maxWidth};`
|
|
950
1071
|
: '';
|
|
1072
|
+
// Render original value if in localization mode and action has the field
|
|
1073
|
+
const originalValueDisplay = this.isTranslating && this.action && fieldName in this.action
|
|
1074
|
+
? this.renderOriginalValue(fieldName, this.action[fieldName])
|
|
1075
|
+
: html ``;
|
|
951
1076
|
const fieldContent = this.renderFieldContent(fieldName, config, value, errors);
|
|
1077
|
+
const content = html ` ${originalValueDisplay} ${fieldContent} `;
|
|
952
1078
|
// Wrap in container with style if maxWidth is specified
|
|
953
1079
|
if (containerStyle) {
|
|
954
|
-
return html `<div style="${containerStyle}">${
|
|
1080
|
+
return html `<div style="${containerStyle}">${content}</div>`;
|
|
955
1081
|
}
|
|
956
|
-
return
|
|
1082
|
+
return content;
|
|
957
1083
|
}
|
|
958
1084
|
renderOptionalField(fieldName, config, value) {
|
|
959
1085
|
// If the field has a value or has been revealed, show it
|
|
@@ -984,9 +1110,76 @@ export class NodeEditor extends RapidElement {
|
|
|
984
1110
|
fieldName
|
|
985
1111
|
]);
|
|
986
1112
|
}
|
|
1113
|
+
renderCategoryLocalizationTable() {
|
|
1114
|
+
const categories = this.formData.categories || {};
|
|
1115
|
+
const categoryEntries = Object.entries(categories);
|
|
1116
|
+
if (categoryEntries.length === 0) {
|
|
1117
|
+
return html `<div>No categories to localize</div>`;
|
|
1118
|
+
}
|
|
1119
|
+
const languageName = getStore().getLanguageName(this.languageCode);
|
|
1120
|
+
return html `
|
|
1121
|
+
<div class="category-localization-table">
|
|
1122
|
+
${categoryEntries.map(([categoryUuid, categoryData]) => html `
|
|
1123
|
+
<div class="category-localization-row">
|
|
1124
|
+
<div class="original-name">${categoryData.originalName}</div>
|
|
1125
|
+
<div class="localized-name">
|
|
1126
|
+
<temba-textinput
|
|
1127
|
+
name="${categoryUuid}"
|
|
1128
|
+
placeholder="${languageName} Translation"
|
|
1129
|
+
value="${categoryData.localizedName || ''}"
|
|
1130
|
+
@change=${(e) => this.handleCategoryLocalizationChange(categoryUuid, e.target.value)}
|
|
1131
|
+
></temba-textinput>
|
|
1132
|
+
</div>
|
|
1133
|
+
</div>
|
|
1134
|
+
`)}
|
|
1135
|
+
</div>
|
|
1136
|
+
`;
|
|
1137
|
+
}
|
|
1138
|
+
handleCategoryLocalizationChange(categoryUuid, value) {
|
|
1139
|
+
// Update formData with new localized value
|
|
1140
|
+
if (!this.formData.categories) {
|
|
1141
|
+
this.formData.categories = {};
|
|
1142
|
+
}
|
|
1143
|
+
if (!this.formData.categories[categoryUuid]) {
|
|
1144
|
+
this.formData.categories[categoryUuid] = {};
|
|
1145
|
+
}
|
|
1146
|
+
this.formData.categories[categoryUuid].localizedName = value;
|
|
1147
|
+
// Trigger a re-render
|
|
1148
|
+
this.requestUpdate();
|
|
1149
|
+
}
|
|
1150
|
+
renderOriginalValue(fieldName, originalValue) {
|
|
1151
|
+
// Format the original value for display
|
|
1152
|
+
let displayValue = '';
|
|
1153
|
+
if (Array.isArray(originalValue)) {
|
|
1154
|
+
if (originalValue.length === 0) {
|
|
1155
|
+
return html ``; // Don't show anything for empty arrays
|
|
1156
|
+
}
|
|
1157
|
+
// For arrays, join with commas
|
|
1158
|
+
displayValue = originalValue.join(', ');
|
|
1159
|
+
}
|
|
1160
|
+
else if (typeof originalValue === 'string') {
|
|
1161
|
+
displayValue = originalValue;
|
|
1162
|
+
}
|
|
1163
|
+
else if (originalValue) {
|
|
1164
|
+
displayValue = String(originalValue);
|
|
1165
|
+
}
|
|
1166
|
+
// Don't show if empty
|
|
1167
|
+
if (!displayValue || displayValue.trim() === '') {
|
|
1168
|
+
return html ``;
|
|
1169
|
+
}
|
|
1170
|
+
return html `
|
|
1171
|
+
<div class="original-value">
|
|
1172
|
+
<div class="original-value-content">${displayValue}</div>
|
|
1173
|
+
</div>
|
|
1174
|
+
`;
|
|
1175
|
+
}
|
|
987
1176
|
renderFieldContent(fieldName, config, value, errors) {
|
|
1177
|
+
// In localization mode, make all fields optional (not required)
|
|
1178
|
+
const fieldConfig = this.isTranslating
|
|
1179
|
+
? { ...config, required: false }
|
|
1180
|
+
: config;
|
|
988
1181
|
// Use FieldRenderer for consistent field rendering
|
|
989
|
-
return FieldRenderer.renderField(fieldName,
|
|
1182
|
+
return FieldRenderer.renderField(fieldName, fieldConfig, value, {
|
|
990
1183
|
errors,
|
|
991
1184
|
onChange: (e) => {
|
|
992
1185
|
// Handle different change event types
|
|
@@ -1330,6 +1523,12 @@ export class NodeEditor extends RapidElement {
|
|
|
1330
1523
|
if (!config) {
|
|
1331
1524
|
return html ` <div>No configuration available</div> `;
|
|
1332
1525
|
}
|
|
1526
|
+
// Special rendering for category localization
|
|
1527
|
+
if (this.isTranslating &&
|
|
1528
|
+
config.localizable === 'categories' &&
|
|
1529
|
+
this.formData.categories) {
|
|
1530
|
+
return this.renderCategoryLocalizationTable();
|
|
1531
|
+
}
|
|
1333
1532
|
// Use the new fields configuration system
|
|
1334
1533
|
if (config.form) {
|
|
1335
1534
|
// If layout is specified, use it
|
|
@@ -1374,6 +1573,10 @@ export class NodeEditor extends RapidElement {
|
|
|
1374
1573
|
if (!(config === null || config === void 0 ? void 0 : config.gutter) || config.gutter.length === 0) {
|
|
1375
1574
|
return html ``;
|
|
1376
1575
|
}
|
|
1576
|
+
// Don't show gutter when localizing categories
|
|
1577
|
+
if (this.isTranslating && config.localizable === 'categories') {
|
|
1578
|
+
return html ``;
|
|
1579
|
+
}
|
|
1377
1580
|
// Use the same layout rendering system for gutter fields
|
|
1378
1581
|
const renderedFields = new Set();
|
|
1379
1582
|
return html `
|
|
@@ -1443,17 +1646,25 @@ export class NodeEditor extends RapidElement {
|
|
|
1443
1646
|
if (!this.isOpen) {
|
|
1444
1647
|
return html ``;
|
|
1445
1648
|
}
|
|
1446
|
-
const headerColor = this.getHeaderColor();
|
|
1649
|
+
const headerColor = this.isTranslating ? '#505050' : this.getHeaderColor();
|
|
1650
|
+
const headerTextColor = this.isTranslating ? '#fff' : '#fff';
|
|
1447
1651
|
const config = this.getConfig();
|
|
1448
1652
|
const dialogSize = (config === null || config === void 0 ? void 0 : config.dialogSize) || 'medium'; // Default to 'large' if not specified
|
|
1653
|
+
const languageName = this.isTranslating
|
|
1654
|
+
? getStore().getLanguageName(this.languageCode)
|
|
1655
|
+
: '';
|
|
1656
|
+
let header = (config === null || config === void 0 ? void 0 : config.name) || 'Edit';
|
|
1657
|
+
if (this.isTranslating) {
|
|
1658
|
+
header = languageName ? `${languageName} - ${header}` : header;
|
|
1659
|
+
}
|
|
1449
1660
|
return html `
|
|
1450
1661
|
<temba-dialog
|
|
1451
|
-
header="${
|
|
1662
|
+
header="${header}"
|
|
1452
1663
|
.open="${this.isOpen}"
|
|
1453
1664
|
@temba-button-clicked=${this.handleDialogButtonClick}
|
|
1454
1665
|
primaryButtonName="Save"
|
|
1455
1666
|
cancelButtonName="Cancel"
|
|
1456
|
-
style="--header-bg: ${headerColor}"
|
|
1667
|
+
style="--header-bg: ${headerColor}; --header-text: ${headerTextColor};"
|
|
1457
1668
|
size="${dialogSize}"
|
|
1458
1669
|
>
|
|
1459
1670
|
<div class="node-editor-form">
|
|
@@ -1498,4 +1709,13 @@ __decorate([
|
|
|
1498
1709
|
__decorate([
|
|
1499
1710
|
state()
|
|
1500
1711
|
], NodeEditor.prototype, "revealedOptionalFields", void 0);
|
|
1712
|
+
__decorate([
|
|
1713
|
+
fromStore(zustand, (state) => state.languageCode)
|
|
1714
|
+
], NodeEditor.prototype, "languageCode", void 0);
|
|
1715
|
+
__decorate([
|
|
1716
|
+
fromStore(zustand, (state) => state.isTranslating)
|
|
1717
|
+
], NodeEditor.prototype, "isTranslating", void 0);
|
|
1718
|
+
__decorate([
|
|
1719
|
+
fromStore(zustand, (state) => state.flowDefinition)
|
|
1720
|
+
], NodeEditor.prototype, "flowDefinition", void 0);
|
|
1501
1721
|
//# sourceMappingURL=NodeEditor.js.map
|