@nyaruka/temba-components 0.140.0 → 0.141.1
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/.lintstagedrc.js +10 -0
- package/CHANGELOG.md +22 -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 +263 -156
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +1 -1
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +1 -1
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +239 -43
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +61 -14
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +4 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +4 -1
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js +6 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +6 -2
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +13 -0
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +7 -5
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +10 -3
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_contact_field.js +18 -5
- package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +0 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +0 -1
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_run_result.js +10 -4
- package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +7 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +0 -1
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/layout/Modax.js +20 -2
- package/out-tsc/src/layout/Modax.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +14 -1
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +10 -1
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/live/TembaChart.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/simulator/Simulator.js +11 -0
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +13 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/version.js +9 -0
- package/out-tsc/src/version.js.map +1 -0
- package/out-tsc/test/actions/add_contact_groups.test.js +35 -0
- package/out-tsc/test/actions/add_contact_groups.test.js.map +1 -1
- package/out-tsc/test/actions/add_input_labels.test.js +53 -0
- package/out-tsc/test/actions/add_input_labels.test.js.map +1 -0
- package/out-tsc/test/actions/enter_flow.test.js +71 -0
- package/out-tsc/test/actions/enter_flow.test.js.map +1 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js +24 -0
- package/out-tsc/test/actions/remove_contact_groups.test.js.map +1 -1
- package/out-tsc/test/actions/send_broadcast.test.js +41 -0
- package/out-tsc/test/actions/send_broadcast.test.js.map +1 -1
- package/out-tsc/test/actions/set_contact_channel.test.js +67 -0
- package/out-tsc/test/actions/set_contact_channel.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_field.test.js +52 -0
- package/out-tsc/test/actions/set_contact_field.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_language.test.js +39 -0
- package/out-tsc/test/actions/set_contact_language.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_name.test.js +28 -0
- package/out-tsc/test/actions/set_contact_name.test.js.map +1 -0
- package/out-tsc/test/actions/set_contact_status.test.js +44 -0
- package/out-tsc/test/actions/set_contact_status.test.js.map +1 -0
- package/out-tsc/test/actions/set_run_result.test.js +47 -0
- package/out-tsc/test/actions/set_run_result.test.js.map +1 -0
- package/out-tsc/test/actions/start_session.test.js +76 -0
- package/out-tsc/test/actions/start_session.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_contact_field.test.js +50 -0
- package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_run_result.test.js +82 -0
- package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_ticket.test.js +139 -0
- package/out-tsc/test/nodes/split_by_ticket.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_webhook.test.js +111 -0
- package/out-tsc/test/nodes/split_by_webhook.test.js.map +1 -0
- package/out-tsc/test/temba-contact-chat.test.js +12 -0
- package/out-tsc/test/temba-contact-chat.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +206 -0
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +19 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +4 -1
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +4 -2
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +3 -9
- package/rollup.components.mjs +7 -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/add_input_labels/editor/multiple-labels.png +0 -0
- package/screenshots/truth/actions/add_input_labels/editor/single-label.png +0 -0
- package/screenshots/truth/actions/add_input_labels/render/multiple-labels.png +0 -0
- package/screenshots/truth/actions/add_input_labels/render/single-label.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/editor/long-flow-name.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/basic-flow.png +0 -0
- package/screenshots/truth/actions/enter_flow/render/long-flow-name.png +0 -0
- package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
- package/screenshots/truth/actions/play_audio/render/static-url.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/say_msg/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/text-with-audio-url.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_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/set_contact_channel/editor/sms-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/editor/whatsapp-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/render/sms-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_channel/render/whatsapp-channel.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/clear-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/editor/set-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/render/clear-value.png +0 -0
- package/screenshots/truth/actions/set_contact_field/render/set-value.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/english.png +0 -0
- package/screenshots/truth/actions/set_contact_language/editor/french.png +0 -0
- package/screenshots/truth/actions/set_contact_language/render/english.png +0 -0
- package/screenshots/truth/actions/set_contact_language/render/french.png +0 -0
- package/screenshots/truth/actions/set_contact_name/editor/expression-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/editor/static-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/render/expression-name.png +0 -0
- package/screenshots/truth/actions/set_contact_name/render/static-name.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/active.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/archived.png +0 -0
- package/screenshots/truth/actions/set_contact_status/editor/blocked.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/active.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/archived.png +0 -0
- package/screenshots/truth/actions/set_contact_status/render/blocked.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/expression-value.png +0 -0
- package/screenshots/truth/actions/set_run_result/editor/with-category.png +0 -0
- package/screenshots/truth/actions/set_run_result/render/expression-value.png +0 -0
- package/screenshots/truth/actions/set_run_result/render/with-category.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/editor/wait.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/basic-categorization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/custom-input-and-result-name.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/editor/many-categories.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/minimal-categories.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/editor/ab-test-multiple-variants.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
- package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.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_audio/render/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.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/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.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/FloatingTab.ts +1 -1
- package/src/flow/CanvasNode.ts +1 -1
- package/src/flow/Editor.ts +299 -88
- package/src/flow/Plumber.ts +89 -14
- package/src/flow/actions/add_contact_groups.ts +4 -1
- package/src/flow/actions/add_input_labels.ts +4 -1
- package/src/flow/actions/remove_contact_groups.ts +6 -1
- package/src/flow/actions/send_broadcast.ts +6 -2
- package/src/flow/actions/set_contact_channel.ts +13 -1
- package/src/flow/actions/set_contact_status.ts +7 -5
- package/src/flow/actions/start_session.ts +10 -3
- package/src/flow/nodes/split_by_contact_field.ts +16 -5
- package/src/flow/nodes/split_by_expression.ts +1 -1
- package/src/flow/nodes/split_by_llm_categorize.ts +0 -1
- package/src/flow/nodes/split_by_random.ts +0 -1
- package/src/flow/nodes/split_by_run_result.ts +10 -4
- package/src/flow/nodes/wait_for_digits.ts +2 -1
- package/src/flow/nodes/wait_for_response.ts +1 -1
- package/src/form/FieldRenderer.ts +7 -0
- package/src/layout/Dialog.ts +0 -1
- package/src/layout/Modax.ts +19 -2
- package/src/list/ContentMenu.ts +15 -1
- package/src/live/ContactChat.ts +10 -1
- package/src/live/TembaChart.ts +1 -1
- 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/simulator/Simulator.ts +12 -0
- package/src/store/AppState.ts +15 -0
- package/src/store/flow-definition.d.ts +1 -0
- package/src/version.ts +10 -0
- package/test/actions/add_contact_groups.test.ts +38 -0
- package/test/actions/add_input_labels.test.ts +67 -0
- package/test/actions/enter_flow.test.ts +88 -0
- package/test/actions/remove_contact_groups.test.ts +29 -0
- package/test/actions/send_broadcast.test.ts +44 -0
- package/test/actions/set_contact_channel.test.ts +88 -0
- package/test/actions/set_contact_field.test.ts +68 -0
- package/test/actions/set_contact_language.test.ts +55 -0
- package/test/actions/set_contact_name.test.ts +39 -0
- package/test/actions/set_contact_status.test.ts +64 -0
- package/test/actions/set_run_result.test.ts +61 -0
- package/test/actions/start_session.test.ts +82 -0
- package/test/nodes/split_by_contact_field.test.ts +59 -0
- package/test/nodes/split_by_run_result.test.ts +100 -0
- package/test/nodes/split_by_ticket.test.ts +157 -0
- package/test/nodes/split_by_webhook.test.ts +131 -0
- package/test/temba-contact-chat.test.ts +17 -0
- package/test/temba-flow-editor.test.ts +264 -0
- package/test/temba-flow-plumber.test.ts +62 -0
- package/test/temba-select.test.ts +6 -1
- package/test/utils.test.ts +4 -2
- package/web-dev-server.config.mjs +5 -1
- package/web-test-runner.config.mjs +4 -1
|
@@ -8,6 +8,7 @@ import { RapidElement } from '../RapidElement';
|
|
|
8
8
|
import { repeat } from 'lit-html/directives/repeat.js';
|
|
9
9
|
import { CustomEventType } from '../interfaces';
|
|
10
10
|
import { generateUUID, postJSON, fetchResults, getClasses } from '../utils';
|
|
11
|
+
import { TEMBA_COMPONENTS_VERSION } from '../version';
|
|
11
12
|
import { formatIssueMessage, getNodeBounds, calculateReflowPositions, snapToGrid } from './utils';
|
|
12
13
|
import { ACTION_CONFIG, NODE_CONFIG } from './config';
|
|
13
14
|
import { ACTION_GROUP_METADATA } from './types';
|
|
@@ -22,7 +23,7 @@ export function findNodeForExit(definition, exitUuid) {
|
|
|
22
23
|
}
|
|
23
24
|
return null;
|
|
24
25
|
}
|
|
25
|
-
const SAVE_QUIET_TIME =
|
|
26
|
+
const SAVE_QUIET_TIME = 2000;
|
|
26
27
|
const DRAG_THRESHOLD = 5;
|
|
27
28
|
const AUTO_TRANSLATE_MODELS_ENDPOINT = '/api/internal/llms.json';
|
|
28
29
|
// Offset for positioning dropped action node relative to mouse cursor
|
|
@@ -68,6 +69,13 @@ export class Editor extends RapidElement {
|
|
|
68
69
|
}
|
|
69
70
|
static get styles() {
|
|
70
71
|
return css `
|
|
72
|
+
#editor-container {
|
|
73
|
+
position: relative;
|
|
74
|
+
flex: 1;
|
|
75
|
+
display: flex;
|
|
76
|
+
min-height: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
71
79
|
#editor {
|
|
72
80
|
overflow: scroll;
|
|
73
81
|
flex: 1;
|
|
@@ -546,6 +554,71 @@ export class Editor extends RapidElement {
|
|
|
546
554
|
color: tomato;
|
|
547
555
|
flex-shrink: 0;
|
|
548
556
|
}
|
|
557
|
+
|
|
558
|
+
.empty-flow {
|
|
559
|
+
position: sticky;
|
|
560
|
+
top: 80px;
|
|
561
|
+
left: 0;
|
|
562
|
+
right: 0;
|
|
563
|
+
height: 0;
|
|
564
|
+
display: flex;
|
|
565
|
+
justify-content: center;
|
|
566
|
+
pointer-events: none;
|
|
567
|
+
z-index: 50;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.empty-flow-content {
|
|
571
|
+
display: flex;
|
|
572
|
+
flex-direction: column;
|
|
573
|
+
align-items: center;
|
|
574
|
+
gap: 16px;
|
|
575
|
+
text-align: center;
|
|
576
|
+
pointer-events: auto;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.empty-flow-title {
|
|
580
|
+
font-size: 18px;
|
|
581
|
+
font-weight: 600;
|
|
582
|
+
color: #374151;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.empty-flow-description {
|
|
586
|
+
font-size: 14px;
|
|
587
|
+
color: #6b7280;
|
|
588
|
+
max-width: 320px;
|
|
589
|
+
line-height: 1.5;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.empty-flow-button {
|
|
593
|
+
background: var(--color-primary-dark);
|
|
594
|
+
border: none;
|
|
595
|
+
color: #fff;
|
|
596
|
+
padding: 10px 20px;
|
|
597
|
+
border-radius: var(--curvature);
|
|
598
|
+
font-size: 14px;
|
|
599
|
+
font-weight: 600;
|
|
600
|
+
cursor: pointer;
|
|
601
|
+
transition: opacity 0.2s ease;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.empty-flow-button:hover {
|
|
605
|
+
opacity: 0.9;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.save-indicator {
|
|
609
|
+
position: absolute;
|
|
610
|
+
top: 8px;
|
|
611
|
+
right: 16px;
|
|
612
|
+
padding: 6px 10px;
|
|
613
|
+
z-index: 10000;
|
|
614
|
+
pointer-events: none;
|
|
615
|
+
opacity: 0;
|
|
616
|
+
transition: opacity 0.15s ease-in-out;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.save-indicator.visible {
|
|
620
|
+
opacity: 1;
|
|
621
|
+
}
|
|
549
622
|
`;
|
|
550
623
|
}
|
|
551
624
|
constructor() {
|
|
@@ -588,6 +661,8 @@ export class Editor extends RapidElement {
|
|
|
588
661
|
this.revisions = [];
|
|
589
662
|
this.viewingRevision = null;
|
|
590
663
|
this.isLoadingRevisions = false;
|
|
664
|
+
this.isSaving = false;
|
|
665
|
+
this.saveError = null;
|
|
591
666
|
this.preRevertState = null;
|
|
592
667
|
this.translationCache = new Map();
|
|
593
668
|
// NodeEditor state - handles both node and action editing
|
|
@@ -622,6 +697,7 @@ export class Editor extends RapidElement {
|
|
|
622
697
|
this.setupGlobalEventListeners();
|
|
623
698
|
if (changes.has('flow')) {
|
|
624
699
|
getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
|
|
700
|
+
this.fetchRevisions();
|
|
625
701
|
}
|
|
626
702
|
this.plumber.on('connection:drag', (connection) => {
|
|
627
703
|
this.dragFromNodeId = connection.data.nodeId;
|
|
@@ -749,9 +825,14 @@ export class Editor extends RapidElement {
|
|
|
749
825
|
}
|
|
750
826
|
if (changes.has('dirtyDate')) {
|
|
751
827
|
if (this.dirtyDate) {
|
|
828
|
+
this.isSaving = true;
|
|
752
829
|
this.debouncedSave();
|
|
753
830
|
}
|
|
754
831
|
}
|
|
832
|
+
if (changes.has('saveError') && this.saveError) {
|
|
833
|
+
this.showSaveErrorDialog(this.saveError);
|
|
834
|
+
this.saveError = null;
|
|
835
|
+
}
|
|
755
836
|
if (changes.has('languageCode')) {
|
|
756
837
|
this.translationCache.clear();
|
|
757
838
|
}
|
|
@@ -791,13 +872,26 @@ export class Editor extends RapidElement {
|
|
|
791
872
|
}
|
|
792
873
|
}, SAVE_QUIET_TIME);
|
|
793
874
|
}
|
|
875
|
+
definitionForSave(definition) {
|
|
876
|
+
return {
|
|
877
|
+
...definition,
|
|
878
|
+
_ui: {
|
|
879
|
+
...definition._ui,
|
|
880
|
+
editor: TEMBA_COMPONENTS_VERSION
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
}
|
|
794
884
|
saveChanges(definitionOverride) {
|
|
795
|
-
const definition = definitionOverride || this.definition;
|
|
796
|
-
|
|
885
|
+
const definition = this.definitionForSave(definitionOverride || this.definition);
|
|
886
|
+
this.isSaving = true;
|
|
797
887
|
return getStore()
|
|
798
888
|
.postJSON(`/flow/revisions/${this.flow}/`, definition)
|
|
799
889
|
.then((response) => {
|
|
800
890
|
var _b;
|
|
891
|
+
if (response.status < 200 || response.status >= 300) {
|
|
892
|
+
this.saveError = this.extractErrorMessage(response);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
801
895
|
// Update flow info and revision with the response data
|
|
802
896
|
if (response.json) {
|
|
803
897
|
const state = getStore().getState();
|
|
@@ -807,16 +901,53 @@ export class Editor extends RapidElement {
|
|
|
807
901
|
if (((_b = response.json.revision) === null || _b === void 0 ? void 0 : _b.revision) !== undefined) {
|
|
808
902
|
state.setRevision(response.json.revision.revision);
|
|
809
903
|
}
|
|
810
|
-
//
|
|
811
|
-
|
|
812
|
-
this.fetchRevisions();
|
|
813
|
-
}
|
|
904
|
+
// Refresh revisions list so the tab visibility stays up to date
|
|
905
|
+
this.fetchRevisions();
|
|
814
906
|
}
|
|
907
|
+
getStore().getState().setDirtyDate(null);
|
|
815
908
|
})
|
|
816
909
|
.catch((error) => {
|
|
817
910
|
console.error('Failed to save flow:', error);
|
|
911
|
+
if (error instanceof Response) {
|
|
912
|
+
this.saveError = `Server error (${error.status}). Your changes have not been saved.`;
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
this.saveError =
|
|
916
|
+
'Unable to reach the server. Please check your connection and try again.';
|
|
917
|
+
}
|
|
918
|
+
})
|
|
919
|
+
.finally(() => {
|
|
920
|
+
this.isSaving = false;
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
extractErrorMessage(response) {
|
|
924
|
+
if (response.json) {
|
|
925
|
+
if (typeof response.json.detail === 'string') {
|
|
926
|
+
return response.json.detail;
|
|
927
|
+
}
|
|
928
|
+
if (typeof response.json.error === 'string') {
|
|
929
|
+
return response.json.error;
|
|
930
|
+
}
|
|
931
|
+
if (typeof response.json.description === 'string') {
|
|
932
|
+
return response.json.description;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return `Save failed with status ${response.status}.`;
|
|
936
|
+
}
|
|
937
|
+
showSaveErrorDialog(message) {
|
|
938
|
+
const dialog = document.createElement('temba-dialog');
|
|
939
|
+
dialog.header = 'Save Failed';
|
|
940
|
+
dialog.primaryButtonName = '';
|
|
941
|
+
dialog.cancelButtonName = 'Dismiss';
|
|
942
|
+
const content = document.createElement('div');
|
|
943
|
+
content.style.cssText = 'padding: 20px; font-size: 14px; line-height: 1.5;';
|
|
944
|
+
content.textContent = message;
|
|
945
|
+
dialog.appendChild(content);
|
|
946
|
+
document.body.appendChild(dialog);
|
|
947
|
+
dialog.open = true;
|
|
948
|
+
dialog.addEventListener('temba-dialog-hidden', () => {
|
|
949
|
+
document.body.removeChild(dialog);
|
|
818
950
|
});
|
|
819
|
-
getStore().getState().setDirtyDate(null);
|
|
820
951
|
}
|
|
821
952
|
startActivityFetching() {
|
|
822
953
|
// Don't start if simulator is active
|
|
@@ -848,6 +979,10 @@ export class Editor extends RapidElement {
|
|
|
848
979
|
}
|
|
849
980
|
const state = store.getState();
|
|
850
981
|
state.fetchActivity(activityEndpoint).then(() => {
|
|
982
|
+
// Guard against responses arriving after the editor is disconnected
|
|
983
|
+
if (!this.isConnected) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
851
986
|
// Schedule next fetch with exponential backoff (max 5 minutes)
|
|
852
987
|
this.activityInterval = Math.min(60000 * 5, this.activityInterval + 100);
|
|
853
988
|
if (this.activityTimer !== null) {
|
|
@@ -879,6 +1014,9 @@ export class Editor extends RapidElement {
|
|
|
879
1014
|
if (canvas) {
|
|
880
1015
|
canvas.removeEventListener('contextmenu', this.boundCanvasContextMenu);
|
|
881
1016
|
}
|
|
1017
|
+
// Clear all flow-specific data from the store so stale data
|
|
1018
|
+
// isn't briefly visible when a different flow is opened.
|
|
1019
|
+
zustand.getState().clearFlowData();
|
|
882
1020
|
}
|
|
883
1021
|
setupGlobalEventListeners() {
|
|
884
1022
|
document.addEventListener('mousemove', this.boundMouseMove);
|
|
@@ -1577,6 +1715,25 @@ export class Editor extends RapidElement {
|
|
|
1577
1715
|
});
|
|
1578
1716
|
}
|
|
1579
1717
|
}
|
|
1718
|
+
handleEmptyFlowClick(event) {
|
|
1719
|
+
const editor = this.querySelector('#editor');
|
|
1720
|
+
if (!editor)
|
|
1721
|
+
return;
|
|
1722
|
+
// Scroll to top-left
|
|
1723
|
+
editor.scrollTo({ left: 0, top: 0, behavior: 'smooth' });
|
|
1724
|
+
// Place node at top-left of the canvas
|
|
1725
|
+
const nodeLeft = 0;
|
|
1726
|
+
const nodeTop = 0;
|
|
1727
|
+
const canvasMenu = this.querySelector('temba-canvas-menu');
|
|
1728
|
+
if (canvasMenu) {
|
|
1729
|
+
const button = event.currentTarget;
|
|
1730
|
+
const rect = button.getBoundingClientRect();
|
|
1731
|
+
const menuWidth = 265;
|
|
1732
|
+
const menuX = rect.left + rect.width / 2 - menuWidth / 2;
|
|
1733
|
+
const menuY = rect.bottom + 8;
|
|
1734
|
+
canvasMenu.show(menuX, menuY, { x: nodeLeft, y: nodeTop }, false);
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1580
1737
|
handleCanvasMenuSelection(event) {
|
|
1581
1738
|
const selection = event.detail;
|
|
1582
1739
|
const store = getStore();
|
|
@@ -2647,7 +2804,7 @@ export class Editor extends RapidElement {
|
|
|
2647
2804
|
}
|
|
2648
2805
|
renderIssuesTab() {
|
|
2649
2806
|
var _b;
|
|
2650
|
-
if (!((_b = this.flowIssues) === null || _b === void 0 ? void 0 : _b.length))
|
|
2807
|
+
if (!((_b = this.flowIssues) === null || _b === void 0 ? void 0 : _b.length) || !this.revisionsWindowHidden)
|
|
2651
2808
|
return '';
|
|
2652
2809
|
return html `
|
|
2653
2810
|
<temba-floating-tab
|
|
@@ -2691,6 +2848,8 @@ export class Editor extends RapidElement {
|
|
|
2691
2848
|
`;
|
|
2692
2849
|
}
|
|
2693
2850
|
renderRevisionsTab() {
|
|
2851
|
+
if (this.revisions.length <= 1)
|
|
2852
|
+
return '';
|
|
2694
2853
|
return html `
|
|
2695
2854
|
<temba-floating-tab
|
|
2696
2855
|
id="revisions-tab"
|
|
@@ -2958,6 +3117,11 @@ export class Editor extends RapidElement {
|
|
|
2958
3117
|
`;
|
|
2959
3118
|
}
|
|
2960
3119
|
renderLocalizationTab() {
|
|
3120
|
+
var _b;
|
|
3121
|
+
if (!this.revisionsWindowHidden)
|
|
3122
|
+
return '';
|
|
3123
|
+
if (((_b = this.definition) === null || _b === void 0 ? void 0 : _b.nodes.length) === 0)
|
|
3124
|
+
return '';
|
|
2961
3125
|
const languages = this.getLocalizationLanguages();
|
|
2962
3126
|
if (!languages.length) {
|
|
2963
3127
|
return html ``;
|
|
@@ -3018,21 +3182,41 @@ export class Editor extends RapidElement {
|
|
|
3018
3182
|
return html `${style} ${this.renderIssuesWindow()}
|
|
3019
3183
|
${this.renderRevisionsWindow()} ${this.renderLocalizationWindow()}
|
|
3020
3184
|
${this.renderAutoTranslateDialog()}
|
|
3021
|
-
<div id="editor">
|
|
3022
|
-
<div
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3185
|
+
<div id="editor-container">
|
|
3186
|
+
<div id="editor">
|
|
3187
|
+
${this.definition &&
|
|
3188
|
+
this.definition.nodes.length === 0 &&
|
|
3189
|
+
!this.isReadOnly()
|
|
3190
|
+
? html `<div class="empty-flow">
|
|
3191
|
+
<div class="empty-flow-content">
|
|
3192
|
+
<div class="empty-flow-title">This flow is empty</div>
|
|
3193
|
+
<div class="empty-flow-description">
|
|
3194
|
+
Get started by adding your first action or split to define
|
|
3195
|
+
how this flow will work.
|
|
3196
|
+
</div>
|
|
3197
|
+
<button
|
|
3198
|
+
class="empty-flow-button"
|
|
3199
|
+
@click=${this.handleEmptyFlowClick}
|
|
3200
|
+
>
|
|
3201
|
+
Add first step
|
|
3202
|
+
</button>
|
|
3203
|
+
</div>
|
|
3204
|
+
</div>`
|
|
3205
|
+
: ''}
|
|
3028
3206
|
<div
|
|
3029
|
-
id="
|
|
3030
|
-
class="${
|
|
3207
|
+
id="grid"
|
|
3208
|
+
class="${this.viewingRevision ? 'viewing-revision' : ''}"
|
|
3209
|
+
style="min-width:100%;width:${this.canvasSize
|
|
3210
|
+
.width}px; height:${this.canvasSize.height}px"
|
|
3211
|
+
>
|
|
3212
|
+
<div
|
|
3213
|
+
id="canvas"
|
|
3214
|
+
class="${getClasses({
|
|
3031
3215
|
'viewing-revision': !!this.viewingRevision,
|
|
3032
3216
|
'read-only-connections': !!this.viewingRevision || this.isTranslating
|
|
3033
3217
|
})}"
|
|
3034
|
-
|
|
3035
|
-
|
|
3218
|
+
>
|
|
3219
|
+
${this.definition
|
|
3036
3220
|
? repeat([...this.definition.nodes].sort((a, b) => a.uuid.localeCompare(b.uuid)), (node) => node.uuid, (node) => {
|
|
3037
3221
|
var _b, _c, _d;
|
|
3038
3222
|
const position = ((_c = (_b = this.definition._ui) === null || _b === void 0 ? void 0 : _b.nodes[node.uuid]) === null || _c === void 0 ? void 0 : _c.position) || {
|
|
@@ -3046,43 +3230,49 @@ export class Editor extends RapidElement {
|
|
|
3046
3230
|
const isFlowStart = this.definition.nodes.length > 0 &&
|
|
3047
3231
|
this.definition.nodes[0].uuid === node.uuid;
|
|
3048
3232
|
return html `<temba-flow-node
|
|
3049
|
-
|
|
3050
|
-
? '
|
|
3051
|
-
: ''} ${
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3233
|
+
class="draggable ${dragging
|
|
3234
|
+
? 'dragging'
|
|
3235
|
+
: ''} ${selected ? 'selected' : ''} ${isFlowStart
|
|
3236
|
+
? 'flow-start'
|
|
3237
|
+
: ''}"
|
|
3238
|
+
@mousedown=${this.handleMouseDown.bind(this)}
|
|
3239
|
+
uuid=${node.uuid}
|
|
3240
|
+
data-node-uuid=${node.uuid}
|
|
3241
|
+
style="left:${position.left}px; top:${position.top}px;transition: all 0.2s ease-in-out;"
|
|
3242
|
+
.plumber=${this.plumber}
|
|
3243
|
+
.node=${node}
|
|
3244
|
+
.ui=${this.definition._ui.nodes[node.uuid]}
|
|
3245
|
+
@temba-node-deleted=${(event) => {
|
|
3060
3246
|
this.deleteNodes([event.detail.uuid]);
|
|
3061
3247
|
}}
|
|
3062
|
-
|
|
3248
|
+
></temba-flow-node>`;
|
|
3063
3249
|
})
|
|
3064
3250
|
: html `<temba-loading></temba-loading>`}
|
|
3065
|
-
|
|
3251
|
+
${repeat(Object.entries(stickies), ([uuid]) => uuid, ([uuid, sticky]) => {
|
|
3066
3252
|
var _b;
|
|
3067
3253
|
const position = sticky.position || { left: 0, top: 0 };
|
|
3068
3254
|
const dragging = this.isDragging && ((_b = this.currentDragItem) === null || _b === void 0 ? void 0 : _b.uuid) === uuid;
|
|
3069
3255
|
const selected = this.selectedItems.has(uuid);
|
|
3070
3256
|
return html `<temba-sticky-note
|
|
3071
|
-
|
|
3257
|
+
class="draggable ${dragging ? 'dragging' : ''} ${selected
|
|
3072
3258
|
? 'selected'
|
|
3073
3259
|
: ''}"
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3260
|
+
@mousedown=${this.handleMouseDown.bind(this)}
|
|
3261
|
+
style="left:${position.left}px; top:${position.top}px;"
|
|
3262
|
+
uuid=${uuid}
|
|
3263
|
+
.data=${sticky}
|
|
3264
|
+
.dragging=${dragging}
|
|
3265
|
+
.selected=${selected}
|
|
3266
|
+
></temba-sticky-note>`;
|
|
3081
3267
|
})}
|
|
3082
|
-
|
|
3083
|
-
|
|
3268
|
+
${this.renderSelectionBox()} ${this.renderCanvasDropPreview()}
|
|
3269
|
+
${this.renderConnectionPlaceholder()}
|
|
3270
|
+
</div>
|
|
3084
3271
|
</div>
|
|
3085
3272
|
</div>
|
|
3273
|
+
<div class="save-indicator ${this.isSaving ? 'visible' : ''}">
|
|
3274
|
+
<temba-loading units="3" size="8"></temba-loading>
|
|
3275
|
+
</div>
|
|
3086
3276
|
</div>
|
|
3087
3277
|
|
|
3088
3278
|
${this.editingNode || this.editingAction
|
|
@@ -3213,6 +3403,12 @@ __decorate([
|
|
|
3213
3403
|
__decorate([
|
|
3214
3404
|
state()
|
|
3215
3405
|
], Editor.prototype, "isLoadingRevisions", void 0);
|
|
3406
|
+
__decorate([
|
|
3407
|
+
state()
|
|
3408
|
+
], Editor.prototype, "isSaving", void 0);
|
|
3409
|
+
__decorate([
|
|
3410
|
+
state()
|
|
3411
|
+
], Editor.prototype, "saveError", void 0);
|
|
3216
3412
|
__decorate([
|
|
3217
3413
|
state()
|
|
3218
3414
|
], Editor.prototype, "editingNode", void 0);
|