@nyaruka/temba-components 0.135.9 → 0.136.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/CHANGELOG.md +16 -0
- package/demo/components/webchat/example.html +4 -2
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +1323 -317
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/Icons.js +2 -1
- package/out-tsc/src/Icons.js.map +1 -1
- package/out-tsc/src/flow/CanvasNode.js +11 -0
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +224 -2
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +320 -1
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/layout/FloatingWindow.js +30 -8
- package/out-tsc/src/layout/FloatingWindow.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +1827 -0
- package/out-tsc/src/simulator/Simulator.js.map +1 -0
- package/out-tsc/src/store/AppState.js +33 -0
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/src/utils.js +48 -0
- package/out-tsc/src/utils.js.map +1 -1
- package/out-tsc/temba-modules.js +2 -0
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-flow-editor.test.js +1 -1
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js +3 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +3 -1
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +642 -0
- package/out-tsc/test/temba-simulator.test.js.map +1 -0
- package/out-tsc/test/utils.test.js +1 -1
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/simulator/after-message-sent.png +0 -0
- package/screenshots/truth/simulator/after-reset.png +0 -0
- package/screenshots/truth/simulator/attachment-menu.png +0 -0
- package/screenshots/truth/simulator/context-expanded.png +0 -0
- package/screenshots/truth/simulator/context-explorer-open.png +0 -0
- package/screenshots/truth/simulator/event-info.png +0 -0
- package/screenshots/truth/simulator/image-attachment.png +0 -0
- package/screenshots/truth/simulator/open-initial.png +0 -0
- package/screenshots/truth/simulator/quick-replies.png +0 -0
- package/src/Icons.ts +2 -1
- package/src/flow/CanvasNode.ts +12 -0
- package/src/flow/Editor.ts +240 -1
- package/src/flow/Plumber.ts +371 -2
- package/src/interfaces.ts +2 -1
- package/src/layout/FloatingWindow.ts +36 -11
- package/src/simulator/Simulator.ts +2008 -0
- package/src/store/AppState.ts +53 -0
- package/src/utils.ts +53 -0
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/route.svg +1 -0
- package/static/svg/work/used/route.svg +3 -0
- package/temba-modules.ts +2 -0
- package/test/temba-flow-editor.test.ts +1 -1
- package/test/temba-flow-plumber-connections.test.ts +4 -1
- package/test/temba-flow-plumber.test.ts +4 -1
- package/test/temba-simulator.test.ts +866 -0
- package/test/utils.test.ts +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temba-simulator.test.js","sourceRoot":"","sources":["../../test/temba-simulator.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { fixture, expect, assert } from '@open-wc/testing';\nimport { Simulator } from '../src/simulator/Simulator';\nimport {\n assertScreenshot,\n getClip,\n mockPOST,\n clearMockPosts,\n delay,\n waitForCondition,\n loadStore\n} from './utils.test';\n\nconst FLOW_UUID = 'test-flow-123';\n\nconst createSimulator = async (attrs: any = {}) => {\n // load store first since simulator depends on it\n await loadStore();\n\n const defaults = {\n flow: FLOW_UUID,\n animationTime: '0' // disable animations for deterministic tests\n };\n const mergedAttrs = { ...defaults, ...attrs };\n\n const attrString = Object.entries(mergedAttrs)\n .map(([key, value]) => `${key}=\"${value}\"`)\n .join(' ');\n\n const simulator: Simulator = await fixture(\n `<temba-simulator ${attrString}></temba-simulator>`\n );\n\n // reset cookie-based properties for deterministic tests\n simulator.size = 'medium';\n (simulator as any).following = true;\n (simulator as any).contextExplorerOpen = false;\n await simulator.updateComplete;\n\n return simulator;\n};\n\n// helper to open the simulator\nconst openSimulator = async (simulator: Simulator) => {\n const tab = simulator.shadowRoot.querySelector('temba-floating-tab') as any;\n expect(tab).to.exist;\n\n // trigger the button clicked event on the tab\n tab.dispatchEvent(new CustomEvent('temba-button-clicked', { bubbles: true }));\n\n await simulator.updateComplete;\n // brief delay for async API mock processing\n await delay(50);\n};\n\n// helper to get clip for the simulator window (fixed positioning)\nconst getSimulatorClip = (\n simulator: Simulator,\n includeContext: boolean = false\n) => {\n const phoneWindow = simulator.shadowRoot.querySelector(\n 'temba-floating-window'\n ) as any;\n\n if (!phoneWindow) {\n // if window not open, use default clip\n return getClip(simulator);\n }\n\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n if (!windowElement) {\n return getClip(simulator);\n }\n\n const windowBounds = windowElement.getBoundingClientRect();\n\n if (includeContext) {\n // get the context explorer and phone to clip just those areas\n const phoneSimulator = phoneWindow.querySelector(\n '.phone-simulator'\n ) as HTMLElement;\n if (!phoneSimulator) {\n return getClip(simulator);\n }\n\n const contextExplorer = phoneSimulator.querySelector(\n '.context-explorer'\n ) as HTMLElement;\n const phoneFrame = phoneSimulator.querySelector(\n '.phone-frame'\n ) as HTMLElement;\n\n if (!contextExplorer || !phoneFrame) {\n return {\n x: windowBounds.x,\n y: windowBounds.y,\n width: windowBounds.width,\n height: windowBounds.height\n };\n }\n\n const contextBounds = contextExplorer.getBoundingClientRect();\n const phoneBounds = phoneFrame.getBoundingClientRect();\n\n // clip from the left edge of context explorer to the right edge of phone frame only\n // do not include the option-pane which is to the right of the phone\n // keep padding within the phone bounds to avoid capturing the gap to the option pane\n const padding = 10;\n const leftX = contextBounds.x - padding;\n\n // don't extend past the phone frame right edge - the option pane is close by\n const rightX = phoneBounds.right;\n\n const topY = Math.min(contextBounds.y, phoneBounds.y) - padding;\n const bottomY =\n Math.max(contextBounds.bottom, phoneBounds.bottom) + padding;\n\n return {\n x: leftX,\n y: topY,\n width: rightX - leftX,\n height: bottomY - topY\n };\n }\n\n // the phone-simulator is in the light DOM of the phoneWindow (slotted content)\n const phoneSimulator = phoneWindow.querySelector(\n '.phone-simulator'\n ) as HTMLElement;\n if (!phoneSimulator) {\n return getClip(simulator);\n }\n\n // get the phone-frame from within the phone-simulator\n const phoneFrame = phoneSimulator.querySelector(\n '.phone-frame'\n ) as HTMLElement;\n if (!phoneFrame) {\n // fallback to window bounds if phone-frame not found\n return {\n x: windowBounds.x,\n y: windowBounds.y,\n width: windowBounds.width,\n height: windowBounds.height\n };\n }\n\n const frameBounds = phoneFrame.getBoundingClientRect();\n\n // add padding around the phone frame\n const padding = 10;\n return {\n x: frameBounds.x - padding,\n y: frameBounds.y - padding,\n width: frameBounds.width + padding * 2,\n height: frameBounds.height + padding * 2\n };\n};\n\n// mock responses for simulation endpoints\nconst mockSimulatorStart = () => {\n const response = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg: {\n uuid: 'msg-1',\n text: 'Hello! How can I help you today?',\n urn: 'tel:+12065551212'\n }\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {},\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'Test User',\n urns: {\n tel: ['+12065551212'],\n __default__: '+12065551212'\n },\n fields: {\n age: '25',\n city: 'Seattle'\n }\n },\n trigger: {\n type: 'manual',\n __default__: 'manual'\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, response);\n};\n\nconst mockSimulatorResume = (responseText: string, quickReplies?: string[]) => {\n const msg: any = {\n uuid: 'msg-response',\n text: responseText,\n urn: 'tel:+12065551212'\n };\n\n if (quickReplies) {\n msg.quick_replies = quickReplies.map((text) => ({ text }));\n }\n\n const response = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: 'exit-1'\n },\n {\n uuid: 'step-2',\n node_uuid: 'node-2',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {\n age: '25',\n city: 'Seattle'\n },\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'Test User',\n urns: {\n tel: ['+12065551212'],\n __default__: '+12065551212'\n },\n fields: {\n age: '25',\n city: 'Seattle'\n }\n },\n results: {\n user_response: {\n value: responseText,\n __default__: responseText\n }\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, response);\n};\n\ndescribe('temba-simulator', () => {\n beforeEach(() => {\n clearMockPosts();\n });\n\n it('can be created', async () => {\n const simulator: Simulator = await createSimulator();\n assert.instanceOf(simulator, Simulator);\n expect(simulator.flow).to.equal(FLOW_UUID);\n expect(simulator.endpoint).to.equal(`/flow/simulate/${FLOW_UUID}/`);\n });\n\n it('opens simulator window and starts flow', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n // ensure consistent size for screenshot\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n const phoneWindow = simulator.shadowRoot.querySelector(\n 'temba-floating-window'\n ) as any;\n expect(phoneWindow).to.exist;\n\n // verify phone screen is visible\n const phoneScreen = simulator.shadowRoot.querySelector('.phone-screen');\n expect(phoneScreen).to.exist;\n\n // verify initial message is displayed\n const messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.greaterThan(0);\n\n await assertScreenshot(\n 'simulator/open-initial',\n getSimulatorClip(simulator)\n );\n });\n\n it('sends a text message', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // count initial messages\n let messages = simulator.shadowRoot.querySelectorAll('.message');\n const initialCount = messages.length;\n\n // mock the resume response\n mockSimulatorResume('Thanks for your message!');\n\n // type a message\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n expect(input).to.exist;\n\n input.value = 'Hello from test';\n input.dispatchEvent(new Event('input'));\n await simulator.updateComplete;\n\n // press enter to send\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n await simulator.updateComplete;\n // brief delay for async API mock processing\n await delay(100);\n\n // verify we have more messages than before\n messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.greaterThan(initialCount);\n\n // ensure DOM is settled\n await simulator.updateComplete;\n\n await assertScreenshot(\n 'simulator/after-message-sent',\n getSimulatorClip(simulator)\n );\n });\n\n it('tests message flow and takes screenshot', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // clear previous mocks and set up new mock for a response\n clearMockPosts();\n mockSimulatorResume('Thank you for your message!', ['Yes', 'No', 'Maybe']);\n\n // send a message\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n input.value = 'Test message';\n input.dispatchEvent(new Event('input'));\n\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n // wait for quick replies to appear\n await waitForCondition(\n () =>\n simulator.shadowRoot.querySelectorAll('.quick-reply-btn').length > 0,\n 2000\n );\n await simulator.updateComplete;\n\n // take screenshot with quick replies\n await assertScreenshot(\n 'simulator/quick-replies',\n getSimulatorClip(simulator)\n );\n });\n\n it('opens attachment menu', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // click the attachment button\n const attachmentButton = simulator.shadowRoot.querySelector(\n '.attachment-button'\n ) as HTMLElement;\n expect(attachmentButton).to.exist;\n attachmentButton.click();\n\n await simulator.updateComplete;\n\n // verify attachment menu is displayed\n const attachmentMenu =\n simulator.shadowRoot.querySelector('.attachment-menu');\n expect(attachmentMenu).to.exist;\n expect(attachmentMenu.classList.contains('open')).to.be.true;\n\n await assertScreenshot(\n 'simulator/attachment-menu',\n getSimulatorClip(simulator)\n );\n });\n\n it('sends an image attachment', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n // reset attachment indices for deterministic testing\n simulator.resetAttachmentIndices();\n await openSimulator(simulator);\n\n // mock the response for image attachment\n mockSimulatorResume('Nice picture!');\n\n // open attachment menu and click image option\n const attachmentButton = simulator.shadowRoot.querySelector(\n '.attachment-button'\n ) as HTMLElement;\n attachmentButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n const imageMenuItem = Array.from(\n simulator.shadowRoot.querySelectorAll('.attachment-menu-item')\n ).find((el) => el.textContent?.includes('Image')) as HTMLElement;\n expect(imageMenuItem).to.exist;\n imageMenuItem.click();\n\n await delay(100);\n await simulator.updateComplete;\n\n // verify attachment wrapper is displayed (image attachments show in attachments not messages)\n const attachmentWrappers = simulator.shadowRoot.querySelectorAll(\n '.attachment-wrapper'\n );\n expect(attachmentWrappers.length).to.be.greaterThan(0);\n\n await assertScreenshot(\n 'simulator/image-attachment',\n getSimulatorClip(simulator)\n );\n });\n\n it('opens context explorer', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // find and click the context explorer button (has expressions icon)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n expect(contextButton).to.exist;\n contextButton.click();\n\n await simulator.updateComplete;\n await delay(100);\n\n // verify context explorer is displayed\n const contextExplorer =\n simulator.shadowRoot.querySelector('.context-explorer');\n expect(contextExplorer).to.exist;\n expect(contextExplorer.classList.contains('open')).to.be.true;\n\n // delay for context explorer to fully render\n await delay(300);\n await simulator.updateComplete;\n await document.fonts.ready;\n\n await assertScreenshot(\n 'simulator/context-explorer-open',\n getSimulatorClip(simulator, true)\n );\n });\n\n it('expands context tree items', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // ensure context explorer starts closed\n if ((simulator as any).contextExplorerOpen) {\n // click to close it first\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n contextButton.click();\n await simulator.updateComplete;\n await delay(100);\n }\n\n // now open context explorer\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const contextButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"expressions\"]')\n ) as HTMLElement;\n expect(contextButton).to.exist;\n contextButton.click();\n\n await simulator.updateComplete;\n await delay(100);\n\n // verify context explorer is now open\n expect((simulator as any).contextExplorerOpen).to.be.true;\n const contextExplorer =\n simulator.shadowRoot.querySelector('.context-explorer');\n expect(contextExplorer).to.exist;\n expect(contextExplorer.classList.contains('open')).to.be.true;\n\n // find and click on an expandable item (should have context-item-expandable class)\n const expandableItems = simulator.shadowRoot.querySelectorAll(\n '.context-item-expandable'\n );\n expect(expandableItems.length).to.be.greaterThan(0);\n\n const firstExpandable = expandableItems[0] as HTMLElement;\n firstExpandable.click();\n\n // wait for children to be displayed with specific content\n await waitForCondition(() => {\n const children =\n simulator.shadowRoot.querySelectorAll('.context-children');\n if (children.length === 0) return false;\n // also check that the children have rendered content\n const items = simulator.shadowRoot.querySelectorAll('.context-item');\n return items.length > expandableItems.length;\n }, 2000);\n\n // verify children are displayed\n const contextChildren =\n simulator.shadowRoot.querySelectorAll('.context-children');\n expect(contextChildren.length).to.be.greaterThan(0);\n\n await simulator.updateComplete;\n // delay for DOM to fully render expanded content (context rendering is complex)\n await delay(300);\n await simulator.updateComplete;\n\n // ensure fonts are loaded and give extra time for rendering\n await document.fonts.ready;\n\n // wait for any pending animation frames\n await new Promise((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(resolve))\n );\n await delay(200);\n\n await assertScreenshot(\n 'simulator/context-expanded',\n getSimulatorClip(simulator, true)\n );\n });\n\n it('cycles simulator size', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // initially should be medium (set in createSimulator)\n expect(simulator.size).to.equal('medium');\n\n // find and click the size button (shows current size as text)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n expect(sizeButton).to.exist;\n sizeButton.click();\n\n await simulator.updateComplete;\n\n // should now be large (medium -> large)\n expect(simulator.size).to.equal('large');\n });\n\n it('resets simulation', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // send a message first\n mockSimulatorResume('Response to test message');\n const input = simulator.shadowRoot.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n input.value = 'Test message';\n input.dispatchEvent(new Event('input'));\n\n const enterEvent = new KeyboardEvent('keyup', {\n key: 'Enter',\n bubbles: true\n });\n input.dispatchEvent(enterEvent);\n\n await delay(1000);\n await simulator.updateComplete;\n\n // verify we have multiple messages\n let messages = simulator.shadowRoot.querySelectorAll('.message');\n const messageCountBefore = messages.length;\n expect(messageCountBefore).to.be.greaterThan(1);\n\n // mock the start response for reset\n mockSimulatorStart();\n\n // click the reset button (has delete icon)\n const optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n const resetButton = optionButtons.find((btn) =>\n btn.querySelector('temba-icon[name=\"delete\"]')\n ) as HTMLElement;\n expect(resetButton).to.exist;\n resetButton.click();\n\n await delay(100);\n await simulator.updateComplete;\n\n // verify messages are reset - should go back to just initial message\n messages = simulator.shadowRoot.querySelectorAll('.message');\n expect(messages.length).to.be.lessThan(messageCountBefore);\n\n await assertScreenshot(\n 'simulator/after-reset',\n getSimulatorClip(simulator)\n );\n });\n\n it('displays event info messages', async () => {\n const responseWithEvents = {\n session: {\n status: 'waiting',\n trigger: {\n type: 'manual',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' }\n },\n runs: [\n {\n uuid: 'run-1',\n flow: { uuid: FLOW_UUID, name: 'Test Flow' },\n status: 'waiting',\n path: [\n {\n uuid: 'step-1',\n node_uuid: 'node-1',\n arrived_on: new Date().toISOString(),\n exit_uuid: null\n }\n ]\n }\n ],\n environment: {\n date_format: 'YYYY-MM-DD',\n time_format: 'HH:mm',\n timezone: 'America/New_York',\n allowed_languages: ['eng'],\n default_country: 'US'\n }\n },\n events: [\n {\n type: 'contact_field_changed',\n created_on: new Date().toISOString(),\n field: { key: 'name', name: 'Name' },\n value: { text: 'John Doe' }\n },\n {\n type: 'msg_created',\n created_on: new Date().toISOString(),\n msg: {\n uuid: 'msg-1',\n text: 'Your name has been updated!',\n urn: 'tel:+12065551212'\n }\n }\n ],\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n urns: ['tel:+12065551212'],\n fields: {\n name: 'John Doe'\n },\n groups: [],\n language: 'eng',\n status: 'active',\n created_on: new Date().toISOString()\n },\n context: {\n contact: {\n uuid: 'fb3787ab-2eda-48a0-a2bc-e2ddadec1286',\n name: 'John Doe',\n fields: {\n name: 'John Doe'\n }\n }\n }\n };\n\n mockPOST(/\\/flow\\/simulate\\/.*\\//, responseWithEvents);\n\n const simulator: Simulator = await createSimulator();\n simulator.size = 'medium';\n await simulator.updateComplete;\n await openSimulator(simulator);\n\n // verify event info is displayed\n const eventInfo = simulator.shadowRoot.querySelectorAll('.event-info');\n expect(eventInfo.length).to.be.greaterThan(0);\n\n await assertScreenshot('simulator/event-info', getSimulatorClip(simulator));\n });\n\n it('displays different simulator sizes', async () => {\n mockSimulatorStart();\n\n const simulator: Simulator = await createSimulator();\n await openSimulator(simulator);\n\n // get size button - find it by checking if textContent is a size indicator\n let optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n let sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n expect(sizeButton).to.exist;\n\n // cycle to next size\n sizeButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n // verify size changed\n expect(simulator.size).to.equal('large');\n\n // re-query the button after it updated\n optionButtons = Array.from(\n simulator.shadowRoot.querySelectorAll('.option-btn')\n );\n sizeButton = optionButtons.find((btn) => {\n const text = btn.textContent?.trim();\n return text === 'S' || text === 'M' || text === 'L';\n }) as HTMLElement;\n\n // cycle to next size\n sizeButton.click();\n await simulator.updateComplete;\n await delay(200);\n\n expect(simulator.size).to.equal('small');\n });\n\n it('verifies simulator endpoint configuration', async () => {\n const simulator: Simulator = await createSimulator();\n\n // verify endpoint is set correctly from flow prop\n expect(simulator.endpoint).to.equal(`/flow/simulate/${FLOW_UUID}/`);\n\n // change flow prop and verify endpoint updates\n simulator.flow = 'different-flow-456';\n await simulator.updateComplete;\n\n expect(simulator.endpoint).to.equal('/flow/simulate/different-flow-456/');\n });\n});\n"]}
|
|
@@ -173,7 +173,7 @@ export const waitForCondition = async (predicate, maxAttempts = 20, delayMs = 50
|
|
|
173
173
|
export const assertScreenshot = async (filename, clip, waitForNetwork = false) => {
|
|
174
174
|
// detect if we're running in copilot's environment and use adaptive threshold
|
|
175
175
|
const isCopilotEnvironment = window.isCopilotEnvironment;
|
|
176
|
-
const threshold = isCopilotEnvironment ? 1.0 : 0.
|
|
176
|
+
const threshold = isCopilotEnvironment ? 1.0 : 0.2;
|
|
177
177
|
const exclude = [];
|
|
178
178
|
try {
|
|
179
179
|
await window.matchPageSnapshot(`${filename}.png`, clip, exclude, threshold, waitForNetwork);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../temba-modules';\nimport { DateTime } from 'luxon';\ninterface Clip {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nimport { expect, fixture, html, assert } from '@open-wc/testing';\n\n// disable transitions for all tests to prevent flaky screenshot tests\nconst style = document.createElement('style');\nstyle.textContent = `\n * {\n --transition-speed: 0ms !important;\n }\n`;\ndocument.head.appendChild(style);\n\n// prevent resize event listeners from being added during tests\n// this prevents flaky positioning in components that adjust on resize\nconst originalAddEventListener = window.addEventListener;\nwindow.addEventListener = function (type, listener, options) {\n if (type === 'resize') {\n // skip adding resize listeners during tests\n return;\n }\n return originalAddEventListener.call(this, type, listener, options);\n} as typeof window.addEventListener;\nimport MouseHelper from './MouseHelper';\nimport { Store } from '../src/store/Store';\nimport { stub } from 'sinon';\nimport { Select, SelectOption } from '../src/form/select/Select';\nimport { Options } from '../src/display/Options';\nimport { Attachment } from '../src/interfaces';\nimport { Compose } from '../src/form/Compose';\n\nexport interface CodeMock {\n endpoint: RegExp;\n body: string;\n headers: any;\n status: string;\n}\n\nconst gets: CodeMock[] = [];\nlet posts: CodeMock[] = [];\nlet normalFetch;\n\nexport const showMouse = async () => {\n const mouse = await fixture(html`<mouse-helper />`);\n assert.instanceOf(mouse, MouseHelper);\n};\n\nexport const getAttributes = (attrs: any = {}) => {\n return `${Object.keys(attrs)\n .map((name: string) => {\n if (typeof attrs[name] === 'boolean' && attrs[name]) {\n return name;\n }\n return `${name}='${attrs[name]}'`;\n })\n .join(' ')}`;\n};\n\nexport const getComponent = async (\n tag,\n attrs: any = {},\n slot = '',\n width = 250,\n height = 0,\n style = ''\n) => {\n const spec = `<${tag} ${getAttributes(attrs)}>${slot}</${tag}>`;\n const parentNode = document.createElement('div');\n const styleAttribute = `\n ${width > 0 ? `width:${width}px;` : ``} \n ${height > 0 ? `height:${height}px;` : ``}\n ${style ? style : ``}\n `;\n parentNode.setAttribute('style', styleAttribute);\n return await fixture(spec, { parentNode });\n};\n\nconst createResponse = (mocked) => {\n const mockResponse = new window.Response(mocked.body, {\n status: mocked.status,\n headers: {\n 'Content-type': 'text/html',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst createJSONResponse = (mocked) => {\n const mockResponse = new window.Response(JSON.stringify(mocked.body), {\n status: mocked.status,\n headers: {\n 'Content-type': 'application/json',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst getResponse = (endpoint: string, options = { method: 'GET' }) => {\n // check if our path has been mocked in code\n const mocks = options.method === 'GET' ? gets : posts;\n const codeMock = mocks.find((mock) => mock.endpoint.test(endpoint));\n\n if (codeMock) {\n if (typeof codeMock.body === 'string') {\n // see if we are being mocked to a file\n if (codeMock.body.startsWith('/')) {\n endpoint = codeMock.body;\n } else {\n return createResponse(codeMock);\n }\n } else {\n return createJSONResponse(codeMock);\n }\n }\n // otherwise fetch over http\n return normalFetch(endpoint, options);\n};\n\nbefore(async () => {\n normalFetch = window.fetch;\n stub(window, 'fetch').callsFake(getResponse);\n await setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });\n});\n\nafter(() => {\n (window.fetch as any).restore();\n});\n\nconst mockMapping = {\n '/test-assets/api/users/admin1.json': [\n /\\/api\\/v2\\/users.json\\?email=admin1@nyaruka.com/\n ],\n '/test-assets/api/users/editor1.json': [\n /\\/api\\/v2\\/users.json\\?email=editor1@nyaruka.com/\n ],\n '/test-assets/api/users/agent1.json': [\n /\\/api\\/v2\\/users.json\\?email=agent1@nyaruka.com/\n ],\n '/test-assets/api/users/viewer1.json': [\n /\\/api\\/v2\\/users.json\\?email=viewer1@nyaruka.com/\n ],\n '/test-assets/contacts/contact-tickets.json': [\n /\\/api\\/v2\\/tickets.json\\?contact=24d64810-3315-4ff5-be85-48e3fe055bf9/\n ]\n};\n\nexport const mockAPI = () => {\n for (const key in mockMapping) {\n const urls = mockMapping[key];\n for (const url of urls) {\n mockGET(url, key);\n }\n }\n\n // Add mock data for contact form endpoints\n mockGET(/\\/api\\/v2\\/channels\\.json/, {\n results: [\n { uuid: 'chan-1', name: 'WhatsApp Channel' },\n { uuid: 'chan-2', name: 'Telegram Channel' },\n { uuid: 'chan-3', name: 'SMS Channel' },\n { uuid: 'chan-4', name: 'Facebook Messenger' }\n ]\n });\n\n mockGET(/\\/api\\/v2\\/languages\\.json/, {\n results: [\n { iso: 'eng', name: 'English' },\n { iso: 'spa', name: 'Spanish' },\n { iso: 'fra', name: 'French' },\n { iso: 'por', name: 'Portuguese' },\n { iso: 'deu', name: 'German' }\n ]\n });\n};\n\nexport const mockGET = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n gets.push({ endpoint, body, headers, status });\n};\n\nexport const mockPOST = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n posts.push({ endpoint, body, headers, status });\n};\n\nexport const clearMockPosts = () => {\n posts = [];\n};\n\nexport const checkTimers = (clock: any) => {\n expect(!!clock.timers).to.equal(true, 'Expected timers not found');\n expect(\n Object.keys(clock.timers).length,\n `Timers still to be run ${JSON.stringify(clock.timers)}`\n ).to.equal(0);\n};\n\nexport const delay = (millis: number) => {\n return new Promise(function (resolve) {\n window.setTimeout(resolve, millis);\n });\n};\n\n// Enhanced wait utility for more robust testing\nexport const waitForCondition = async (\n predicate: () => boolean,\n maxAttempts: number = 20,\n delayMs: number = 50\n): Promise<void> => {\n let attempts = 0;\n while (!predicate() && attempts < maxAttempts) {\n await delay(delayMs);\n attempts++;\n }\n if (!predicate()) {\n throw new Error(\n `Condition not met after ${maxAttempts} attempts (${\n maxAttempts * delayMs\n }ms)`\n );\n }\n};\n\nexport const assertScreenshot = async (\n filename: string,\n clip: Clip,\n waitForNetwork: boolean = false\n) => {\n // detect if we're running in copilot's environment and use adaptive threshold\n const isCopilotEnvironment = (window as any).isCopilotEnvironment;\n const threshold = isCopilotEnvironment ? 1.0 : 0.1;\n const exclude: Clip[] = [];\n\n try {\n await (window as any).matchPageSnapshot(\n `${filename}.png`,\n clip,\n exclude,\n threshold,\n waitForNetwork\n );\n } catch (error) {\n if (error.message) {\n throw new Error(\n `${error.message} ${\n error.expected\n ? `Expected ${error.expected} but got ${error.actual}`\n : ''\n } ${error.files ? `\\n${error.files.join('\\n')}` : ''}`\n );\n }\n throw new Error(error);\n }\n};\n\nexport const getClip = (ele: HTMLElement) => {\n let clip: any = ele.getBoundingClientRect();\n if (!clip.width || !clip.height) {\n clip = ele.shadowRoot.firstElementChild.getBoundingClientRect();\n }\n\n // add some padding\n const padding = 10;\n const width = clip.width + padding * 2;\n const height = clip.height + padding * 2;\n const y = clip.y - padding;\n const x = clip.x - padding;\n\n const newClip = {\n x,\n y,\n width,\n height,\n bottom: y + height,\n right: x + width,\n top: y,\n left: x\n };\n\n return newClip;\n};\n\nexport const mouseClickElement = async (ele: HTMLElement | Element) => {\n const bounds = ele.getBoundingClientRect();\n await mouseClick(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n};\n\nexport const getHTMLAttrs = (attrs: any = {}) => {\n return Object.keys(attrs)\n .map((name: string) => `${name}='${attrs[name]}'`)\n .join(' ');\n};\n\nexport const getHTML = (tag: string, attrs: any = {}) => {\n return `<${tag} ${getHTMLAttrs(attrs)}></${tag}>`;\n};\n\nexport const loadStore = async () => {\n const store: Store = await fixture(\n `<temba-store \n completion='/test-assets/store/editor.json'\n groups='/test-assets/store/groups.json'\n languages='/test-assets/store/languages.json'\n fields='/test-assets/store/fields.json'\n users='/test-assets/store/users.json'\n workspace='/test-assets/store/workspace.json'\n />`\n );\n await store.initialHttpComplete;\n await store.initialHttpComplete;\n\n return store;\n};\n\nexport const mockNow = (isodate: string) => {\n return stub(DateTime, 'now').returns(DateTime.fromISO(isodate));\n};\n\nexport const getOptions = (select: Select<SelectOption>): Options => {\n return select.shadowRoot.querySelector('temba-options[visible]');\n};\n\nexport const clickOption = async (\n clock: any,\n select: Select<SelectOption>,\n index: number\n) => {\n const options = getOptions(select);\n if (!options) {\n throw new Error('No options element found');\n }\n\n // Wait for the specific option to be available, but only if it's not already there\n const existingOption = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n if (!existingOption) {\n try {\n // Increased wait time to handle slower CI environments\n await waitForCondition(\n () => {\n const option = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n return !!option;\n },\n 10,\n 25\n );\n } catch (e) {\n throw new Error(`Option at index ${index} not found after waiting`);\n }\n }\n\n const option = options.shadowRoot.querySelector(\n `[data-option-index=\"${index}\"]`\n ) as HTMLDivElement;\n\n await mouseClickElement(option);\n await options.updateComplete;\n await select.updateComplete;\n await clock.runAll();\n\n checkTimers(clock);\n};\nexport const openSelect = async (clock: any, select: Select<SelectOption>) => {\n const container = select.shadowRoot.querySelector('.select-container');\n container.dispatchEvent(new MouseEvent('click', { bubbles: true }));\n\n clock.runAll();\n\n // add more explicit waiting and clock ticks\n await select.updateComplete;\n clock.runAll();\n\n // reduce wait time for options to become visible\n await waitFor(25);\n clock.runAll();\n\n // For non-endpoint selects, options might be immediately available\n // For endpoint selects, we need to wait for them to load\n const hasEndpoint = select.getAttribute('endpoint');\n if (hasEndpoint) {\n try {\n // Wait for options to be properly rendered and visible (but only for endpoint selects)\n // Increased max attempts to handle slower CI environments\n await waitForCondition(\n () => {\n const options = select.shadowRoot.querySelector(\n 'temba-options[visible]'\n );\n return options && options.isConnected;\n },\n 10,\n 25\n );\n } catch (e) {\n // If condition fails, continue - some tests might not need options to be visible immediately\n }\n }\n};\n\nexport const openAndClick = async (\n clock: any,\n select: Select<SelectOption>,\n idx: number\n) => {\n await openSelect(clock, select);\n\n // Add this line to ensure proper timing when running as part of a test suite\n await select.updateComplete;\n clock.tick(25); // Reduced from 50 to give minimum time for options to render\n\n await clickOption(clock, select, idx);\n};\n\n// valid = attachments that are uploaded sent to the server when the user clicks send\nexport const getValidAttachments = (numFiles = 2): Attachment[] => {\n const attachments = [];\n let index = 1;\n while (index <= numFiles) {\n const s = 's' + index;\n const attachment = {\n uuid: s,\n content_type: 'image/png',\n type: 'image/png',\n filename: 'name_' + s,\n url: 'url_' + s,\n size: 1024,\n error: null\n } as Attachment;\n attachments.push(attachment);\n index++;\n }\n return attachments;\n};\n\nexport const updateComponent = async (\n compose: Compose,\n text?: string,\n attachments?: Attachment[]\n): Promise<void> => {\n compose.initialText = text ? text : '';\n compose.currentAttachments = attachments ? attachments : [];\n await compose.updateComplete;\n};\nexport const getValidText = () => {\n return 'sà-wàd-dee!';\n};\n\n// Helper for waiting for select pagination to complete\nexport const waitForSelectPagination = async (\n select: Select<SelectOption>,\n clock: any,\n expectedCount: number,\n maxAttempts: number = 30\n): Promise<void> => {\n let attempts = 0;\n while (attempts < maxAttempts) {\n // Ensure we're not still fetching\n if (!select.fetching && select.visibleOptions.length >= expectedCount) {\n return;\n }\n\n await select.updateComplete;\n clock.runAll();\n\n // Give more time between attempts for slow CI environments\n await delay(75);\n\n attempts++;\n }\n\n throw new Error(\n `Pagination did not complete after ${maxAttempts} attempts (${\n maxAttempts * 75\n }ms). ` +\n `Expected ${expectedCount} options, got ${select.visibleOptions.length}. ` +\n `Fetching: ${select.fetching}`\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":"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","sourcesContent":["import '../temba-modules';\nimport { DateTime } from 'luxon';\ninterface Clip {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nimport { expect, fixture, html, assert } from '@open-wc/testing';\n\n// disable transitions for all tests to prevent flaky screenshot tests\nconst style = document.createElement('style');\nstyle.textContent = `\n * {\n --transition-speed: 0ms !important;\n }\n`;\ndocument.head.appendChild(style);\n\n// prevent resize event listeners from being added during tests\n// this prevents flaky positioning in components that adjust on resize\nconst originalAddEventListener = window.addEventListener;\nwindow.addEventListener = function (type, listener, options) {\n if (type === 'resize') {\n // skip adding resize listeners during tests\n return;\n }\n return originalAddEventListener.call(this, type, listener, options);\n} as typeof window.addEventListener;\nimport MouseHelper from './MouseHelper';\nimport { Store } from '../src/store/Store';\nimport { stub } from 'sinon';\nimport { Select, SelectOption } from '../src/form/select/Select';\nimport { Options } from '../src/display/Options';\nimport { Attachment } from '../src/interfaces';\nimport { Compose } from '../src/form/Compose';\n\nexport interface CodeMock {\n endpoint: RegExp;\n body: string;\n headers: any;\n status: string;\n}\n\nconst gets: CodeMock[] = [];\nlet posts: CodeMock[] = [];\nlet normalFetch;\n\nexport const showMouse = async () => {\n const mouse = await fixture(html`<mouse-helper />`);\n assert.instanceOf(mouse, MouseHelper);\n};\n\nexport const getAttributes = (attrs: any = {}) => {\n return `${Object.keys(attrs)\n .map((name: string) => {\n if (typeof attrs[name] === 'boolean' && attrs[name]) {\n return name;\n }\n return `${name}='${attrs[name]}'`;\n })\n .join(' ')}`;\n};\n\nexport const getComponent = async (\n tag,\n attrs: any = {},\n slot = '',\n width = 250,\n height = 0,\n style = ''\n) => {\n const spec = `<${tag} ${getAttributes(attrs)}>${slot}</${tag}>`;\n const parentNode = document.createElement('div');\n const styleAttribute = `\n ${width > 0 ? `width:${width}px;` : ``} \n ${height > 0 ? `height:${height}px;` : ``}\n ${style ? style : ``}\n `;\n parentNode.setAttribute('style', styleAttribute);\n return await fixture(spec, { parentNode });\n};\n\nconst createResponse = (mocked) => {\n const mockResponse = new window.Response(mocked.body, {\n status: mocked.status,\n headers: {\n 'Content-type': 'text/html',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst createJSONResponse = (mocked) => {\n const mockResponse = new window.Response(JSON.stringify(mocked.body), {\n status: mocked.status,\n headers: {\n 'Content-type': 'application/json',\n ...mocked.headers\n }\n });\n\n return Promise.resolve(mockResponse);\n};\n\nconst getResponse = (endpoint: string, options = { method: 'GET' }) => {\n // check if our path has been mocked in code\n const mocks = options.method === 'GET' ? gets : posts;\n const codeMock = mocks.find((mock) => mock.endpoint.test(endpoint));\n\n if (codeMock) {\n if (typeof codeMock.body === 'string') {\n // see if we are being mocked to a file\n if (codeMock.body.startsWith('/')) {\n endpoint = codeMock.body;\n } else {\n return createResponse(codeMock);\n }\n } else {\n return createJSONResponse(codeMock);\n }\n }\n // otherwise fetch over http\n return normalFetch(endpoint, options);\n};\n\nbefore(async () => {\n normalFetch = window.fetch;\n stub(window, 'fetch').callsFake(getResponse);\n await setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });\n});\n\nafter(() => {\n (window.fetch as any).restore();\n});\n\nconst mockMapping = {\n '/test-assets/api/users/admin1.json': [\n /\\/api\\/v2\\/users.json\\?email=admin1@nyaruka.com/\n ],\n '/test-assets/api/users/editor1.json': [\n /\\/api\\/v2\\/users.json\\?email=editor1@nyaruka.com/\n ],\n '/test-assets/api/users/agent1.json': [\n /\\/api\\/v2\\/users.json\\?email=agent1@nyaruka.com/\n ],\n '/test-assets/api/users/viewer1.json': [\n /\\/api\\/v2\\/users.json\\?email=viewer1@nyaruka.com/\n ],\n '/test-assets/contacts/contact-tickets.json': [\n /\\/api\\/v2\\/tickets.json\\?contact=24d64810-3315-4ff5-be85-48e3fe055bf9/\n ]\n};\n\nexport const mockAPI = () => {\n for (const key in mockMapping) {\n const urls = mockMapping[key];\n for (const url of urls) {\n mockGET(url, key);\n }\n }\n\n // Add mock data for contact form endpoints\n mockGET(/\\/api\\/v2\\/channels\\.json/, {\n results: [\n { uuid: 'chan-1', name: 'WhatsApp Channel' },\n { uuid: 'chan-2', name: 'Telegram Channel' },\n { uuid: 'chan-3', name: 'SMS Channel' },\n { uuid: 'chan-4', name: 'Facebook Messenger' }\n ]\n });\n\n mockGET(/\\/api\\/v2\\/languages\\.json/, {\n results: [\n { iso: 'eng', name: 'English' },\n { iso: 'spa', name: 'Spanish' },\n { iso: 'fra', name: 'French' },\n { iso: 'por', name: 'Portuguese' },\n { iso: 'deu', name: 'German' }\n ]\n });\n};\n\nexport const mockGET = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n gets.push({ endpoint, body, headers, status });\n};\n\nexport const mockPOST = (\n endpoint: RegExp,\n body: any,\n headers: any = {},\n status = '200'\n) => {\n posts.push({ endpoint, body, headers, status });\n};\n\nexport const clearMockPosts = () => {\n posts = [];\n};\n\nexport const checkTimers = (clock: any) => {\n expect(!!clock.timers).to.equal(true, 'Expected timers not found');\n expect(\n Object.keys(clock.timers).length,\n `Timers still to be run ${JSON.stringify(clock.timers)}`\n ).to.equal(0);\n};\n\nexport const delay = (millis: number) => {\n return new Promise(function (resolve) {\n window.setTimeout(resolve, millis);\n });\n};\n\n// Enhanced wait utility for more robust testing\nexport const waitForCondition = async (\n predicate: () => boolean,\n maxAttempts: number = 20,\n delayMs: number = 50\n): Promise<void> => {\n let attempts = 0;\n while (!predicate() && attempts < maxAttempts) {\n await delay(delayMs);\n attempts++;\n }\n if (!predicate()) {\n throw new Error(\n `Condition not met after ${maxAttempts} attempts (${\n maxAttempts * delayMs\n }ms)`\n );\n }\n};\n\nexport const assertScreenshot = async (\n filename: string,\n clip: Clip,\n waitForNetwork: boolean = false\n) => {\n // detect if we're running in copilot's environment and use adaptive threshold\n const isCopilotEnvironment = (window as any).isCopilotEnvironment;\n const threshold = isCopilotEnvironment ? 1.0 : 0.2;\n const exclude: Clip[] = [];\n\n try {\n await (window as any).matchPageSnapshot(\n `${filename}.png`,\n clip,\n exclude,\n threshold,\n waitForNetwork\n );\n } catch (error) {\n if (error.message) {\n throw new Error(\n `${error.message} ${\n error.expected\n ? `Expected ${error.expected} but got ${error.actual}`\n : ''\n } ${error.files ? `\\n${error.files.join('\\n')}` : ''}`\n );\n }\n throw new Error(error);\n }\n};\n\nexport const getClip = (ele: HTMLElement) => {\n let clip: any = ele.getBoundingClientRect();\n if (!clip.width || !clip.height) {\n clip = ele.shadowRoot.firstElementChild.getBoundingClientRect();\n }\n\n // add some padding\n const padding = 10;\n const width = clip.width + padding * 2;\n const height = clip.height + padding * 2;\n const y = clip.y - padding;\n const x = clip.x - padding;\n\n const newClip = {\n x,\n y,\n width,\n height,\n bottom: y + height,\n right: x + width,\n top: y,\n left: x\n };\n\n return newClip;\n};\n\nexport const mouseClickElement = async (ele: HTMLElement | Element) => {\n const bounds = ele.getBoundingClientRect();\n await mouseClick(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n};\n\nexport const getHTMLAttrs = (attrs: any = {}) => {\n return Object.keys(attrs)\n .map((name: string) => `${name}='${attrs[name]}'`)\n .join(' ');\n};\n\nexport const getHTML = (tag: string, attrs: any = {}) => {\n return `<${tag} ${getHTMLAttrs(attrs)}></${tag}>`;\n};\n\nexport const loadStore = async () => {\n const store: Store = await fixture(\n `<temba-store \n completion='/test-assets/store/editor.json'\n groups='/test-assets/store/groups.json'\n languages='/test-assets/store/languages.json'\n fields='/test-assets/store/fields.json'\n users='/test-assets/store/users.json'\n workspace='/test-assets/store/workspace.json'\n />`\n );\n await store.initialHttpComplete;\n await store.initialHttpComplete;\n\n return store;\n};\n\nexport const mockNow = (isodate: string) => {\n return stub(DateTime, 'now').returns(DateTime.fromISO(isodate));\n};\n\nexport const getOptions = (select: Select<SelectOption>): Options => {\n return select.shadowRoot.querySelector('temba-options[visible]');\n};\n\nexport const clickOption = async (\n clock: any,\n select: Select<SelectOption>,\n index: number\n) => {\n const options = getOptions(select);\n if (!options) {\n throw new Error('No options element found');\n }\n\n // Wait for the specific option to be available, but only if it's not already there\n const existingOption = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n if (!existingOption) {\n try {\n // Increased wait time to handle slower CI environments\n await waitForCondition(\n () => {\n const option = options.shadowRoot?.querySelector(\n `[data-option-index=\"${index}\"]`\n );\n return !!option;\n },\n 10,\n 25\n );\n } catch (e) {\n throw new Error(`Option at index ${index} not found after waiting`);\n }\n }\n\n const option = options.shadowRoot.querySelector(\n `[data-option-index=\"${index}\"]`\n ) as HTMLDivElement;\n\n await mouseClickElement(option);\n await options.updateComplete;\n await select.updateComplete;\n await clock.runAll();\n\n checkTimers(clock);\n};\nexport const openSelect = async (clock: any, select: Select<SelectOption>) => {\n const container = select.shadowRoot.querySelector('.select-container');\n container.dispatchEvent(new MouseEvent('click', { bubbles: true }));\n\n clock.runAll();\n\n // add more explicit waiting and clock ticks\n await select.updateComplete;\n clock.runAll();\n\n // reduce wait time for options to become visible\n await waitFor(25);\n clock.runAll();\n\n // For non-endpoint selects, options might be immediately available\n // For endpoint selects, we need to wait for them to load\n const hasEndpoint = select.getAttribute('endpoint');\n if (hasEndpoint) {\n try {\n // Wait for options to be properly rendered and visible (but only for endpoint selects)\n // Increased max attempts to handle slower CI environments\n await waitForCondition(\n () => {\n const options = select.shadowRoot.querySelector(\n 'temba-options[visible]'\n );\n return options && options.isConnected;\n },\n 10,\n 25\n );\n } catch (e) {\n // If condition fails, continue - some tests might not need options to be visible immediately\n }\n }\n};\n\nexport const openAndClick = async (\n clock: any,\n select: Select<SelectOption>,\n idx: number\n) => {\n await openSelect(clock, select);\n\n // Add this line to ensure proper timing when running as part of a test suite\n await select.updateComplete;\n clock.tick(25); // Reduced from 50 to give minimum time for options to render\n\n await clickOption(clock, select, idx);\n};\n\n// valid = attachments that are uploaded sent to the server when the user clicks send\nexport const getValidAttachments = (numFiles = 2): Attachment[] => {\n const attachments = [];\n let index = 1;\n while (index <= numFiles) {\n const s = 's' + index;\n const attachment = {\n uuid: s,\n content_type: 'image/png',\n type: 'image/png',\n filename: 'name_' + s,\n url: 'url_' + s,\n size: 1024,\n error: null\n } as Attachment;\n attachments.push(attachment);\n index++;\n }\n return attachments;\n};\n\nexport const updateComponent = async (\n compose: Compose,\n text?: string,\n attachments?: Attachment[]\n): Promise<void> => {\n compose.initialText = text ? text : '';\n compose.currentAttachments = attachments ? attachments : [];\n await compose.updateComplete;\n};\nexport const getValidText = () => {\n return 'sà-wàd-dee!';\n};\n\n// Helper for waiting for select pagination to complete\nexport const waitForSelectPagination = async (\n select: Select<SelectOption>,\n clock: any,\n expectedCount: number,\n maxAttempts: number = 30\n): Promise<void> => {\n let attempts = 0;\n while (attempts < maxAttempts) {\n // Ensure we're not still fetching\n if (!select.fetching && select.visibleOptions.length >= expectedCount) {\n return;\n }\n\n await select.updateComplete;\n clock.runAll();\n\n // Give more time between attempts for slow CI environments\n await delay(75);\n\n attempts++;\n }\n\n throw new Error(\n `Pagination did not complete after ${maxAttempts} attempts (${\n maxAttempts * 75\n }ms). ` +\n `Expected ${expectedCount} options, got ${select.visibleOptions.length}. ` +\n `Fetching: ${select.fetching}`\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
|
package/src/Icons.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-duplicate-enum-values */
|
|
2
2
|
// for cache busting we dynamically generate a fingerprint, use yarn svg to update
|
|
3
|
-
export const SVG_FINGERPRINT = '
|
|
3
|
+
export const SVG_FINGERPRINT = '129c04a9f99f9f4e99c436a68bc95470';
|
|
4
4
|
|
|
5
5
|
// only icons below are included in the sprite sheet
|
|
6
6
|
export enum Icon {
|
|
@@ -76,6 +76,7 @@ export enum Icon {
|
|
|
76
76
|
flow_surveyor = 'tablet-01',
|
|
77
77
|
flow_user = 'hard-drive',
|
|
78
78
|
flows = 'flow',
|
|
79
|
+
follow = 'route',
|
|
79
80
|
global = 'at-sign',
|
|
80
81
|
grid = 'dots-grid',
|
|
81
82
|
group = 'users-01',
|
package/src/flow/CanvasNode.ts
CHANGED
|
@@ -43,6 +43,9 @@ export class CanvasNode extends RapidElement {
|
|
|
43
43
|
)
|
|
44
44
|
private includeCategoriesInTranslation!: boolean;
|
|
45
45
|
|
|
46
|
+
@fromStore(zustand, (state: AppState) => state.getCurrentActivity())
|
|
47
|
+
private activity!: any;
|
|
48
|
+
|
|
46
49
|
// Track exits that are in "removing" state
|
|
47
50
|
private exitRemovalTimeouts: Map<string, number> = new Map();
|
|
48
51
|
|
|
@@ -1572,6 +1575,10 @@ export class CanvasNode extends RapidElement {
|
|
|
1572
1575
|
supportsLocalization &&
|
|
1573
1576
|
!this.includeCategoriesInTranslation;
|
|
1574
1577
|
|
|
1578
|
+
// Get active contact count for this node
|
|
1579
|
+
const activeCount =
|
|
1580
|
+
(this.activity?.nodes && this.activity.nodes[this.node.uuid]) || 0;
|
|
1581
|
+
|
|
1575
1582
|
return html`
|
|
1576
1583
|
<div
|
|
1577
1584
|
id="${this.node.uuid}"
|
|
@@ -1582,6 +1589,11 @@ export class CanvasNode extends RapidElement {
|
|
|
1582
1589
|
})}
|
|
1583
1590
|
style="left:${this.ui.position.left}px;top:${this.ui.position.top}px"
|
|
1584
1591
|
>
|
|
1592
|
+
${activeCount > 0
|
|
1593
|
+
? html`<div class="active-count">
|
|
1594
|
+
${activeCount.toLocaleString()}
|
|
1595
|
+
</div>`
|
|
1596
|
+
: ''}
|
|
1585
1597
|
${nodeConfig && nodeConfig.type !== 'execute_actions'
|
|
1586
1598
|
? html`<div class="router" style="position: relative;">
|
|
1587
1599
|
<div
|
package/src/flow/Editor.ts
CHANGED
|
@@ -125,9 +125,15 @@ export class Editor extends RapidElement {
|
|
|
125
125
|
@property({ type: Array })
|
|
126
126
|
public features: string[] = [];
|
|
127
127
|
|
|
128
|
+
private activityTimer: number | null = null;
|
|
129
|
+
private activityInterval = 100; // Start with 100ms interval for fast initial load
|
|
130
|
+
|
|
128
131
|
@fromStore(zustand, (state: AppState) => state.flowDefinition)
|
|
129
132
|
private definition!: FlowDefinition;
|
|
130
133
|
|
|
134
|
+
@fromStore(zustand, (state: AppState) => state.simulatorActive)
|
|
135
|
+
private simulatorActive!: boolean;
|
|
136
|
+
|
|
131
137
|
@fromStore(zustand, (state: AppState) => state.canvasSize)
|
|
132
138
|
private canvasSize!: { width: number; height: number };
|
|
133
139
|
|
|
@@ -143,6 +149,9 @@ export class Editor extends RapidElement {
|
|
|
143
149
|
@fromStore(zustand, (state: AppState) => state.workspace)
|
|
144
150
|
private workspace!: Workspace;
|
|
145
151
|
|
|
152
|
+
@fromStore(zustand, (state: AppState) => state.getCurrentActivity())
|
|
153
|
+
private activityData!: any;
|
|
154
|
+
|
|
146
155
|
// Drag state
|
|
147
156
|
@state()
|
|
148
157
|
private isDragging = false;
|
|
@@ -379,6 +388,125 @@ export class Editor extends RapidElement {
|
|
|
379
388
|
z-index: 10;
|
|
380
389
|
}
|
|
381
390
|
|
|
391
|
+
/* Activity overlays on connections */
|
|
392
|
+
.jtk-overlay.activity-overlay {
|
|
393
|
+
background: #f3f3f3;
|
|
394
|
+
border: 1px solid #d9d9d9;
|
|
395
|
+
color: #333;
|
|
396
|
+
border-radius: 4px;
|
|
397
|
+
padding: 2px 4px;
|
|
398
|
+
font-size: 10px;
|
|
399
|
+
font-weight: 600;
|
|
400
|
+
line-height: 0.9;
|
|
401
|
+
cursor: pointer;
|
|
402
|
+
z-index: 500;
|
|
403
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/* Active contact count on nodes */
|
|
407
|
+
.active-count {
|
|
408
|
+
position: absolute;
|
|
409
|
+
background: var(--color-primary-dark, #3498db);
|
|
410
|
+
border: 1px solid var(--color-primary-darker, #2980b9);
|
|
411
|
+
border-radius: 12px;
|
|
412
|
+
padding: 3px 5px;
|
|
413
|
+
color: #fff;
|
|
414
|
+
font-weight: 500;
|
|
415
|
+
top: -10px;
|
|
416
|
+
left: -10px;
|
|
417
|
+
font-size: 13px;
|
|
418
|
+
min-width: 22px;
|
|
419
|
+
text-align: center;
|
|
420
|
+
z-index: 600;
|
|
421
|
+
line-height: 1;
|
|
422
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Recent contacts popup */
|
|
426
|
+
@keyframes popupBounceIn {
|
|
427
|
+
0% {
|
|
428
|
+
transform: scale(0.8);
|
|
429
|
+
opacity: 0;
|
|
430
|
+
}
|
|
431
|
+
50% {
|
|
432
|
+
transform: scale(1.05);
|
|
433
|
+
}
|
|
434
|
+
100% {
|
|
435
|
+
transform: scale(1);
|
|
436
|
+
opacity: 1;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.recent-contacts-popup {
|
|
441
|
+
display: none;
|
|
442
|
+
position: absolute;
|
|
443
|
+
width: 200px;
|
|
444
|
+
background: #f3f3f3;
|
|
445
|
+
border-radius: 10px;
|
|
446
|
+
box-shadow: 0 1px 3px 1px rgba(130, 130, 130, 0.2);
|
|
447
|
+
z-index: 1015;
|
|
448
|
+
transform-origin: top center;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.recent-contacts-popup.show {
|
|
452
|
+
display: block;
|
|
453
|
+
animation: popupBounceIn 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.recent-contacts-popup .popup-title {
|
|
457
|
+
background: #999;
|
|
458
|
+
color: #fff;
|
|
459
|
+
padding: 6px 0;
|
|
460
|
+
text-align: center;
|
|
461
|
+
border-top-left-radius: 10px;
|
|
462
|
+
border-top-right-radius: 10px;
|
|
463
|
+
font-size: 12px;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.recent-contacts-popup .no-contacts-message {
|
|
467
|
+
padding: 15px;
|
|
468
|
+
text-align: center;
|
|
469
|
+
color: #999;
|
|
470
|
+
font-size: 12px;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.recent-contacts-popup .contact-row {
|
|
474
|
+
padding: 8px 10px;
|
|
475
|
+
border-top: 1px solid #e0e0e0;
|
|
476
|
+
text-align: left;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.recent-contacts-popup .contact-row:last-child {
|
|
480
|
+
border-bottom-left-radius: 10px;
|
|
481
|
+
border-bottom-right-radius: 10px;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.recent-contacts-popup .contact-name {
|
|
485
|
+
display: block;
|
|
486
|
+
font-weight: 500;
|
|
487
|
+
font-size: 12px;
|
|
488
|
+
color: var(--color-link-primary, #1d4ed8);
|
|
489
|
+
cursor: pointer;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.recent-contacts-popup .contact-name:hover {
|
|
493
|
+
text-decoration: underline;
|
|
494
|
+
color: var(--color-link-primary, #1d4ed8);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.recent-contacts-popup .contact-operand {
|
|
498
|
+
padding-top: 3px;
|
|
499
|
+
font-size: 11px;
|
|
500
|
+
color: #666;
|
|
501
|
+
word-wrap: break-word;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.recent-contacts-popup .contact-time {
|
|
505
|
+
padding-top: 3px;
|
|
506
|
+
font-size: 10px;
|
|
507
|
+
color: #999;
|
|
508
|
+
}
|
|
509
|
+
|
|
382
510
|
/* Connection dragging feedback */
|
|
383
511
|
body svg.jtk-connector.jtk-dragging {
|
|
384
512
|
z-index: 99999 !important;
|
|
@@ -612,7 +740,7 @@ export class Editor extends RapidElement {
|
|
|
612
740
|
changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
|
|
613
741
|
): void {
|
|
614
742
|
super.firstUpdated(changes);
|
|
615
|
-
this.plumber = new Plumber(this.querySelector('#canvas'));
|
|
743
|
+
this.plumber = new Plumber(this.querySelector('#canvas'), this);
|
|
616
744
|
this.setupGlobalEventListeners();
|
|
617
745
|
if (changes.has('flow')) {
|
|
618
746
|
getStore().getState().fetchRevision(`/flow/revisions/${this.flow}`);
|
|
@@ -692,6 +820,29 @@ export class Editor extends RapidElement {
|
|
|
692
820
|
}
|
|
693
821
|
|
|
694
822
|
this.translationCache.clear();
|
|
823
|
+
|
|
824
|
+
// Start fetching activity data when definition is loaded
|
|
825
|
+
if (this.definition?.uuid) {
|
|
826
|
+
this.startActivityFetching();
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if (changes.has('simulatorActive')) {
|
|
831
|
+
if (this.simulatorActive) {
|
|
832
|
+
// Stop polling when simulator becomes active
|
|
833
|
+
this.stopActivityFetching();
|
|
834
|
+
} else {
|
|
835
|
+
// Resume polling and refresh activity when simulator closes
|
|
836
|
+
this.activityInterval = 100; // Reset to fast initial interval
|
|
837
|
+
this.startActivityFetching();
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (changes.has('activityData')) {
|
|
842
|
+
// Update plumber with new activity data
|
|
843
|
+
if (this.plumber) {
|
|
844
|
+
this.plumber.setActivityData(this.activityData);
|
|
845
|
+
}
|
|
695
846
|
}
|
|
696
847
|
|
|
697
848
|
if (changes.has('dirtyDate')) {
|
|
@@ -768,6 +919,52 @@ export class Editor extends RapidElement {
|
|
|
768
919
|
getStore().getState().setDirtyDate(null);
|
|
769
920
|
}
|
|
770
921
|
|
|
922
|
+
private startActivityFetching(): void {
|
|
923
|
+
// Don't start if simulator is active
|
|
924
|
+
if (this.simulatorActive) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
// Fetch immediately
|
|
928
|
+
this.fetchActivityData();
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
private stopActivityFetching(): void {
|
|
932
|
+
if (this.activityTimer !== null) {
|
|
933
|
+
clearTimeout(this.activityTimer);
|
|
934
|
+
this.activityTimer = null;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
private fetchActivityData(): void {
|
|
939
|
+
if (!this.definition?.uuid) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Don't fetch if simulator is active
|
|
944
|
+
if (this.simulatorActive) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
const activityEndpoint = `/flow/activity/${this.definition.uuid}/`;
|
|
949
|
+
const store = getStore();
|
|
950
|
+
if (!store) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
const state = store.getState();
|
|
954
|
+
state.fetchActivity(activityEndpoint).then(() => {
|
|
955
|
+
// Schedule next fetch with exponential backoff (max 5 minutes)
|
|
956
|
+
this.activityInterval = Math.min(60000 * 5, this.activityInterval + 100);
|
|
957
|
+
|
|
958
|
+
if (this.activityTimer !== null) {
|
|
959
|
+
clearTimeout(this.activityTimer);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
this.activityTimer = window.setTimeout(() => {
|
|
963
|
+
this.fetchActivityData();
|
|
964
|
+
}, this.activityInterval);
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
|
|
771
968
|
private handleLanguageChange(languageCode: string): void {
|
|
772
969
|
zustand.getState().setLanguageCode(languageCode);
|
|
773
970
|
|
|
@@ -785,6 +982,10 @@ export class Editor extends RapidElement {
|
|
|
785
982
|
clearTimeout(this.saveTimer);
|
|
786
983
|
this.saveTimer = null;
|
|
787
984
|
}
|
|
985
|
+
if (this.activityTimer !== null) {
|
|
986
|
+
clearTimeout(this.activityTimer);
|
|
987
|
+
this.activityTimer = null;
|
|
988
|
+
}
|
|
788
989
|
document.removeEventListener('mousemove', this.boundMouseMove);
|
|
789
990
|
document.removeEventListener('mouseup', this.boundMouseUp);
|
|
790
991
|
document.removeEventListener('mousedown', this.boundGlobalMouseDown);
|
|
@@ -2927,6 +3128,44 @@ export class Editor extends RapidElement {
|
|
|
2927
3128
|
`;
|
|
2928
3129
|
}
|
|
2929
3130
|
|
|
3131
|
+
/**
|
|
3132
|
+
* Focus on a specific node by smoothly scrolling it to the center of the canvas
|
|
3133
|
+
*/
|
|
3134
|
+
public focusNode(nodeUuid: string) {
|
|
3135
|
+
const nodeElement = this.querySelector(
|
|
3136
|
+
`temba-flow-node[uuid="${nodeUuid}"]`
|
|
3137
|
+
) as HTMLElement;
|
|
3138
|
+
if (!nodeElement) {
|
|
3139
|
+
return;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
const editor = this.querySelector('#editor') as HTMLElement;
|
|
3143
|
+
if (!editor) {
|
|
3144
|
+
return;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
// Get the editor's dimensions and scroll position
|
|
3148
|
+
const editorRect = editor.getBoundingClientRect();
|
|
3149
|
+
const editorCenterX = editorRect.width / 2;
|
|
3150
|
+
const editorCenterY = editorRect.height / 2;
|
|
3151
|
+
|
|
3152
|
+
// Get node position relative to the editor's scroll container
|
|
3153
|
+
const nodeRect = nodeElement.getBoundingClientRect();
|
|
3154
|
+
const nodeCenterX = nodeElement.offsetLeft + nodeRect.width / 2;
|
|
3155
|
+
const nodeCenterY = nodeElement.offsetTop + nodeRect.height / 2;
|
|
3156
|
+
|
|
3157
|
+
// Calculate the scroll position needed to center the node
|
|
3158
|
+
const targetScrollX = nodeCenterX - editorCenterX;
|
|
3159
|
+
const targetScrollY = nodeCenterY - editorCenterY;
|
|
3160
|
+
|
|
3161
|
+
// Smooth scroll the editor container to the target position
|
|
3162
|
+
editor.scrollTo({
|
|
3163
|
+
left: Math.max(0, targetScrollX),
|
|
3164
|
+
top: Math.max(0, targetScrollY),
|
|
3165
|
+
behavior: 'smooth'
|
|
3166
|
+
});
|
|
3167
|
+
}
|
|
3168
|
+
|
|
2930
3169
|
public render(): TemplateResult {
|
|
2931
3170
|
// we have to embed our own style since we are in light DOM
|
|
2932
3171
|
const style = html`<style>
|