@nyaruka/temba-components 0.139.0 → 0.141.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/cla.yml +1 -1
- package/.github/workflows/copilot-setup-steps.yml +6 -1
- package/.lintstagedrc.js +10 -0
- package/CHANGELOG.md +32 -0
- package/demo/data/flows/sample-flow.json +24 -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 +702 -338
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +10 -7
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/display/Dropdown.js +3 -1
- package/out-tsc/src/display/Dropdown.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +4 -4
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/display/Thumbnail.js +163 -5
- package/out-tsc/src/display/Thumbnail.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +65 -23
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +369 -49
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +118 -10
- package/out-tsc/src/flow/NodeEditor.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/StickyNote.js +13 -4
- package/out-tsc/src/flow/StickyNote.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/audio-player.js +112 -0
- package/out-tsc/src/flow/actions/audio-player.js.map +1 -0
- package/out-tsc/src/flow/actions/enter_flow.js +43 -0
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
- package/out-tsc/src/flow/actions/play_audio.js +57 -4
- package/out-tsc/src/flow/actions/play_audio.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/say_msg.js +86 -3
- package/out-tsc/src/flow/actions/say_msg.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/config.js +11 -3
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/shared-rules.js +1 -1
- package/out-tsc/src/flow/nodes/shared-rules.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/terminal.js +7 -0
- package/out-tsc/src/flow/nodes/terminal.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js +77 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_dial.js +151 -0
- package/out-tsc/src/flow/nodes/wait_for_dial.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_digits.js +61 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_menu.js +173 -2
- package/out-tsc/src/flow/nodes/wait_for_menu.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/flow/operators.js +21 -5
- package/out-tsc/src/flow/operators.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +79 -3
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +4 -2
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +56 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +51 -7
- 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/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 +21 -4
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +102 -3
- package/out-tsc/src/store/AppState.js.map +1 -1
- 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/play_audio.test.js +118 -0
- package/out-tsc/test/actions/play_audio.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/say_msg.test.js +158 -0
- package/out-tsc/test/actions/say_msg.test.js.map +1 -0
- 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/nodes/wait_for_audio.test.js +156 -0
- package/out-tsc/test/nodes/wait_for_audio.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_dial.test.js +336 -0
- package/out-tsc/test/nodes/wait_for_dial.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js +198 -84
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_menu.test.js +340 -0
- package/out-tsc/test/nodes/wait_for_menu.test.js.map +1 -0
- package/out-tsc/test/temba-flow-collision.test.js +261 -6
- package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +187 -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-node-type-selector.test.js +6 -6
- package/out-tsc/test/temba-node-type-selector.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/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/editor/expression-url.png +0 -0
- package/screenshots/truth/actions/play_audio/editor/static-url.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/editor/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.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/router.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/editor/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/editor/basic-dial.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.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/editor/menu-with-digits.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/Chat.ts +13 -7
- package/src/display/Dropdown.ts +3 -1
- package/src/display/FloatingTab.ts +4 -4
- package/src/display/Thumbnail.ts +162 -2
- package/src/flow/CanvasNode.ts +70 -24
- package/src/flow/Editor.ts +440 -99
- package/src/flow/NodeEditor.ts +137 -9
- package/src/flow/Plumber.ts +89 -14
- package/src/flow/StickyNote.ts +14 -4
- package/src/flow/actions/add_contact_groups.ts +4 -1
- package/src/flow/actions/add_input_labels.ts +4 -1
- package/src/flow/actions/audio-player.ts +127 -0
- package/src/flow/actions/enter_flow.ts +44 -0
- package/src/flow/actions/play_audio.ts +64 -5
- package/src/flow/actions/remove_contact_groups.ts +6 -1
- package/src/flow/actions/say_msg.ts +94 -4
- 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/config.ts +11 -3
- package/src/flow/nodes/shared-rules.ts +1 -1
- 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/terminal.ts +9 -0
- package/src/flow/nodes/wait_for_audio.ts +88 -0
- package/src/flow/nodes/wait_for_dial.ts +176 -0
- package/src/flow/nodes/wait_for_digits.ts +87 -2
- package/src/flow/nodes/wait_for_menu.ts +209 -3
- package/src/flow/nodes/wait_for_response.ts +1 -1
- package/src/flow/operators.ts +23 -5
- package/src/flow/types.ts +23 -1
- package/src/flow/utils.ts +82 -3
- package/src/form/ArrayEditor.ts +4 -2
- package/src/form/FieldRenderer.ts +71 -1
- package/src/interfaces.ts +2 -1
- package/src/layout/Dialog.ts +52 -7
- package/src/layout/Modax.ts +19 -2
- package/src/list/ContentMenu.ts +15 -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 +25 -4
- package/src/store/AppState.ts +120 -1
- package/src/store/flow-definition.d.ts +2 -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/play_audio.test.ts +155 -0
- package/test/actions/remove_contact_groups.test.ts +29 -0
- package/test/actions/say_msg.test.ts +196 -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/nodes/wait_for_audio.test.ts +182 -0
- package/test/nodes/wait_for_dial.test.ts +382 -0
- package/test/nodes/wait_for_digits.test.ts +233 -109
- package/test/nodes/wait_for_menu.test.ts +383 -0
- package/test/temba-flow-collision.test.ts +286 -6
- package/test/temba-flow-editor.test.ts +240 -0
- package/test/temba-flow-plumber.test.ts +62 -0
- package/test/temba-node-type-selector.test.ts +6 -6
- package/test/temba-select.test.ts +6 -1
- package/test/utils.test.ts +4 -2
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { css, html } from 'lit';
|
|
3
3
|
import { RapidElement } from '../RapidElement';
|
|
4
|
-
import { property } from 'lit/decorators.js';
|
|
4
|
+
import { property, state } from 'lit/decorators.js';
|
|
5
5
|
import { getClasses } from '../utils';
|
|
6
6
|
import { WebChatIcon } from '../webchat';
|
|
7
7
|
var ThumbnailContentType;
|
|
@@ -27,6 +27,11 @@ export class Thumbnail extends RapidElement {
|
|
|
27
27
|
this.preview = true;
|
|
28
28
|
// cached tile URL for location thumbnails
|
|
29
29
|
this.tileUrl = '';
|
|
30
|
+
// audio player state
|
|
31
|
+
this.audio = null;
|
|
32
|
+
this.audioPlaying = false;
|
|
33
|
+
this.audioProgress = 0;
|
|
34
|
+
this.audioDuration = 0;
|
|
30
35
|
}
|
|
31
36
|
static get styles() {
|
|
32
37
|
return css `
|
|
@@ -72,11 +77,57 @@ export class Thumbnail extends RapidElement {
|
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
.thumb.document,
|
|
75
|
-
.thumb.audio,
|
|
76
80
|
.thumb.video {
|
|
77
81
|
border: 1px solid #eee;
|
|
78
82
|
}
|
|
79
83
|
|
|
84
|
+
.audio-player {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
gap: 6px;
|
|
88
|
+
padding: 6px 8px;
|
|
89
|
+
background: rgba(0, 0, 0, 0.05);
|
|
90
|
+
border-radius: var(--curvature);
|
|
91
|
+
cursor: default;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.audio-play-btn {
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
color: #666;
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
flex-shrink: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.audio-play-btn:hover {
|
|
103
|
+
color: #333;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.audio-progress-bar {
|
|
107
|
+
flex: 1;
|
|
108
|
+
height: 3px;
|
|
109
|
+
background: #ddd;
|
|
110
|
+
border-radius: 2px;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
min-width: 60px;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.audio-progress-fill {
|
|
117
|
+
height: 100%;
|
|
118
|
+
background: var(--color-primary, #2387ca);
|
|
119
|
+
border-radius: 2px;
|
|
120
|
+
transition: width 0.15s linear;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.audio-time {
|
|
124
|
+
font-size: 11px;
|
|
125
|
+
color: #999;
|
|
126
|
+
flex-shrink: 0;
|
|
127
|
+
min-width: 28px;
|
|
128
|
+
text-align: right;
|
|
129
|
+
}
|
|
130
|
+
|
|
80
131
|
.wrapper:hover .thumb.icon {
|
|
81
132
|
}
|
|
82
133
|
|
|
@@ -109,6 +160,58 @@ export class Thumbnail extends RapidElement {
|
|
|
109
160
|
}
|
|
110
161
|
`;
|
|
111
162
|
}
|
|
163
|
+
handleAudioPlayClick(e) {
|
|
164
|
+
e.stopPropagation();
|
|
165
|
+
if (!this.audio) {
|
|
166
|
+
this.audio = new Audio(this.url);
|
|
167
|
+
this.audio.addEventListener('timeupdate', () => {
|
|
168
|
+
if (this.audio.duration) {
|
|
169
|
+
this.audioProgress = this.audio.currentTime / this.audio.duration;
|
|
170
|
+
this.audioDuration = this.audio.duration;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
this.audio.addEventListener('ended', () => {
|
|
174
|
+
this.audioPlaying = false;
|
|
175
|
+
this.audioProgress = 0;
|
|
176
|
+
});
|
|
177
|
+
this.audio.addEventListener('error', () => {
|
|
178
|
+
this.audioPlaying = false;
|
|
179
|
+
this.audioProgress = 0;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (this.audioPlaying) {
|
|
183
|
+
this.audio.pause();
|
|
184
|
+
this.audioPlaying = false;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
this.audio.play().catch(() => {
|
|
188
|
+
this.audioPlaying = false;
|
|
189
|
+
});
|
|
190
|
+
this.audioPlaying = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
handleProgressClick(e) {
|
|
194
|
+
e.stopPropagation();
|
|
195
|
+
if (!this.audio || !this.audio.duration)
|
|
196
|
+
return;
|
|
197
|
+
const bar = e.currentTarget;
|
|
198
|
+
const rect = bar.getBoundingClientRect();
|
|
199
|
+
const pct = (e.clientX - rect.left) / rect.width;
|
|
200
|
+
this.audio.currentTime = pct * this.audio.duration;
|
|
201
|
+
}
|
|
202
|
+
formatTime(seconds) {
|
|
203
|
+
const s = Math.floor(seconds);
|
|
204
|
+
const m = Math.floor(s / 60);
|
|
205
|
+
const rem = s % 60;
|
|
206
|
+
return `${m}:${rem.toString().padStart(2, '0')}`;
|
|
207
|
+
}
|
|
208
|
+
disconnectedCallback() {
|
|
209
|
+
super.disconnectedCallback();
|
|
210
|
+
if (this.audio) {
|
|
211
|
+
this.audio.pause();
|
|
212
|
+
this.audio = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
112
215
|
// convert lat/lng to tile coordinates for OSM
|
|
113
216
|
latLngToTile(lat, lng, zoom) {
|
|
114
217
|
const n = Math.pow(2, zoom);
|
|
@@ -198,6 +301,9 @@ export class Thumbnail extends RapidElement {
|
|
|
198
301
|
const osmUrl = `https://www.openstreetmap.org/?mlat=${this.latitude}&mlon=${this.longitude}#map=15/${this.latitude}/${this.longitude}`;
|
|
199
302
|
window.open(osmUrl, '_blank');
|
|
200
303
|
}
|
|
304
|
+
else if (this.contentType === ThumbnailContentType.AUDIO) {
|
|
305
|
+
// audio has inline controls, no click action needed
|
|
306
|
+
}
|
|
201
307
|
else {
|
|
202
308
|
window.open(this.url, '_blank');
|
|
203
309
|
}
|
|
@@ -209,10 +315,14 @@ export class Thumbnail extends RapidElement {
|
|
|
209
315
|
window.open(this.url, '_blank');
|
|
210
316
|
}
|
|
211
317
|
render() {
|
|
318
|
+
var _a;
|
|
212
319
|
return html `
|
|
213
320
|
<div
|
|
214
321
|
@click=${this.handleThumbnailClicked.bind(this)}
|
|
215
322
|
class="${getClasses({ wrapper: true, zoom: this.zoom })}"
|
|
323
|
+
style="${this.contentType === ThumbnailContentType.AUDIO
|
|
324
|
+
? 'cursor: default;'
|
|
325
|
+
: ''}"
|
|
216
326
|
url=${this.url}
|
|
217
327
|
>
|
|
218
328
|
${this.contentType === ThumbnailContentType.IMAGE && this.preview
|
|
@@ -220,14 +330,53 @@ export class Thumbnail extends RapidElement {
|
|
|
220
330
|
class="observe thumb ${this.contentType}"
|
|
221
331
|
src="${this.url}"
|
|
222
332
|
></img></div>`
|
|
223
|
-
:
|
|
333
|
+
: this.contentType === ThumbnailContentType.AUDIO
|
|
334
|
+
? html `<div class="audio-player">
|
|
335
|
+
<div class="audio-play-btn" @click=${this.handleAudioPlayClick}>
|
|
336
|
+
${this.audioPlaying
|
|
337
|
+
? html `<svg
|
|
338
|
+
viewBox="0 0 24 24"
|
|
339
|
+
width="14"
|
|
340
|
+
height="14"
|
|
341
|
+
fill="currentColor"
|
|
342
|
+
>
|
|
343
|
+
<rect x="5" y="3" width="4" height="18" />
|
|
344
|
+
<rect x="15" y="3" width="4" height="18" />
|
|
345
|
+
</svg>`
|
|
346
|
+
: html `<svg
|
|
347
|
+
viewBox="0 0 24 24"
|
|
348
|
+
width="14"
|
|
349
|
+
height="14"
|
|
350
|
+
fill="currentColor"
|
|
351
|
+
>
|
|
352
|
+
<polygon points="6,3 20,12 6,21" />
|
|
353
|
+
</svg>`}
|
|
354
|
+
</div>
|
|
355
|
+
<div
|
|
356
|
+
class="audio-progress-bar"
|
|
357
|
+
@click=${this.handleProgressClick}
|
|
358
|
+
>
|
|
359
|
+
<div
|
|
360
|
+
class="audio-progress-fill"
|
|
361
|
+
style="width: ${this.audioProgress * 100}%"
|
|
362
|
+
></div>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="audio-time">
|
|
365
|
+
${this.audioDuration
|
|
366
|
+
? this.formatTime(this.audioPlaying || this.audioProgress > 0
|
|
367
|
+
? ((_a = this.audio) === null || _a === void 0 ? void 0 : _a.currentTime) || 0
|
|
368
|
+
: this.audioDuration)
|
|
369
|
+
: ''}
|
|
370
|
+
</div>
|
|
371
|
+
</div>`
|
|
372
|
+
: html `
|
|
224
373
|
${this.contentType === ThumbnailContentType.LOCATION
|
|
225
|
-
|
|
374
|
+
? html `<img
|
|
226
375
|
style="height:125px;margin-bottom:-3px;border-radius:var(--curvature);"
|
|
227
376
|
src="${this.tileUrl}"
|
|
228
377
|
alt="Location preview"
|
|
229
378
|
/>`
|
|
230
|
-
|
|
379
|
+
: html `<div
|
|
231
380
|
style="padding:1em; background:rgba(0,0,0,.05);border-radius:var(--curvature);"
|
|
232
381
|
>
|
|
233
382
|
<temba-icon
|
|
@@ -267,4 +416,13 @@ __decorate([
|
|
|
267
416
|
__decorate([
|
|
268
417
|
property({ type: String, attribute: false })
|
|
269
418
|
], Thumbnail.prototype, "tileUrl", void 0);
|
|
419
|
+
__decorate([
|
|
420
|
+
state()
|
|
421
|
+
], Thumbnail.prototype, "audioPlaying", void 0);
|
|
422
|
+
__decorate([
|
|
423
|
+
state()
|
|
424
|
+
], Thumbnail.prototype, "audioProgress", void 0);
|
|
425
|
+
__decorate([
|
|
426
|
+
state()
|
|
427
|
+
], Thumbnail.prototype, "audioDuration", void 0);
|
|
270
428
|
//# sourceMappingURL=Thumbnail.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Thumbnail.js","sourceRoot":"","sources":["../../../src/display/Thumbnail.ts"],"names":[],"mappings":"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","sourcesContent":["import { PropertyValueMap, css, html } from 'lit';\nimport { RapidElement } from '../RapidElement';\nimport { property } from 'lit/decorators.js';\nimport { getClasses } from '../utils';\nimport { Lightbox } from './Lightbox';\nimport { WebChatIcon } from '../webchat';\n\nenum ThumbnailContentType {\n IMAGE = 'image',\n AUDIO = 'audio',\n VIDEO = 'video',\n DOCUMENT = 'document',\n LOCATION = 'location',\n OTHER = 'other'\n}\n\nconst ThumbnailIcons = {\n [ThumbnailContentType.IMAGE]: WebChatIcon.attachment_image,\n [ThumbnailContentType.AUDIO]: WebChatIcon.attachment_audio,\n [ThumbnailContentType.VIDEO]: WebChatIcon.attachment_video,\n [ThumbnailContentType.DOCUMENT]: WebChatIcon.attachment_document,\n [ThumbnailContentType.OTHER]: WebChatIcon.attachment\n};\n\nexport class Thumbnail extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: inline;\n }\n\n .wrapper {\n padding: var(--thumb-padding, 0.4em);\n background: var(--thumb-background, #fff);\n box-shadow: var(--widget-box-shadow);\n cursor: pointer;\n border-radius: calc(var(--curvature) * 1.5);\n border: 0px solid #f3f3f3;\n }\n\n .wrapper.zoom {\n border: none;\n padding: 0 !important;\n border-radius: 0 !important;\n overflow: hidden !important;\n }\n\n .zoom .thumb {\n border-radius: 0px !important;\n width: calc(var(--thumb-size, 4em) + 0.8em);\n max-height: calc(90vh - 10em);\n }\n\n .thumb {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n border-radius: var(--curvature);\n max-height: calc(var(--thumb-size, 4em) * 2);\n max-width: calc(var(--thumb-size, 4em) * 2);\n height: var(--thumb-size, 4em);\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 400;\n color: var(--thumb-icon, #bbb);\n }\n\n .thumb.document,\n .thumb.audio,\n .thumb.video {\n border: 1px solid #eee;\n }\n\n .wrapper:hover .thumb.icon {\n }\n\n .viewer {\n display: block;\n }\n\n .zoom .viewer {\n display: block;\n }\n\n .download {\n display: none;\n position: absolute;\n right: 0em;\n bottom: 0em;\n border-radius: var(--curvature);\n transform: scale(0.2) translate(3em, 3em);\n padding: 0.4em;\n }\n\n .zoom .download {\n display: block;\n background: rgba(0, 0, 0, 0.5);\n }\n\n .zoom .download:hover {\n background: rgba(0, 0, 0, 0.6);\n cursor: pointer;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n attachment: string;\n\n @property({ type: Number })\n ratio: number = 0;\n\n @property({ type: Boolean })\n preview: boolean = true;\n\n @property({ type: Boolean, attribute: false })\n zoom: boolean;\n\n @property({ type: String, attribute: true })\n contentType: string;\n\n @property({ type: Number, attribute: false })\n latitude: number;\n\n @property({ type: Number, attribute: false })\n longitude: number;\n\n // cached tile URL for location thumbnails\n @property({ type: String, attribute: false })\n private tileUrl: string = '';\n\n // convert lat/lng to tile coordinates for OSM\n private latLngToTile(lat: number, lng: number, zoom: number) {\n const n = Math.pow(2, zoom);\n const x = Math.floor(((lng + 180) / 360) * n);\n const latRad = (lat * Math.PI) / 180;\n const y = Math.floor(\n ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2) *\n n\n );\n return { x, y, z: zoom };\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n\n if (\n changes.has('contentType') &&\n this.contentType === ThumbnailContentType.IMAGE\n ) {\n const toObserve = this.shadowRoot.querySelector('.observe');\n if (toObserve) {\n new ResizeObserver((e, observer) => {\n if (toObserve.clientHeight > 0 && toObserve.clientWidth > 0) {\n this.ratio = toObserve.clientHeight / toObserve.clientWidth;\n this.preview =\n this.ratio === 0 || (this.ratio > 0.25 && this.ratio <= 1.5);\n observer.disconnect();\n }\n }).observe(toObserve);\n }\n }\n\n // convert our attachment to a url and label\n if (changes.has('attachment')) {\n if (this.attachment) {\n const splitIndex = this.attachment.indexOf(':');\n if (splitIndex === -1) {\n this.url = this.attachment;\n } else {\n const contentType = this.attachment.substring(0, splitIndex);\n this.url = this.attachment.substring(splitIndex + 1);\n\n if (contentType.startsWith('image')) {\n this.contentType = ThumbnailContentType.IMAGE;\n } else if (contentType.startsWith('audio')) {\n this.contentType = ThumbnailContentType.AUDIO;\n } else if (contentType.startsWith('video')) {\n this.contentType = ThumbnailContentType.VIDEO;\n } else if (contentType.startsWith('application')) {\n this.contentType = ThumbnailContentType.DOCUMENT;\n } else if (contentType.startsWith('geo')) {\n this.contentType = ThumbnailContentType.LOCATION;\n // Parse coordinates from URL which is already stripped of \"geo:\" prefix\n // Format is now just: lat,lng\n const coords = this.url.match(/^([^,]+),([^,]+)/);\n if (coords) {\n this.latitude = parseFloat(coords[1]);\n this.longitude = parseFloat(coords[2]);\n }\n } else {\n this.contentType = ThumbnailContentType.OTHER;\n }\n }\n }\n }\n\n // calculate tile URL when latitude/longitude changes\n if (changes.has('latitude') || changes.has('longitude')) {\n if (\n this.latitude !== undefined &&\n this.longitude !== undefined &&\n !isNaN(this.latitude) &&\n !isNaN(this.longitude)\n ) {\n const tile = this.latLngToTile(this.latitude, this.longitude, 13);\n this.tileUrl = `https://tile.openstreetmap.org/${tile.z}/${tile.x}/${tile.y}.png`;\n } else {\n this.tileUrl = '';\n }\n }\n }\n\n public handleThumbnailClicked() {\n if (this.contentType === ThumbnailContentType.IMAGE && this.preview) {\n window.setTimeout(() => {\n const lightbox = document.querySelector('temba-lightbox') as Lightbox;\n lightbox.showElement(this);\n }, 100);\n } else if (this.contentType === ThumbnailContentType.LOCATION) {\n // open location in openstreetmap\n const osmUrl = `https://www.openstreetmap.org/?mlat=${this.latitude}&mlon=${this.longitude}#map=15/${this.latitude}/${this.longitude}`;\n window.open(osmUrl, '_blank');\n } else {\n window.open(this.url, '_blank');\n }\n }\n\n public handleDownload(e: Event) {\n e.stopPropagation();\n e.preventDefault();\n\n // open this.url in another tab\n window.open(this.url, '_blank');\n }\n\n public render() {\n return html`\n <div\n @click=${this.handleThumbnailClicked.bind(this)}\n class=\"${getClasses({ wrapper: true, zoom: this.zoom })}\"\n url=${this.url}\n >\n ${this.contentType === ThumbnailContentType.IMAGE && this.preview\n ? html`<div class=\"\"><div class=\"download\" @click=${this.handleDownload.bind(\n this\n )}><temba-icon size=\"1\" style=\"color:#fff;\" name=\"download\"></temba-icon></div><img\n class=\"observe thumb ${this.contentType}\"\n src=\"${this.url}\"\n ></img></div>`\n : html`\n ${this.contentType === ThumbnailContentType.LOCATION\n ? html`<img\n style=\"height:125px;margin-bottom:-3px;border-radius:var(--curvature);\"\n src=\"${this.tileUrl}\"\n alt=\"Location preview\"\n />`\n : html`<div\n style=\"padding:1em; background:rgba(0,0,0,.05);border-radius:var(--curvature);\"\n >\n <temba-icon\n size=\"1.5\"\n name=\"${ThumbnailIcons[this.contentType]}\"\n ></temba-icon>\n </div>`}\n `}\n </div>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Thumbnail.js","sourceRoot":"","sources":["../../../src/display/Thumbnail.ts"],"names":[],"mappings":"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","sourcesContent":["import { PropertyValueMap, css, html } from 'lit';\nimport { RapidElement } from '../RapidElement';\nimport { property, state } from 'lit/decorators.js';\nimport { getClasses } from '../utils';\nimport { Lightbox } from './Lightbox';\nimport { WebChatIcon } from '../webchat';\n\nenum ThumbnailContentType {\n IMAGE = 'image',\n AUDIO = 'audio',\n VIDEO = 'video',\n DOCUMENT = 'document',\n LOCATION = 'location',\n OTHER = 'other'\n}\n\nconst ThumbnailIcons = {\n [ThumbnailContentType.IMAGE]: WebChatIcon.attachment_image,\n [ThumbnailContentType.AUDIO]: WebChatIcon.attachment_audio,\n [ThumbnailContentType.VIDEO]: WebChatIcon.attachment_video,\n [ThumbnailContentType.DOCUMENT]: WebChatIcon.attachment_document,\n [ThumbnailContentType.OTHER]: WebChatIcon.attachment\n};\n\nexport class Thumbnail extends RapidElement {\n static get styles() {\n return css`\n :host {\n display: inline;\n }\n\n .wrapper {\n padding: var(--thumb-padding, 0.4em);\n background: var(--thumb-background, #fff);\n box-shadow: var(--widget-box-shadow);\n cursor: pointer;\n border-radius: calc(var(--curvature) * 1.5);\n border: 0px solid #f3f3f3;\n }\n\n .wrapper.zoom {\n border: none;\n padding: 0 !important;\n border-radius: 0 !important;\n overflow: hidden !important;\n }\n\n .zoom .thumb {\n border-radius: 0px !important;\n width: calc(var(--thumb-size, 4em) + 0.8em);\n max-height: calc(90vh - 10em);\n }\n\n .thumb {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n border-radius: var(--curvature);\n max-height: calc(var(--thumb-size, 4em) * 2);\n max-width: calc(var(--thumb-size, 4em) * 2);\n height: var(--thumb-size, 4em);\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: 400;\n color: var(--thumb-icon, #bbb);\n }\n\n .thumb.document,\n .thumb.video {\n border: 1px solid #eee;\n }\n\n .audio-player {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n background: rgba(0, 0, 0, 0.05);\n border-radius: var(--curvature);\n cursor: default;\n }\n\n .audio-play-btn {\n cursor: pointer;\n color: #666;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .audio-play-btn:hover {\n color: #333;\n }\n\n .audio-progress-bar {\n flex: 1;\n height: 3px;\n background: #ddd;\n border-radius: 2px;\n overflow: hidden;\n min-width: 60px;\n cursor: pointer;\n }\n\n .audio-progress-fill {\n height: 100%;\n background: var(--color-primary, #2387ca);\n border-radius: 2px;\n transition: width 0.15s linear;\n }\n\n .audio-time {\n font-size: 11px;\n color: #999;\n flex-shrink: 0;\n min-width: 28px;\n text-align: right;\n }\n\n .wrapper:hover .thumb.icon {\n }\n\n .viewer {\n display: block;\n }\n\n .zoom .viewer {\n display: block;\n }\n\n .download {\n display: none;\n position: absolute;\n right: 0em;\n bottom: 0em;\n border-radius: var(--curvature);\n transform: scale(0.2) translate(3em, 3em);\n padding: 0.4em;\n }\n\n .zoom .download {\n display: block;\n background: rgba(0, 0, 0, 0.5);\n }\n\n .zoom .download:hover {\n background: rgba(0, 0, 0, 0.6);\n cursor: pointer;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n @property({ type: String })\n attachment: string;\n\n @property({ type: Number })\n ratio: number = 0;\n\n @property({ type: Boolean })\n preview: boolean = true;\n\n @property({ type: Boolean, attribute: false })\n zoom: boolean;\n\n @property({ type: String, attribute: true })\n contentType: string;\n\n @property({ type: Number, attribute: false })\n latitude: number;\n\n @property({ type: Number, attribute: false })\n longitude: number;\n\n // cached tile URL for location thumbnails\n @property({ type: String, attribute: false })\n private tileUrl: string = '';\n\n // audio player state\n private audio: HTMLAudioElement | null = null;\n\n @state()\n private audioPlaying = false;\n\n @state()\n private audioProgress = 0;\n\n @state()\n private audioDuration = 0;\n\n private handleAudioPlayClick(e: Event) {\n e.stopPropagation();\n\n if (!this.audio) {\n this.audio = new Audio(this.url);\n this.audio.addEventListener('timeupdate', () => {\n if (this.audio.duration) {\n this.audioProgress = this.audio.currentTime / this.audio.duration;\n this.audioDuration = this.audio.duration;\n }\n });\n this.audio.addEventListener('ended', () => {\n this.audioPlaying = false;\n this.audioProgress = 0;\n });\n this.audio.addEventListener('error', () => {\n this.audioPlaying = false;\n this.audioProgress = 0;\n });\n }\n\n if (this.audioPlaying) {\n this.audio.pause();\n this.audioPlaying = false;\n } else {\n this.audio.play().catch(() => {\n this.audioPlaying = false;\n });\n this.audioPlaying = true;\n }\n }\n\n private handleProgressClick(e: MouseEvent) {\n e.stopPropagation();\n if (!this.audio || !this.audio.duration) return;\n const bar = e.currentTarget as HTMLElement;\n const rect = bar.getBoundingClientRect();\n const pct = (e.clientX - rect.left) / rect.width;\n this.audio.currentTime = pct * this.audio.duration;\n }\n\n private formatTime(seconds: number): string {\n const s = Math.floor(seconds);\n const m = Math.floor(s / 60);\n const rem = s % 60;\n return `${m}:${rem.toString().padStart(2, '0')}`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n if (this.audio) {\n this.audio.pause();\n this.audio = null;\n }\n }\n\n // convert lat/lng to tile coordinates for OSM\n private latLngToTile(lat: number, lng: number, zoom: number) {\n const n = Math.pow(2, zoom);\n const x = Math.floor(((lng + 180) / 360) * n);\n const latRad = (lat * Math.PI) / 180;\n const y = Math.floor(\n ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2) *\n n\n );\n return { x, y, z: zoom };\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n\n if (\n changes.has('contentType') &&\n this.contentType === ThumbnailContentType.IMAGE\n ) {\n const toObserve = this.shadowRoot.querySelector('.observe');\n if (toObserve) {\n new ResizeObserver((e, observer) => {\n if (toObserve.clientHeight > 0 && toObserve.clientWidth > 0) {\n this.ratio = toObserve.clientHeight / toObserve.clientWidth;\n this.preview =\n this.ratio === 0 || (this.ratio > 0.25 && this.ratio <= 1.5);\n observer.disconnect();\n }\n }).observe(toObserve);\n }\n }\n\n // convert our attachment to a url and label\n if (changes.has('attachment')) {\n if (this.attachment) {\n const splitIndex = this.attachment.indexOf(':');\n if (splitIndex === -1) {\n this.url = this.attachment;\n } else {\n const contentType = this.attachment.substring(0, splitIndex);\n this.url = this.attachment.substring(splitIndex + 1);\n\n if (contentType.startsWith('image')) {\n this.contentType = ThumbnailContentType.IMAGE;\n } else if (contentType.startsWith('audio')) {\n this.contentType = ThumbnailContentType.AUDIO;\n } else if (contentType.startsWith('video')) {\n this.contentType = ThumbnailContentType.VIDEO;\n } else if (contentType.startsWith('application')) {\n this.contentType = ThumbnailContentType.DOCUMENT;\n } else if (contentType.startsWith('geo')) {\n this.contentType = ThumbnailContentType.LOCATION;\n // Parse coordinates from URL which is already stripped of \"geo:\" prefix\n // Format is now just: lat,lng\n const coords = this.url.match(/^([^,]+),([^,]+)/);\n if (coords) {\n this.latitude = parseFloat(coords[1]);\n this.longitude = parseFloat(coords[2]);\n }\n } else {\n this.contentType = ThumbnailContentType.OTHER;\n }\n }\n }\n }\n\n // calculate tile URL when latitude/longitude changes\n if (changes.has('latitude') || changes.has('longitude')) {\n if (\n this.latitude !== undefined &&\n this.longitude !== undefined &&\n !isNaN(this.latitude) &&\n !isNaN(this.longitude)\n ) {\n const tile = this.latLngToTile(this.latitude, this.longitude, 13);\n this.tileUrl = `https://tile.openstreetmap.org/${tile.z}/${tile.x}/${tile.y}.png`;\n } else {\n this.tileUrl = '';\n }\n }\n }\n\n public handleThumbnailClicked() {\n if (this.contentType === ThumbnailContentType.IMAGE && this.preview) {\n window.setTimeout(() => {\n const lightbox = document.querySelector('temba-lightbox') as Lightbox;\n lightbox.showElement(this);\n }, 100);\n } else if (this.contentType === ThumbnailContentType.LOCATION) {\n // open location in openstreetmap\n const osmUrl = `https://www.openstreetmap.org/?mlat=${this.latitude}&mlon=${this.longitude}#map=15/${this.latitude}/${this.longitude}`;\n window.open(osmUrl, '_blank');\n } else if (this.contentType === ThumbnailContentType.AUDIO) {\n // audio has inline controls, no click action needed\n } else {\n window.open(this.url, '_blank');\n }\n }\n\n public handleDownload(e: Event) {\n e.stopPropagation();\n e.preventDefault();\n\n // open this.url in another tab\n window.open(this.url, '_blank');\n }\n\n public render() {\n return html`\n <div\n @click=${this.handleThumbnailClicked.bind(this)}\n class=\"${getClasses({ wrapper: true, zoom: this.zoom })}\"\n style=\"${this.contentType === ThumbnailContentType.AUDIO\n ? 'cursor: default;'\n : ''}\"\n url=${this.url}\n >\n ${this.contentType === ThumbnailContentType.IMAGE && this.preview\n ? html`<div class=\"\"><div class=\"download\" @click=${this.handleDownload.bind(\n this\n )}><temba-icon size=\"1\" style=\"color:#fff;\" name=\"download\"></temba-icon></div><img\n class=\"observe thumb ${this.contentType}\"\n src=\"${this.url}\"\n ></img></div>`\n : this.contentType === ThumbnailContentType.AUDIO\n ? html`<div class=\"audio-player\">\n <div class=\"audio-play-btn\" @click=${this.handleAudioPlayClick}>\n ${this.audioPlaying\n ? html`<svg\n viewBox=\"0 0 24 24\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n >\n <rect x=\"5\" y=\"3\" width=\"4\" height=\"18\" />\n <rect x=\"15\" y=\"3\" width=\"4\" height=\"18\" />\n </svg>`\n : html`<svg\n viewBox=\"0 0 24 24\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n >\n <polygon points=\"6,3 20,12 6,21\" />\n </svg>`}\n </div>\n <div\n class=\"audio-progress-bar\"\n @click=${this.handleProgressClick}\n >\n <div\n class=\"audio-progress-fill\"\n style=\"width: ${this.audioProgress * 100}%\"\n ></div>\n </div>\n <div class=\"audio-time\">\n ${this.audioDuration\n ? this.formatTime(\n this.audioPlaying || this.audioProgress > 0\n ? this.audio?.currentTime || 0\n : this.audioDuration\n )\n : ''}\n </div>\n </div>`\n : html`\n ${this.contentType === ThumbnailContentType.LOCATION\n ? html`<img\n style=\"height:125px;margin-bottom:-3px;border-radius:var(--curvature);\"\n src=\"${this.tileUrl}\"\n alt=\"Location preview\"\n />`\n : html`<div\n style=\"padding:1em; background:rgba(0,0,0,.05);border-radius:var(--curvature);\"\n >\n <temba-icon\n size=\"1.5\"\n name=\"${ThumbnailIcons[this.contentType]}\"\n ></temba-icon>\n </div>`}\n `}\n </div>\n `;\n }\n}\n"]}
|
|
@@ -95,7 +95,7 @@ export class CanvasNode extends RapidElement {
|
|
|
95
95
|
z-index: 10;
|
|
96
96
|
transition: all 100ms ease-in-out;
|
|
97
97
|
align-self: center;
|
|
98
|
-
margin-right:0.
|
|
98
|
+
margin-right: 0.3em;
|
|
99
99
|
border: 0px solid red;
|
|
100
100
|
width: 1em;
|
|
101
101
|
pointer-events: auto; /* Ensure remove button can receive events */
|
|
@@ -111,6 +111,12 @@ export class CanvasNode extends RapidElement {
|
|
|
111
111
|
pointer-events: none !important;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
/* Issue indicators - hatched red title bar */
|
|
115
|
+
.action-content.has-issues .cn-title,
|
|
116
|
+
.node.has-issues > .router .cn-title {
|
|
117
|
+
background: repeating-linear-gradient(120deg, tomato, tomato 6px, #ff7056 0, #ff7056 18px) !important;
|
|
118
|
+
}
|
|
119
|
+
|
|
114
120
|
.action.sortable {
|
|
115
121
|
display: flex;
|
|
116
122
|
align-items: stretch;
|
|
@@ -472,10 +478,14 @@ export class CanvasNode extends RapidElement {
|
|
|
472
478
|
// make our initial connections
|
|
473
479
|
// We use setTimeout to allow for DOM updates to complete before querying for exits
|
|
474
480
|
this.connectionTimeout = window.setTimeout(() => {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
481
|
+
var _b;
|
|
482
|
+
// Terminal nodes have no visible exits
|
|
483
|
+
if (((_b = this.ui) === null || _b === void 0 ? void 0 : _b.type) !== 'terminal') {
|
|
484
|
+
for (const exit of this.node.exits) {
|
|
485
|
+
this.plumber.makeSource(exit.uuid);
|
|
486
|
+
if (exit.destination_uuid) {
|
|
487
|
+
this.plumber.connectIds(this.node.uuid, exit.uuid, exit.destination_uuid);
|
|
488
|
+
}
|
|
479
489
|
}
|
|
480
490
|
}
|
|
481
491
|
// Note: revalidation is handled by plumber's processPendingConnections which calls repaintEverything
|
|
@@ -771,6 +781,10 @@ export class CanvasNode extends RapidElement {
|
|
|
771
781
|
}
|
|
772
782
|
this.requestUpdate();
|
|
773
783
|
}
|
|
784
|
+
getTopCenter(el) {
|
|
785
|
+
const rect = el.getBoundingClientRect();
|
|
786
|
+
return { x: rect.left + rect.width / 2, y: rect.top };
|
|
787
|
+
}
|
|
774
788
|
handleActionMouseDown(event, action) {
|
|
775
789
|
// Don't handle clicks on the remove button, drag handle, or when action is in removing state
|
|
776
790
|
const target = event.target;
|
|
@@ -812,10 +826,17 @@ export class CanvasNode extends RapidElement {
|
|
|
812
826
|
// Only fire the action edit event if we haven't dragged beyond the threshold
|
|
813
827
|
// AND either there's no Editor parent (test case) or the Editor didn't drag the node
|
|
814
828
|
if (distance <= DRAG_THRESHOLD && (!editor || !editorWasDragging)) {
|
|
829
|
+
// Use top-center of the action element as the dialog origin
|
|
830
|
+
const actionEl = event.currentTarget;
|
|
831
|
+
const origin = actionEl
|
|
832
|
+
? this.getTopCenter(actionEl)
|
|
833
|
+
: { x: event.clientX, y: event.clientY };
|
|
815
834
|
// Fire event to request action editing
|
|
816
835
|
this.fireCustomEvent(CustomEventType.ActionEditRequested, {
|
|
817
836
|
action,
|
|
818
|
-
nodeUuid: this.node.uuid
|
|
837
|
+
nodeUuid: this.node.uuid,
|
|
838
|
+
originX: origin.x,
|
|
839
|
+
originY: origin.y
|
|
819
840
|
});
|
|
820
841
|
}
|
|
821
842
|
}
|
|
@@ -914,18 +935,24 @@ export class CanvasNode extends RapidElement {
|
|
|
914
935
|
// Using literal 5 instead of DRAG_THRESHOLD since it's not imported
|
|
915
936
|
// Fire event to request node editing if the node has a router
|
|
916
937
|
if (this.node.router) {
|
|
938
|
+
// Use top-center of the node as the dialog origin
|
|
939
|
+
const origin = this.getTopCenter(this);
|
|
917
940
|
// If router node has exactly one action, open the action editor directly
|
|
918
941
|
if (this.node.actions && this.node.actions.length === 1) {
|
|
919
942
|
this.fireCustomEvent(CustomEventType.ActionEditRequested, {
|
|
920
943
|
action: this.node.actions[0],
|
|
921
|
-
nodeUuid: this.node.uuid
|
|
944
|
+
nodeUuid: this.node.uuid,
|
|
945
|
+
originX: origin.x,
|
|
946
|
+
originY: origin.y
|
|
922
947
|
});
|
|
923
948
|
}
|
|
924
949
|
else {
|
|
925
950
|
// Otherwise open the node editor as before
|
|
926
951
|
this.fireCustomEvent(CustomEventType.NodeEditRequested, {
|
|
927
952
|
node: this.node,
|
|
928
|
-
nodeUI: this.ui
|
|
953
|
+
nodeUI: this.ui,
|
|
954
|
+
originX: origin.x,
|
|
955
|
+
originY: origin.y
|
|
929
956
|
});
|
|
930
957
|
}
|
|
931
958
|
}
|
|
@@ -1061,17 +1088,15 @@ export class CanvasNode extends RapidElement {
|
|
|
1061
1088
|
this.requestUpdate();
|
|
1062
1089
|
}
|
|
1063
1090
|
renderTitle(config, action, index, isRemoving = false) {
|
|
1064
|
-
var _b, _c, _d, _e;
|
|
1091
|
+
var _b, _c, _d, _e, _f;
|
|
1065
1092
|
const color = config.group
|
|
1066
1093
|
? (_b = ACTION_GROUP_METADATA[config.group]) === null || _b === void 0 ? void 0 : _b.color
|
|
1067
1094
|
: '#aaaaaa';
|
|
1095
|
+
const isTerminal = ((_c = this.ui) === null || _c === void 0 ? void 0 : _c.type) === 'terminal';
|
|
1068
1096
|
return html `<div class="cn-title" style="background:${color}">
|
|
1069
|
-
${
|
|
1070
|
-
? html `<
|
|
1071
|
-
|
|
1072
|
-
name="sort"
|
|
1073
|
-
></temba-icon>`
|
|
1074
|
-
: ((_e = (_d = this.node) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.length) > 1
|
|
1097
|
+
${isTerminal
|
|
1098
|
+
? html `<div class="title-spacer"></div>`
|
|
1099
|
+
: ((_d = this.ui) === null || _d === void 0 ? void 0 : _d.type) === 'execute_actions' || ((_f = (_e = this.node) === null || _e === void 0 ? void 0 : _e.actions) === null || _f === void 0 ? void 0 : _f.length) > 1
|
|
1075
1100
|
? html `<temba-icon
|
|
1076
1101
|
class="drag-handle ${this.isReadOnly() ? 'read-only-hidden' : ''}"
|
|
1077
1102
|
name="sort"
|
|
@@ -1080,7 +1105,9 @@ export class CanvasNode extends RapidElement {
|
|
|
1080
1105
|
|
|
1081
1106
|
<div class="name">${isRemoving ? 'Remove?' : config.name}</div>
|
|
1082
1107
|
<div
|
|
1083
|
-
class="remove-button ${this.isReadOnly()
|
|
1108
|
+
class="remove-button ${isTerminal || this.isReadOnly()
|
|
1109
|
+
? 'read-only-hidden'
|
|
1110
|
+
: ''}"
|
|
1084
1111
|
@click=${(e) => this.handleActionRemoveClick(e, action, index)}
|
|
1085
1112
|
title="Remove action"
|
|
1086
1113
|
>
|
|
@@ -1165,7 +1192,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1165
1192
|
return localizedAction;
|
|
1166
1193
|
}
|
|
1167
1194
|
renderAction(node, action, index) {
|
|
1168
|
-
var _b, _c, _d;
|
|
1195
|
+
var _b, _c, _d, _e;
|
|
1169
1196
|
const config = ACTION_CONFIG[action.type];
|
|
1170
1197
|
const isRemoving = this.actionRemovingState.has(action.uuid);
|
|
1171
1198
|
const isLocalizable = (config === null || config === void 0 ? void 0 : config.localizable) && config.localizable.length > 0;
|
|
@@ -1176,6 +1203,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1176
1203
|
// Get the localized action if translating
|
|
1177
1204
|
const displayAction = this.getLocalizedAction(action);
|
|
1178
1205
|
if (config) {
|
|
1206
|
+
const hasIssues = (_e = this.issuesByAction) === null || _e === void 0 ? void 0 : _e.has(action.uuid);
|
|
1179
1207
|
const classes = [
|
|
1180
1208
|
'action',
|
|
1181
1209
|
'sortable',
|
|
@@ -1189,7 +1217,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1189
1217
|
.join(' ');
|
|
1190
1218
|
return html `<div class="${classes}" id="action-${index}">
|
|
1191
1219
|
<div
|
|
1192
|
-
class="action-content"
|
|
1220
|
+
class="action-content ${hasIssues ? 'has-issues' : ''}"
|
|
1193
1221
|
@mousedown=${(e) => !isDisabled && this.handleActionMouseDown(e, action)}
|
|
1194
1222
|
@mouseup=${(e) => !isDisabled && this.handleActionMouseUp(e, action)}
|
|
1195
1223
|
style="cursor: ${isDisabled ? 'not-allowed' : 'pointer'}"
|
|
@@ -1320,7 +1348,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1320
1348
|
return this.viewingRevision || this.isTranslating;
|
|
1321
1349
|
}
|
|
1322
1350
|
render() {
|
|
1323
|
-
var _b;
|
|
1351
|
+
var _b, _c, _d, _e;
|
|
1324
1352
|
if (!this.node || !this.ui) {
|
|
1325
1353
|
return html `<div class="node">Loading...</div>`;
|
|
1326
1354
|
}
|
|
@@ -1332,13 +1360,17 @@ export class CanvasNode extends RapidElement {
|
|
|
1332
1360
|
!this.includeCategoriesInTranslation;
|
|
1333
1361
|
// Get active contact count for this node
|
|
1334
1362
|
const activeCount = (((_b = this.activity) === null || _b === void 0 ? void 0 : _b.nodes) && this.activity.nodes[this.node.uuid]) || 0;
|
|
1363
|
+
// Check for node-level issues or action-level issues on any action in this node
|
|
1364
|
+
const nodeHasIssues = ((_c = this.issuesByNode) === null || _c === void 0 ? void 0 : _c.has(this.node.uuid)) ||
|
|
1365
|
+
((_d = this.node.actions) === null || _d === void 0 ? void 0 : _d.some((a) => { var _b; return (_b = this.issuesByAction) === null || _b === void 0 ? void 0 : _b.has(a.uuid); }));
|
|
1335
1366
|
return html `
|
|
1336
1367
|
<div
|
|
1337
1368
|
id="${this.node.uuid}"
|
|
1338
1369
|
class=${getClasses({
|
|
1339
1370
|
node: true,
|
|
1340
1371
|
'execute-actions': this.ui.type === 'execute_actions',
|
|
1341
|
-
'non-localizable': isNodeDisabled
|
|
1372
|
+
'non-localizable': isNodeDisabled,
|
|
1373
|
+
'has-issues': nodeHasIssues
|
|
1342
1374
|
})}
|
|
1343
1375
|
style="left:${this.ui.position.left}px;top:${this.ui.position.top}px"
|
|
1344
1376
|
>
|
|
@@ -1347,7 +1379,9 @@ export class CanvasNode extends RapidElement {
|
|
|
1347
1379
|
${activeCount.toLocaleString()}
|
|
1348
1380
|
</div>`
|
|
1349
1381
|
: ''}
|
|
1350
|
-
${nodeConfig &&
|
|
1382
|
+
${nodeConfig &&
|
|
1383
|
+
nodeConfig.type !== 'execute_actions' &&
|
|
1384
|
+
nodeConfig.type !== 'terminal'
|
|
1351
1385
|
? html `<div class="router" style="position: relative;">
|
|
1352
1386
|
<div
|
|
1353
1387
|
@mousedown=${(e) => this.handleNodeMouseDown(e)}
|
|
@@ -1360,7 +1394,7 @@ export class CanvasNode extends RapidElement {
|
|
|
1360
1394
|
: null}
|
|
1361
1395
|
</div>
|
|
1362
1396
|
</div>`
|
|
1363
|
-
: this.node.actions.length > 0
|
|
1397
|
+
: ((_e = this.node.actions) === null || _e === void 0 ? void 0 : _e.length) > 0
|
|
1364
1398
|
? this.ui.type === 'execute_actions'
|
|
1365
1399
|
? html `<temba-sortable-list
|
|
1366
1400
|
dragHandle="drag-handle"
|
|
@@ -1388,7 +1422,9 @@ export class CanvasNode extends RapidElement {
|
|
|
1388
1422
|
${this.renderRouter(this.node.router, this.ui)}
|
|
1389
1423
|
${this.renderCategories(this.node)}
|
|
1390
1424
|
</div>`
|
|
1391
|
-
:
|
|
1425
|
+
: this.ui.type === 'terminal'
|
|
1426
|
+
? ''
|
|
1427
|
+
: html `<div class="action-exits">
|
|
1392
1428
|
${repeat(this.node.exits, (exit) => exit.uuid, (exit) => this.renderExit(exit))}
|
|
1393
1429
|
</div>`}
|
|
1394
1430
|
${this.ui.type === 'execute_actions' && !this.isReadOnly()
|
|
@@ -1431,4 +1467,10 @@ __decorate([
|
|
|
1431
1467
|
__decorate([
|
|
1432
1468
|
fromStore(zustand, (state) => state.getCurrentActivity())
|
|
1433
1469
|
], CanvasNode.prototype, "activity", void 0);
|
|
1470
|
+
__decorate([
|
|
1471
|
+
fromStore(zustand, (state) => state.issuesByNode)
|
|
1472
|
+
], CanvasNode.prototype, "issuesByNode", void 0);
|
|
1473
|
+
__decorate([
|
|
1474
|
+
fromStore(zustand, (state) => state.issuesByAction)
|
|
1475
|
+
], CanvasNode.prototype, "issuesByAction", void 0);
|
|
1434
1476
|
//# sourceMappingURL=CanvasNode.js.map
|