@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.740 1.118 C 7.221 1.327,6.920 1.836,4.718 6.240 C 2.218 11.241,2.170 11.364,2.475 12.093 C 2.609 12.414,2.878 12.708,3.123 12.801 C 3.353 12.888,4.796 12.960,6.330 12.960 C 7.865 12.960,9.120 12.999,9.120 13.046 C 9.120 13.093,8.544 15.048,7.840 17.390 C 7.136 19.731,6.560 21.851,6.560 22.100 C 6.560 22.690,7.179 23.129,7.738 22.935 C 8.123 22.802,20.460 10.117,20.999 9.302 C 21.442 8.632,21.362 7.938,20.788 7.454 L 20.295 7.040 16.868 7.040 C 14.982 7.040,13.440 7.022,13.441 7.000 C 13.441 6.978,13.837 5.916,14.320 4.640 C 14.803 3.364,15.199 2.158,15.199 1.960 C 15.200 1.762,15.056 1.456,14.880 1.280 C 14.580 0.980,14.354 0.961,11.320 0.970 C 9.538 0.976,7.927 1.042,7.740 1.118 M12.622 3.480 C 12.528 3.722,12.134 4.769,11.746 5.808 C 10.545 9.020,10.460 8.939,15.116 8.997 L 18.613 9.040 14.245 13.565 C 11.843 16.054,9.851 18.064,9.819 18.032 C 9.786 18.000,10.156 16.653,10.640 15.040 C 11.124 13.426,11.520 12.010,11.520 11.893 C 11.520 11.776,11.376 11.536,11.200 11.360 C 10.902 11.062,10.667 11.040,7.759 11.040 L 4.639 11.040 6.640 7.040 L 8.641 3.040 10.717 3.040 L 12.792 3.040 12.622 3.480 " stroke="none" fill-rule="evenodd" fill="black"></path></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M14.2495 2H8.49395C8.31447 2 8.22473 2 8.14551 2.02733C8.07544 2.05149 8.01163 2.09093 7.95868 2.14279C7.89881 2.20143 7.85868 2.2817 7.77841 2.44223L3.57841 10.8422C3.38673 11.2256 3.29089 11.4173 3.31391 11.5731C3.33401 11.7091 3.40927 11.8309 3.52197 11.9097C3.65104 12 3.86534 12 4.29395 12H10.4995L7.49953 22L19.6926 9.35531C20.104 8.9287 20.3097 8.7154 20.3217 8.53288C20.3321 8.37446 20.2667 8.22049 20.1454 8.11803C20.0057 8 19.7094 8 19.1167 8H11.9995L14.2495 2Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
</svg>
|
package/temba-modules.ts
CHANGED
|
@@ -58,6 +58,8 @@ import { MediaPicker } from './src/form/MediaPicker';
|
|
|
58
58
|
import { Editor } from './src/flow/Editor';
|
|
59
59
|
import { CanvasNode } from './src/flow/CanvasNode';
|
|
60
60
|
import { StickyNote } from './src/flow/StickyNote';
|
|
61
|
+
import { CanvasMenu } from './src/flow/CanvasMenu';
|
|
62
|
+
import { NodeTypeSelector } from './src/flow/NodeTypeSelector';
|
|
61
63
|
import { ContactNotepad } from './src/live/ContactNotepad';
|
|
62
64
|
import { ProgressBar } from './src/display/ProgressBar';
|
|
63
65
|
import { StartProgress } from './src/live/StartProgress';
|
|
@@ -143,6 +145,8 @@ addCustomElement('temba-flow-editor', Editor);
|
|
|
143
145
|
addCustomElement('temba-node-editor', NodeEditor);
|
|
144
146
|
addCustomElement('temba-flow-node', CanvasNode);
|
|
145
147
|
addCustomElement('temba-sticky-note', StickyNote);
|
|
148
|
+
addCustomElement('temba-canvas-menu', CanvasMenu);
|
|
149
|
+
addCustomElement('temba-node-type-selector', NodeTypeSelector);
|
|
146
150
|
addCustomElement('temba-contact-notepad', ContactNotepad);
|
|
147
151
|
addCustomElement('temba-progress', ProgressBar);
|
|
148
152
|
addCustomElement('temba-start-progress', StartProgress);
|
package/test/ActionHelper.ts
CHANGED
|
@@ -111,9 +111,9 @@ export class ActionTest<T extends Action> {
|
|
|
111
111
|
expect(convertedAction.uuid).to.equal(action.uuid);
|
|
112
112
|
expect(convertedAction.type).to.equal(action.type);
|
|
113
113
|
|
|
114
|
-
// Validate the
|
|
114
|
+
// Validate the form data
|
|
115
115
|
if (this.actionConfig.validate) {
|
|
116
|
-
const validation = this.actionConfig.validate(
|
|
116
|
+
const validation = this.actionConfig.validate(formData);
|
|
117
117
|
expect(validation.valid).to.be.true;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -126,7 +126,7 @@ export class ActionTest<T extends Action> {
|
|
|
126
126
|
testBasicProperties() {
|
|
127
127
|
it('has correct basic properties', () => {
|
|
128
128
|
expect(this.actionConfig.name).to.be.a('string');
|
|
129
|
-
expect(this.actionConfig.
|
|
129
|
+
expect(this.actionConfig.group).to.exist;
|
|
130
130
|
|
|
131
131
|
// toFormData and fromFormData are optional - only needed for complex data transformations
|
|
132
132
|
if (this.actionConfig.toFormData) {
|
package/test/NodeHelper.ts
CHANGED
|
@@ -144,9 +144,12 @@ export class NodeTest<T extends Node> {
|
|
|
144
144
|
expect(this.nodeConfig.name).to.be.a('string');
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
//
|
|
148
|
-
if (this.nodeConfig.
|
|
149
|
-
expect(this.nodeConfig.
|
|
147
|
+
// EditorType is optional but recommended
|
|
148
|
+
if (this.nodeConfig.editorType) {
|
|
149
|
+
expect(this.nodeConfig.editorType).to.be.an('object');
|
|
150
|
+
expect(this.nodeConfig.editorType.color).to.be.a('string');
|
|
151
|
+
expect(this.nodeConfig.editorType.title).to.be.a('string');
|
|
152
|
+
expect(this.nodeConfig.editorType.description).to.be.a('string');
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
// toFormData and fromFormData are optional - only needed for complex data transformations
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { add_contact_urn } from '../../src/flow/actions/add_contact_urn';
|
|
3
|
+
import { AddContactUrn } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the add_contact_urn action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('add_contact_urn action config', () => {
|
|
10
|
+
const helper = new ActionTest(add_contact_urn, 'add_contact_urn');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(add_contact_urn.name).to.equal('Add URN');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'add_contact_urn',
|
|
25
|
+
scheme: 'tel',
|
|
26
|
+
path: '+12065551212'
|
|
27
|
+
} as AddContactUrn,
|
|
28
|
+
'phone-number'
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
helper.testAction(
|
|
32
|
+
{
|
|
33
|
+
uuid: 'test-action-2',
|
|
34
|
+
type: 'add_contact_urn',
|
|
35
|
+
scheme: 'whatsapp',
|
|
36
|
+
path: '+447123456789'
|
|
37
|
+
} as AddContactUrn,
|
|
38
|
+
'whatsapp'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
helper.testAction(
|
|
42
|
+
{
|
|
43
|
+
uuid: 'test-action-3',
|
|
44
|
+
type: 'add_contact_urn',
|
|
45
|
+
scheme: 'facebook',
|
|
46
|
+
path: '1234567890'
|
|
47
|
+
} as AddContactUrn,
|
|
48
|
+
'facebook-id'
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
helper.testAction(
|
|
52
|
+
{
|
|
53
|
+
uuid: 'test-action-4',
|
|
54
|
+
type: 'add_contact_urn',
|
|
55
|
+
scheme: 'telegram',
|
|
56
|
+
path: '987654321'
|
|
57
|
+
} as AddContactUrn,
|
|
58
|
+
'telegram-id'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
helper.testAction(
|
|
62
|
+
{
|
|
63
|
+
uuid: 'test-action-5',
|
|
64
|
+
type: 'add_contact_urn',
|
|
65
|
+
scheme: 'instagram',
|
|
66
|
+
path: 'user_instagram_handle'
|
|
67
|
+
} as AddContactUrn,
|
|
68
|
+
'instagram-handle'
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
helper.testAction(
|
|
72
|
+
{
|
|
73
|
+
uuid: 'test-action-6',
|
|
74
|
+
type: 'add_contact_urn',
|
|
75
|
+
scheme: 'tel',
|
|
76
|
+
path: '@run.results.phone_number'
|
|
77
|
+
} as AddContactUrn,
|
|
78
|
+
'expression-phone'
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
helper.testAction(
|
|
82
|
+
{
|
|
83
|
+
uuid: 'test-action-7',
|
|
84
|
+
type: 'add_contact_urn',
|
|
85
|
+
scheme: 'facebook',
|
|
86
|
+
path: '@fields.facebook_id'
|
|
87
|
+
} as AddContactUrn,
|
|
88
|
+
'expression-facebook'
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
helper.testAction(
|
|
92
|
+
{
|
|
93
|
+
uuid: 'test-action-8',
|
|
94
|
+
type: 'add_contact_urn',
|
|
95
|
+
scheme: 'line',
|
|
96
|
+
path: 'U1234567890abcdef1234567890abcdef'
|
|
97
|
+
} as AddContactUrn,
|
|
98
|
+
'line-id'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
helper.testAction(
|
|
102
|
+
{
|
|
103
|
+
uuid: 'test-action-9',
|
|
104
|
+
type: 'add_contact_urn',
|
|
105
|
+
scheme: 'viber',
|
|
106
|
+
path: '0123456789ABC='
|
|
107
|
+
} as AddContactUrn,
|
|
108
|
+
'viber-id'
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
helper.testAction(
|
|
112
|
+
{
|
|
113
|
+
uuid: 'test-action-10',
|
|
114
|
+
type: 'add_contact_urn',
|
|
115
|
+
scheme: 'wechat',
|
|
116
|
+
path: 'wechatuser123'
|
|
117
|
+
} as AddContactUrn,
|
|
118
|
+
'wechat-id'
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('validation', () => {
|
|
123
|
+
it('validates that scheme is required', () => {
|
|
124
|
+
const formData = {
|
|
125
|
+
scheme: [],
|
|
126
|
+
path: '+12065551212'
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const result = add_contact_urn.validate!(formData);
|
|
130
|
+
|
|
131
|
+
expect(result.valid).to.be.false;
|
|
132
|
+
expect(result.errors.scheme).to.equal('URN type is required');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('validates that path is required', () => {
|
|
136
|
+
const formData = {
|
|
137
|
+
scheme: [{ name: 'Phone Number', value: 'tel' }],
|
|
138
|
+
path: ''
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const result = add_contact_urn.validate!(formData);
|
|
142
|
+
|
|
143
|
+
expect(result.valid).to.be.false;
|
|
144
|
+
expect(result.errors.path).to.equal('URN value is required');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('validates that path with only whitespace is invalid', () => {
|
|
148
|
+
const formData = {
|
|
149
|
+
scheme: [{ name: 'Phone Number', value: 'tel' }],
|
|
150
|
+
path: ' '
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const result = add_contact_urn.validate!(formData);
|
|
154
|
+
|
|
155
|
+
expect(result.valid).to.be.false;
|
|
156
|
+
expect(result.errors.path).to.equal('URN value is required');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('validates successfully with both scheme and path', () => {
|
|
160
|
+
const formData = {
|
|
161
|
+
scheme: [{ name: 'Phone Number', value: 'tel' }],
|
|
162
|
+
path: '+12065551212'
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const result = add_contact_urn.validate!(formData);
|
|
166
|
+
|
|
167
|
+
expect(result.valid).to.be.true;
|
|
168
|
+
expect(Object.keys(result.errors)).to.have.lengthOf(0);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('validates successfully with expression in path', () => {
|
|
172
|
+
const formData = {
|
|
173
|
+
scheme: [{ name: 'Facebook ID', value: 'facebook' }],
|
|
174
|
+
path: '@fields.facebook_id'
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const result = add_contact_urn.validate!(formData);
|
|
178
|
+
|
|
179
|
+
expect(result.valid).to.be.true;
|
|
180
|
+
expect(Object.keys(result.errors)).to.have.lengthOf(0);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('round-trip transformation', () => {
|
|
185
|
+
it('should preserve action structure through toFormData -> fromFormData', () => {
|
|
186
|
+
const originalAction: AddContactUrn = {
|
|
187
|
+
uuid: 'test-uuid-123',
|
|
188
|
+
type: 'add_contact_urn',
|
|
189
|
+
scheme: 'whatsapp',
|
|
190
|
+
path: '+447123456789'
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const formData = add_contact_urn.toFormData!(originalAction);
|
|
194
|
+
const convertedAction = add_contact_urn.fromFormData!(
|
|
195
|
+
formData
|
|
196
|
+
) as AddContactUrn;
|
|
197
|
+
|
|
198
|
+
expect(convertedAction.uuid).to.equal(originalAction.uuid);
|
|
199
|
+
expect(convertedAction.type).to.equal(originalAction.type);
|
|
200
|
+
expect(convertedAction.scheme).to.equal(originalAction.scheme);
|
|
201
|
+
expect(convertedAction.path).to.equal(originalAction.path);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should handle different URN schemes correctly', () => {
|
|
205
|
+
const schemes = ['tel', 'facebook', 'telegram', 'instagram', 'whatsapp'];
|
|
206
|
+
|
|
207
|
+
schemes.forEach((scheme) => {
|
|
208
|
+
const originalAction: AddContactUrn = {
|
|
209
|
+
uuid: 'test-uuid',
|
|
210
|
+
type: 'add_contact_urn',
|
|
211
|
+
scheme: scheme,
|
|
212
|
+
path: 'test-value'
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const formData = add_contact_urn.toFormData!(originalAction);
|
|
216
|
+
const convertedAction = add_contact_urn.fromFormData!(
|
|
217
|
+
formData
|
|
218
|
+
) as AddContactUrn;
|
|
219
|
+
|
|
220
|
+
expect(convertedAction.scheme).to.equal(scheme);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should handle expressions in path', () => {
|
|
225
|
+
const originalAction: AddContactUrn = {
|
|
226
|
+
uuid: 'test-uuid',
|
|
227
|
+
type: 'add_contact_urn',
|
|
228
|
+
scheme: 'tel',
|
|
229
|
+
path: '@run.results.phone_number'
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const formData = add_contact_urn.toFormData!(originalAction);
|
|
233
|
+
const convertedAction = add_contact_urn.fromFormData!(
|
|
234
|
+
formData
|
|
235
|
+
) as AddContactUrn;
|
|
236
|
+
|
|
237
|
+
expect(convertedAction.path).to.equal('@run.results.phone_number');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should default to tel scheme if scheme is missing in form data', () => {
|
|
241
|
+
const formData = {
|
|
242
|
+
uuid: 'test-uuid',
|
|
243
|
+
scheme: [],
|
|
244
|
+
path: '+12065551212'
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const convertedAction = add_contact_urn.fromFormData!(
|
|
248
|
+
formData
|
|
249
|
+
) as AddContactUrn;
|
|
250
|
+
|
|
251
|
+
expect(convertedAction.scheme).to.equal('tel');
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe('form data structure', () => {
|
|
256
|
+
it('should convert scheme to select array format in toFormData', () => {
|
|
257
|
+
const action: AddContactUrn = {
|
|
258
|
+
uuid: 'test-uuid',
|
|
259
|
+
type: 'add_contact_urn',
|
|
260
|
+
scheme: 'whatsapp',
|
|
261
|
+
path: '+447123456789'
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const formData = add_contact_urn.toFormData!(action);
|
|
265
|
+
|
|
266
|
+
expect(formData.scheme).to.be.an('array');
|
|
267
|
+
expect(formData.scheme).to.have.lengthOf(1);
|
|
268
|
+
expect(formData.scheme[0]).to.deep.include({
|
|
269
|
+
name: 'WhatsApp Number',
|
|
270
|
+
value: 'whatsapp'
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should handle unknown scheme gracefully', () => {
|
|
275
|
+
const action: AddContactUrn = {
|
|
276
|
+
uuid: 'test-uuid',
|
|
277
|
+
type: 'add_contact_urn',
|
|
278
|
+
scheme: 'unknown_scheme',
|
|
279
|
+
path: 'some-value'
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const formData = add_contact_urn.toFormData!(action);
|
|
283
|
+
|
|
284
|
+
expect(formData.scheme).to.be.null;
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing';
|
|
2
|
+
import { send_broadcast } from '../../src/flow/actions/send_broadcast';
|
|
3
|
+
import { SendBroadcast } from '../../src/store/flow-definition';
|
|
4
|
+
import { ActionTest } from '../ActionHelper';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Test suite for the send_broadcast action configuration.
|
|
8
|
+
*/
|
|
9
|
+
describe('send_broadcast action config', () => {
|
|
10
|
+
const helper = new ActionTest(send_broadcast, 'send_broadcast');
|
|
11
|
+
|
|
12
|
+
describe('basic properties', () => {
|
|
13
|
+
helper.testBasicProperties();
|
|
14
|
+
|
|
15
|
+
it('has correct name', () => {
|
|
16
|
+
expect(send_broadcast.name).to.equal('Send Broadcast');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('action scenarios', () => {
|
|
21
|
+
helper.testAction(
|
|
22
|
+
{
|
|
23
|
+
uuid: 'test-action-1',
|
|
24
|
+
type: 'send_broadcast',
|
|
25
|
+
text: 'Important announcement for all subscribers!',
|
|
26
|
+
groups: [
|
|
27
|
+
{ uuid: 'group-1', name: 'Subscribers' },
|
|
28
|
+
{ uuid: 'group-2', name: 'VIP Members' }
|
|
29
|
+
],
|
|
30
|
+
contacts: []
|
|
31
|
+
} as SendBroadcast,
|
|
32
|
+
'groups-only'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
helper.testAction(
|
|
36
|
+
{
|
|
37
|
+
uuid: 'test-action-2',
|
|
38
|
+
type: 'send_broadcast',
|
|
39
|
+
text: 'Personal message to specific contacts.',
|
|
40
|
+
groups: [],
|
|
41
|
+
contacts: [
|
|
42
|
+
{ uuid: 'contact-1', name: 'Alice Johnson' },
|
|
43
|
+
{ uuid: 'contact-2', name: 'Bob Smith' }
|
|
44
|
+
]
|
|
45
|
+
} as SendBroadcast,
|
|
46
|
+
'contacts-only'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
helper.testAction(
|
|
50
|
+
{
|
|
51
|
+
uuid: 'test-action-3',
|
|
52
|
+
type: 'send_broadcast',
|
|
53
|
+
text: 'Urgent update for everyone!',
|
|
54
|
+
groups: [{ uuid: 'group-1', name: 'All Members' }],
|
|
55
|
+
contacts: [{ uuid: 'contact-1', name: 'Admin' }]
|
|
56
|
+
} as SendBroadcast,
|
|
57
|
+
'groups-and-contacts'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
helper.testAction(
|
|
61
|
+
{
|
|
62
|
+
uuid: 'test-action-4',
|
|
63
|
+
type: 'send_broadcast',
|
|
64
|
+
text: 'Multi-line broadcast message.\n\nThis is the second paragraph.\n\nAnd the third.',
|
|
65
|
+
groups: [{ uuid: 'group-1', name: 'Newsletter Subscribers' }],
|
|
66
|
+
contacts: []
|
|
67
|
+
} as SendBroadcast,
|
|
68
|
+
'multiline-text'
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
helper.testAction(
|
|
72
|
+
{
|
|
73
|
+
uuid: 'test-action-5',
|
|
74
|
+
type: 'send_broadcast',
|
|
75
|
+
text: 'Broadcast with attachments',
|
|
76
|
+
groups: [{ uuid: 'group-1', name: 'Members' }],
|
|
77
|
+
contacts: [],
|
|
78
|
+
attachments: [
|
|
79
|
+
'image/jpeg:https://example.com/photo.jpg',
|
|
80
|
+
'application/pdf:https://example.com/document.pdf'
|
|
81
|
+
]
|
|
82
|
+
} as SendBroadcast,
|
|
83
|
+
'with-attachments'
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
helper.testAction(
|
|
87
|
+
{
|
|
88
|
+
uuid: 'test-action-6',
|
|
89
|
+
type: 'send_broadcast',
|
|
90
|
+
text: 'Message to many groups',
|
|
91
|
+
groups: [
|
|
92
|
+
{ uuid: 'group-1', name: 'Group A' },
|
|
93
|
+
{ uuid: 'group-2', name: 'Group B' },
|
|
94
|
+
{ uuid: 'group-3', name: 'Group C' },
|
|
95
|
+
{ uuid: 'group-4', name: 'Group D' }
|
|
96
|
+
],
|
|
97
|
+
contacts: []
|
|
98
|
+
} as SendBroadcast,
|
|
99
|
+
'many-groups'
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('form data conversion', () => {
|
|
104
|
+
it('converts action to form data correctly', () => {
|
|
105
|
+
const action: SendBroadcast = {
|
|
106
|
+
uuid: 'test-uuid',
|
|
107
|
+
type: 'send_broadcast',
|
|
108
|
+
text: 'Test message',
|
|
109
|
+
groups: [{ uuid: 'group-1', name: 'Test Group' }],
|
|
110
|
+
contacts: [{ uuid: 'contact-1', name: 'Test Contact' }],
|
|
111
|
+
attachments: ['image/jpeg:test.jpg']
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const formData = send_broadcast.toFormData(action);
|
|
115
|
+
|
|
116
|
+
expect(formData.uuid).to.equal('test-uuid');
|
|
117
|
+
expect(formData.text).to.equal('Test message');
|
|
118
|
+
expect(formData.recipients).to.have.lengthOf(2);
|
|
119
|
+
expect(formData.attachments).to.deep.equal(['image/jpeg:test.jpg']);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('converts form data to action correctly with contacts only', () => {
|
|
123
|
+
const formData = {
|
|
124
|
+
uuid: 'test-uuid',
|
|
125
|
+
recipients: [
|
|
126
|
+
{ uuid: 'contact-1', name: 'Contact 1' },
|
|
127
|
+
{ uuid: 'contact-2', name: 'Contact 2' }
|
|
128
|
+
],
|
|
129
|
+
text: 'Test message',
|
|
130
|
+
attachments: []
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const action = send_broadcast.fromFormData(formData) as SendBroadcast;
|
|
134
|
+
|
|
135
|
+
expect(action.uuid).to.equal('test-uuid');
|
|
136
|
+
expect(action.type).to.equal('send_broadcast');
|
|
137
|
+
expect(action.text).to.equal('Test message');
|
|
138
|
+
expect(action.contacts).to.have.lengthOf(2);
|
|
139
|
+
expect(action.groups).to.have.lengthOf(0);
|
|
140
|
+
expect(action.attachments).to.be.undefined;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('converts form data to action correctly with groups only', () => {
|
|
144
|
+
const formData = {
|
|
145
|
+
uuid: 'test-uuid',
|
|
146
|
+
recipients: [
|
|
147
|
+
{ uuid: 'group-1', name: 'Group 1', group: true },
|
|
148
|
+
{ uuid: 'group-2', name: 'Group 2', group: true }
|
|
149
|
+
],
|
|
150
|
+
text: 'Test message',
|
|
151
|
+
attachments: []
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const action = send_broadcast.fromFormData(formData) as SendBroadcast;
|
|
155
|
+
|
|
156
|
+
expect(action.contacts).to.have.lengthOf(0);
|
|
157
|
+
expect(action.groups).to.have.lengthOf(2);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('converts form data to action correctly with mixed recipients', () => {
|
|
161
|
+
const formData = {
|
|
162
|
+
uuid: 'test-uuid',
|
|
163
|
+
recipients: [
|
|
164
|
+
{ uuid: 'contact-1', name: 'Contact 1' },
|
|
165
|
+
{ uuid: 'group-1', name: 'Group 1', group: true }
|
|
166
|
+
],
|
|
167
|
+
text: 'Test message',
|
|
168
|
+
attachments: ['image/jpeg:test.jpg']
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const action = send_broadcast.fromFormData(formData) as SendBroadcast;
|
|
172
|
+
|
|
173
|
+
expect(action.contacts).to.have.lengthOf(1);
|
|
174
|
+
expect(action.groups).to.have.lengthOf(1);
|
|
175
|
+
expect(action.attachments).to.deep.equal(['image/jpeg:test.jpg']);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('sanitizes text by trimming whitespace', () => {
|
|
179
|
+
const formData = {
|
|
180
|
+
uuid: 'test-uuid',
|
|
181
|
+
recipients: [{ uuid: 'contact-1', name: 'Test Contact' }],
|
|
182
|
+
text: ' Test message \n '
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
send_broadcast.sanitize(formData);
|
|
186
|
+
|
|
187
|
+
expect(formData.text).to.equal('Test message');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -118,15 +118,14 @@ describe('send_email action config', () => {
|
|
|
118
118
|
|
|
119
119
|
describe('validation edge cases', () => {
|
|
120
120
|
it('fails validation for empty addresses array', () => {
|
|
121
|
-
const
|
|
121
|
+
const formData = {
|
|
122
122
|
uuid: 'test-action',
|
|
123
|
-
type: 'send_email',
|
|
124
123
|
addresses: [],
|
|
125
124
|
subject: 'Test Subject',
|
|
126
125
|
body: 'Test Body'
|
|
127
126
|
};
|
|
128
127
|
|
|
129
|
-
const result = send_email.validate(
|
|
128
|
+
const result = send_email.validate(formData);
|
|
130
129
|
expect(result.valid).to.be.false;
|
|
131
130
|
expect(result.errors.addresses).to.equal(
|
|
132
131
|
'At least one recipient email address is required'
|
|
@@ -134,15 +133,14 @@ describe('send_email action config', () => {
|
|
|
134
133
|
});
|
|
135
134
|
|
|
136
135
|
it('fails validation for null addresses', () => {
|
|
137
|
-
const
|
|
136
|
+
const formData = {
|
|
138
137
|
uuid: 'test-action',
|
|
139
|
-
type: 'send_email',
|
|
140
138
|
addresses: null as any,
|
|
141
139
|
subject: 'Test Subject',
|
|
142
140
|
body: 'Test Body'
|
|
143
141
|
};
|
|
144
142
|
|
|
145
|
-
const result = send_email.validate(
|
|
143
|
+
const result = send_email.validate(formData);
|
|
146
144
|
expect(result.valid).to.be.false;
|
|
147
145
|
expect(result.errors.addresses).to.equal(
|
|
148
146
|
'At least one recipient email address is required'
|
|
@@ -150,15 +148,14 @@ describe('send_email action config', () => {
|
|
|
150
148
|
});
|
|
151
149
|
|
|
152
150
|
it('fails validation for undefined addresses', () => {
|
|
153
|
-
const
|
|
151
|
+
const formData = {
|
|
154
152
|
uuid: 'test-action',
|
|
155
|
-
type: 'send_email',
|
|
156
153
|
addresses: undefined as any,
|
|
157
154
|
subject: 'Test Subject',
|
|
158
155
|
body: 'Test Body'
|
|
159
156
|
};
|
|
160
157
|
|
|
161
|
-
const result = send_email.validate(
|
|
158
|
+
const result = send_email.validate(formData);
|
|
162
159
|
expect(result.valid).to.be.false;
|
|
163
160
|
expect(result.errors.addresses).to.equal(
|
|
164
161
|
'At least one recipient email address is required'
|
|
@@ -166,47 +163,44 @@ describe('send_email action config', () => {
|
|
|
166
163
|
});
|
|
167
164
|
|
|
168
165
|
it('passes validation with valid email addresses', () => {
|
|
169
|
-
const
|
|
166
|
+
const formData = {
|
|
170
167
|
uuid: 'test-action',
|
|
171
|
-
|
|
172
|
-
addresses: ['valid@example.com'],
|
|
168
|
+
addresses: [{ name: 'valid@example.com', value: 'valid@example.com' }],
|
|
173
169
|
subject: 'Test Subject',
|
|
174
170
|
body: 'Test Body'
|
|
175
171
|
};
|
|
176
172
|
|
|
177
|
-
const result = send_email.validate(
|
|
173
|
+
const result = send_email.validate(formData);
|
|
178
174
|
expect(result.valid).to.be.true;
|
|
179
175
|
expect(Object.keys(result.errors)).to.have.length(0);
|
|
180
176
|
});
|
|
181
177
|
|
|
182
178
|
it('passes validation with multiple email addresses', () => {
|
|
183
|
-
const
|
|
179
|
+
const formData = {
|
|
184
180
|
uuid: 'test-action',
|
|
185
|
-
type: 'send_email',
|
|
186
181
|
addresses: [
|
|
187
|
-
'user1@example.com',
|
|
188
|
-
'user2@example.com',
|
|
189
|
-
'user3@example.com'
|
|
182
|
+
{ name: 'user1@example.com', value: 'user1@example.com' },
|
|
183
|
+
{ name: 'user2@example.com', value: 'user2@example.com' },
|
|
184
|
+
{ name: 'user3@example.com', value: 'user3@example.com' }
|
|
190
185
|
],
|
|
191
186
|
subject: 'Test Subject',
|
|
192
187
|
body: 'Test Body'
|
|
193
188
|
};
|
|
194
189
|
|
|
195
|
-
const result = send_email.validate(
|
|
190
|
+
const result = send_email.validate(formData);
|
|
196
191
|
expect(result.valid).to.be.true;
|
|
197
192
|
expect(Object.keys(result.errors)).to.have.length(0);
|
|
198
193
|
});
|
|
199
194
|
|
|
200
195
|
it('passes validation with empty subject and body', () => {
|
|
201
|
-
const
|
|
196
|
+
const formData = {
|
|
202
197
|
uuid: 'test-action',
|
|
203
|
-
|
|
204
|
-
addresses: ['test@example.com'],
|
|
198
|
+
addresses: [{ name: 'test@example.com', value: 'test@example.com' }],
|
|
205
199
|
subject: '',
|
|
206
200
|
body: ''
|
|
207
201
|
};
|
|
208
202
|
|
|
209
|
-
const result = send_email.validate(
|
|
203
|
+
const result = send_email.validate(formData);
|
|
210
204
|
expect(result.valid).to.be.true;
|
|
211
205
|
expect(Object.keys(result.errors)).to.have.length(0);
|
|
212
206
|
});
|