@nyaruka/temba-components 0.138.6 → 0.140.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/cla.yml +1 -1
- package/.github/workflows/copilot-setup-steps.yml +6 -1
- package/CHANGELOG.md +26 -0
- package/demo/data/flows/sample-flow.json +24 -0
- package/dist/locales/es.js +5 -5
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/fr.js +5 -5
- package/dist/locales/fr.js.map +1 -1
- package/dist/locales/locale-codes.js +2 -11
- package/dist/locales/locale-codes.js.map +1 -1
- package/dist/locales/pt.js +5 -5
- package/dist/locales/pt.js.map +1 -1
- package/dist/temba-components.js +1112 -882
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +10 -7
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/display/Dropdown.js +3 -1
- package/out-tsc/src/display/Dropdown.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +25 -32
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/display/Thumbnail.js +163 -5
- package/out-tsc/src/display/Thumbnail.js.map +1 -1
- package/out-tsc/src/flow/CanvasMenu.js +5 -3
- package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +70 -29
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +290 -239
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +118 -10
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +757 -403
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/flow/StickyNote.js +13 -4
- package/out-tsc/src/flow/StickyNote.js.map +1 -1
- package/out-tsc/src/flow/actions/audio-player.js +112 -0
- package/out-tsc/src/flow/actions/audio-player.js.map +1 -0
- package/out-tsc/src/flow/actions/enter_flow.js +43 -0
- package/out-tsc/src/flow/actions/enter_flow.js.map +1 -0
- package/out-tsc/src/flow/actions/play_audio.js +57 -4
- package/out-tsc/src/flow/actions/play_audio.js.map +1 -1
- package/out-tsc/src/flow/actions/say_msg.js +86 -3
- package/out-tsc/src/flow/actions/say_msg.js.map +1 -1
- package/out-tsc/src/flow/config.js +11 -3
- package/out-tsc/src/flow/config.js.map +1 -1
- package/out-tsc/src/flow/nodes/shared-rules.js +1 -1
- package/out-tsc/src/flow/nodes/shared-rules.js.map +1 -1
- package/out-tsc/src/flow/nodes/terminal.js +7 -0
- package/out-tsc/src/flow/nodes/terminal.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js +77 -0
- package/out-tsc/src/flow/nodes/wait_for_audio.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_dial.js +151 -0
- package/out-tsc/src/flow/nodes/wait_for_dial.js.map +1 -0
- package/out-tsc/src/flow/nodes/wait_for_digits.js +61 -1
- package/out-tsc/src/flow/nodes/wait_for_digits.js.map +1 -1
- package/out-tsc/src/flow/nodes/wait_for_menu.js +173 -2
- package/out-tsc/src/flow/nodes/wait_for_menu.js.map +1 -1
- package/out-tsc/src/flow/operators.js +21 -5
- package/out-tsc/src/flow/operators.js.map +1 -1
- package/out-tsc/src/flow/types.js.map +1 -1
- package/out-tsc/src/flow/utils.js +213 -65
- package/out-tsc/src/flow/utils.js.map +1 -1
- package/out-tsc/src/form/ArrayEditor.js +4 -2
- package/out-tsc/src/form/ArrayEditor.js.map +1 -1
- package/out-tsc/src/form/FieldRenderer.js +49 -0
- package/out-tsc/src/form/FieldRenderer.js.map +1 -1
- package/out-tsc/src/interfaces.js +2 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/Dialog.js +52 -7
- package/out-tsc/src/layout/Dialog.js.map +1 -1
- package/out-tsc/src/list/TicketList.js +4 -1
- package/out-tsc/src/list/TicketList.js.map +1 -1
- package/out-tsc/src/live/TembaChart.js.map +1 -1
- package/out-tsc/src/locales/es.js +5 -5
- package/out-tsc/src/locales/es.js.map +1 -1
- package/out-tsc/src/locales/fr.js +5 -5
- package/out-tsc/src/locales/fr.js.map +1 -1
- package/out-tsc/src/locales/locale-codes.js +2 -11
- package/out-tsc/src/locales/locale-codes.js.map +1 -1
- package/out-tsc/src/locales/pt.js +5 -5
- package/out-tsc/src/locales/pt.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +10 -3
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +89 -3
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/test/actions/play_audio.test.js +118 -0
- package/out-tsc/test/actions/play_audio.test.js.map +1 -0
- package/out-tsc/test/actions/say_msg.test.js +158 -0
- package/out-tsc/test/actions/say_msg.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_audio.test.js +156 -0
- package/out-tsc/test/nodes/wait_for_audio.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_dial.test.js +336 -0
- package/out-tsc/test/nodes/wait_for_dial.test.js.map +1 -0
- package/out-tsc/test/nodes/wait_for_digits.test.js +198 -84
- package/out-tsc/test/nodes/wait_for_digits.test.js.map +1 -1
- package/out-tsc/test/nodes/wait_for_menu.test.js +340 -0
- package/out-tsc/test/nodes/wait_for_menu.test.js.map +1 -0
- package/out-tsc/test/temba-floating-tab.test.js +4 -6
- package/out-tsc/test/temba-floating-tab.test.js.map +1 -1
- package/out-tsc/test/temba-flow-collision.test.js +473 -220
- package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +0 -2
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js +83 -84
- package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +102 -93
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-node-type-selector.test.js +6 -6
- package/out-tsc/test/temba-node-type-selector.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/actions/play_audio/editor/expression-url.png +0 -0
- package/screenshots/truth/actions/play_audio/editor/static-url.png +0 -0
- package/screenshots/truth/actions/play_audio/render/expression-url.png +0 -0
- package/screenshots/truth/actions/play_audio/render/static-url.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/editor/text-with-audio-url.png +0 -0
- package/screenshots/truth/actions/say_msg/render/multiline-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/simple-text.png +0 -0
- package/screenshots/truth/actions/say_msg/render/text-with-audio-url.png +0 -0
- package/screenshots/truth/editor/router.png +0 -0
- package/screenshots/truth/editor/wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_audio/editor/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_audio/render/basic-audio-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/editor/basic-dial.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/editor/dial-with-limits.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/basic-dial.png +0 -0
- package/screenshots/truth/nodes/wait_for_dial/render/dial-with-limits.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/basic-digits-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/digits-with-rules.png +0 -0
- package/screenshots/truth/nodes/wait_for_menu/editor/menu-with-digits.png +0 -0
- package/screenshots/truth/nodes/wait_for_menu/render/menu-with-digits.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/editor/short-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/basic-wait.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/custom-result-name.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/no-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_response/render/short-timeout.png +0 -0
- package/src/display/Chat.ts +13 -7
- package/src/display/Dropdown.ts +3 -1
- package/src/display/FloatingTab.ts +24 -33
- package/src/display/Thumbnail.ts +162 -2
- package/src/flow/CanvasMenu.ts +8 -3
- package/src/flow/CanvasNode.ts +75 -30
- package/src/flow/Editor.ts +336 -288
- package/src/flow/NodeEditor.ts +137 -9
- package/src/flow/Plumber.ts +1011 -457
- package/src/flow/StickyNote.ts +14 -4
- package/src/flow/actions/audio-player.ts +127 -0
- package/src/flow/actions/enter_flow.ts +44 -0
- package/src/flow/actions/play_audio.ts +64 -5
- package/src/flow/actions/say_msg.ts +94 -4
- package/src/flow/config.ts +11 -3
- package/src/flow/nodes/shared-rules.ts +1 -1
- package/src/flow/nodes/terminal.ts +9 -0
- package/src/flow/nodes/wait_for_audio.ts +88 -0
- package/src/flow/nodes/wait_for_dial.ts +176 -0
- package/src/flow/nodes/wait_for_digits.ts +86 -2
- package/src/flow/nodes/wait_for_menu.ts +209 -3
- package/src/flow/operators.ts +23 -5
- package/src/flow/types.ts +23 -1
- package/src/flow/utils.ts +238 -81
- package/src/form/ArrayEditor.ts +4 -2
- package/src/form/FieldRenderer.ts +64 -1
- package/src/interfaces.ts +3 -1
- package/src/layout/Dialog.ts +53 -7
- package/src/list/TicketList.ts +4 -1
- package/src/live/TembaChart.ts +1 -1
- package/src/locales/es.ts +13 -18
- package/src/locales/fr.ts +13 -18
- package/src/locales/locale-codes.ts +2 -11
- package/src/locales/pt.ts +13 -18
- package/src/simulator/Simulator.ts +13 -3
- package/src/store/AppState.ts +105 -1
- package/src/store/flow-definition.d.ts +2 -0
- package/test/actions/play_audio.test.ts +155 -0
- package/test/actions/say_msg.test.ts +196 -0
- package/test/nodes/wait_for_audio.test.ts +182 -0
- package/test/nodes/wait_for_dial.test.ts +382 -0
- package/test/nodes/wait_for_digits.test.ts +233 -109
- package/test/nodes/wait_for_menu.test.ts +383 -0
- package/test/temba-floating-tab.test.ts +4 -6
- package/test/temba-flow-collision.test.ts +495 -293
- package/test/temba-flow-editor.test.ts +0 -2
- package/test/temba-flow-plumber-connections.test.ts +97 -97
- package/test/temba-flow-plumber.test.ts +116 -103
- package/test/temba-node-type-selector.test.ts +6 -6
- package/screenshots/truth/nodes/wait_for_digits/editor/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/editor/verification-code.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/phone-number-collection.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/single-digit-with-timeout.png +0 -0
- package/screenshots/truth/nodes/wait_for_digits/render/verification-code.png +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temba-node-type-selector.test.js","sourceRoot":"","sources":["../../test/temba-node-type-selector.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { NodeTypeSelector } from '../src/flow/NodeTypeSelector';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-node-type-selector', () => {\n const createSelector = async () => {\n const component = (await getComponent(\n 'temba-node-type-selector',\n {},\n '',\n 700,\n 600\n )) as NodeTypeSelector;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const selector = await createSelector();\n assert.instanceOf(selector, NodeTypeSelector);\n expect(selector.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const selector = await createSelector();\n expect(selector.open).to.be.false;\n\n // component should not be in DOM when closed\n expect(selector.hasAttribute('open')).to.be.false;\n });\n\n it('shows dialog when opened in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('action');\n expect(selector.hasAttribute('open')).to.be.true;\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/action-mode', getClip(dialog));\n });\n\n it('shows dialog when opened in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('split');\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/split-mode', getClip(dialog));\n });\n\n it('displays action types in action mode', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select an Action');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('displays split types in split mode', async () => {\n const selector = await createSelector();\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select a Split');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('closes when close() is called', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n\n selector.close();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when overlay is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const overlay = selector.shadowRoot?.querySelector(\n '.overlay'\n ) as HTMLElement;\n overlay.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when cancel button is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const cancelButton = selector.shadowRoot?.querySelector(\n 'temba-button'\n ) as HTMLElement;\n cancelButton.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('fires selection event when node type is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n selector.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on first node item\n const firstNodeItem = selector.shadowRoot?.querySelector(\n '.node-item'\n ) as HTMLElement;\n firstNodeItem.click();\n await selector.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.have.property('nodeType');\n expect(selectionDetail).to.have.property('position');\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n expect(selector.open).to.be.false;\n });\n\n it('filters actions by flow type - voice flow should show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should have Say Message and Play Audio\n expect(titles).to.include('Say Message');\n expect(titles).to.include('Play Audio');\n });\n\n it('filters actions by flow type - message flow should not show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should not have Say Message or Play Audio\n expect(titles).to.not.include('Say Message');\n expect(titles).to.not.include('Play Audio');\n });\n\n it('filters splits by flow type - message flow should show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should have Wait for Response\n expect(titles).to.include('Wait for Response');\n });\n\n it('filters splits by flow type - voice flow should not show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should not have Wait for Response\n expect(titles).to.not.include('Wait for Response');\n\n // but should have Wait for Digits and Wait for Menu Selection\n expect(titles).to.include('Wait for Digits');\n expect(titles).to.include('Wait for Menu Selection');\n });\n\n it('filters by features - AI feature enables AI splits', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['ai'];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // split_by_llm_categorize (Split by AI) is filtered out for old editor compatibility\n // so it should NOT appear even when AI feature is enabled\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - without AI feature, AI splits are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without ai feature, should not have Call AI or Split by AI\n expect(titles).to.not.include('Call AI');\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - airtime feature enables airtime actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['airtime'];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // with airtime feature, should have Send Airtime\n expect(titles).to.include('Send Airtime');\n });\n\n it('filters by features - without airtime feature, airtime actions are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without airtime feature, should not have Send Airtime\n expect(titles).to.not.include('Send Airtime');\n });\n\n it('hides actions/nodes with empty flowTypes array from selector', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns false for empty flowTypes array\n const configWithEmptyFlowTypes = {\n name: 'Test Action',\n type: 'test_action',\n flowTypes: [] // empty array should hide from all flow types\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n // call private method via any to test behavior\n const isAvailable = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailable).to.be.false;\n\n // test with different flow types - should still be false\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailableVoice).to.be.false;\n });\n\n it('shows actions/nodes with undefined flowTypes for all flow types', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns true for undefined flowTypes\n const configWithUndefinedFlowTypes = {\n name: 'Test Action',\n type: 'test_action'\n // flowTypes is undefined - should be available for all\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n const isAvailable = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailable).to.be.true;\n\n // test with different flow types - should still be true\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailableVoice).to.be.true;\n });\n\n describe('alias filtering', () => {\n it('should not show split_by_run_result twice when aliases exist', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items rendered in the selector\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n // Count how many times \"Split by Result\" appears\n let splitByResultCount = 0;\n nodeItems.forEach((item) => {\n const title = item.querySelector('.node-item-title');\n if (title?.textContent?.includes('Split by Result')) {\n splitByResultCount++;\n }\n });\n\n // Should only appear once, not twice\n expect(splitByResultCount).to.equal(1);\n });\n\n it('should not show split_by_run_result_delimited type in the selector', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundDelimitedType = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_run_result_delimited') {\n foundDelimitedType = true;\n }\n });\n\n expect(foundDelimitedType).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"temba-node-type-selector.test.js","sourceRoot":"","sources":["../../test/temba-node-type-selector.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;QAChC,MAAM,SAAS,GAAG,CAAC,MAAM,YAAY,CACnC,0BAA0B,EAC1B,EAAE,EACF,EAAE,EACF,GAAG,EACH,GAAG,CACJ,CAAqB,CAAC;QACvB,MAAM,SAAS,CAAC,cAAc,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF,EAAE,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAElC,6CAA6C;QAC7C,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;;QACvD,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QAExC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAEjD,MAAM,MAAM,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CAAC,SAAS,CAAgB,CAAC;QAC5E,MAAM,gBAAgB,CAAC,gCAAgC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;;QACtD,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QAExC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAExC,MAAM,MAAM,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CAAC,SAAS,CAAgB,CAAC;QAC5E,MAAM,gBAAgB,CAAC,+BAA+B,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;;QACpD,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,KAAK,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAExD,4BAA4B;QAC5B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;QACtE,MAAM,CAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;;QAClD,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,KAAK,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAEtD,4BAA4B;QAC5B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC;QACtE,MAAM,CAAC,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAEjC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;;QAC9C,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,OAAO,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CAChD,UAAU,CACI,CAAC;QACjB,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;;QACpD,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,YAAY,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CACrD,cAAc,CACA,CAAC;QACjB,YAAY,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;;QAC/D,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,IAAI,eAAe,GAAG,IAAI,CAAC;QAE3B,QAAQ,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,KAAU,EAAE,EAAE;YAC1D,cAAc,GAAG,IAAI,CAAC;YACtB,eAAe,GAAG,KAAK,CAAC,MAAM,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,2BAA2B;QAC3B,MAAM,aAAa,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,aAAa,CACtD,YAAY,CACE,CAAC;QACjB,aAAa,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAClC,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;;QACxF,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,wDAAwD;QACxD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;;QAC9F,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,6DAA6D;QAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;;QACxF,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,6CAA6C;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;;QAC1F,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,+CAA+C;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAEnD,oDAAoD;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;;QAClE,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,qFAAqF;QACrF,0DAA0D;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;;QAC9E,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,QAAQ,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,6DAA6D;QAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;;QAC7E,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,iDAAiD;QACjD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;;QACzF,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QACxC,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,QAAQ,CAAC,QAAQ,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,CAAC,cAAc,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,2BAA2B;QAC3B,MAAM,SAAS,GAAG,MAAA,QAAQ,CAAC,UAAU,0CAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WACtD,OAAA,MAAA,IAAI,CAAC,WAAW,0CAAE,IAAI,EAAE,CAAA,EAAA,CACzB,CAAC;QAEF,wDAAwD;QACxD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QAExC,sEAAsE;QACtE,MAAM,wBAAwB,GAAG;YAC/B,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,EAAE,CAAC,8CAA8C;SAC7D,CAAC;QAEF,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,+CAA+C;QAC/C,MAAM,WAAW,GAAI,QAAgB,CAAC,iBAAiB,CACrD,wBAAwB,CACzB,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QAEhC,yDAAyD;QACzD,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,gBAAgB,GAAI,QAAgB,CAAC,iBAAiB,CAC1D,wBAAwB,CACzB,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;QAExC,mEAAmE;QACnE,MAAM,4BAA4B,GAAG;YACnC,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,aAAa;YACnB,uDAAuD;SACxD,CAAC;QAEF,QAAQ,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,WAAW,GAAI,QAAgB,CAAC,iBAAiB,CACrD,4BAA4B,CAC7B,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAE/B,wDAAwD;QACxD,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC5B,MAAM,QAAQ,CAAC,cAAc,CAAC;QAE9B,MAAM,gBAAgB,GAAI,QAAgB,CAAC,iBAAiB,CAC1D,4BAA4B,CAC7B,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;YAC5E,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;YAExC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;YAE9B,kDAAkD;YAClD,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;YAEtE,iDAAiD;YACjD,IAAI,kBAAkB,GAAG,CAAC,CAAC;YAC3B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;;gBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;gBACrD,IAAI,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,WAAW,0CAAE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;oBACpD,kBAAkB,EAAE,CAAC;gBACvB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,qCAAqC;YACrC,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;YAClF,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;YAExC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;YAE9B,8DAA8D;YAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;YAEtE,IAAI,kBAAkB,GAAG,KAAK,CAAC;YAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAChD,IAAI,QAAQ,KAAK,+BAA+B,EAAE,CAAC;oBACjD,kBAAkB,GAAG,IAAI,CAAC;gBAC5B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;YAExC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC3C,MAAM,QAAQ,CAAC,cAAc,CAAC;YAE9B,8DAA8D;YAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;YAEtE,IAAI,kBAAkB,GAAG,KAAK,CAAC;YAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAChD,IAAI,QAAQ,KAAK,yBAAyB,EAAE,CAAC;oBAC3C,kBAAkB,GAAG,IAAI,CAAC;gBAC5B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAC;YAExC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5C,MAAM,QAAQ,CAAC,cAAc,CAAC;YAE9B,8DAA8D;YAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;YAEtE,IAAI,kBAAkB,GAAG,KAAK,CAAC;YAC/B,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;gBAChD,IAAI,QAAQ,KAAK,yBAAyB,EAAE,CAAC;oBAC3C,kBAAkB,GAAG,IAAI,CAAC;gBAC5B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { expect, assert } from '@open-wc/testing';\nimport { NodeTypeSelector } from '../src/flow/NodeTypeSelector';\nimport { assertScreenshot, getClip, getComponent } from './utils.test';\n\ndescribe('temba-node-type-selector', () => {\n const createSelector = async () => {\n const component = (await getComponent(\n 'temba-node-type-selector',\n {},\n '',\n 700,\n 600\n )) as NodeTypeSelector;\n await component.updateComplete;\n return component;\n };\n\n it('can be created', async () => {\n const selector = await createSelector();\n assert.instanceOf(selector, NodeTypeSelector);\n expect(selector.open).to.be.false;\n });\n\n it('is not visible when closed', async () => {\n const selector = await createSelector();\n expect(selector.open).to.be.false;\n\n // component should not be in DOM when closed\n expect(selector.hasAttribute('open')).to.be.false;\n });\n\n it('shows dialog when opened in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('action');\n expect(selector.hasAttribute('open')).to.be.true;\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/action-mode', getClip(dialog));\n });\n\n it('shows dialog when opened in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n expect(selector.mode).to.equal('split');\n\n const dialog = selector.shadowRoot?.querySelector('.dialog') as HTMLElement;\n await assertScreenshot('node-type-selector/split-mode', getClip(dialog));\n });\n\n it('displays action types in action mode', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select an Action');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('displays split types in split mode', async () => {\n const selector = await createSelector();\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const title = selector.shadowRoot?.querySelector('.header h2');\n expect(title?.textContent).to.equal('Select a Split');\n\n // verify we have node items\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item');\n expect(nodeItems?.length).to.be.greaterThan(0);\n });\n\n it('closes when close() is called', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n expect(selector.open).to.be.true;\n\n selector.close();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when overlay is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const overlay = selector.shadowRoot?.querySelector(\n '.overlay'\n ) as HTMLElement;\n overlay.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('closes when cancel button is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n const cancelButton = selector.shadowRoot?.querySelector(\n 'temba-button'\n ) as HTMLElement;\n cancelButton.click();\n await selector.updateComplete;\n\n expect(selector.open).to.be.false;\n });\n\n it('fires selection event when node type is clicked', async () => {\n const selector = await createSelector();\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n let selectionFired = false;\n let selectionDetail = null;\n\n selector.addEventListener('temba-selection', (event: any) => {\n selectionFired = true;\n selectionDetail = event.detail;\n });\n\n // click on first node item\n const firstNodeItem = selector.shadowRoot?.querySelector(\n '.node-item'\n ) as HTMLElement;\n firstNodeItem.click();\n await selector.updateComplete;\n\n expect(selectionFired).to.be.true;\n expect(selectionDetail).to.have.property('nodeType');\n expect(selectionDetail).to.have.property('position');\n expect(selectionDetail.position).to.deep.equal({ x: 100, y: 100 });\n expect(selector.open).to.be.false;\n });\n\n it('filters actions by flow type - voice flow should show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should have Say Message and Play Recording\n expect(titles).to.include('Say Message');\n expect(titles).to.include('Play Recording');\n });\n\n it('filters actions by flow type - message flow should not show voice-only actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should not have Say Message or Play Recording\n expect(titles).to.not.include('Say Message');\n expect(titles).to.not.include('Play Recording');\n });\n\n it('filters splits by flow type - message flow should show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // message flow should have Wait for Response\n expect(titles).to.include('Wait for Response');\n });\n\n it('filters splits by flow type - voice flow should not show wait for response', async () => {\n const selector = await createSelector();\n selector.flowType = 'voice';\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // voice flow should not have Wait for Response\n expect(titles).to.not.include('Wait for Response');\n\n // but should have Wait for Digits and Wait for Menu\n expect(titles).to.include('Wait for Digits');\n expect(titles).to.include('Wait for Menu');\n });\n\n it('filters by features - AI feature enables AI splits', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['ai'];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // split_by_llm_categorize (Split by AI) is filtered out for old editor compatibility\n // so it should NOT appear even when AI feature is enabled\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - without AI feature, AI splits are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without ai feature, should not have Call AI or Split by AI\n expect(titles).to.not.include('Call AI');\n expect(titles).to.not.include('Split by AI');\n });\n\n it('filters by features - airtime feature enables airtime actions', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = ['airtime'];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // with airtime feature, should have Send Airtime\n expect(titles).to.include('Send Airtime');\n });\n\n it('filters by features - without airtime feature, airtime actions are hidden', async () => {\n const selector = await createSelector();\n selector.flowType = 'message';\n selector.features = [];\n await selector.updateComplete;\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // get all node item titles\n const nodeItems = selector.shadowRoot?.querySelectorAll('.node-item-title');\n const titles = Array.from(nodeItems || []).map((item) =>\n item.textContent?.trim()\n );\n\n // without airtime feature, should not have Send Airtime\n expect(titles).to.not.include('Send Airtime');\n });\n\n it('hides actions/nodes with empty flowTypes array from selector', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns false for empty flowTypes array\n const configWithEmptyFlowTypes = {\n name: 'Test Action',\n type: 'test_action',\n flowTypes: [] // empty array should hide from all flow types\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n // call private method via any to test behavior\n const isAvailable = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailable).to.be.false;\n\n // test with different flow types - should still be false\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithEmptyFlowTypes\n );\n expect(isAvailableVoice).to.be.false;\n });\n\n it('shows actions/nodes with undefined flowTypes for all flow types', async () => {\n const selector = await createSelector();\n\n // test that isConfigAvailable returns true for undefined flowTypes\n const configWithUndefinedFlowTypes = {\n name: 'Test Action',\n type: 'test_action'\n // flowTypes is undefined - should be available for all\n };\n\n selector.flowType = 'message';\n await selector.updateComplete;\n\n const isAvailable = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailable).to.be.true;\n\n // test with different flow types - should still be true\n selector.flowType = 'voice';\n await selector.updateComplete;\n\n const isAvailableVoice = (selector as any).isConfigAvailable(\n configWithUndefinedFlowTypes\n );\n expect(isAvailableVoice).to.be.true;\n });\n\n describe('alias filtering', () => {\n it('should not show split_by_run_result twice when aliases exist', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items rendered in the selector\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n // Count how many times \"Split by Result\" appears\n let splitByResultCount = 0;\n nodeItems.forEach((item) => {\n const title = item.querySelector('.node-item-title');\n if (title?.textContent?.includes('Split by Result')) {\n splitByResultCount++;\n }\n });\n\n // Should only appear once, not twice\n expect(splitByResultCount).to.equal(1);\n });\n\n it('should not show split_by_run_result_delimited type in the selector', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundDelimitedType = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_run_result_delimited') {\n foundDelimitedType = true;\n }\n });\n\n expect(foundDelimitedType).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in split mode', async () => {\n const selector = await createSelector();\n\n selector.show('split', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n\n it('should not show split_by_llm_categorize in action mode', async () => {\n const selector = await createSelector();\n\n selector.show('action', { x: 100, y: 100 });\n await selector.updateComplete;\n\n // Get all the node items and check their data-type attributes\n const nodeItems = selector.shadowRoot!.querySelectorAll('.node-item');\n\n let foundLLMCategorize = false;\n nodeItems.forEach((item) => {\n const typeAttr = item.getAttribute('data-type');\n if (typeAttr === 'split_by_llm_categorize') {\n foundLLMCategorize = true;\n }\n });\n\n expect(foundLLMCategorize).to.be.false;\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/display/Chat.ts
CHANGED
|
@@ -833,8 +833,14 @@ export class Chat extends RapidElement {
|
|
|
833
833
|
}
|
|
834
834
|
|
|
835
835
|
// for type equivalence, treat all non-message types as the same
|
|
836
|
-
const isMsg1 =
|
|
837
|
-
|
|
836
|
+
const isMsg1 =
|
|
837
|
+
msg1.type === 'msg_created' ||
|
|
838
|
+
msg1.type === 'msg_received' ||
|
|
839
|
+
msg1.type === 'ivr_created';
|
|
840
|
+
const isMsg2 =
|
|
841
|
+
msg2.type === 'msg_created' ||
|
|
842
|
+
msg2.type === 'msg_received' ||
|
|
843
|
+
msg2.type === 'ivr_created';
|
|
838
844
|
const typeMatch =
|
|
839
845
|
isMsg1 && isMsg2 ? msg1.type === msg2.type : isMsg1 === isMsg2;
|
|
840
846
|
|
|
@@ -999,12 +1005,12 @@ export class Chat extends RapidElement {
|
|
|
999
1005
|
|
|
1000
1006
|
const name = currentMsg._user?.name;
|
|
1001
1007
|
|
|
1008
|
+
const isMessageType =
|
|
1009
|
+
currentMsg.type === 'msg_received' ||
|
|
1010
|
+
currentMsg.type === 'msg_created' ||
|
|
1011
|
+
currentMsg.type === 'ivr_created';
|
|
1002
1012
|
const showAvatar =
|
|
1003
|
-
this.avatars &&
|
|
1004
|
-
(((currentMsg.type === 'msg_received' ||
|
|
1005
|
-
currentMsg.type === 'msg_created') &&
|
|
1006
|
-
this.agent) ||
|
|
1007
|
-
!incoming);
|
|
1013
|
+
this.avatars && ((isMessageType && this.agent) || !incoming);
|
|
1008
1014
|
|
|
1009
1015
|
const isSystem = !currentMsg._user?.uuid;
|
|
1010
1016
|
|
package/src/display/Dropdown.ts
CHANGED
|
@@ -40,10 +40,12 @@ export class Dropdown extends RapidElement {
|
|
|
40
40
|
opacity: 0;
|
|
41
41
|
border-radius: calc(var(--curvature) * 1.5);
|
|
42
42
|
background: #fff;
|
|
43
|
-
transition:
|
|
43
|
+
transition: opacity calc(0.8 * var(--transition-speed)) var(--bounce),
|
|
44
|
+
transform calc(0.8 * var(--transition-speed)) var(--bounce);
|
|
44
45
|
user-select: none;
|
|
45
46
|
margin-top: 0px;
|
|
46
47
|
margin-left: 0px;
|
|
48
|
+
transform: translateY(0) scale(1);
|
|
47
49
|
box-shadow: var(--dropdown-shadow);
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css, html, PropertyValueMap, TemplateResult } from 'lit';
|
|
2
|
-
import { property } from 'lit/decorators.js';
|
|
2
|
+
import { property, state } from 'lit/decorators.js';
|
|
3
3
|
import { RapidElement } from '../RapidElement';
|
|
4
4
|
import { CustomEventType } from '../interfaces';
|
|
5
5
|
import { getClasses } from '../utils';
|
|
@@ -8,13 +8,12 @@ export class FloatingTab extends RapidElement {
|
|
|
8
8
|
static get styles() {
|
|
9
9
|
return css`
|
|
10
10
|
.tab.hidden {
|
|
11
|
-
transform: translateX(100%);
|
|
11
|
+
transform: translateX(calc(100% + var(--floating-tab-right, 0px)));
|
|
12
12
|
}
|
|
13
13
|
.tab {
|
|
14
14
|
position: fixed;
|
|
15
|
-
right:
|
|
15
|
+
right: var(--floating-tab-right, 0px);
|
|
16
16
|
z-index: 4998;
|
|
17
|
-
transition: transform var(--transition-duration, 300ms) ease-in-out;
|
|
18
17
|
display: flex;
|
|
19
18
|
align-items: center;
|
|
20
19
|
padding: 12px;
|
|
@@ -22,8 +21,11 @@ export class FloatingTab extends RapidElement {
|
|
|
22
21
|
border-bottom-left-radius: 8px;
|
|
23
22
|
cursor: pointer;
|
|
24
23
|
box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.2);
|
|
25
|
-
transition:
|
|
26
|
-
|
|
24
|
+
transition: transform calc(var(--transition-duration, 300ms) * 0.7)
|
|
25
|
+
ease-in-out,
|
|
26
|
+
padding-right calc(var(--transition-duration, 300ms) * 0.7)
|
|
27
|
+
ease-in-out,
|
|
28
|
+
box-shadow calc(var(--transition-duration, 300ms) * 0.7) ease-in-out;
|
|
27
29
|
user-select: none;
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -64,7 +66,9 @@ export class FloatingTab extends RapidElement {
|
|
|
64
66
|
`;
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
static TAB_HEIGHT = 50;
|
|
69
|
+
static TAB_HEIGHT = 50;
|
|
70
|
+
static TAB_GAP = 4;
|
|
71
|
+
static START_TOP = 100;
|
|
68
72
|
static allTabs: FloatingTab[] = [];
|
|
69
73
|
|
|
70
74
|
@property({ type: String })
|
|
@@ -77,24 +81,18 @@ export class FloatingTab extends RapidElement {
|
|
|
77
81
|
color = '#6B7280';
|
|
78
82
|
|
|
79
83
|
@property({ type: Number })
|
|
80
|
-
|
|
84
|
+
order = 0;
|
|
85
|
+
|
|
86
|
+
@state()
|
|
87
|
+
top = 100;
|
|
81
88
|
|
|
82
89
|
@property({ type: Boolean })
|
|
83
90
|
hidden = false;
|
|
84
91
|
|
|
85
|
-
private autoPositioned = false;
|
|
86
|
-
|
|
87
92
|
connectedCallback() {
|
|
88
93
|
super.connectedCallback();
|
|
89
94
|
FloatingTab.allTabs.push(this);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
protected firstUpdated(): void {
|
|
93
|
-
// only auto-calculate position if no top was provided (still at default -1)
|
|
94
|
-
if (this.top === -1) {
|
|
95
|
-
this.autoPositioned = true;
|
|
96
|
-
this.updatePosition();
|
|
97
|
-
}
|
|
95
|
+
FloatingTab.updateAllPositions();
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
disconnectedCallback() {
|
|
@@ -103,23 +101,16 @@ export class FloatingTab extends RapidElement {
|
|
|
103
101
|
if (index > -1) {
|
|
104
102
|
FloatingTab.allTabs.splice(index, 1);
|
|
105
103
|
}
|
|
106
|
-
|
|
107
|
-
FloatingTab.allTabs.forEach((tab) => {
|
|
108
|
-
if (tab.autoPositioned) {
|
|
109
|
-
tab.updatePosition();
|
|
110
|
-
}
|
|
111
|
-
});
|
|
104
|
+
FloatingTab.updateAllPositions();
|
|
112
105
|
}
|
|
113
106
|
|
|
114
|
-
private
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.top = 150 + index * (FloatingTab.TAB_HEIGHT + 0);
|
|
122
|
-
}
|
|
107
|
+
private static updateAllPositions() {
|
|
108
|
+
const sorted = [...FloatingTab.allTabs].sort((a, b) => a.order - b.order);
|
|
109
|
+
sorted.forEach((tab, index) => {
|
|
110
|
+
tab.top =
|
|
111
|
+
FloatingTab.START_TOP +
|
|
112
|
+
index * (FloatingTab.TAB_HEIGHT + FloatingTab.TAB_GAP);
|
|
113
|
+
});
|
|
123
114
|
}
|
|
124
115
|
|
|
125
116
|
public updated(
|
package/src/display/Thumbnail.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PropertyValueMap, css, html } from 'lit';
|
|
2
2
|
import { RapidElement } from '../RapidElement';
|
|
3
|
-
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { property, state } from 'lit/decorators.js';
|
|
4
4
|
import { getClasses } from '../utils';
|
|
5
5
|
import { Lightbox } from './Lightbox';
|
|
6
6
|
import { WebChatIcon } from '../webchat';
|
|
@@ -67,11 +67,57 @@ export class Thumbnail extends RapidElement {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
.thumb.document,
|
|
70
|
-
.thumb.audio,
|
|
71
70
|
.thumb.video {
|
|
72
71
|
border: 1px solid #eee;
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
.audio-player {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: 6px;
|
|
78
|
+
padding: 6px 8px;
|
|
79
|
+
background: rgba(0, 0, 0, 0.05);
|
|
80
|
+
border-radius: var(--curvature);
|
|
81
|
+
cursor: default;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.audio-play-btn {
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
color: #666;
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
flex-shrink: 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.audio-play-btn:hover {
|
|
93
|
+
color: #333;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.audio-progress-bar {
|
|
97
|
+
flex: 1;
|
|
98
|
+
height: 3px;
|
|
99
|
+
background: #ddd;
|
|
100
|
+
border-radius: 2px;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
min-width: 60px;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.audio-progress-fill {
|
|
107
|
+
height: 100%;
|
|
108
|
+
background: var(--color-primary, #2387ca);
|
|
109
|
+
border-radius: 2px;
|
|
110
|
+
transition: width 0.15s linear;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.audio-time {
|
|
114
|
+
font-size: 11px;
|
|
115
|
+
color: #999;
|
|
116
|
+
flex-shrink: 0;
|
|
117
|
+
min-width: 28px;
|
|
118
|
+
text-align: right;
|
|
119
|
+
}
|
|
120
|
+
|
|
75
121
|
.wrapper:hover .thumb.icon {
|
|
76
122
|
}
|
|
77
123
|
|
|
@@ -133,6 +179,74 @@ export class Thumbnail extends RapidElement {
|
|
|
133
179
|
@property({ type: String, attribute: false })
|
|
134
180
|
private tileUrl: string = '';
|
|
135
181
|
|
|
182
|
+
// audio player state
|
|
183
|
+
private audio: HTMLAudioElement | null = null;
|
|
184
|
+
|
|
185
|
+
@state()
|
|
186
|
+
private audioPlaying = false;
|
|
187
|
+
|
|
188
|
+
@state()
|
|
189
|
+
private audioProgress = 0;
|
|
190
|
+
|
|
191
|
+
@state()
|
|
192
|
+
private audioDuration = 0;
|
|
193
|
+
|
|
194
|
+
private handleAudioPlayClick(e: Event) {
|
|
195
|
+
e.stopPropagation();
|
|
196
|
+
|
|
197
|
+
if (!this.audio) {
|
|
198
|
+
this.audio = new Audio(this.url);
|
|
199
|
+
this.audio.addEventListener('timeupdate', () => {
|
|
200
|
+
if (this.audio.duration) {
|
|
201
|
+
this.audioProgress = this.audio.currentTime / this.audio.duration;
|
|
202
|
+
this.audioDuration = this.audio.duration;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
this.audio.addEventListener('ended', () => {
|
|
206
|
+
this.audioPlaying = false;
|
|
207
|
+
this.audioProgress = 0;
|
|
208
|
+
});
|
|
209
|
+
this.audio.addEventListener('error', () => {
|
|
210
|
+
this.audioPlaying = false;
|
|
211
|
+
this.audioProgress = 0;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (this.audioPlaying) {
|
|
216
|
+
this.audio.pause();
|
|
217
|
+
this.audioPlaying = false;
|
|
218
|
+
} else {
|
|
219
|
+
this.audio.play().catch(() => {
|
|
220
|
+
this.audioPlaying = false;
|
|
221
|
+
});
|
|
222
|
+
this.audioPlaying = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private handleProgressClick(e: MouseEvent) {
|
|
227
|
+
e.stopPropagation();
|
|
228
|
+
if (!this.audio || !this.audio.duration) return;
|
|
229
|
+
const bar = e.currentTarget as HTMLElement;
|
|
230
|
+
const rect = bar.getBoundingClientRect();
|
|
231
|
+
const pct = (e.clientX - rect.left) / rect.width;
|
|
232
|
+
this.audio.currentTime = pct * this.audio.duration;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private formatTime(seconds: number): string {
|
|
236
|
+
const s = Math.floor(seconds);
|
|
237
|
+
const m = Math.floor(s / 60);
|
|
238
|
+
const rem = s % 60;
|
|
239
|
+
return `${m}:${rem.toString().padStart(2, '0')}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
disconnectedCallback() {
|
|
243
|
+
super.disconnectedCallback();
|
|
244
|
+
if (this.audio) {
|
|
245
|
+
this.audio.pause();
|
|
246
|
+
this.audio = null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
136
250
|
// convert lat/lng to tile coordinates for OSM
|
|
137
251
|
private latLngToTile(lat: number, lng: number, zoom: number) {
|
|
138
252
|
const n = Math.pow(2, zoom);
|
|
@@ -227,6 +341,8 @@ export class Thumbnail extends RapidElement {
|
|
|
227
341
|
// open location in openstreetmap
|
|
228
342
|
const osmUrl = `https://www.openstreetmap.org/?mlat=${this.latitude}&mlon=${this.longitude}#map=15/${this.latitude}/${this.longitude}`;
|
|
229
343
|
window.open(osmUrl, '_blank');
|
|
344
|
+
} else if (this.contentType === ThumbnailContentType.AUDIO) {
|
|
345
|
+
// audio has inline controls, no click action needed
|
|
230
346
|
} else {
|
|
231
347
|
window.open(this.url, '_blank');
|
|
232
348
|
}
|
|
@@ -245,6 +361,9 @@ export class Thumbnail extends RapidElement {
|
|
|
245
361
|
<div
|
|
246
362
|
@click=${this.handleThumbnailClicked.bind(this)}
|
|
247
363
|
class="${getClasses({ wrapper: true, zoom: this.zoom })}"
|
|
364
|
+
style="${this.contentType === ThumbnailContentType.AUDIO
|
|
365
|
+
? 'cursor: default;'
|
|
366
|
+
: ''}"
|
|
248
367
|
url=${this.url}
|
|
249
368
|
>
|
|
250
369
|
${this.contentType === ThumbnailContentType.IMAGE && this.preview
|
|
@@ -254,6 +373,47 @@ export class Thumbnail extends RapidElement {
|
|
|
254
373
|
class="observe thumb ${this.contentType}"
|
|
255
374
|
src="${this.url}"
|
|
256
375
|
></img></div>`
|
|
376
|
+
: this.contentType === ThumbnailContentType.AUDIO
|
|
377
|
+
? html`<div class="audio-player">
|
|
378
|
+
<div class="audio-play-btn" @click=${this.handleAudioPlayClick}>
|
|
379
|
+
${this.audioPlaying
|
|
380
|
+
? html`<svg
|
|
381
|
+
viewBox="0 0 24 24"
|
|
382
|
+
width="14"
|
|
383
|
+
height="14"
|
|
384
|
+
fill="currentColor"
|
|
385
|
+
>
|
|
386
|
+
<rect x="5" y="3" width="4" height="18" />
|
|
387
|
+
<rect x="15" y="3" width="4" height="18" />
|
|
388
|
+
</svg>`
|
|
389
|
+
: html`<svg
|
|
390
|
+
viewBox="0 0 24 24"
|
|
391
|
+
width="14"
|
|
392
|
+
height="14"
|
|
393
|
+
fill="currentColor"
|
|
394
|
+
>
|
|
395
|
+
<polygon points="6,3 20,12 6,21" />
|
|
396
|
+
</svg>`}
|
|
397
|
+
</div>
|
|
398
|
+
<div
|
|
399
|
+
class="audio-progress-bar"
|
|
400
|
+
@click=${this.handleProgressClick}
|
|
401
|
+
>
|
|
402
|
+
<div
|
|
403
|
+
class="audio-progress-fill"
|
|
404
|
+
style="width: ${this.audioProgress * 100}%"
|
|
405
|
+
></div>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="audio-time">
|
|
408
|
+
${this.audioDuration
|
|
409
|
+
? this.formatTime(
|
|
410
|
+
this.audioPlaying || this.audioProgress > 0
|
|
411
|
+
? this.audio?.currentTime || 0
|
|
412
|
+
: this.audioDuration
|
|
413
|
+
)
|
|
414
|
+
: ''}
|
|
415
|
+
</div>
|
|
416
|
+
</div>`
|
|
257
417
|
: html`
|
|
258
418
|
${this.contentType === ThumbnailContentType.LOCATION
|
|
259
419
|
? html`<img
|
package/src/flow/CanvasMenu.ts
CHANGED
|
@@ -98,14 +98,16 @@ export class CanvasMenu extends RapidElement {
|
|
|
98
98
|
): void {
|
|
99
99
|
super.firstUpdated(_changedProperties);
|
|
100
100
|
|
|
101
|
-
// Close menu when clicking outside
|
|
101
|
+
// Close menu when clicking outside — use mousedown instead of click
|
|
102
|
+
// to avoid being triggered by the click synthesized from a drag-and-drop
|
|
103
|
+
// (mousedown on exit + mouseup on canvas = click on common ancestor)
|
|
102
104
|
const handleClickOutside = (e: MouseEvent) => {
|
|
103
105
|
if (this.open && !this.contains(e.target as Node)) {
|
|
104
106
|
this.close();
|
|
105
107
|
}
|
|
106
108
|
};
|
|
107
109
|
|
|
108
|
-
document.addEventListener('
|
|
110
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
109
111
|
|
|
110
112
|
// Store cleanup function
|
|
111
113
|
(this as any)._clickOutsideHandler = handleClickOutside;
|
|
@@ -114,7 +116,10 @@ export class CanvasMenu extends RapidElement {
|
|
|
114
116
|
disconnectedCallback(): void {
|
|
115
117
|
super.disconnectedCallback();
|
|
116
118
|
if ((this as any)._clickOutsideHandler) {
|
|
117
|
-
document.removeEventListener(
|
|
119
|
+
document.removeEventListener(
|
|
120
|
+
'mousedown',
|
|
121
|
+
(this as any)._clickOutsideHandler
|
|
122
|
+
);
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
|