@nyaruka/temba-components 0.131.1 → 0.131.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +4 -1
- package/CHANGELOG.md +75 -1
- package/demo/components/floating-tabs/example.html +400 -0
- package/demo/components/flow/index.html +1 -1
- package/demo/data/flows/food-order.json +2 -2
- package/demo/data/flows/sample-flow.json +113 -125
- package/demo/data/flows/voicemail.json +613 -0
- package/demo/index.html +6 -0
- package/dist/locales/es.js +5 -5
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +5 -5
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/locale-codes.js +11 -2
- package/dist/locales/locale-codes.js.map +1 -1
- package/dist/locales/pt.js +5 -5
- package/dist/locales/pt.js.map +1 -1
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +1773 -662
- 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/display/FloatingTab.js +167 -0
- package/out-tsc/src/display/FloatingTab.js.map +1 -0
- package/out-tsc/src/display/ProgressBar.js +22 -2
- package/out-tsc/src/display/ProgressBar.js.map +1 -1
- package/out-tsc/src/events.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +200 -0
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -0
- package/out-tsc/src/flow/CanvasNode.js +489 -47
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +1417 -67
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +479 -112
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/NodeTypeSelector.js +540 -0
- package/out-tsc/src/flow/NodeTypeSelector.js.map +1 -0
- package/out-tsc/src/flow/StickyNote.js +12 -3
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_groups.js +4 -3
- package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/add_contact_urn.js +63 -4
- package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
- package/out-tsc/src/flow/actions/add_input_labels.js +4 -3
- package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
- package/out-tsc/src/flow/actions/play_audio.js +3 -2
- package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
- package/out-tsc/src/flow/actions/remove_contact_groups.js +7 -5
- package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
- package/out-tsc/src/flow/actions/request_optin.js +3 -2
- package/out-tsc/src/flow/actions/request_optin.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +3 -2
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/send_broadcast.js +77 -23
- package/out-tsc/src/flow/actions/send_broadcast.js.map +1 -1
- package/out-tsc/src/flow/actions/send_email.js +5 -5
- package/out-tsc/src/flow/actions/send_email.js.map +1 -1
- package/out-tsc/src/flow/actions/send_msg.js +101 -21
- package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_channel.js +6 -9
- package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_field.js +20 -20
- package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_language.js +3 -2
- package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_name.js +3 -12
- package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
- package/out-tsc/src/flow/actions/set_contact_status.js +3 -2
- package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
- package/out-tsc/src/flow/actions/set_run_result.js +4 -3
- package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
- package/out-tsc/src/flow/actions/start_session.js +181 -6
- package/out-tsc/src/flow/actions/start_session.js.map +1 -1
- package/out-tsc/src/flow/config.js +11 -23
- 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 +71 -0
- package/out-tsc/src/flow/nodes/shared.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_airtime.js +211 -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 +152 -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 +73 -2
- package/out-tsc/src/flow/nodes/split_by_expression.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_groups.js +18 -10
- package/out-tsc/src/flow/nodes/split_by_groups.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_intent.js +8 -0
- package/out-tsc/src/flow/nodes/split_by_intent.js.map +1 -0
- package/out-tsc/src/flow/nodes/split_by_llm.js +11 -3
- package/out-tsc/src/flow/nodes/split_by_llm.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js +10 -3
- package/out-tsc/src/flow/nodes/split_by_llm_categorize.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_random.js +10 -4
- package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_resthook.js +113 -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 +211 -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 +158 -2
- package/out-tsc/src/flow/nodes/split_by_scheme.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_subflow.js +13 -5
- package/out-tsc/src/flow/nodes/split_by_subflow.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_ticket.js +10 -3
- package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
- package/out-tsc/src/flow/nodes/split_by_webhook.js +10 -3
- package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js +3 -2
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_menu.js +3 -2
- package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_response.js +38 -568
- package/out-tsc/src/flow/nodes/wait_for_response.js.map +1 -1
- package/out-tsc/src/flow/types.js +86 -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/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/layout/FloatingWindow.js +346 -0
- package/out-tsc/src/layout/FloatingWindow.js.map +1 -0
- 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 +6 -25
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/locales/es.js +5 -5
- package/out-tsc/src/locales/es.js.map +1 -1
- package/out-tsc/src/locales/fr.js +5 -5
- package/out-tsc/src/locales/fr.js.map +1 -1
- package/out-tsc/src/locales/locale-codes.js +11 -2
- package/out-tsc/src/locales/locale-codes.js.map +1 -1
- package/out-tsc/src/locales/pt.js +5 -5
- package/out-tsc/src/locales/pt.js.map +1 -1
- package/out-tsc/src/store/AppState.js +120 -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 +8 -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-floating-tab.test.js +91 -0
- package/out-tsc/test/temba-floating-tab.test.js.map +1 -0
- package/out-tsc/test/temba-floating-window.test.js +301 -0
- package/out-tsc/test/temba-floating-window.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor-node.test.js +202 -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-localization.test.js +471 -0
- package/out-tsc/test/temba-localization.test.js.map +1 -0
- 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 +265 -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 +20 -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/floating-tab/default.png +0 -0
- package/screenshots/truth/floating-tab/gray.png +0 -0
- package/screenshots/truth/floating-tab/green.png +0 -0
- package/screenshots/truth/floating-tab/hidden.png +0 -0
- package/screenshots/truth/floating-tab/hover.png +0 -0
- package/screenshots/truth/floating-tab/purple.png +0 -0
- package/screenshots/truth/floating-window/chromeless.png +0 -0
- package/screenshots/truth/floating-window/custom-size.png +0 -0
- package/screenshots/truth/floating-window/default.png +0 -0
- package/screenshots/truth/floating-window/with-header.png +0 -0
- package/screenshots/truth/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/display/FloatingTab.ts +174 -0
- package/src/display/ProgressBar.ts +22 -2
- package/src/events.ts +2 -8
- package/src/flow/CanvasMenu.ts +217 -0
- package/src/flow/CanvasNode.ts +596 -40
- package/src/flow/Editor.ts +1721 -45
- package/src/flow/NodeEditor.ts +621 -144
- package/src/flow/NodeTypeSelector.ts +636 -0
- package/src/flow/StickyNote.ts +12 -3
- package/src/flow/actions/add_contact_groups.ts +5 -4
- package/src/flow/actions/add_contact_urn.ts +78 -4
- package/src/flow/actions/add_input_labels.ts +5 -4
- package/src/flow/actions/play_audio.ts +3 -2
- package/src/flow/actions/remove_contact_groups.ts +16 -6
- package/src/flow/actions/request_optin.ts +3 -2
- package/src/flow/actions/say_msg.ts +3 -2
- package/src/flow/actions/send_broadcast.ts +86 -23
- package/src/flow/actions/send_email.ts +12 -6
- package/src/flow/actions/send_msg.ts +155 -34
- package/src/flow/actions/set_contact_channel.ts +6 -11
- package/src/flow/actions/set_contact_field.ts +21 -25
- package/src/flow/actions/set_contact_language.ts +11 -4
- package/src/flow/actions/set_contact_name.ts +4 -15
- package/src/flow/actions/set_contact_status.ts +4 -3
- package/src/flow/actions/set_run_result.ts +5 -4
- package/src/flow/actions/start_session.ts +210 -6
- package/src/flow/config.ts +11 -23
- package/src/flow/currencies.ts +51 -0
- package/src/flow/nodes/shared-rules.ts +301 -0
- package/src/flow/nodes/shared.ts +87 -0
- package/src/flow/nodes/split_by_airtime.ts +255 -5
- package/src/flow/nodes/split_by_contact_field.ts +195 -3
- package/src/flow/nodes/split_by_expression.ts +104 -2
- package/src/flow/nodes/split_by_groups.ts +26 -11
- package/src/flow/nodes/split_by_intent.ts +8 -0
- package/src/flow/nodes/split_by_llm.ts +22 -4
- package/src/flow/nodes/split_by_llm_categorize.ts +22 -5
- package/src/flow/nodes/split_by_random.ts +16 -6
- package/src/flow/nodes/split_by_resthook.ts +140 -0
- package/src/flow/nodes/split_by_run_result.ts +259 -3
- package/src/flow/nodes/split_by_scheme.ts +202 -2
- package/src/flow/nodes/split_by_subflow.ts +17 -5
- package/src/flow/nodes/split_by_ticket.ts +15 -4
- package/src/flow/nodes/split_by_webhook.ts +17 -6
- package/src/flow/nodes/wait_for_digits.ts +3 -2
- package/src/flow/nodes/wait_for_menu.ts +3 -2
- package/src/flow/nodes/wait_for_response.ts +59 -680
- package/src/flow/types.ts +156 -23
- package/src/flow/utils.ts +108 -14
- package/src/form/FieldRenderer.ts +2 -4
- package/src/interfaces.ts +3 -0
- package/src/layout/FloatingWindow.ts +386 -0
- package/src/list/SortableList.ts +109 -34
- package/src/live/ContactChat.ts +7 -25
- package/src/locales/es.ts +18 -13
- package/src/locales/fr.ts +18 -13
- package/src/locales/locale-codes.ts +11 -2
- package/src/locales/pt.ts +18 -13
- package/src/store/AppState.ts +173 -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/llms.json +18 -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 +8 -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-floating-tab.test.ts +110 -0
- package/test/temba-floating-window.test.ts +477 -0
- package/test/temba-flow-editor-node.test.ts +246 -2
- package/test/temba-flow-editor.test.ts +7 -8
- package/test/temba-localization.test.ts +611 -0
- package/test/temba-node-editor.test.ts +3 -1
- package/test/temba-node-type-selector.test.ts +355 -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 +22 -0
- package/test-assets/contacts/history.json +14 -21
- package/test-assets/select/llms.json +2 -2
- package/web-dev-server.config.mjs +49 -1
- package/web-test-runner.config.mjs +0 -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/out-tsc/src/flow/nodes/wait_for_audio.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_image.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_image.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_location.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_location.js.map +0 -1
- package/out-tsc/src/flow/nodes/wait_for_video.js +0 -7
- package/out-tsc/src/flow/nodes/wait_for_video.js.map +0 -1
- package/src/flow/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/nodes/wait_for_audio.ts +0 -7
- package/src/flow/nodes/wait_for_image.ts +0 -7
- package/src/flow/nodes/wait_for_location.ts +0 -7
- package/src/flow/nodes/wait_for_video.ts +0 -7
package/src/locales/fr.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
// Do not modify this file by hand!
|
|
3
|
+
// Re-generate this file by running lit-localize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
+
|
|
11
|
+
export const templates = {
|
|
12
|
+
's73b4d70c02f4b4e0': `No options`,
|
|
13
|
+
'scf1453991c986b25': `Tab to complete, enter to select`,
|
|
14
|
+
's8f02e3a18ffc083a': `Are not currently in a flow`,
|
|
15
|
+
's638236250662c6b3': `Have sent a message in the last`,
|
|
16
|
+
's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
|
|
17
|
+
};
|
|
18
|
+
|
|
@@ -10,9 +10,18 @@ export const sourceLocale = `en`;
|
|
|
10
10
|
* The other locale codes that this application is localized into. Sorted
|
|
11
11
|
* lexicographically.
|
|
12
12
|
*/
|
|
13
|
-
export const targetLocales = [
|
|
13
|
+
export const targetLocales = [
|
|
14
|
+
`es`,
|
|
15
|
+
`fr`,
|
|
16
|
+
`pt`,
|
|
17
|
+
] as const;
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* All valid project locale codes. Sorted lexicographically.
|
|
17
21
|
*/
|
|
18
|
-
export const allLocales = [
|
|
22
|
+
export const allLocales = [
|
|
23
|
+
`en`,
|
|
24
|
+
`es`,
|
|
25
|
+
`fr`,
|
|
26
|
+
`pt`,
|
|
27
|
+
] as const;
|
package/src/locales/pt.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
|
|
2
|
+
// Do not modify this file by hand!
|
|
3
|
+
// Re-generate this file by running lit-localize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
|
+
|
|
11
|
+
export const templates = {
|
|
12
|
+
's73b4d70c02f4b4e0': `No options`,
|
|
13
|
+
'scf1453991c986b25': `Tab to complete, enter to select`,
|
|
14
|
+
's8f02e3a18ffc083a': `Are not currently in a flow`,
|
|
15
|
+
's638236250662c6b3': `Have sent a message in the last`,
|
|
16
|
+
's4788ee206c4570c7': `Have not started this flow in the last 90 days`,
|
|
17
|
+
};
|
|
18
|
+
|
package/src/store/AppState.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
FlowDefinition,
|
|
7
7
|
FlowPosition,
|
|
8
8
|
Node,
|
|
9
|
+
NodeUI,
|
|
9
10
|
Router,
|
|
10
11
|
StickyNote
|
|
11
12
|
} from './flow-definition';
|
|
@@ -95,6 +96,7 @@ export interface AppState {
|
|
|
95
96
|
uuid: string,
|
|
96
97
|
node: { actions: Action[]; uuid: string; exits: Exit[]; router?: Router }
|
|
97
98
|
): unknown;
|
|
99
|
+
updateNodeUIConfig(uuid: string, config: Record<string, any>): unknown;
|
|
98
100
|
updateConnection(
|
|
99
101
|
nodeUuid: string,
|
|
100
102
|
exitUuid: string,
|
|
@@ -105,6 +107,19 @@ export interface AppState {
|
|
|
105
107
|
removeStickyNotes: (uuids: string[]) => void;
|
|
106
108
|
updateStickyNote(uuid: string, sticky: StickyNote): void;
|
|
107
109
|
createStickyNote(position: FlowPosition): string;
|
|
110
|
+
createNode(nodeType: string, position: FlowPosition): string;
|
|
111
|
+
addNode(node: Node, nodeUI: NodeUI): void;
|
|
112
|
+
updateLocalization(
|
|
113
|
+
languageCode: string,
|
|
114
|
+
actionUuid: string,
|
|
115
|
+
localizationData: Record<string, any>
|
|
116
|
+
): void;
|
|
117
|
+
setTranslationFilters: (filters: { categories: boolean }) => void;
|
|
118
|
+
markAutoTranslated: (
|
|
119
|
+
languageCode: string,
|
|
120
|
+
uuid: string,
|
|
121
|
+
attributes: string[]
|
|
122
|
+
) => void;
|
|
108
123
|
}
|
|
109
124
|
|
|
110
125
|
export const zustand = createStore<AppState>()(
|
|
@@ -290,6 +305,18 @@ export const zustand = createStore<AppState>()(
|
|
|
290
305
|
});
|
|
291
306
|
},
|
|
292
307
|
|
|
308
|
+
updateNodeUIConfig: (uuid: string, config: Record<string, any>) => {
|
|
309
|
+
set((state: AppState) => {
|
|
310
|
+
if (state.flowDefinition._ui.nodes[uuid]) {
|
|
311
|
+
if (!state.flowDefinition._ui.nodes[uuid].config) {
|
|
312
|
+
state.flowDefinition._ui.nodes[uuid].config = {};
|
|
313
|
+
}
|
|
314
|
+
Object.assign(state.flowDefinition._ui.nodes[uuid].config, config);
|
|
315
|
+
}
|
|
316
|
+
state.dirtyDate = new Date();
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
|
|
293
320
|
updateConnection: (
|
|
294
321
|
nodeUuid: string,
|
|
295
322
|
exitUuid: string,
|
|
@@ -338,6 +365,152 @@ export const zustand = createStore<AppState>()(
|
|
|
338
365
|
state.dirtyDate = new Date();
|
|
339
366
|
});
|
|
340
367
|
return uuid;
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
createNode: (nodeType: string, position: FlowPosition): string => {
|
|
371
|
+
const uuid = generateUUID();
|
|
372
|
+
const exitUuid = generateUUID();
|
|
373
|
+
|
|
374
|
+
set((state: AppState) => {
|
|
375
|
+
// Create a basic node with a single exit
|
|
376
|
+
const newNode: Node = {
|
|
377
|
+
uuid,
|
|
378
|
+
actions: [],
|
|
379
|
+
exits: [
|
|
380
|
+
{
|
|
381
|
+
uuid: exitUuid,
|
|
382
|
+
destination_uuid: null
|
|
383
|
+
}
|
|
384
|
+
]
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// Add the node to the flow definition
|
|
388
|
+
state.flowDefinition.nodes.push(newNode);
|
|
389
|
+
|
|
390
|
+
// Set up UI for the node
|
|
391
|
+
if (!state.flowDefinition._ui.nodes) {
|
|
392
|
+
state.flowDefinition._ui.nodes = {};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
state.flowDefinition._ui.nodes[uuid] = {
|
|
396
|
+
position,
|
|
397
|
+
type: nodeType as any,
|
|
398
|
+
config: {}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
state.dirtyDate = new Date();
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
return uuid;
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
addNode: (node: Node, nodeUI: NodeUI) => {
|
|
408
|
+
set((state: AppState) => {
|
|
409
|
+
// Add the node to the flow definition
|
|
410
|
+
state.flowDefinition.nodes.push(node);
|
|
411
|
+
|
|
412
|
+
// Set up UI for the node
|
|
413
|
+
if (!state.flowDefinition._ui.nodes) {
|
|
414
|
+
state.flowDefinition._ui.nodes = {};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
state.flowDefinition._ui.nodes[node.uuid] = nodeUI;
|
|
418
|
+
|
|
419
|
+
state.dirtyDate = new Date();
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
updateLocalization: (
|
|
424
|
+
languageCode: string,
|
|
425
|
+
actionUuid: string,
|
|
426
|
+
localizationData: Record<string, any>
|
|
427
|
+
) => {
|
|
428
|
+
set((state: AppState) => {
|
|
429
|
+
// Initialize localization structure if it doesn't exist
|
|
430
|
+
if (!state.flowDefinition.localization) {
|
|
431
|
+
state.flowDefinition.localization = {};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (!state.flowDefinition.localization[languageCode]) {
|
|
435
|
+
state.flowDefinition.localization[languageCode] = {};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Update or remove the localization for this action
|
|
439
|
+
if (Object.keys(localizationData).length > 0) {
|
|
440
|
+
state.flowDefinition.localization[languageCode][actionUuid] =
|
|
441
|
+
localizationData;
|
|
442
|
+
} else {
|
|
443
|
+
// If no localized values, remove the entry
|
|
444
|
+
delete state.flowDefinition.localization[languageCode][actionUuid];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Clean up empty language sections
|
|
448
|
+
if (
|
|
449
|
+
Object.keys(state.flowDefinition.localization[languageCode])
|
|
450
|
+
.length === 0
|
|
451
|
+
) {
|
|
452
|
+
delete state.flowDefinition.localization[languageCode];
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Clean up empty localization object
|
|
456
|
+
if (Object.keys(state.flowDefinition.localization).length === 0) {
|
|
457
|
+
delete state.flowDefinition.localization;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
state.dirtyDate = new Date();
|
|
461
|
+
});
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
setTranslationFilters: (filters: { categories: boolean }) => {
|
|
465
|
+
set((state: AppState) => {
|
|
466
|
+
if (!state.flowDefinition?._ui) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const currentFilters = state.flowDefinition._ui
|
|
471
|
+
.translation_filters || {
|
|
472
|
+
categories: false
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
state.flowDefinition._ui.translation_filters = {
|
|
476
|
+
...currentFilters,
|
|
477
|
+
categories: !!filters.categories
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
state.dirtyDate = new Date();
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
markAutoTranslated: (
|
|
485
|
+
languageCode: string,
|
|
486
|
+
uuid: string,
|
|
487
|
+
attributes: string[]
|
|
488
|
+
) => {
|
|
489
|
+
set((state: AppState) => {
|
|
490
|
+
if (!state.flowDefinition?._ui) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (!state.flowDefinition._ui.auto_translations) {
|
|
495
|
+
state.flowDefinition._ui.auto_translations = {};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (!state.flowDefinition._ui.auto_translations[languageCode]) {
|
|
499
|
+
state.flowDefinition._ui.auto_translations[languageCode] = {};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const existing =
|
|
503
|
+
state.flowDefinition._ui.auto_translations[languageCode][uuid] ||
|
|
504
|
+
[];
|
|
505
|
+
|
|
506
|
+
const merged = Array.from(
|
|
507
|
+
new Set([...existing, ...(attributes || [])])
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
state.flowDefinition._ui.auto_translations[languageCode][uuid] =
|
|
511
|
+
merged;
|
|
512
|
+
state.dirtyDate = new Date();
|
|
513
|
+
});
|
|
341
514
|
}
|
|
342
515
|
}))
|
|
343
516
|
)
|
|
@@ -147,6 +147,7 @@ export interface SendBroadcast extends Action {
|
|
|
147
147
|
text: string;
|
|
148
148
|
groups: Group[];
|
|
149
149
|
contacts: NamedObject[];
|
|
150
|
+
attachments?: string[];
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
export interface EnterFlow extends Action {
|
|
@@ -161,26 +162,22 @@ export interface StartSession extends Action {
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
export interface TransferAirtime extends Action {
|
|
164
|
-
amounts: number
|
|
165
|
-
result_name: string;
|
|
165
|
+
amounts: Record<string, number>;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
export interface CallClassifier extends Action {
|
|
169
169
|
classifier: NamedObject;
|
|
170
170
|
input: string;
|
|
171
|
-
result_name: string;
|
|
172
171
|
}
|
|
173
172
|
|
|
174
173
|
export interface CallResthook extends Action {
|
|
175
174
|
resthook: string;
|
|
176
|
-
result_name: string;
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
export interface CallLLM extends Action {
|
|
180
178
|
llm: NamedObject;
|
|
181
179
|
instructions: string;
|
|
182
180
|
input: string;
|
|
183
|
-
result_name?: string;
|
|
184
181
|
output_local?: string;
|
|
185
182
|
}
|
|
186
183
|
|
package/src/utils.ts
CHANGED
|
@@ -514,18 +514,6 @@ export class Stubbable {
|
|
|
514
514
|
|
|
515
515
|
export const stubbable = new Stubbable();
|
|
516
516
|
|
|
517
|
-
export const spreadAttributes = (obj): TemplateResult[] => {
|
|
518
|
-
return Object.entries(obj).map(([key, value]) => {
|
|
519
|
-
if (key.startsWith('@')) {
|
|
520
|
-
return html`@${key.slice(1)}=${value}`;
|
|
521
|
-
} else if (key.startsWith('.')) {
|
|
522
|
-
return html`.${key.slice(1)}=${value}`;
|
|
523
|
-
} else {
|
|
524
|
-
return html`${key}=${value}`;
|
|
525
|
-
}
|
|
526
|
-
});
|
|
527
|
-
};
|
|
528
|
-
|
|
529
517
|
export const timeSince = (
|
|
530
518
|
date: Date,
|
|
531
519
|
options: { compareDate?: Date; hideRecentText?: boolean; suffix?: string } = {
|
|
@@ -1125,6 +1113,338 @@ export const createMultiCategoryRouter = (
|
|
|
1125
1113
|
};
|
|
1126
1114
|
};
|
|
1127
1115
|
|
|
1116
|
+
// Helper function to check if a category is a system category
|
|
1117
|
+
export const isSystemCategory = (categoryName: string): boolean => {
|
|
1118
|
+
return ['No Response', 'Other', 'All Responses', 'Timeout'].includes(
|
|
1119
|
+
categoryName
|
|
1120
|
+
);
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
// Helper function to check if a UUID belongs to a system category
|
|
1124
|
+
export const isSystemCategoryUuid = (
|
|
1125
|
+
uuid: string,
|
|
1126
|
+
categories: any[]
|
|
1127
|
+
): boolean => {
|
|
1128
|
+
const category = categories.find((cat) => cat.uuid === uuid);
|
|
1129
|
+
return category ? isSystemCategory(category.name) : false;
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// Helper function to generate default category name based on operator and operands
|
|
1133
|
+
export const generateDefaultCategoryName = (
|
|
1134
|
+
operator: string,
|
|
1135
|
+
getOperatorConfig: (type: string) => any | undefined,
|
|
1136
|
+
value1?: string,
|
|
1137
|
+
value2?: string
|
|
1138
|
+
): string => {
|
|
1139
|
+
const operatorConfig = getOperatorConfig(operator);
|
|
1140
|
+
if (!operatorConfig) return '';
|
|
1141
|
+
|
|
1142
|
+
// Fixed category names (no operands)
|
|
1143
|
+
if (operatorConfig.operands === 0) {
|
|
1144
|
+
return operatorConfig.categoryName || '';
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Dynamic category names based on operands
|
|
1148
|
+
const cleanValue1 = (value1 || '').trim();
|
|
1149
|
+
const cleanValue2 = (value2 || '').trim();
|
|
1150
|
+
|
|
1151
|
+
// Helper to capitalize first letter
|
|
1152
|
+
const capitalize = (str: string) => {
|
|
1153
|
+
if (!str) return '';
|
|
1154
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
// Handle different operator types
|
|
1158
|
+
switch (operator) {
|
|
1159
|
+
// Word/phrase operators - capitalize first letter of value
|
|
1160
|
+
case 'has_any_word':
|
|
1161
|
+
case 'has_all_words':
|
|
1162
|
+
case 'has_phrase':
|
|
1163
|
+
case 'has_only_phrase':
|
|
1164
|
+
case 'has_beginning':
|
|
1165
|
+
return cleanValue1 ? capitalize(cleanValue1) : '';
|
|
1166
|
+
|
|
1167
|
+
// Pattern operators - show as-is
|
|
1168
|
+
case 'has_pattern':
|
|
1169
|
+
return cleanValue1;
|
|
1170
|
+
|
|
1171
|
+
// Number comparison operators - include symbol
|
|
1172
|
+
case 'has_number_eq':
|
|
1173
|
+
return cleanValue1 ? `= ${cleanValue1}` : '';
|
|
1174
|
+
case 'has_number_lt':
|
|
1175
|
+
return cleanValue1 ? `< ${cleanValue1}` : '';
|
|
1176
|
+
case 'has_number_lte':
|
|
1177
|
+
return cleanValue1 ? `≤ ${cleanValue1}` : '';
|
|
1178
|
+
case 'has_number_gt':
|
|
1179
|
+
return cleanValue1 ? `> ${cleanValue1}` : '';
|
|
1180
|
+
case 'has_number_gte':
|
|
1181
|
+
return cleanValue1 ? `≥ ${cleanValue1}` : '';
|
|
1182
|
+
|
|
1183
|
+
// Number between - range format
|
|
1184
|
+
case 'has_number_between':
|
|
1185
|
+
if (cleanValue1 && cleanValue2) {
|
|
1186
|
+
return `${cleanValue1} - ${cleanValue2}`;
|
|
1187
|
+
}
|
|
1188
|
+
return '';
|
|
1189
|
+
|
|
1190
|
+
// Date operators - format with relative expressions
|
|
1191
|
+
case 'has_date_lt':
|
|
1192
|
+
case 'has_date_lte':
|
|
1193
|
+
if (cleanValue1) {
|
|
1194
|
+
// Parse relative date expression (e.g., "today + 5" or "today - 3")
|
|
1195
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
1196
|
+
if (match) {
|
|
1197
|
+
const [, base, operator, days] = match;
|
|
1198
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
1199
|
+
return `Before ${base} ${operator} ${days} ${dayWord}`;
|
|
1200
|
+
}
|
|
1201
|
+
// Fallback for other date formats
|
|
1202
|
+
return `Before ${cleanValue1}`;
|
|
1203
|
+
}
|
|
1204
|
+
return '';
|
|
1205
|
+
|
|
1206
|
+
case 'has_date_gt':
|
|
1207
|
+
case 'has_date_gte':
|
|
1208
|
+
if (cleanValue1) {
|
|
1209
|
+
// Parse relative date expression
|
|
1210
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
1211
|
+
if (match) {
|
|
1212
|
+
const [, base, operator, days] = match;
|
|
1213
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
1214
|
+
return `After ${base} ${operator} ${days} ${dayWord}`;
|
|
1215
|
+
}
|
|
1216
|
+
// Fallback for other date formats
|
|
1217
|
+
return `After ${cleanValue1}`;
|
|
1218
|
+
}
|
|
1219
|
+
return '';
|
|
1220
|
+
|
|
1221
|
+
case 'has_date_eq':
|
|
1222
|
+
if (cleanValue1) {
|
|
1223
|
+
// Parse relative date expression
|
|
1224
|
+
const match = cleanValue1.match(/^(today)\s*([+-])\s*(\d+)$/i);
|
|
1225
|
+
if (match) {
|
|
1226
|
+
const [, base, operator, days] = match;
|
|
1227
|
+
const dayWord = days === '1' ? 'day' : 'days';
|
|
1228
|
+
return `${base} ${operator} ${days} ${dayWord}`;
|
|
1229
|
+
}
|
|
1230
|
+
return cleanValue1;
|
|
1231
|
+
}
|
|
1232
|
+
return '';
|
|
1233
|
+
|
|
1234
|
+
default:
|
|
1235
|
+
// Fallback - capitalize first value
|
|
1236
|
+
return cleanValue1 ? capitalize(cleanValue1) : '';
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1240
|
+
// Helper function to create a rules-based router (used by wait_for_response and split_by_expression)
|
|
1241
|
+
export const createRulesRouter = (
|
|
1242
|
+
operand: string,
|
|
1243
|
+
userRules: any[],
|
|
1244
|
+
getOperatorConfig: (type: string) => any | undefined,
|
|
1245
|
+
existingCategories: any[] = [],
|
|
1246
|
+
existingExits: any[] = [],
|
|
1247
|
+
existingCases: any[] = []
|
|
1248
|
+
) => {
|
|
1249
|
+
const categories: RouterCategory[] = [];
|
|
1250
|
+
const exits: RouterExit[] = [];
|
|
1251
|
+
const cases: RouterCase[] = [];
|
|
1252
|
+
|
|
1253
|
+
// Filter existing categories to get only user-defined rules (exclude system categories)
|
|
1254
|
+
const existingUserCategories = existingCategories.filter(
|
|
1255
|
+
(cat) => !isSystemCategory(cat.name)
|
|
1256
|
+
);
|
|
1257
|
+
|
|
1258
|
+
// Track categories as we create them (case-insensitive lookup)
|
|
1259
|
+
const createdCategories = new Map<
|
|
1260
|
+
string,
|
|
1261
|
+
{ uuid: string; name: string; exit_uuid: string }
|
|
1262
|
+
>();
|
|
1263
|
+
|
|
1264
|
+
// Process rules in their original order to preserve rule order
|
|
1265
|
+
userRules.forEach((rule, ruleIndex) => {
|
|
1266
|
+
const categoryKey = rule.category.trim().toLowerCase();
|
|
1267
|
+
const categoryName = rule.category.trim(); // Use original casing
|
|
1268
|
+
|
|
1269
|
+
let categoryInfo = createdCategories.get(categoryKey);
|
|
1270
|
+
|
|
1271
|
+
if (!categoryInfo) {
|
|
1272
|
+
// First time seeing this category - create it
|
|
1273
|
+
|
|
1274
|
+
// Smart category matching: try by name first, then fall back to position
|
|
1275
|
+
let existingCategory = existingUserCategories.find(
|
|
1276
|
+
(cat) => cat.name.toLowerCase() === categoryKey
|
|
1277
|
+
);
|
|
1278
|
+
|
|
1279
|
+
// If no match by name, try by position (for category rename scenarios)
|
|
1280
|
+
const categoryCreationOrder = Array.from(createdCategories.keys()).length;
|
|
1281
|
+
if (
|
|
1282
|
+
!existingCategory &&
|
|
1283
|
+
categoryCreationOrder < existingUserCategories.length
|
|
1284
|
+
) {
|
|
1285
|
+
const candidateCategory = existingUserCategories[categoryCreationOrder];
|
|
1286
|
+
// Double-check that this candidate is not a system category UUID
|
|
1287
|
+
if (
|
|
1288
|
+
candidateCategory &&
|
|
1289
|
+
!isSystemCategoryUuid(candidateCategory.uuid, existingCategories)
|
|
1290
|
+
) {
|
|
1291
|
+
existingCategory = candidateCategory;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
const existingExit = existingCategory
|
|
1296
|
+
? existingExits.find((exit) => exit.uuid === existingCategory.exit_uuid)
|
|
1297
|
+
: null;
|
|
1298
|
+
|
|
1299
|
+
// Generate UUIDs, ensuring we don't reuse system category UUIDs
|
|
1300
|
+
let exitUuid = existingExit?.uuid || generateUUID();
|
|
1301
|
+
let categoryUuid = existingCategory?.uuid || generateUUID();
|
|
1302
|
+
|
|
1303
|
+
// Additional safety check: if somehow we got a system category UUID, generate new ones
|
|
1304
|
+
if (isSystemCategoryUuid(categoryUuid, existingCategories)) {
|
|
1305
|
+
categoryUuid = generateUUID();
|
|
1306
|
+
exitUuid = generateUUID();
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
categoryInfo = {
|
|
1310
|
+
uuid: categoryUuid,
|
|
1311
|
+
name: categoryName,
|
|
1312
|
+
exit_uuid: exitUuid
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
createdCategories.set(categoryKey, categoryInfo);
|
|
1316
|
+
|
|
1317
|
+
// Add category and exit
|
|
1318
|
+
categories.push({
|
|
1319
|
+
uuid: categoryUuid,
|
|
1320
|
+
name: categoryName,
|
|
1321
|
+
exit_uuid: exitUuid
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
exits.push({
|
|
1325
|
+
uuid: exitUuid,
|
|
1326
|
+
destination_uuid: existingExit?.destination_uuid || null
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// Create case for this rule
|
|
1331
|
+
let existingCase = existingCases[ruleIndex];
|
|
1332
|
+
|
|
1333
|
+
// If we can't find by position, try to find by matching rule content
|
|
1334
|
+
if (!existingCase && existingCases.length > 0) {
|
|
1335
|
+
existingCase = existingCases.find((case_) => {
|
|
1336
|
+
// Find the category for this case
|
|
1337
|
+
const caseCategory = existingCategories.find(
|
|
1338
|
+
(cat) => cat.uuid === case_.category_uuid
|
|
1339
|
+
);
|
|
1340
|
+
|
|
1341
|
+
// Match by operator type and category name
|
|
1342
|
+
return (
|
|
1343
|
+
case_.type === rule.operator &&
|
|
1344
|
+
caseCategory?.name.toLowerCase() === categoryKey
|
|
1345
|
+
);
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
const caseUuid = existingCase?.uuid || generateUUID();
|
|
1350
|
+
|
|
1351
|
+
// Parse rule value based on operator configuration
|
|
1352
|
+
const operatorConfig = getOperatorConfig(rule.operator);
|
|
1353
|
+
let arguments_: string[] = [];
|
|
1354
|
+
|
|
1355
|
+
if (operatorConfig) {
|
|
1356
|
+
if (operatorConfig.operands === 0) {
|
|
1357
|
+
// No operands needed
|
|
1358
|
+
arguments_ = [];
|
|
1359
|
+
} else if (operatorConfig.operands === 2) {
|
|
1360
|
+
// Split value for two operands (e.g., "1 10" for between)
|
|
1361
|
+
arguments_ = rule.value.split(' ').filter((arg: string) => arg.trim());
|
|
1362
|
+
} else {
|
|
1363
|
+
// Single operand - but split words for operators that expect multiple words
|
|
1364
|
+
if (rule.value && rule.value.trim()) {
|
|
1365
|
+
// Split on spaces and filter out empty strings
|
|
1366
|
+
arguments_ = rule.value
|
|
1367
|
+
.trim()
|
|
1368
|
+
.split(/\s+/)
|
|
1369
|
+
.filter((arg: string) => arg.length > 0);
|
|
1370
|
+
} else {
|
|
1371
|
+
arguments_ = [];
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
} else {
|
|
1375
|
+
// Fallback for unknown operators - split on spaces if value exists
|
|
1376
|
+
if (rule.value && rule.value.trim()) {
|
|
1377
|
+
arguments_ = rule.value
|
|
1378
|
+
.trim()
|
|
1379
|
+
.split(/\s+/)
|
|
1380
|
+
.filter((arg: string) => arg.length > 0);
|
|
1381
|
+
} else {
|
|
1382
|
+
arguments_ = [];
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
cases.push({
|
|
1387
|
+
uuid: caseUuid,
|
|
1388
|
+
type: rule.operator,
|
|
1389
|
+
arguments: arguments_,
|
|
1390
|
+
category_uuid: categoryInfo.uuid
|
|
1391
|
+
});
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
// Add default category (always present)
|
|
1395
|
+
// Name is "Other" if there are user rules, "All Responses" if there are no user rules
|
|
1396
|
+
const defaultCategoryName = userRules.length > 0 ? 'Other' : 'All Responses';
|
|
1397
|
+
|
|
1398
|
+
// Try to find existing default category by name (prefer exact match)
|
|
1399
|
+
let existingDefaultCategory = existingCategories.find(
|
|
1400
|
+
(cat) => cat.name === defaultCategoryName
|
|
1401
|
+
);
|
|
1402
|
+
|
|
1403
|
+
// If no exact match, try to find the other possible default category name
|
|
1404
|
+
if (!existingDefaultCategory) {
|
|
1405
|
+
const alternateName = userRules.length > 0 ? 'All Responses' : 'Other';
|
|
1406
|
+
existingDefaultCategory = existingCategories.find(
|
|
1407
|
+
(cat) => cat.name === alternateName
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
const existingDefaultExit = existingDefaultCategory
|
|
1412
|
+
? existingExits.find(
|
|
1413
|
+
(exit) => exit.uuid === existingDefaultCategory.exit_uuid
|
|
1414
|
+
)
|
|
1415
|
+
: null;
|
|
1416
|
+
|
|
1417
|
+
const defaultExitUuid = existingDefaultExit?.uuid || generateUUID();
|
|
1418
|
+
const defaultCategoryUuid = existingDefaultCategory?.uuid || generateUUID();
|
|
1419
|
+
|
|
1420
|
+
categories.push({
|
|
1421
|
+
uuid: defaultCategoryUuid,
|
|
1422
|
+
name: defaultCategoryName,
|
|
1423
|
+
exit_uuid: defaultExitUuid
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
exits.push({
|
|
1427
|
+
uuid: defaultExitUuid,
|
|
1428
|
+
destination_uuid: existingDefaultExit?.destination_uuid || null
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
// Find the default category (either "Other" or "All Responses")
|
|
1432
|
+
const defaultCategory = categories.find(
|
|
1433
|
+
(cat) => cat.name === 'Other' || cat.name === 'All Responses'
|
|
1434
|
+
);
|
|
1435
|
+
|
|
1436
|
+
return {
|
|
1437
|
+
router: {
|
|
1438
|
+
type: 'switch' as const,
|
|
1439
|
+
categories: categories,
|
|
1440
|
+
default_category_uuid: defaultCategory?.uuid,
|
|
1441
|
+
operand: operand,
|
|
1442
|
+
cases: cases
|
|
1443
|
+
},
|
|
1444
|
+
exits: exits
|
|
1445
|
+
};
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1128
1448
|
export const titleCase = (str: string) => {
|
|
1129
1449
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
1130
1450
|
};
|