@nyaruka/temba-components 0.131.0 → 0.131.2
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/publish.yml +4 -1
- package/CHANGELOG.md +67 -1
- package/demo/data/flows/food-order.json +2 -2
- package/demo/data/flows/sample-flow.json +74 -125
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +1156 -619
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +4 -1
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +200 -0
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -0
- package/out-tsc/src/flow/CanvasNode.js +327 -19
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +562 -66
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +240 -93
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +499 -0
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -0
- package/out-tsc/src/flow/actions/add_contact_groups.js +3 -3
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +62 -4
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +3 -3
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/play_audio.js +2 -2
- package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js +6 -5
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/request_optin.js +2 -2
- package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +2 -2
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +76 -23
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +4 -5
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +9 -19
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +5 -9
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +19 -20
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +2 -2
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +2 -12
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +2 -2
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +3 -3
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +180 -6
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/config.js +11 -15
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/currencies.js +45 -0
- package/out-tsc/src/flow/currencies.js.map +1 -0
- package/out-tsc/src/flow/nodes/shared-rules.js +257 -0
- package/out-tsc/src/flow/nodes/shared-rules.js.map +1 -0
- package/out-tsc/src/flow/nodes/shared.js +17 -0
- package/out-tsc/src/flow/nodes/shared.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_airtime.js +205 -5
- package/out-tsc/src/flow/nodes/split_by_airtime.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_contact_field.js +147 -3
- package/out-tsc/src/flow/nodes/split_by_contact_field.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_expression.js +68 -2
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_groups.js +12 -9
- package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_intent.js +7 -0
- package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_llm.js +3 -2
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +2 -2
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +3 -3
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +108 -0
- package/out-tsc/src/flow/nodes/split_by_resthook.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_run_result.js +206 -3
- package/out-tsc/src/flow/nodes/split_by_run_result.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_scheme.js +153 -2
- package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +6 -4
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_ticket.js +3 -2
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +3 -2
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_audio.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_image.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_image.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_location.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_location.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_menu.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +32 -567
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_video.js +2 -2
- package/out-tsc/src/flow/nodes/wait_for_video.js.map +1 -1
- package/out-tsc/src/flow/types.js +71 -12
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +101 -14
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/ContactSearch.js +1 -1
- package/out-tsc/src/form/ContactSearch.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +2 -4
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +3 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/SortableList.js +98 -33
- package/out-tsc/src/list/SortableList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +15 -18
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/store/AppState.js +53 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/utils.js +254 -13
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/temba-modules.js +4 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/ActionHelper.js +3 -3
- package/out-tsc/test/ActionHelper.js.map +1 -1
- package/out-tsc/test/NodeHelper.js +6 -3
- package/out-tsc/test/NodeHelper.js.map +1 -1
- package/out-tsc/test/actions/add_contact_urn.test.js +202 -0
- package/out-tsc/test/actions/add_contact_urn.test.js.map +1 -0
- package/out-tsc/test/actions/send_broadcast.test.js +148 -0
- package/out-tsc/test/actions/send_broadcast.test.js.map +1 -0
- package/out-tsc/test/actions/send_email.test.js +17 -23
- package/out-tsc/test/actions/send_email.test.js.map +1 -1
- package/out-tsc/test/actions/send_msg.test.js +33 -15
- package/out-tsc/test/actions/send_msg.test.js.map +1 -1
- package/out-tsc/test/actions/start_session.test.js +116 -0
- package/out-tsc/test/actions/start_session.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_airtime.test.js +604 -0
- package/out-tsc/test/nodes/split_by_airtime.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_contact_field.test.js +387 -0
- package/out-tsc/test/nodes/split_by_contact_field.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_expression.test.js +614 -0
- package/out-tsc/test/nodes/split_by_expression.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_random.test.js +3 -3
- package/out-tsc/test/nodes/split_by_random.test.js.map +1 -1
- package/out-tsc/test/nodes/split_by_resthook.test.js +337 -0
- package/out-tsc/test/nodes/split_by_resthook.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_run_result.test.js +920 -0
- package/out-tsc/test/nodes/split_by_run_result.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_scheme.test.js +399 -0
- package/out-tsc/test/nodes/split_by_scheme.test.js.map +1 -0
- package/out-tsc/test/nodes/split_by_subflow.test.js +333 -0
- package/out-tsc/test/nodes/split_by_subflow.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js +2 -2
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_response.test.js +2 -1
- package/out-tsc/test/nodes/wait_for_response.test.js.map +1 -1
- package/out-tsc/test/temba-action-drag-between-nodes.test.js +252 -0
- package/out-tsc/test/temba-action-drag-between-nodes.test.js.map +1 -0
- package/out-tsc/test/temba-canvas-menu.test.js +122 -0
- package/out-tsc/test/temba-canvas-menu.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor-node.test.js +85 -2
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +7 -8
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-node-editor.test.js +3 -1
- package/out-tsc/test/temba-node-editor.test.js.map +1 -1
- package/out-tsc/test/temba-node-type-selector.test.js +115 -0
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -0
- package/out-tsc/test/temba-omnibox.test.js +2 -1
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-sortable-list.test.js +51 -0
- package/out-tsc/test/temba-sortable-list.test.js.map +1 -1
- package/out-tsc/test/temba-utils-index.test.js +1 -27
- package/out-tsc/test/temba-utils-index.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +2 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +2 -1
- package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
- 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/editor/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/editor/whatsapp.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-facebook.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/expression-phone.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/facebook-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/instagram-handle.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/line-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/phone-number.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/telegram-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/viber-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/wechat-id.png +0 -0
- package/screenshots/truth/actions/add_contact_urn/render/whatsapp.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
- package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_broadcast/editor/with-attachments.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/contacts-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/groups-only.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/many-groups.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/send_broadcast/render/with-attachments.png +0 -0
- package/screenshots/truth/actions/send_email/editor/complex-business-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/empty-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/long-subject.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiline-body.png +0 -0
- package/screenshots/truth/actions/send_email/editor/multiple-recipients.png +0 -0
- package/screenshots/truth/actions/send_email/editor/simple-email.png +0 -0
- package/screenshots/truth/actions/send_email/editor/with-expressions.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/editor/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/editor/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/long-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/multiline-text-with-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-linebreaks.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-many-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-with-quick-replies.png +0 -0
- package/screenshots/truth/actions/send_msg/render/text-without-quick-replies.png +0 -0
- package/screenshots/truth/actions/start_session/editor/contact-query.png +0 -0
- package/screenshots/truth/actions/start_session/editor/contacts-only.png +0 -0
- package/screenshots/truth/actions/start_session/editor/create-contact.png +0 -0
- package/screenshots/truth/actions/start_session/editor/groups-and-contacts.png +0 -0
- package/screenshots/truth/actions/start_session/editor/groups-only.png +0 -0
- package/screenshots/truth/actions/start_session/editor/many-recipients.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/canvas-menu/open.png +0 -0
- package/screenshots/truth/editor/router.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/list/fields-dragging.png +0 -0
- package/screenshots/truth/list/sortable-dragging.png +0 -0
- package/screenshots/truth/node-type-selector/action-mode.png +0 -0
- package/screenshots/truth/node-type-selector/split-mode.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/information-extraction.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/sentiment-analysis.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/summarization.png +0 -0
- package/screenshots/truth/nodes/split_by_llm/editor/translation-task.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_digits/editor/basic-digits-wait.png +0 -0
- 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/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/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/Icons.ts +4 -1
- package/src/events.ts +2 -6
- package/src/flow/CanvasMenu.ts +217 -0
- package/src/flow/CanvasNode.ts +408 -10
- package/src/flow/Editor.ts +683 -44
- package/src/flow/NodeEditor.ts +304 -125
- package/src/flow/NodeTypeSelector.ts +592 -0
- package/src/flow/actions/add_contact_groups.ts +4 -4
- package/src/flow/actions/add_contact_urn.ts +76 -4
- package/src/flow/actions/add_input_labels.ts +4 -4
- package/src/flow/actions/play_audio.ts +2 -2
- package/src/flow/actions/remove_contact_groups.ts +14 -6
- package/src/flow/actions/request_optin.ts +2 -2
- package/src/flow/actions/say_msg.ts +2 -2
- package/src/flow/actions/send_broadcast.ts +85 -23
- package/src/flow/actions/send_email.ts +10 -6
- package/src/flow/actions/send_msg.ts +22 -32
- package/src/flow/actions/set_contact_channel.ts +5 -11
- package/src/flow/actions/set_contact_field.ts +20 -25
- package/src/flow/actions/set_contact_language.ts +9 -4
- package/src/flow/actions/set_contact_name.ts +3 -15
- package/src/flow/actions/set_contact_status.ts +3 -3
- package/src/flow/actions/set_run_result.ts +4 -4
- package/src/flow/actions/start_session.ts +208 -6
- package/src/flow/config.ts +13 -15
- package/src/flow/currencies.ts +51 -0
- package/src/flow/nodes/shared-rules.ts +301 -0
- package/src/flow/nodes/shared.ts +18 -0
- package/src/flow/nodes/split_by_airtime.ts +238 -5
- package/src/flow/nodes/split_by_contact_field.ts +185 -3
- package/src/flow/nodes/split_by_expression.ts +94 -2
- package/src/flow/nodes/split_by_groups.ts +15 -10
- package/src/flow/nodes/split_by_intent.ts +7 -0
- package/src/flow/nodes/split_by_llm.ts +4 -3
- package/src/flow/nodes/split_by_llm_categorize.ts +4 -4
- package/src/flow/nodes/split_by_random.ts +5 -5
- package/src/flow/nodes/split_by_resthook.ts +130 -0
- package/src/flow/nodes/split_by_run_result.ts +249 -3
- package/src/flow/nodes/split_by_scheme.ts +192 -2
- package/src/flow/nodes/split_by_subflow.ts +6 -4
- package/src/flow/nodes/split_by_ticket.ts +4 -3
- package/src/flow/nodes/split_by_webhook.ts +6 -5
- package/src/flow/nodes/wait_for_audio.ts +2 -2
- package/src/flow/nodes/wait_for_digits.ts +2 -2
- package/src/flow/nodes/wait_for_image.ts +2 -2
- package/src/flow/nodes/wait_for_location.ts +2 -2
- package/src/flow/nodes/wait_for_menu.ts +2 -2
- package/src/flow/nodes/wait_for_response.ts +48 -679
- package/src/flow/nodes/wait_for_video.ts +2 -2
- package/src/flow/types.ts +109 -23
- package/src/flow/utils.ts +108 -14
- package/src/form/ContactSearch.ts +1 -1
- package/src/form/FieldRenderer.ts +2 -4
- package/src/interfaces.ts +3 -0
- package/src/list/SortableList.ts +109 -34
- package/src/live/ContactChat.ts +15 -18
- package/src/store/AppState.ts +69 -0
- package/src/store/flow-definition.d.ts +2 -5
- package/src/utils.ts +332 -12
- package/static/api/channels.json +46 -0
- package/static/api/resthooks.json +31 -0
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/lightning-02.svg +1 -0
- package/static/svg/work/used/lightning-02.svg +3 -0
- package/temba-modules.ts +4 -0
- package/test/ActionHelper.ts +3 -3
- package/test/NodeHelper.ts +6 -3
- package/test/actions/add_contact_urn.test.ts +287 -0
- package/test/actions/send_broadcast.test.ts +190 -0
- package/test/actions/send_email.test.ts +17 -23
- package/test/actions/send_msg.test.ts +39 -15
- package/test/actions/start_session.test.ts +151 -0
- package/test/nodes/split_by_airtime.test.ts +673 -0
- package/test/nodes/split_by_contact_field.test.ts +451 -0
- package/test/nodes/split_by_expression.test.ts +751 -0
- package/test/nodes/split_by_random.test.ts +3 -3
- package/test/nodes/split_by_resthook.test.ts +398 -0
- package/test/nodes/split_by_run_result.test.ts +1109 -0
- package/test/nodes/split_by_scheme.test.ts +486 -0
- package/test/nodes/split_by_subflow.test.ts +381 -0
- package/test/nodes/wait_for_digits.test.ts +2 -2
- package/test/nodes/wait_for_response.test.ts +2 -1
- package/test/temba-action-drag-between-nodes.test.ts +301 -0
- package/test/temba-canvas-menu.test.ts +156 -0
- package/test/temba-flow-editor-node.test.ts +102 -2
- package/test/temba-flow-editor.test.ts +7 -8
- package/test/temba-node-editor.test.ts +3 -1
- package/test/temba-node-type-selector.test.ts +152 -0
- package/test/temba-omnibox.test.ts +2 -1
- package/test/temba-sortable-list.test.ts +69 -0
- package/test/temba-utils-index.test.ts +0 -35
- package/test/utils.test.ts +2 -0
- package/test-assets/contacts/history.json +14 -20
- package/web-dev-server.config.mjs +3 -1
- package/out-tsc/src/flow/actions/call_classifier.js +0 -11
- package/out-tsc/src/flow/actions/call_classifier.js.map +0 -1
- package/out-tsc/src/flow/actions/call_resthook.js +0 -11
- package/out-tsc/src/flow/actions/call_resthook.js.map +0 -1
- package/out-tsc/src/flow/actions/split_by_expression_example.js +0 -77
- package/out-tsc/src/flow/actions/split_by_expression_example.js.map +0 -1
- package/out-tsc/src/flow/actions/transfer_airtime.js +0 -11
- package/out-tsc/src/flow/actions/transfer_airtime.js.map +0 -1
- package/src/flow/actions/call_classifier.ts +0 -12
- package/src/flow/actions/call_resthook.ts +0 -12
- package/src/flow/actions/split_by_expression_example.ts +0 -88
- package/src/flow/actions/transfer_airtime.ts +0 -12
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { css, html, PropertyValueMap, TemplateResult } from 'lit';
|
|
2
2
|
import { repeat } from 'lit/directives/repeat.js';
|
|
3
3
|
import { ACTION_CONFIG, ActionConfig, NODE_CONFIG, NodeConfig } from './config';
|
|
4
|
+
import { ACTION_GROUP_METADATA, SPLIT_GROUP_METADATA } from './types';
|
|
4
5
|
import { Action, Exit, Node, NodeUI, Router } from '../store/flow-definition';
|
|
5
6
|
import { property } from 'lit/decorators.js';
|
|
6
7
|
import { RapidElement } from '../RapidElement';
|
|
@@ -46,6 +47,18 @@ export class CanvasNode extends RapidElement {
|
|
|
46
47
|
private nodeClickStartPos: { x: number; y: number } | null = null;
|
|
47
48
|
private pendingNodeClick: { event: MouseEvent } | null = null;
|
|
48
49
|
|
|
50
|
+
// Track the height of the action being dragged (captured at drag start)
|
|
51
|
+
private draggedActionHeight: number = 0;
|
|
52
|
+
|
|
53
|
+
// Track external action drag (action being dragged from another node)
|
|
54
|
+
private externalDragInfo: {
|
|
55
|
+
action: Action;
|
|
56
|
+
sourceNodeUuid: string;
|
|
57
|
+
actionIndex: number;
|
|
58
|
+
dropIndex: number;
|
|
59
|
+
actionHeight: number;
|
|
60
|
+
} | null = null;
|
|
61
|
+
|
|
49
62
|
static get styles() {
|
|
50
63
|
return css`
|
|
51
64
|
|
|
@@ -160,7 +173,7 @@ export class CanvasNode extends RapidElement {
|
|
|
160
173
|
pointer-events: auto; /* Ensure drag handle can receive events */
|
|
161
174
|
}
|
|
162
175
|
.title-spacer {
|
|
163
|
-
width:
|
|
176
|
+
width: 1.8em;
|
|
164
177
|
|
|
165
178
|
}
|
|
166
179
|
|
|
@@ -339,12 +352,79 @@ export class CanvasNode extends RapidElement {
|
|
|
339
352
|
border-top-left-radius: var(--curvature);
|
|
340
353
|
border-top-right-radius: var(--curvature);
|
|
341
354
|
}
|
|
355
|
+
|
|
356
|
+
/* Add action button */
|
|
357
|
+
.add-action-button {
|
|
358
|
+
position: absolute;
|
|
359
|
+
bottom: 0.5em;
|
|
360
|
+
right: 0.5em;
|
|
361
|
+
width: 1.5em;
|
|
362
|
+
height: 1.5em;
|
|
363
|
+
border-radius: 50%;
|
|
364
|
+
background: var(--color-primary, #3b82f6);
|
|
365
|
+
color: white;
|
|
366
|
+
display: flex;
|
|
367
|
+
align-items: center;
|
|
368
|
+
justify-content: center;
|
|
369
|
+
cursor: pointer;
|
|
370
|
+
opacity: 0;
|
|
371
|
+
transition: opacity 200ms ease-in-out;
|
|
372
|
+
z-index: 10;
|
|
373
|
+
pointer-events: auto;
|
|
374
|
+
font-size: 0.9em;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.node.execute-actions:hover .add-action-button {
|
|
378
|
+
opacity: 0.8;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.add-action-button:hover {
|
|
382
|
+
opacity: 1 !important;
|
|
383
|
+
transform: scale(1.1);
|
|
384
|
+
}
|
|
342
385
|
}`;
|
|
343
386
|
}
|
|
344
387
|
|
|
345
388
|
constructor() {
|
|
346
389
|
super();
|
|
347
390
|
this.handleActionOrderChanged = this.handleActionOrderChanged.bind(this);
|
|
391
|
+
this.handleActionDragStart = this.handleActionDragStart.bind(this);
|
|
392
|
+
this.handleActionDragExternal = this.handleActionDragExternal.bind(this);
|
|
393
|
+
this.handleActionDragInternal = this.handleActionDragInternal.bind(this);
|
|
394
|
+
this.handleActionDragStop = this.handleActionDragStop.bind(this);
|
|
395
|
+
this.handleExternalActionDragOver =
|
|
396
|
+
this.handleExternalActionDragOver.bind(this);
|
|
397
|
+
this.handleExternalActionDrop = this.handleExternalActionDrop.bind(this);
|
|
398
|
+
this.handleExternalActionDragLeave =
|
|
399
|
+
this.handleExternalActionDragLeave.bind(this);
|
|
400
|
+
this.handleActionShowGhost = this.handleActionShowGhost.bind(this);
|
|
401
|
+
this.handleActionHideGhost = this.handleActionHideGhost.bind(this);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
connectedCallback() {
|
|
405
|
+
super.connectedCallback();
|
|
406
|
+
|
|
407
|
+
// Listen for external action drag events from Editor
|
|
408
|
+
this.addEventListener(
|
|
409
|
+
'action-drag-over',
|
|
410
|
+
this.handleExternalActionDragOver as EventListener
|
|
411
|
+
);
|
|
412
|
+
this.addEventListener(
|
|
413
|
+
'action-drop',
|
|
414
|
+
this.handleExternalActionDrop as EventListener
|
|
415
|
+
);
|
|
416
|
+
this.addEventListener(
|
|
417
|
+
'action-drag-leave',
|
|
418
|
+
this.handleExternalActionDragLeave as EventListener
|
|
419
|
+
);
|
|
420
|
+
this.addEventListener(
|
|
421
|
+
'action-show-ghost',
|
|
422
|
+
this.handleActionShowGhost as EventListener
|
|
423
|
+
);
|
|
424
|
+
this.addEventListener(
|
|
425
|
+
'action-hide-ghost',
|
|
426
|
+
this.handleActionHideGhost as EventListener
|
|
427
|
+
);
|
|
348
428
|
}
|
|
349
429
|
|
|
350
430
|
protected updated(
|
|
@@ -391,6 +471,28 @@ export class CanvasNode extends RapidElement {
|
|
|
391
471
|
// Remove the event listener when the component is removed
|
|
392
472
|
super.disconnectedCallback();
|
|
393
473
|
|
|
474
|
+
// Remove external drag event listeners
|
|
475
|
+
this.removeEventListener(
|
|
476
|
+
'action-drag-over',
|
|
477
|
+
this.handleExternalActionDragOver as EventListener
|
|
478
|
+
);
|
|
479
|
+
this.removeEventListener(
|
|
480
|
+
'action-drop',
|
|
481
|
+
this.handleExternalActionDrop as EventListener
|
|
482
|
+
);
|
|
483
|
+
this.removeEventListener(
|
|
484
|
+
'action-drag-leave',
|
|
485
|
+
this.handleExternalActionDragLeave as EventListener
|
|
486
|
+
);
|
|
487
|
+
this.removeEventListener(
|
|
488
|
+
'action-show-ghost',
|
|
489
|
+
this.handleActionShowGhost as EventListener
|
|
490
|
+
);
|
|
491
|
+
this.removeEventListener(
|
|
492
|
+
'action-hide-ghost',
|
|
493
|
+
this.handleActionHideGhost as EventListener
|
|
494
|
+
);
|
|
495
|
+
|
|
394
496
|
// Clear any pending exit removal timeouts
|
|
395
497
|
this.exitRemovalTimeouts.forEach((timeoutId) => {
|
|
396
498
|
clearTimeout(timeoutId);
|
|
@@ -615,6 +717,82 @@ export class CanvasNode extends RapidElement {
|
|
|
615
717
|
.updateNode(this.node.uuid, { ...this.node, actions: newActions });
|
|
616
718
|
}
|
|
617
719
|
|
|
720
|
+
private handleActionDragStart(event: CustomEvent) {
|
|
721
|
+
// Capture the height of the action being dragged
|
|
722
|
+
const actionId = event.detail.id;
|
|
723
|
+
const actionElement = this.querySelector(`#${actionId}`) as HTMLElement;
|
|
724
|
+
|
|
725
|
+
if (actionElement) {
|
|
726
|
+
const rect = actionElement.getBoundingClientRect();
|
|
727
|
+
this.draggedActionHeight = rect.height;
|
|
728
|
+
} else {
|
|
729
|
+
// Fallback to a reasonable default
|
|
730
|
+
this.draggedActionHeight = 60;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
private handleActionDragExternal(event: CustomEvent) {
|
|
735
|
+
// stop propagation of the original event from SortableList
|
|
736
|
+
event.stopPropagation();
|
|
737
|
+
|
|
738
|
+
// get the action being dragged
|
|
739
|
+
const actionId = event.detail.id;
|
|
740
|
+
const splitId = actionId.split('-');
|
|
741
|
+
if (splitId.length < 2 || isNaN(parseInt(splitId[1], 10))) {
|
|
742
|
+
// invalid format, do not proceed
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const actionIndex = parseInt(splitId[1], 10);
|
|
746
|
+
const action = this.node.actions[actionIndex];
|
|
747
|
+
|
|
748
|
+
// fire event to editor to show canvas drop preview, including the captured height
|
|
749
|
+
this.fireCustomEvent(CustomEventType.DragExternal, {
|
|
750
|
+
action,
|
|
751
|
+
nodeUuid: this.node.uuid,
|
|
752
|
+
actionIndex,
|
|
753
|
+
mouseX: event.detail.mouseX,
|
|
754
|
+
mouseY: event.detail.mouseY,
|
|
755
|
+
actionHeight: this.draggedActionHeight
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
private handleActionDragInternal(_event: CustomEvent) {
|
|
760
|
+
// stop propagation of the original event from SortableList
|
|
761
|
+
_event.stopPropagation();
|
|
762
|
+
|
|
763
|
+
// fire event to editor to hide canvas drop preview
|
|
764
|
+
this.fireCustomEvent(CustomEventType.DragInternal, {});
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
private handleActionDragStop(event: CustomEvent) {
|
|
768
|
+
const isExternal = event.detail.isExternal;
|
|
769
|
+
|
|
770
|
+
if (isExternal) {
|
|
771
|
+
// stop propagation of the original event from SortableList
|
|
772
|
+
event.stopPropagation();
|
|
773
|
+
|
|
774
|
+
// get the action being dragged
|
|
775
|
+
const actionId = event.detail.id;
|
|
776
|
+
const split = actionId.split('-');
|
|
777
|
+
if (split.length < 2 || isNaN(Number(split[1]))) {
|
|
778
|
+
// invalid actionId format, do not proceed
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const actionIndex = parseInt(split[1], 10);
|
|
782
|
+
const action = this.node.actions[actionIndex];
|
|
783
|
+
|
|
784
|
+
// fire event to editor to create new node
|
|
785
|
+
this.fireCustomEvent(CustomEventType.DragStop, {
|
|
786
|
+
action,
|
|
787
|
+
nodeUuid: this.node.uuid,
|
|
788
|
+
actionIndex,
|
|
789
|
+
isExternal: true,
|
|
790
|
+
mouseX: event.detail.mouseX,
|
|
791
|
+
mouseY: event.detail.mouseY
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
618
796
|
private handleActionMouseDown(event: MouseEvent, action: Action): void {
|
|
619
797
|
// Don't handle clicks on the remove button, drag handle, or when action is in removing state
|
|
620
798
|
const target = event.target as HTMLElement;
|
|
@@ -813,16 +991,171 @@ export class CanvasNode extends RapidElement {
|
|
|
813
991
|
this.pendingNodeClick = null;
|
|
814
992
|
}
|
|
815
993
|
|
|
994
|
+
private handleAddActionClick(event: MouseEvent): void {
|
|
995
|
+
event.preventDefault();
|
|
996
|
+
event.stopPropagation();
|
|
997
|
+
|
|
998
|
+
// Fire event to request adding a new action to this node
|
|
999
|
+
this.fireCustomEvent(CustomEventType.AddActionRequested, {
|
|
1000
|
+
nodeUuid: this.node.uuid
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
private calculateDropIndex(mouseY: number): number {
|
|
1005
|
+
// Get the sortable list element
|
|
1006
|
+
const sortableList = this.querySelector('temba-sortable-list');
|
|
1007
|
+
if (!sortableList || !this.node.actions)
|
|
1008
|
+
return this.node.actions?.length ?? 0;
|
|
1009
|
+
|
|
1010
|
+
// Get all action elements
|
|
1011
|
+
const actionElements = Array.from(
|
|
1012
|
+
sortableList.querySelectorAll('.action.sortable')
|
|
1013
|
+
);
|
|
1014
|
+
|
|
1015
|
+
if (actionElements.length === 0) {
|
|
1016
|
+
return 0;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// Find where to insert based on mouse Y position
|
|
1020
|
+
for (let i = 0; i < actionElements.length; i++) {
|
|
1021
|
+
const actionElement = actionElements[i] as HTMLElement;
|
|
1022
|
+
const rect = actionElement.getBoundingClientRect();
|
|
1023
|
+
const centerY = rect.top + rect.height / 2;
|
|
1024
|
+
|
|
1025
|
+
if (mouseY < centerY) {
|
|
1026
|
+
return i;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// If past all elements, insert at the end
|
|
1031
|
+
return actionElements.length;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
private handleExternalActionDragOver(event: CustomEvent): void {
|
|
1035
|
+
// Only handle if this is an execute_actions node
|
|
1036
|
+
if (this.ui.type !== 'execute_actions') return;
|
|
1037
|
+
|
|
1038
|
+
const { action, sourceNodeUuid, actionIndex, mouseY, actionHeight } =
|
|
1039
|
+
event.detail;
|
|
1040
|
+
|
|
1041
|
+
// Don't accept drops from the same node
|
|
1042
|
+
if (sourceNodeUuid === this.node.uuid) return;
|
|
1043
|
+
|
|
1044
|
+
// Calculate where to drop
|
|
1045
|
+
const dropIndex = this.calculateDropIndex(mouseY);
|
|
1046
|
+
|
|
1047
|
+
// Store the drag info
|
|
1048
|
+
this.externalDragInfo = {
|
|
1049
|
+
action,
|
|
1050
|
+
sourceNodeUuid,
|
|
1051
|
+
actionIndex,
|
|
1052
|
+
dropIndex,
|
|
1053
|
+
actionHeight: actionHeight || 60 // fallback to 60px if not provided
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
// Request update to show placeholder
|
|
1057
|
+
this.requestUpdate();
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
private handleExternalActionDragLeave(_event: CustomEvent): void {
|
|
1061
|
+
// Clear external drag state when drag leaves this node
|
|
1062
|
+
this.externalDragInfo = null;
|
|
1063
|
+
this.requestUpdate();
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
private handleActionShowGhost(_event: CustomEvent): void {
|
|
1067
|
+
// Show the ghost element in the sortable list
|
|
1068
|
+
const sortableList = this.querySelector('temba-sortable-list');
|
|
1069
|
+
if (sortableList) {
|
|
1070
|
+
const ghostElement = document.querySelector('.ghost') as HTMLElement;
|
|
1071
|
+
if (ghostElement) {
|
|
1072
|
+
ghostElement.style.display = 'block';
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
private handleActionHideGhost(_event: CustomEvent): void {
|
|
1078
|
+
// Hide the ghost element in the sortable list
|
|
1079
|
+
const sortableList = this.querySelector('temba-sortable-list');
|
|
1080
|
+
if (sortableList) {
|
|
1081
|
+
const ghostElement = document.querySelector('.ghost') as HTMLElement;
|
|
1082
|
+
if (ghostElement) {
|
|
1083
|
+
ghostElement.style.display = 'none';
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
private handleExternalActionDrop(event: CustomEvent): void {
|
|
1089
|
+
// Only handle if this is an execute_actions node
|
|
1090
|
+
if (this.ui.type !== 'execute_actions') return;
|
|
1091
|
+
|
|
1092
|
+
const { action, sourceNodeUuid, actionIndex } = event.detail;
|
|
1093
|
+
|
|
1094
|
+
// Don't accept drops from the same node
|
|
1095
|
+
if (sourceNodeUuid === this.node.uuid) return;
|
|
1096
|
+
|
|
1097
|
+
// Get the drop index from our tracking state
|
|
1098
|
+
const dropIndex =
|
|
1099
|
+
this.externalDragInfo?.dropIndex ?? this.node.actions?.length ?? 0;
|
|
1100
|
+
|
|
1101
|
+
// Clear external drag state
|
|
1102
|
+
this.externalDragInfo = null;
|
|
1103
|
+
|
|
1104
|
+
// Remove the action from the source node
|
|
1105
|
+
const store = getStore();
|
|
1106
|
+
if (!store) return;
|
|
1107
|
+
|
|
1108
|
+
const flowDefinition = store.getState().flowDefinition;
|
|
1109
|
+
if (!flowDefinition) return;
|
|
1110
|
+
|
|
1111
|
+
const sourceNode = flowDefinition.nodes.find(
|
|
1112
|
+
(n) => n.uuid === sourceNodeUuid
|
|
1113
|
+
);
|
|
1114
|
+
|
|
1115
|
+
if (sourceNode) {
|
|
1116
|
+
const updatedSourceActions = sourceNode.actions.filter(
|
|
1117
|
+
(_a, idx) => idx !== actionIndex
|
|
1118
|
+
);
|
|
1119
|
+
|
|
1120
|
+
// If source node has no actions left, remove it
|
|
1121
|
+
if (updatedSourceActions.length === 0) {
|
|
1122
|
+
this.fireCustomEvent(CustomEventType.NodeDeleted, {
|
|
1123
|
+
uuid: sourceNodeUuid
|
|
1124
|
+
});
|
|
1125
|
+
} else {
|
|
1126
|
+
// Update source node
|
|
1127
|
+
const updatedSourceNode = {
|
|
1128
|
+
...sourceNode,
|
|
1129
|
+
actions: updatedSourceActions
|
|
1130
|
+
};
|
|
1131
|
+
getStore()?.getState().updateNode(sourceNodeUuid, updatedSourceNode);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// Add the action to this node at the calculated position
|
|
1136
|
+
const newActions = [...this.node.actions];
|
|
1137
|
+
newActions.splice(dropIndex, 0, action);
|
|
1138
|
+
|
|
1139
|
+
const updatedNode = { ...this.node, actions: newActions };
|
|
1140
|
+
getStore()?.getState().updateNode(this.node.uuid, updatedNode);
|
|
1141
|
+
|
|
1142
|
+
// Request update
|
|
1143
|
+
this.requestUpdate();
|
|
1144
|
+
}
|
|
1145
|
+
|
|
816
1146
|
private renderTitle(
|
|
817
1147
|
config: ActionConfig,
|
|
818
1148
|
action: Action,
|
|
819
1149
|
index: number,
|
|
820
1150
|
isRemoving: boolean = false
|
|
821
1151
|
) {
|
|
822
|
-
|
|
1152
|
+
const color = config.group
|
|
1153
|
+
? ACTION_GROUP_METADATA[config.group]?.color
|
|
1154
|
+
: '#aaaaaa';
|
|
1155
|
+
return html`<div class="cn-title" style="background:${color}">
|
|
823
1156
|
${this.node?.actions?.length > 1
|
|
824
1157
|
? html`<temba-icon class="drag-handle" name="sort"></temba-icon>`
|
|
825
|
-
:
|
|
1158
|
+
: html`<div class="title-spacer"></div>`}
|
|
826
1159
|
|
|
827
1160
|
<div class="name">${isRemoving ? 'Remove?' : config.name}</div>
|
|
828
1161
|
<div
|
|
@@ -836,13 +1169,29 @@ export class CanvasNode extends RapidElement {
|
|
|
836
1169
|
</div>`;
|
|
837
1170
|
}
|
|
838
1171
|
|
|
839
|
-
private renderNodeTitle(
|
|
1172
|
+
private renderNodeTitle(
|
|
1173
|
+
config: NodeConfig,
|
|
1174
|
+
node: Node,
|
|
1175
|
+
ui: NodeUI,
|
|
1176
|
+
isRemoving: boolean = false
|
|
1177
|
+
) {
|
|
1178
|
+
// Get color from the appropriate metadata (either ACTION or SPLIT)
|
|
1179
|
+
const color = config.group
|
|
1180
|
+
? ACTION_GROUP_METADATA[config.group]?.color ||
|
|
1181
|
+
SPLIT_GROUP_METADATA[config.group]?.color
|
|
1182
|
+
: '#aaaaaa';
|
|
840
1183
|
return html`<div
|
|
841
1184
|
class="cn-title ${isRemoving ? 'removing' : ''}"
|
|
842
|
-
style="background:${
|
|
1185
|
+
style="background:${color}"
|
|
843
1186
|
>
|
|
844
1187
|
<div class="title-spacer"></div>
|
|
845
|
-
<div class="name"
|
|
1188
|
+
<div class="name">
|
|
1189
|
+
${isRemoving
|
|
1190
|
+
? 'Remove?'
|
|
1191
|
+
: config.renderTitle
|
|
1192
|
+
? config.renderTitle(node, ui)
|
|
1193
|
+
: html`${config.name}`}
|
|
1194
|
+
</div>
|
|
846
1195
|
<div
|
|
847
1196
|
class="remove-button"
|
|
848
1197
|
@click=${(e: MouseEvent) => this.handleNodeRemoveClick(e)}
|
|
@@ -853,6 +1202,14 @@ export class CanvasNode extends RapidElement {
|
|
|
853
1202
|
</div>`;
|
|
854
1203
|
}
|
|
855
1204
|
|
|
1205
|
+
private renderDropPlaceholder() {
|
|
1206
|
+
const height = this.externalDragInfo?.actionHeight || 60;
|
|
1207
|
+
return html`<div
|
|
1208
|
+
class="action sortable drop-placeholder"
|
|
1209
|
+
style="height: ${height}px; background: #f3f4f6; border: 2px dashed #d1d5db; border-radius: var(--curvature);"
|
|
1210
|
+
></div>`;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
856
1213
|
private renderAction(node: Node, action: Action, index: number) {
|
|
857
1214
|
const config = ACTION_CONFIG[action.type];
|
|
858
1215
|
const isRemoving = this.actionRemovingState.has(action.uuid);
|
|
@@ -893,6 +1250,31 @@ export class CanvasNode extends RapidElement {
|
|
|
893
1250
|
</div>`;
|
|
894
1251
|
}
|
|
895
1252
|
|
|
1253
|
+
private renderActionsWithPlaceholder() {
|
|
1254
|
+
if (!this.externalDragInfo) {
|
|
1255
|
+
// No external drag, render normally
|
|
1256
|
+
return this.node.actions.map((action, index) =>
|
|
1257
|
+
this.renderAction(this.node, action, index)
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// Insert placeholder at the drop index
|
|
1262
|
+
const result = [];
|
|
1263
|
+
for (let i = 0; i < this.node.actions.length; i++) {
|
|
1264
|
+
if (i === this.externalDragInfo.dropIndex) {
|
|
1265
|
+
result.push(this.renderDropPlaceholder());
|
|
1266
|
+
}
|
|
1267
|
+
result.push(this.renderAction(this.node, this.node.actions[i], i));
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// If dropping at the end, add placeholder after all actions
|
|
1271
|
+
if (this.externalDragInfo.dropIndex >= this.node.actions.length) {
|
|
1272
|
+
result.push(this.renderDropPlaceholder());
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
return result;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
896
1278
|
private renderRouter(router: Router, ui: NodeUI) {
|
|
897
1279
|
const nodeConfig = NODE_CONFIG[ui.type];
|
|
898
1280
|
if (nodeConfig) {
|
|
@@ -978,20 +1360,27 @@ export class CanvasNode extends RapidElement {
|
|
|
978
1360
|
>
|
|
979
1361
|
${this.renderNodeTitle(
|
|
980
1362
|
nodeConfig,
|
|
1363
|
+
this.node,
|
|
1364
|
+
this.ui,
|
|
981
1365
|
this.actionRemovingState.has(this.node.uuid)
|
|
982
1366
|
)}
|
|
983
|
-
${nodeConfig.render
|
|
1367
|
+
${nodeConfig.render
|
|
1368
|
+
? nodeConfig.render(this.node, this.ui)
|
|
1369
|
+
: null}
|
|
984
1370
|
</div>
|
|
985
1371
|
</div>`
|
|
986
1372
|
: this.node.actions.length > 0
|
|
987
1373
|
? this.ui.type === 'execute_actions'
|
|
988
1374
|
? html`<temba-sortable-list
|
|
989
1375
|
dragHandle="drag-handle"
|
|
1376
|
+
externalDrag
|
|
990
1377
|
@temba-order-changed="${this.handleActionOrderChanged}"
|
|
1378
|
+
@temba-drag-start="${this.handleActionDragStart}"
|
|
1379
|
+
@temba-drag-external="${this.handleActionDragExternal}"
|
|
1380
|
+
@temba-drag-internal="${this.handleActionDragInternal}"
|
|
1381
|
+
@temba-drag-stop="${this.handleActionDragStop}"
|
|
991
1382
|
>
|
|
992
|
-
${this.
|
|
993
|
-
this.renderAction(this.node, action, index)
|
|
994
|
-
)}
|
|
1383
|
+
${this.renderActionsWithPlaceholder()}
|
|
995
1384
|
</temba-sortable-list>`
|
|
996
1385
|
: html`${this.node.actions.map((action, index) =>
|
|
997
1386
|
this.renderAction(this.node, action, index)
|
|
@@ -1007,6 +1396,15 @@ export class CanvasNode extends RapidElement {
|
|
|
1007
1396
|
(exit) => this.renderExit(exit)
|
|
1008
1397
|
)}
|
|
1009
1398
|
</div>`}
|
|
1399
|
+
${this.ui.type === 'execute_actions'
|
|
1400
|
+
? html`<div
|
|
1401
|
+
class="add-action-button"
|
|
1402
|
+
@click=${(e: MouseEvent) => this.handleAddActionClick(e)}
|
|
1403
|
+
title="Add action"
|
|
1404
|
+
>
|
|
1405
|
+
<temba-icon name="add"></temba-icon>
|
|
1406
|
+
</div>`
|
|
1407
|
+
: ''}
|
|
1010
1408
|
</div>
|
|
1011
1409
|
`;
|
|
1012
1410
|
}
|