@nyaruka/temba-components 0.136.1 → 0.138.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 +19 -0
- package/demo/components/webchat/example.html +2 -2
- package/dist/temba-components.js +692 -622
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +123 -44
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/display/FloatingTab.js +2 -2
- package/out-tsc/src/display/FloatingTab.js.map +1 -1
- package/out-tsc/src/events/eventRenderers.js +442 -0
- package/out-tsc/src/events/eventRenderers.js.map +1 -0
- package/out-tsc/src/flow/CanvasNode.js +45 -24
- package/out-tsc/src/flow/CanvasNode.js.map +1 -1
- package/out-tsc/src/flow/Editor.js +308 -18
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +0 -1
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/flow/Plumber.js +110 -64
- package/out-tsc/src/flow/Plumber.js.map +1 -1
- package/out-tsc/src/list/ShortcutList.js +1 -1
- package/out-tsc/src/list/ShortcutList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +12 -321
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +439 -575
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/src/store/AppState.js +12 -2
- package/out-tsc/src/store/AppState.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-node.test.js +2 -1
- package/out-tsc/test/temba-flow-editor-node.test.js.map +1 -1
- package/out-tsc/test/temba-flow-editor-revisions.test.js +106 -0
- package/out-tsc/test/temba-flow-editor-revisions.test.js.map +1 -0
- package/out-tsc/test/temba-flow-editor.test.js +14 -10
- package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js +7 -1
- package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
- package/out-tsc/test/temba-flow-plumber.test.js +6 -0
- package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +51 -32
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- 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/display/Chat.ts +123 -44
- package/src/display/FloatingTab.ts +2 -2
- package/src/events/eventRenderers.ts +527 -0
- package/src/flow/CanvasNode.ts +54 -29
- package/src/flow/Editor.ts +360 -19
- package/src/flow/NodeEditor.ts +0 -1
- package/src/flow/Plumber.ts +123 -69
- package/src/list/ShortcutList.ts +1 -1
- package/src/live/ContactChat.ts +17 -376
- package/src/simulator/Simulator.ts +498 -617
- package/src/store/AppState.ts +13 -2
- package/test/temba-flow-editor-node.test.ts +2 -1
- package/test/temba-flow-editor-revisions.test.ts +134 -0
- package/test/temba-flow-editor.test.ts +16 -10
- package/test/temba-flow-plumber-connections.test.ts +7 -1
- package/test/temba-flow-plumber.test.ts +6 -0
- package/test/temba-simulator.test.ts +64 -34
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../src/simulator/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { RapidElement } from '../RapidElement';\nimport { FloatingWindow } from '../layout/FloatingWindow';\nimport { css, PropertyValueMap } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { postJSON, fromCookie } from '../utils';\nimport { getStore } from '../store/Store';\nimport { CustomEventType } from '../interfaces';\n\n// test attachment URLs\nconst TEST_IMAGES = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_a.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_b.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_c.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_d.jpg'\n];\n\nconst TEST_VIDEOS = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_video_a.mp4'\n];\n\nconst TEST_AUDIO = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_audio_a.mp3'\n];\n\nconst TEST_LOCATIONS = [\n 'geo:47.6062,-122.3321', // Seattle\n 'geo:-0.1807,-78.4678', // Quito\n 'geo:-2.9001,-79.0059', // Cuenca\n 'geo:-1.9536,30.0606' // Kigali\n];\n\ninterface Contact {\n uuid: string;\n name?: string;\n urns: string[];\n fields?: { [key: string]: any };\n groups?: any[];\n language?: string;\n status?: string;\n created_on?: string;\n}\n\ninterface Session {\n environment: any;\n runs: any[];\n status: string;\n trigger: any;\n wait?: any;\n}\n\ninterface Message {\n uuid: string;\n text?: string;\n urn: string;\n attachments?: string[];\n quick_replies?: any[];\n}\n\ninterface Event {\n type: string;\n created_on: string;\n msg?: Message;\n [key: string]: any;\n}\n\ninterface RunContext {\n session: Session;\n events: Event[];\n context?: any;\n contact?: Contact;\n}\n\ninterface SimulatorSize {\n phoneWidth: number;\n phoneHeight: number;\n phoneTotalHeight: number;\n phoneScreenHeight: number;\n contextWidth: number;\n contextHeight: number;\n contextOffset: number;\n optionPaneWidth: number;\n optionPaneGap: number;\n windowPadding: number;\n cutoutHeight: number;\n cutoutPadding: number;\n cutoutFontSize: number;\n cutoutIslandWidth: number;\n cutoutIslandHeight: number;\n cutoutIslandTop: number;\n}\n\nconst SIMULATOR_SIZES: Record<string, SimulatorSize> = {\n small: {\n phoneWidth: 270,\n phoneHeight: 576,\n phoneTotalHeight: 576,\n phoneScreenHeight: 376,\n contextWidth: 336,\n contextHeight: 416,\n contextOffset: 48,\n optionPaneWidth: 44,\n optionPaneGap: 10,\n windowPadding: 24,\n cutoutHeight: 32,\n cutoutPadding: 12,\n cutoutFontSize: 10,\n cutoutIslandWidth: 80,\n cutoutIslandHeight: 20,\n cutoutIslandTop: 6\n },\n medium: {\n phoneWidth: 300,\n phoneHeight: 720,\n phoneTotalHeight: 720,\n phoneScreenHeight: 470,\n contextWidth: 420,\n contextHeight: 520,\n contextOffset: 60,\n optionPaneWidth: 44,\n optionPaneGap: 12,\n windowPadding: 30,\n cutoutHeight: 40,\n cutoutPadding: 16,\n cutoutFontSize: 12,\n cutoutIslandWidth: 100,\n cutoutIslandHeight: 24,\n cutoutIslandTop: 8\n },\n large: {\n phoneWidth: 360,\n phoneHeight: 864,\n phoneTotalHeight: 864,\n phoneScreenHeight: 564,\n contextWidth: 504,\n contextHeight: 624,\n contextOffset: 72,\n optionPaneWidth: 44,\n optionPaneGap: 14,\n windowPadding: 36,\n cutoutHeight: 50,\n cutoutPadding: 20,\n cutoutFontSize: 14,\n cutoutIslandWidth: 120,\n cutoutIslandHeight: 30,\n cutoutIslandTop: 10\n }\n};\n\nexport class Simulator extends RapidElement {\n static get styles() {\n return css`\n :host {\n /* size-specific dimensions are set dynamically via inline styles */\n --phone-width: 300px;\n --phone-total-height: 720px;\n --context-width: 420px;\n --context-offset: 60px;\n --option-pane-width: 44px;\n --option-pane-gap: 12px;\n --window-padding: 30px;\n --phone-screen-height: 470px;\n --context-height: 520px;\n --context-closed-left: 332px;\n --animation-time: 200ms;\n }\n\n .phone-simulator {\n padding-left: calc(var(--context-width) + var(--context-offset));\n padding-top: var(--window-padding);\n padding-bottom: var(--window-padding);\n position: relative;\n display: flex;\n align-items: flex-start;\n }\n\n .option-pane {\n margin-top: var(--window-padding);\n margin-left: var(--option-pane-gap);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n border-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n pointer-events: all;\n }\n .option-btn {\n background: rgba(255, 255, 255, 0.1);\n border: none;\n border-radius: 12px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all var(--animation-time) ease;\n color: white;\n }\n .option-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.05);\n }\n .option-btn:active {\n transform: scale(0.95);\n }\n .option-btn.active {\n background: var(--color-primary-dark);\n color: white;\n }\n .option-btn.active:hover {\n background: var(--color-primary-dark);\n }\n\n .phone-frame {\n width: var(--phone-width);\n border-radius: 40px;\n border: 6px solid #1f2937;\n box-shadow: 0 0px 30px rgba(0, 0, 0, 0.4);\n background: #000;\n position: relative;\n overflow: hidden;\n z-index: 2;\n }\n\n .context-explorer {\n width: var(--context-width);\n height: var(--context-height);\n border-top-left-radius: 16px;\n border-bottom-left-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n position: absolute;\n left: var(--context-closed-left);\n top: calc(var(--window-padding) + 40px);\n z-index: 1;\n font-size: 13px;\n color: #374151;\n transition: left calc(var(--animation-time) * 1.5) ease-out,\n opacity calc(var(--animation-time) * 1.5) ease-out;\n opacity: 0;\n pointer-events: none;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n display: flex;\n flex-direction: column;\n padding: 12px;\n }\n\n .context-gutter {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 6px;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 4px;\n margin-right: 32px;\n margin-top: 8px;\n flex-shrink: 0;\n }\n\n .context-gutter-btn {\n width: 14px;\n height: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 6px;\n transition: background var(--animation-time) ease;\n color: rgba(255, 255, 255, 0.6);\n padding: 4px;\n }\n\n .context-gutter-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n }\n\n .context-gutter-btn.active {\n color: #c084fc;\n }\n\n .context-gutter-spacer {\n flex: 1;\n }\n\n .context-explorer-scroll {\n scrollbar-color: rgba(255, 255, 255, 0.3) #4a4a4a;\n scrollbar-width: thin;\n height: 100%;\n overflow-y: scroll;\n padding-right: 10px;\n margin-right: 30px;\n flex-grow: 1;\n }\n\n .context-explorer-bleed {\n height: 100%;\n width: 0px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar {\n width: 18px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n }\n\n .context-explorer.open {\n left: var(--context-offset);\n opacity: 1;\n pointer-events: auto;\n }\n\n .context-item {\n display: flex;\n align-items: flex-start;\n padding: 2px 4px;\n cursor: pointer;\n user-select: none;\n }\n\n .context-item:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n .context-item-expandable {\n display: flex;\n align-items: center;\n }\n\n .context-expand-icon {\n width: 16px;\n display: inline-block;\n text-align: center;\n flex-shrink: 0;\n transition: transform var(--animation-time) ease;\n color: #ffffff;\n }\n\n .context-expand-icon.expanded {\n transform: rotate(90deg);\n }\n\n .context-key {\n color: #ffffff;\n flex-shrink: 0;\n margin-right: 8px;\n display: flex;\n }\n\n .context-key.has-value {\n color: #e8b5e8;\n }\n\n .context-value {\n color: #aaa;\n flex: 1;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .context-children {\n margin-left: 16px;\n }\n\n .context-copy-icon {\n opacity: 0;\n margin-left: 4px;\n transition: opacity var(--animation-time) ease;\n cursor: pointer;\n color: #ccc;\n }\n\n .context-item:hover .context-copy-icon {\n opacity: 1;\n }\n\n .context-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translateX(-50%);\n background: #666;\n color: white;\n padding: 12px 12px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n font-size: 13px;\n z-index: 10;\n animation: slideInUp var(--animation-time) ease-out;\n }\n\n .context-toast .expression {\n color: #e8b5e8;\n font-weight: 600;\n }\n\n @keyframes slideInUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n\n .phone-top {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n cursor: grab;\n }\n .phone-notch {\n background: transparent;\n height: var(--cutout-height);\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 var(--cutout-padding);\n }\n .phone-notch::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0.3) 0%,\n rgba(0, 0, 0, 0.2) 50%,\n transparent 100%\n );\n z-index: -1;\n }\n .dynamic-island {\n top: var(--cutout-island-top);\n left: 50%;\n\n width: var(--cutout-island-width);\n height: var(--cutout-island-height);\n background: #000;\n border-radius: calc(var(--cutout-island-height) / 1.5);\n z-index: 1;\n }\n .phone-notch .time {\n color: #000;\n font-size: var(--cutout-font-size);\n font-weight: 600;\n }\n .phone-notch .status-icons {\n display: flex;\n gap: 4px;\n align-items: center;\n }\n .phone-notch .status-icons span {\n color: #000;\n font-size: var(--cutout-font-size);\n }\n .phone-header {\n background: transparent;\n padding: 10px 15px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n cursor: move;\n user-select: none;\n border-bottom: none;\n pointer-events: all;\n }\n\n .phone-screen {\n background: white;\n padding: 15px;\n padding-top: calc(var(--cutout-height) + 10px);\n padding-bottom: 60px;\n height: var(--phone-screen-height);\n overflow-y: scroll;\n display: flex;\n flex-direction: column;\n scrollbar-color: rgba(0, 0, 0, 0.2) transparent;\n scrollbar-width: thin;\n }\n\n .phone-screen::-webkit-scrollbar {\n width: 8px;\n }\n\n .phone-screen::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .phone-screen::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n }\n\n .phone-screen::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.3);\n }\n\n @keyframes messageAppear {\n 0% {\n opacity: 0;\n transform: scale(0.8);\n }\n 70% {\n opacity: 1;\n transform: scale(1.05);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n .message {\n padding: 10px 14px;\n margin-bottom: 8px;\n border-radius: 18px;\n max-width: 70%;\n font-size: 13px;\n line-height: 1.2;\n }\n .message.animated {\n animation: messageAppear var(--animation-time) ease-out forwards;\n opacity: 0;\n }\n .message.incoming {\n background: #e5e5ea;\n color: #000;\n margin-right: auto;\n border-bottom-left-radius: 4px;\n }\n .message.outgoing {\n background: #007aff;\n color: white;\n margin-left: auto;\n text-align: left;\n border-bottom-right-radius: 4px;\n }\n .attachment-wrapper {\n max-width: 70%;\n margin-bottom: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .attachment-wrapper.incoming {\n margin-right: auto;\n align-items: flex-start;\n }\n .attachment-wrapper.outgoing {\n margin-left: auto;\n align-items: flex-end;\n }\n .attachment-wrapper.animated {\n animation: messageAppear var(--animation-time) ease-out forwards;\n opacity: 0;\n }\n .attachment {\n border-radius: 12px;\n overflow: hidden;\n max-width: 100%;\n }\n .attachment img {\n max-width: 100%;\n display: block;\n border-radius: 12px;\n }\n .attachment video {\n max-width: 100%;\n display: block;\n border-radius: 12px;\n }\n .attachment-audio {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px;\n background: white;\n border: 1px solid #e5e5ea;\n border-radius: 12px;\n min-width: 160px;\n }\n .attachment-wrapper.outgoing .attachment-audio {\n background: white;\n border: none;\n }\n .attachment-audio audio {\n flex: 1;\n max-height: 30px;\n }\n .attachment-location {\n border-radius: 12px;\n overflow: hidden;\n }\n .event-info {\n text-align: center;\n font-size: 11px;\n color: #8e8e93;\n margin: 4px 0;\n padding: 0 10px;\n line-height: 1.3;\n }\n .event-info.animated {\n animation: messageAppear var(--animation-time) ease-out forwards;\n opacity: 0;\n }\n .message-input {\n background: linear-gradient(\n to top,\n rgba(0, 0, 0, 0.1) 0%,\n rgba(0, 0, 0, 0.05) 70%,\n transparent 100%\n );\n padding: 8px 12px;\n border-top: none;\n display: flex;\n align-items: center;\n gap: 8px;\n position: absolute;\n bottom: 0px;\n left: 0px;\n right: 0px;\n z-index: 10;\n }\n .message-input input {\n flex: 1;\n border: 1px solid #c6c6c8;\n border-radius: 20px;\n padding: 8px 15px;\n font-size: 15px;\n margin-bottom: 5px;\n background: white;\n border: none;\n outline: none;\n }\n .message-input input::placeholder {\n color: #8e8e93;\n }\n .attachment-button {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: #fff;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n margin-bottom: 5px;\n transition: all var(--animation-time) ease;\n color: #000;\n }\n .attachment-button:hover {\n background: #f8f8f8ff;\n transform: scale(1.05);\n }\n .attachment-button:active {\n transform: scale(0.95);\n }\n .attachment-menu {\n position: absolute;\n bottom: 55px;\n left: 12px;\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(10px);\n transition: opacity var(--animation-time) ease, transform 0.2s ease;\n z-index: 20;\n }\n .attachment-menu.open {\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n }\n .attachment-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n cursor: pointer;\n transition: background var(--animation-time) ease;\n white-space: nowrap;\n font-size: 14px;\n color: #1f2937;\n }\n .attachment-menu-item:hover {\n background: #f3f4f6;\n }\n .attachment-menu-item temba-icon {\n color: #007aff;\n }\n .quick-replies {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 8px;\n margin-top: 4px;\n margin-bottom: 8px;\n }\n .quick-reply-btn {\n background: white;\n color: #007aff;\n border: 1px solid #007aff;\n border-radius: 18px;\n padding: 4px 8px;\n font-size: 11px;\n cursor: pointer;\n transition: all var(--animation-time) ease;\n white-space: nowrap;\n }\n .quick-reply-btn:hover {\n background: #007aff;\n color: white;\n cursor: pointer;\n }\n .quick-reply-btn:active {\n transform: scale(0.95);\n }\n .quick-reply-btn.animated {\n animation: messageAppear var(--animation-time) ease-out forwards;\n opacity: 0;\n }\n `;\n }\n\n @property({ type: String })\n flow = '';\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Number })\n animationTime = 200;\n\n @fromCookie('simulator-size', 'small')\n size: 'small' | 'medium' | 'large';\n\n @property({ type: Array })\n private events: Event[] = [];\n\n private previousEventCount = 0;\n\n @property({ type: Object })\n private session: Session | null = null;\n\n @property({ type: Object })\n private context: any = null;\n\n @property({ type: Object })\n private contact: 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\n @property({ type: Boolean })\n private sprinting = false;\n\n @property({ type: String })\n private inputValue = '';\n\n @fromCookie('simulator-follow', true)\n private following: boolean;\n\n @fromCookie('simulator-context-open', false)\n private contextExplorerOpen: boolean;\n\n @property({ type: Object })\n private expandedPaths: Set<string> = new Set();\n\n @property({ type: String })\n private copiedExpression = '';\n\n @property({ type: String })\n private toastMessage = '';\n\n @property({ type: Boolean })\n private showAllKeys = true;\n\n private previousWindowWidth = 0;\n\n @property({ type: Array })\n private currentQuickReplies: any[] = [];\n\n @property({ type: Boolean })\n private isVisible = false;\n\n @property({ type: Boolean })\n private attachmentMenuOpen = false;\n\n private boundClickOutsideHandler: ((event: MouseEvent) => void) | null = null;\n\n // attachment cycling indices - initialized randomly\n private imageIndex = Math.floor(Math.random() * TEST_IMAGES.length);\n private videoIndex = Math.floor(Math.random() * TEST_VIDEOS.length);\n private audioIndex = Math.floor(Math.random() * TEST_AUDIO.length);\n private locationIndex = Math.floor(Math.random() * TEST_LOCATIONS.length);\n\n // method to reset attachment indices for testing\n public resetAttachmentIndices() {\n this.imageIndex = 2;\n this.videoIndex = 0;\n this.audioIndex = 0;\n this.locationIndex = 0;\n }\n\n private get sizeConfig(): SimulatorSize {\n return SIMULATOR_SIZES[this.size] || SIMULATOR_SIZES.medium;\n }\n\n private get windowWidth(): number {\n const config = this.sizeConfig;\n return (\n config.contextWidth +\n config.phoneWidth +\n config.optionPaneWidth +\n config.optionPaneGap +\n config.contextOffset\n );\n }\n\n private get leftBoundaryMargin(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset;\n }\n\n private get contextClosedLeft(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset - config.phoneWidth;\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n if (changes.has('flow') && this.flow) {\n this.endpoint = `/flow/simulate/${this.flow}/`;\n }\n\n // handle attachment menu click outside listener\n if (changes.has('attachmentMenuOpen')) {\n if (this.attachmentMenuOpen) {\n // create bound handler if it doesn't exist\n if (!this.boundClickOutsideHandler) {\n this.boundClickOutsideHandler =\n this.handleClickOutsideAttachmentMenu.bind(this);\n }\n // add listener when menu opens\n setTimeout(() => {\n document.addEventListener('click', this.boundClickOutsideHandler);\n }, 0);\n } else {\n // remove listener when menu closes\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n }\n\n // update floating window boundaries when size changes\n if (changes.has('size')) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n // use the stored previous width since phoneWindow.width has already been updated\n const oldWidth = this.previousWindowWidth || phoneWindow.width;\n const oldRight = phoneWindow.left + oldWidth;\n\n const config = this.sizeConfig;\n const newWidth = this.windowWidth;\n\n // store current width for next size change\n this.previousWindowWidth = newWidth;\n\n // update dimensions and boundaries\n phoneWindow.width = newWidth;\n phoneWindow.leftBoundaryMargin = this.leftBoundaryMargin;\n phoneWindow.topBoundaryMargin = config.windowPadding;\n phoneWindow.bottomBoundaryMargin = config.windowPadding;\n\n // keep right edge in same position by adjusting left\n let newLeft = oldRight - newWidth;\n\n // apply same boundary logic as FloatingWindow.handleMouseMove\n const padding = 20;\n const minLeft = padding - this.leftBoundaryMargin;\n const maxLeft =\n window.innerWidth -\n newWidth -\n padding +\n phoneWindow.rightBoundaryMargin;\n\n // clamp to boundaries\n newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));\n\n phoneWindow.left = newLeft;\n\n // adjust vertical position if needed\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n const currentHeight =\n windowElement?.offsetHeight || config.phoneTotalHeight;\n const maxTop = Math.max(\n padding - config.windowPadding,\n window.innerHeight - currentHeight - padding + config.windowPadding\n );\n\n phoneWindow.top = Math.max(\n padding - config.windowPadding,\n Math.min(phoneWindow.top, maxTop)\n );\n }\n });\n } else {\n // store initial width when first rendered\n if (!this.previousWindowWidth) {\n this.previousWindowWidth = this.windowWidth;\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n // clean up event listener when component is removed\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n\n private handleShow() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.show();\n this.isVisible = true;\n getStore().getState().setSimulatorActive(true);\n\n // start the simulation if we haven't already\n if (this.events.length === 0) {\n this.startFlow();\n }\n }\n\n private async startFlow() {\n const now = new Date().toISOString();\n\n // set created_on to simulation start time\n this.contact = { ...this.contact, created_on: now };\n\n const body = {\n contact: this.contact,\n trigger: {\n type: 'manual',\n triggered_on: now,\n flow: { uuid: this.flow, name: 'New Chat' },\n params: {}\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n this.updateRunContext(response.json as RunContext);\n } catch (error) {\n console.error('Failed to start simulation:', error);\n this.events = [\n ...this.events,\n {\n type: 'error',\n created_on: now,\n text: 'Failed to start simulation'\n } as any\n ];\n }\n }\n\n private updateRunContext(runContext: RunContext, msgInEvt?: Event) {\n if (msgInEvt) {\n this.events = [...this.events, msgInEvt];\n }\n\n if (runContext.session) {\n this.session = runContext.session;\n\n // update our contact with the latest from the session\n if (runContext.contact) {\n this.contact = runContext.contact;\n }\n }\n\n // store the context from the response\n if (runContext.context) {\n this.context = runContext.context;\n }\n\n if (runContext.events && runContext.events.length > 0) {\n this.events = [...this.events, ...runContext.events];\n\n // extract quick replies from the most recent sprint\n this.currentQuickReplies = [];\n for (const event of runContext.events) {\n if (event.type === 'msg_created' && event.msg?.quick_replies) {\n this.currentQuickReplies = event.msg.quick_replies;\n }\n }\n }\n\n this.sprinting = false;\n this.requestUpdate();\n this.scrollToBottom();\n this.updateActivity();\n }\n\n private updateActivity() {\n if (!this.session) {\n return;\n }\n\n const pathCounts: { [key: string]: number } = {};\n const nodeCounts: { [nodeUUID: string]: number } = {};\n\n // iterate through all runs to get path segment counts\n for (const run of this.session.runs) {\n if (run.path) {\n for (let i = 0; i < run.path.length - 1; i++) {\n const step = run.path[i];\n const nextStep = run.path[i + 1];\n if (step.exit_uuid && nextStep.node_uuid) {\n const key = step.exit_uuid + ':' + nextStep.node_uuid;\n pathCounts[key] = (pathCounts[key] || 0) + 1;\n }\n }\n }\n\n // set node counts on the last step of any active/waiting runs\n if (run.status === 'active' || run.status === 'waiting') {\n if (run.path && run.path.length > 0) {\n const finalStep = run.path[run.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n nodeCounts[finalStep.node_uuid] =\n (nodeCounts[finalStep.node_uuid] || 0) + 1;\n }\n }\n }\n }\n\n // Update simulator activity in the store\n getStore().getState().updateSimulatorActivity({\n segments: pathCounts,\n nodes: nodeCounts\n });\n\n // Fire follow event if following is enabled\n if (this.following) {\n this.fireFollowEvent();\n }\n }\n\n private fireFollowEvent() {\n if (!this.session || !this.session.runs || this.session.runs.length === 0) {\n return;\n }\n\n // Find the first active or waiting run\n let activeRun = this.session.runs.find(\n (run: any) => run.status === 'active' || run.status === 'waiting'\n );\n\n // If no active/waiting run and simulation has ended, use the first completed run\n if (!activeRun) {\n activeRun = this.session.runs.find(\n (run: any) => run.status === 'completed'\n );\n }\n\n if (activeRun && activeRun.path && activeRun.path.length > 0) {\n const finalStep = activeRun.path[activeRun.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n this.fireCustomEvent(CustomEventType.FollowSimulation, {\n flowUuid: activeRun.flow?.uuid || this.flow,\n nodeUuid: finalStep.node_uuid\n });\n }\n }\n }\n\n private scrollToBottom() {\n // wait for render, then scroll to bottom\n setTimeout(() => {\n const screen = this.shadowRoot?.querySelector('.phone-screen');\n if (screen) {\n screen.scrollTop = screen.scrollHeight;\n }\n // update previous count after animation completes\n this.previousEventCount = this.events.length;\n\n // return focus to input\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n }\n\n private handleClose() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n // phoneWindow.hide();\n\n phoneWindow.handleClose();\n this.isVisible = false;\n getStore().getState().setSimulatorActive(false);\n }\n\n private handleReset() {\n // reset simulation state\n this.events = [];\n this.session = null;\n this.context = null;\n this.inputValue = '';\n this.sprinting = false;\n this.previousEventCount = 0;\n this.currentQuickReplies = [];\n\n // Clear simulator activity data\n getStore().getState().updateSimulatorActivity({\n segments: {},\n nodes: {}\n });\n\n // reset contact to initial state\n this.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\n // restart the flow\n this.startFlow();\n }\n\n private handleToggleFollow() {\n this.following = !this.following;\n }\n\n private handleCycleSize() {\n const sizes: Array<'small' | 'medium' | 'large'> = [\n 'small',\n 'medium',\n 'large'\n ];\n const currentIndex = sizes.indexOf(this.size);\n const nextIndex = (currentIndex + 1) % sizes.length;\n this.size = sizes[nextIndex];\n }\n\n private handleToggleContextExplorer() {\n this.contextExplorerOpen = !this.contextExplorerOpen;\n\n // if opening the context explorer, ensure it's not off-screen\n if (this.contextExplorerOpen) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n const padding = 20;\n const contextExplorerLeft = this.sizeConfig.contextOffset;\n const minWindowLeft = padding - contextExplorerLeft;\n\n if (phoneWindow.left < minWindowLeft) {\n phoneWindow.left = minWindowLeft;\n }\n }\n });\n }\n }\n\n private togglePath(path: string) {\n if (this.expandedPaths.has(path)) {\n this.expandedPaths.delete(path);\n } else {\n this.expandedPaths.add(path);\n }\n this.requestUpdate();\n }\n\n private isExpandable(value: any): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n // check if object has keys other than __default__\n const keys = Object.keys(value).filter((key) => key !== '__default__');\n return keys.length > 0;\n }\n\n private renderContextValue(value: any): TemplateResult | string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'number')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'string')\n return html`<span class=\"context-value\">${value}</span>`;\n if (Array.isArray(value))\n return html`<span class=\"context-value\">[${value.length}]</span>`;\n return '';\n }\n\n private buildExpression(path: string): string {\n return `@${path}`;\n }\n\n private async handleCopyExpression(\n path: string,\n event: Event\n ): Promise<void> {\n event.stopPropagation();\n const expression = this.buildExpression(path);\n try {\n await navigator.clipboard.writeText(expression);\n this.copiedExpression = expression;\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.copiedExpression = '';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy expression:', err);\n }\n }\n\n private handleToggleShowAllKeys() {\n this.showAllKeys = !this.showAllKeys;\n this.toastMessage = this.showAllKeys\n ? 'Showing all keys'\n : 'Filtering out keys without values';\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.toastMessage = '';\n }, 2000);\n }\n\n private renderContextTree(\n obj: any,\n path: string = ''\n ): TemplateResult | TemplateResult[] {\n if (!obj || typeof obj !== 'object') {\n return html``;\n }\n\n let entries = Array.isArray(obj)\n ? obj.map((v, i) => [String(i), v])\n : Object.entries(obj).filter(([key]) => key !== '__default__');\n\n // filter out keys without values if showAllKeys is false\n if (!this.showAllKeys) {\n entries = entries.filter(([, value]) => {\n // keep if expandable (has children)\n if (this.isExpandable(value)) return true;\n // keep if it has a displayable value (not null/undefined)\n if (value === null || value === undefined) return false;\n // keep primitives with values\n return (\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string' ||\n Array.isArray(value)\n );\n });\n }\n\n return html`${entries.map(([key, value]) => {\n const currentPath = path ? `${path}.${key}` : key;\n const isExpanded = this.expandedPaths.has(currentPath);\n const expandable = this.isExpandable(value);\n\n // check if this object has a __default__ value\n let displayValue = value;\n\n if (\n expandable &&\n !Array.isArray(value) &&\n value !== null &&\n typeof value === 'object' &&\n '__default__' in value\n ) {\n displayValue = value.__default__;\n }\n\n return html`\n <div>\n <div\n class=\"context-item ${expandable ? 'context-item-expandable' : ''}\"\n @click=${() => expandable && this.togglePath(currentPath)}\n >\n ${expandable\n ? html`<span\n class=\"context-expand-icon ${isExpanded ? 'expanded' : ''}\"\n >›</span\n >`\n : html`<span class=\"context-expand-icon\"></span>`}\n <span class=\"context-key ${expandable ? 'has-value' : ''}\"\n >${key}\n <temba-icon\n class=\"context-copy-icon\"\n name=\"copy\"\n size=\"0.9\"\n @click=${(e: Event) =>\n this.handleCopyExpression(currentPath, e)}\n ></temba-icon>\n </span>\n ${!isExpanded ? this.renderContextValue(displayValue) : html``}\n </div>\n ${isExpanded\n ? html`<div class=\"context-children\">\n ${this.renderContextTree(value, currentPath)}\n </div>`\n : html``}\n </div>\n `;\n })}`;\n }\n\n private async resume(text: string, attachment?: string) {\n if ((!text && !attachment) || !this.session) {\n return;\n }\n\n this.sprinting = true;\n this.inputValue = '';\n this.currentQuickReplies = [];\n this.attachmentMenuOpen = false;\n\n const now = new Date().toISOString();\n const msgInEvt: Event = {\n uuid: crypto.randomUUID(),\n type: 'msg_received',\n created_on: now,\n msg: {\n uuid: crypto.randomUUID(),\n text: text || '',\n urn: this.contact.urns[0],\n attachments: attachment ? [attachment] : []\n }\n };\n\n // show user's message immediately\n this.events = [...this.events, msgInEvt];\n this.requestUpdate();\n this.scrollToBottom();\n\n const body = {\n session: this.session,\n contact: this.contact,\n resume: {\n type: 'msg',\n event: msgInEvt,\n resumed_on: now\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n\n // add a small delay before showing the reply to simulate typing\n await new Promise((resolve) => setTimeout(resolve, 400));\n\n // pass null for msgInEvt since we already added it\n this.updateRunContext(response.json as RunContext, null);\n } catch (error) {\n console.error('Failed to resume simulation:', error);\n this.events = [\n ...this.events,\n {\n type: 'error',\n created_on: now,\n text: 'Failed to send message'\n } as any\n ];\n this.sprinting = false;\n }\n }\n\n private handleKeyUp(evt: KeyboardEvent) {\n if (evt.key === 'Enter') {\n const input = evt.target as HTMLInputElement;\n const text = input.value.trim();\n if (text) {\n this.resume(text);\n }\n }\n }\n\n private handleInput(evt: Event) {\n const input = evt.target as HTMLInputElement;\n this.inputValue = input.value;\n }\n\n private handleQuickReply(quickReply: string) {\n if (!this.sprinting) {\n this.resume(quickReply);\n }\n }\n\n private handleToggleAttachmentMenu() {\n this.attachmentMenuOpen = !this.attachmentMenuOpen;\n }\n\n private handleClickOutsideAttachmentMenu(event: MouseEvent) {\n if (!this.attachmentMenuOpen) {\n return;\n }\n\n const menu = this.shadowRoot?.querySelector('.attachment-menu');\n const button = this.shadowRoot?.querySelector('.attachment-button');\n\n if (!menu || !button) {\n return;\n }\n\n // check if click is outside both menu and button\n const clickedInsideMenu = menu.contains(event.target as Node);\n const clickedInsideButton = button.contains(event.target as Node);\n\n if (!clickedInsideMenu && !clickedInsideButton) {\n this.attachmentMenuOpen = false;\n }\n }\n\n private handleSendAttachment(attachmentType: string) {\n let attachment = '';\n switch (attachmentType) {\n case 'image':\n attachment = `image/jpeg:${TEST_IMAGES[this.imageIndex]}`;\n this.imageIndex = (this.imageIndex + 1) % TEST_IMAGES.length;\n break;\n case 'video':\n attachment = `video/mp4:${TEST_VIDEOS[this.videoIndex]}`;\n this.videoIndex = (this.videoIndex + 1) % TEST_VIDEOS.length;\n break;\n case 'audio':\n attachment = `audio/mp3:${TEST_AUDIO[this.audioIndex]}`;\n this.audioIndex = (this.audioIndex + 1) % TEST_AUDIO.length;\n break;\n case 'location':\n attachment = TEST_LOCATIONS[this.locationIndex];\n this.locationIndex = (this.locationIndex + 1) % TEST_LOCATIONS.length;\n break;\n }\n\n if (attachment) {\n this.resume('', attachment);\n }\n }\n\n private getEventDescription(event: Event): string | null {\n switch (event.type) {\n case 'contact_groups_changed': {\n const groups = (event as any).groups_added || [];\n const removedGroups = (event as any).groups_removed || [];\n if (groups.length > 0) {\n const groupNames = groups.map((g: any) => `\"${g.name}\"`).join(', ');\n return `Added to ${groupNames}`;\n }\n if (removedGroups.length > 0) {\n const groupNames = removedGroups\n .map((g: any) => `\"${g.name}\"`)\n .join(', ');\n return `Removed from ${groupNames}`;\n }\n break;\n }\n case 'contact_field_changed': {\n const field = (event as any).field;\n const value = (event as any).value;\n const valueText = value ? value.text || value : '';\n if (field) {\n if (valueText) {\n return `Set contact \"${field.name}\" to \"${valueText}\"`;\n } else {\n return `Cleared contact \"${field.name}\"`;\n }\n }\n break;\n }\n case 'contact_language_changed':\n return `Set preferred language to \"${(event as any).language}\"`;\n case 'contact_name_changed':\n return `Set contact name to \"${(event as any).name}\"`;\n case 'contact_status_changed':\n return `Set status to \"${(event as any).status}\"`;\n case 'contact_urns_changed':\n return `Added a URN for the contact`;\n case 'input_labels_added': {\n const labels = (event as any).labels || [];\n if (labels.length > 0) {\n const labelNames = labels.map((l: any) => `\"${l.name}\"`).join(', ');\n return `Message labeled with ${labelNames}`;\n }\n break;\n }\n case 'run_result_changed':\n return `Set result \"${(event as any).name}\" to \"${\n (event as any).value\n }\"`;\n case 'run_started':\n case 'flow_entered': {\n const flow = (event as any).flow;\n if (flow) {\n return `Entered flow \"${flow.name}\"`;\n }\n break;\n }\n case 'run_ended': {\n const flow = (event as any).flow;\n if (flow) {\n return `Exited flow \"${flow.name}\"`;\n }\n break;\n }\n case 'email_created':\n case 'email_sent': {\n const recipients = (event as any).to || (event as any).addresses || [];\n const subject = (event as any).subject;\n const recipientList = recipients\n .map((r: string) => `\"${r}\"`)\n .join(', ');\n return `Sent email to ${recipientList} with subject \"${subject}\"`;\n }\n case 'broadcast_created': {\n const translations = (event as any).translations;\n const baseLanguage = (event as any).base_language;\n if (translations && translations[baseLanguage]) {\n return `Sent broadcast: \"${translations[baseLanguage].text}\"`;\n }\n return `Sent broadcast`;\n }\n case 'session_triggered': {\n const flow = (event as any).flow;\n if (flow) {\n return `Started somebody else in \"${flow.name}\"`;\n }\n break;\n }\n case 'ticket_opened': {\n const ticket = (event as any).ticket;\n if (ticket && ticket.topic) {\n return `Ticket opened with topic \"${ticket.topic.name}\"`;\n }\n return `Ticket opened`;\n }\n case 'resthook_called':\n return `Triggered flow event \"${(event as any).resthook}\"`;\n case 'webhook_called':\n return `Called ${(event as any).url}`;\n case 'service_called': {\n const service = (event as any).service;\n if (service === 'classifier') {\n return `Called classifier`;\n }\n return `Called ${service}`;\n }\n case 'airtime_transferred': {\n const amount = (event as any).actual_amount;\n const currency = (event as any).currency;\n const recipient = (event as any).recipient;\n if (amount && currency && recipient) {\n return `Transferred ${amount} ${currency} to ${recipient}`;\n }\n break;\n }\n case 'info':\n return (event as any).text;\n case 'warning':\n return `⚠️ ${(event as any).text}`;\n }\n return null;\n }\n\n private renderAlertMessage(\n type: 'error' | 'warning' | 'failure',\n text: string,\n animatedClass: string,\n animationDelay: string\n ): TemplateResult {\n const config = {\n error: {\n icon: '❗',\n bgColor: '#fee2e2',\n textColor: '#991b1b',\n defaultText: 'An error occurred'\n },\n warning: {\n icon: '⚠️',\n bgColor: '#fef3c7',\n textColor: 'rgba(125, 87, 18, 0.8)',\n defaultText: 'A warning occurred'\n },\n failure: {\n icon: '💥',\n bgColor: '#fee2e2',\n textColor: '#991b1b',\n defaultText: 'A failure occurred'\n }\n }[type];\n\n return html`\n <div\n class=\"event-info ${animatedClass}\"\n style=\"display:flex; align-items:center; background: ${config.bgColor}; color: ${config.textColor}; padding: 6px; margin: 4px 12px; border-radius: 8px; animation-delay: ${animationDelay}\"\n >\n <div style=\"padding:4px;margin-right:6px;font-size:15px\">\n ${config.icon}\n </div>\n <div style=\"padding-right:2px;text-align:left\">\n ${text || config.defaultText}\n </div>\n </div>\n `;\n }\n\n private renderAttachment(attachment: string): TemplateResult {\n // parse attachment format: \"type/subtype:url\" or \"geo:lat,long\"\n const parts = attachment.split(':');\n const type = parts[0];\n const content = parts.slice(1).join(':'); // rejoin in case url has colons\n\n if (type === 'geo') {\n // use temba-thumbnail for location to get map image\n return html`\n <div class=\"attachment-location\">\n <temba-thumbnail attachment=\"${attachment}\"></temba-thumbnail>\n </div>\n `;\n } else if (type.startsWith('image/')) {\n // custom image rendering\n return html`\n <div class=\"attachment\">\n <img src=\"${content}\" alt=\"Image attachment\" />\n </div>\n `;\n } else if (type.startsWith('video/')) {\n // custom video rendering\n return html`\n <div class=\"attachment\">\n <video controls>\n <source src=\"${content}\" type=\"${type}\" />\n </video>\n </div>\n `;\n } else if (type.startsWith('audio/')) {\n // custom audio rendering\n return html`\n <div class=\"attachment\">\n <div class=\"attachment-audio\">\n <audio controls>\n <source src=\"${content}\" type=\"${type}\" />\n </audio>\n </div>\n </div>\n `;\n }\n\n // fallback for unknown types\n return html`\n <div class=\"attachment\">\n <span>Attachment</span>\n </div>\n `;\n }\n\n private renderMessages(): TemplateResult {\n if (this.events.length === 0) {\n return html`\n <div class=\"message incoming\">👋 Welcome! Starting simulation...</div>\n `;\n }\n\n const eventTemplates = this.events.map((event, index) => {\n // only animate messages that are new (beyond previous count)\n const isNew = index >= this.previousEventCount;\n const animatedClass = isNew ? 'animated' : '';\n // stagger animations for new messages\n const animationDelay = isNew\n ? `${(index - this.previousEventCount) * 0.2}s`\n : '0s';\n\n if (event.type === 'msg_received' && event.msg) {\n const hasAttachments =\n event.msg.attachments && event.msg.attachments.length > 0;\n const hasText = event.msg.text && event.msg.text.trim().length > 0;\n\n return html`\n ${hasAttachments\n ? html`\n <div\n class=\"attachment-wrapper outgoing ${animatedClass}\"\n style=\"animation-delay: ${animationDelay}\"\n >\n ${event.msg.attachments.map((att: string) =>\n this.renderAttachment(att)\n )}\n </div>\n `\n : html``}\n ${hasText\n ? html`\n <div\n class=\"message outgoing ${animatedClass}\"\n style=\"animation-delay: ${animationDelay}\"\n >\n ${event.msg.text}\n </div>\n `\n : html``}\n `;\n } else if (event.type === 'msg_created' && event.msg) {\n const hasAttachments =\n event.msg.attachments && event.msg.attachments.length > 0;\n const hasText = event.msg.text && event.msg.text.trim().length > 0;\n\n return html`\n ${hasAttachments\n ? html`\n <div\n class=\"attachment-wrapper incoming ${animatedClass}\"\n style=\"animation-delay: ${animationDelay}\"\n >\n ${event.msg.attachments.map((att: string) =>\n this.renderAttachment(att)\n )}\n </div>\n `\n : html``}\n ${hasText\n ? html`\n <div\n class=\"message incoming ${animatedClass}\"\n style=\"animation-delay: ${animationDelay}\"\n >\n ${event.msg.text}\n </div>\n `\n : html``}\n `;\n } else if (event.type === 'failure') {\n return this.renderAlertMessage(\n 'failure',\n (event as any).text,\n animatedClass,\n animationDelay\n );\n } else if (event.type === 'warning') {\n return this.renderAlertMessage(\n 'warning',\n (event as any).text,\n animatedClass,\n animationDelay\n );\n } else if (event.type === 'error') {\n return this.renderAlertMessage(\n 'error',\n (event as any).text,\n animatedClass,\n animationDelay\n );\n } else {\n // check if this is an event we should display\n const description = this.getEventDescription(event);\n if (description) {\n return html`\n <div\n class=\"event-info ${animatedClass}\"\n style=\"animation-delay: ${animationDelay}\"\n >\n ${description}\n </div>\n `;\n }\n }\n return html``;\n });\n\n // render quick replies at the end if we have any from the most recent sprint\n const hasQuickReplies = this.currentQuickReplies.length > 0;\n const quickRepliesAnimationDelay =\n this.events.length >= this.previousEventCount\n ? `${(this.events.length - this.previousEventCount) * 0.2}s`\n : '0s';\n\n return html`\n ${eventTemplates}\n ${hasQuickReplies\n ? html`\n <div\n class=\"quick-replies animated\"\n style=\"animation-delay: ${quickRepliesAnimationDelay}\"\n >\n ${this.currentQuickReplies.map(\n (qr: any) => html`\n <button\n class=\"quick-reply-btn animated\"\n style=\"animation-delay: ${quickRepliesAnimationDelay}\"\n @click=${() => this.handleQuickReply(qr.text)}\n >\n ${qr.text}\n </button>\n `\n )}\n </div>\n `\n : html``}\n `;\n }\n\n protected render(): TemplateResult {\n const config = this.sizeConfig;\n\n // set CSS custom properties dynamically based on size\n const styleVars = `\n --phone-width: ${config.phoneWidth}px;\n --phone-total-height: ${config.phoneTotalHeight}px;\n --context-width: ${config.contextWidth}px;\n --context-offset: ${config.contextOffset}px;\n --option-pane-width: ${config.optionPaneWidth}px;\n --option-pane-gap: ${config.optionPaneGap}px;\n --window-padding: ${config.windowPadding}px;\n --phone-screen-height: ${config.phoneScreenHeight}px;\n --context-height: ${config.contextHeight}px;\n --context-closed-left: ${this.contextClosedLeft}px;\n --cutout-height: ${config.cutoutHeight}px;\n --cutout-padding: ${config.cutoutPadding}px;\n --cutout-font-size: ${config.cutoutFontSize}px;\n --cutout-island-width: ${config.cutoutIslandWidth}px;\n --cutout-island-height: ${config.cutoutIslandHeight}px;\n --cutout-island-top: ${config.cutoutIslandTop}px;\n `;\n\n return html`\n <temba-floating-window\n id=\"phone-window\"\n width=\"${this.windowWidth}\"\n leftBoundaryMargin=\"${this.leftBoundaryMargin}\"\n bottomBoundaryMargin=\"${config.windowPadding}\"\n topBoundaryMargin=\"${config.windowPadding}\"\n height=\"${config.phoneTotalHeight}\"\n top=\"0\"\n chromeless\n >\n <div class=\"phone-simulator\" style=\"${styleVars}\">\n <div\n class=\"context-explorer ${this.contextExplorerOpen ? 'open' : ''}\"\n >\n <div class=\"context-explorer-scroll\">\n ${this.context\n ? this.renderContextTree(this.context)\n : html`<div\n style=\"color: #9ca3af; padding: 8px; text-align: center;\"\n >\n No context available\n </div>`}\n </div>\n <div class=\"context-gutter\">\n <div\n class=\"context-gutter-btn ${this.showAllKeys ? '' : 'active'}\"\n @click=${this.handleToggleShowAllKeys}\n title=\"${this.showAllKeys\n ? 'Show keys with values only'\n : 'Show all keys'}\"\n >\n <temba-icon\n name=\"${this.showAllKeys ? 'filter' : 'filter'}\"\n size=\"1\"\n ></temba-icon>\n </div>\n <div class=\"context-gutter-spacer\"></div>\n <div\n class=\"context-gutter-btn\"\n @click=${this.handleToggleContextExplorer}\n title=\"Close\"\n >\n <temba-icon name=\"x\" size=\"1\"></temba-icon>\n </div>\n </div>\n ${this.copiedExpression\n ? html`<div class=\"context-toast\">\n Copied\n <span class=\"expression\">${this.copiedExpression}</span>\n to the clipboard\n </div>`\n : this.toastMessage\n ? html`<div class=\"context-toast\">${this.toastMessage}</div>`\n : html``}\n </div>\n\n <div\n class=\"phone-frame\"\n style=\"pointer-events: ${this.isVisible ? 'all' : 'none'}\"\n >\n <div class=\"phone-top drag-handle\">\n <div class=\"phone-notch\">\n <div class=\"dynamic-island\"></div>\n </div>\n </div>\n <div class=\"phone-screen\">${this.renderMessages()}</div>\n <div class=\"message-input\">\n <button\n class=\"attachment-button\"\n @click=${this.handleToggleAttachmentMenu}\n ?disabled=${this.sprinting}\n >\n <temba-icon name=\"plus\" size=\"1.5\"></temba-icon>\n </button>\n <input\n type=\"text\"\n placeholder=\"Enter Message\"\n .value=${this.inputValue}\n @input=${this.handleInput}\n @keyup=${this.handleKeyUp}\n ?disabled=${this.sprinting}\n />\n <div\n class=\"attachment-menu ${this.attachmentMenuOpen ? 'open' : ''}\"\n >\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('image')}\n >\n <temba-icon name=\"attachment_image\" size=\"1.2\"></temba-icon>\n <span>Image</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('video')}\n >\n <temba-icon name=\"attachment_video\" size=\"1.2\"></temba-icon>\n <span>Video</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('audio')}\n >\n <temba-icon name=\"attachment_audio\" size=\"1.2\"></temba-icon>\n <span>Audio</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('location')}\n >\n <temba-icon\n name=\"attachment_location\"\n size=\"1.2\"\n ></temba-icon>\n <span>Location</span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"option-pane\">\n <button class=\"option-btn\" @click=${this.handleClose} title=\"Close\">\n <temba-icon name=\"x\" size=\"1.5\"></temba-icon>\n </button>\n <button\n class=\"option-btn ${this.following ? 'active' : ''}\"\n @click=${this.handleToggleFollow}\n title=\"${this.following ? 'Following' : 'Follow'}\"\n >\n <temba-icon name=\"follow\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn ${this.contextExplorerOpen ? 'active' : ''}\"\n @click=${this.handleToggleContextExplorer}\n title=\"Context Explorer\"\n >\n <temba-icon name=\"expressions\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn\"\n @click=${this.handleCycleSize}\n title=\"Size: ${this.size}\"\n >\n ${this.size === 'small'\n ? 'S'\n : this.size === 'medium'\n ? 'M'\n : 'L'}\n </button>\n\n <button class=\"option-btn\" @click=${this.handleReset} title=\"Reset\">\n <temba-icon name=\"delete\" size=\"1.5\"></temba-icon>\n </button>\n </div>\n </div>\n </temba-floating-window>\n\n <temba-floating-tab\n id=\"phone-tab\"\n icon=\"simulator\"\n label=\"Phone Simulator\"\n color=\"#10b981\"\n .hidden=${this.isVisible}\n @temba-button-clicked=${this.handleShow}\n ></temba-floating-tab>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../src/simulator/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit-html';\nimport { RapidElement } from '../RapidElement';\nimport { FloatingWindow } from '../layout/FloatingWindow';\nimport { css, PropertyValueMap } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { postJSON, fromCookie, generateUUIDv7 } from '../utils';\nimport { getStore } from '../store/Store';\nimport { CustomEventType } from '../interfaces';\nimport { Chat, ContactEvent, MessageType } from '../display/Chat';\nimport { Events, renderEvent } from '../events/eventRenderers';\n\n// test attachment URLs\nconst TEST_IMAGES = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_a.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_b.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_c.jpg',\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_image_d.jpg'\n];\n\nconst TEST_VIDEOS = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_video_a.mp4'\n];\n\nconst TEST_AUDIO = [\n 'https://s3.amazonaws.com/floweditor-assets.temba.io/simulator/sim_audio_a.mp3'\n];\n\nconst TEST_LOCATIONS = [\n 'geo:47.6062,-122.3321', // Seattle\n 'geo:-0.1807,-78.4678', // Quito\n 'geo:-2.9001,-79.0059', // Cuenca\n 'geo:-1.9536,30.0606' // Kigali\n];\n\ninterface Contact {\n uuid: string;\n name?: string;\n urns: string[];\n fields?: { [key: string]: any };\n groups?: any[];\n language?: string;\n status?: string;\n created_on?: string;\n}\n\ninterface Session {\n environment: any;\n runs: any[];\n status: string;\n trigger: any;\n wait?: any;\n}\n\ninterface Message {\n uuid: string;\n text?: string;\n urn: string;\n attachments?: string[];\n quick_replies?: any[];\n}\n\ninterface Event {\n type: string;\n created_on: string;\n msg?: Message;\n [key: string]: any;\n}\n\ninterface RunContext {\n session: Session;\n events: Event[];\n context?: any;\n contact?: Contact;\n}\n\ninterface SimulatorSize {\n phoneWidth: number;\n phoneTotalHeight: number;\n phoneScreenHeight: number;\n contextWidth: number;\n contextHeight: number;\n contextOffset: number;\n optionPaneWidth: number;\n optionPaneGap: number;\n windowPadding: number;\n cutoutHeight: number;\n cutoutPadding: number;\n cutoutFontSize: number;\n cutoutIslandWidth: number;\n cutoutIslandHeight: number;\n cutoutIslandTop: number;\n}\n\nconst SIMULATOR_SIZES: Record<string, SimulatorSize> = {\n small: {\n phoneWidth: 270,\n phoneTotalHeight: 530,\n phoneScreenHeight: 376,\n contextWidth: 336,\n contextHeight: 416,\n contextOffset: 48,\n optionPaneWidth: 44,\n optionPaneGap: 10,\n windowPadding: 24,\n cutoutHeight: 32,\n cutoutPadding: 12,\n cutoutFontSize: 10,\n cutoutIslandWidth: 80,\n cutoutIslandHeight: 20,\n cutoutIslandTop: 6\n },\n medium: {\n phoneWidth: 300,\n phoneTotalHeight: 600,\n phoneScreenHeight: 470,\n contextWidth: 420,\n contextHeight: 520,\n contextOffset: 60,\n optionPaneWidth: 44,\n optionPaneGap: 12,\n windowPadding: 30,\n cutoutHeight: 40,\n cutoutPadding: 16,\n cutoutFontSize: 12,\n cutoutIslandWidth: 100,\n cutoutIslandHeight: 24,\n cutoutIslandTop: 8\n },\n large: {\n phoneWidth: 360,\n phoneTotalHeight: 700,\n phoneScreenHeight: 564,\n contextWidth: 504,\n contextHeight: 624,\n contextOffset: 72,\n optionPaneWidth: 44,\n optionPaneGap: 14,\n windowPadding: 36,\n cutoutHeight: 50,\n cutoutPadding: 20,\n cutoutFontSize: 14,\n cutoutIslandWidth: 120,\n cutoutIslandHeight: 30,\n cutoutIslandTop: 10\n }\n};\n\nexport class Simulator extends RapidElement {\n static get styles() {\n return css`\n :host {\n /* size-specific dimensions are set dynamically via inline styles */\n --phone-width: 300px;\n --phone-total-height: 720px;\n --context-width: 420px;\n --context-offset: 60px;\n --option-pane-width: 44px;\n --option-pane-gap: 12px;\n --window-padding: 30px;\n --phone-screen-height: 470px;\n --context-height: 520px;\n --context-closed-left: 332px;\n --animation-time: 200ms;\n }\n\n .phone-simulator {\n padding-left: calc(var(--context-width) + var(--context-offset));\n padding-top: var(--window-padding);\n padding-bottom: var(--window-padding);\n position: relative;\n display: flex;\n align-items: flex-start;\n }\n\n .option-pane {\n margin-top: var(--window-padding);\n margin-left: var(--option-pane-gap);\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n border-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n }\n .option-btn {\n background: rgba(255, 255, 255, 0.1);\n border: none;\n border-radius: 12px;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all var(--animation-time) ease;\n color: white;\n }\n .option-btn:hover {\n background: rgba(255, 255, 255, 0.2);\n transform: scale(1.05);\n }\n .option-btn:active {\n transform: scale(0.95);\n }\n .option-btn.active {\n background: var(--color-primary-dark);\n color: white;\n }\n .option-btn.active:hover {\n background: var(--color-primary-dark);\n }\n\n .phone-frame {\n width: var(--phone-width);\n height: var(--phone-total-height);\n border-radius: 40px;\n border: 6px solid #1f2937;\n box-shadow: 0 0px 30px rgba(0, 0, 0, 0.4);\n background: #000;\n position: relative;\n overflow: hidden;\n z-index: 2;\n }\n\n .context-explorer {\n width: var(--context-width);\n height: var(--context-height);\n border-top-left-radius: 16px;\n border-bottom-left-radius: 16px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n position: absolute;\n left: var(--context-closed-left);\n top: calc(var(--window-padding) + 40px);\n z-index: 1;\n font-size: 13px;\n color: #374151;\n transition: left calc(var(--animation-time) * 1.5) ease-out,\n opacity calc(var(--animation-time) * 1.5) ease-out;\n opacity: 0;\n pointer-events: none;\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(10px);\n display: flex;\n flex-direction: column;\n padding: 12px;\n }\n\n .context-gutter {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 6px;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 4px;\n margin-right: 32px;\n margin-top: 8px;\n flex-shrink: 0;\n }\n\n .context-gutter-btn {\n width: 14px;\n height: 14px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border-radius: 6px;\n transition: background var(--animation-time) ease;\n color: rgba(255, 255, 255, 0.6);\n padding: 4px;\n }\n\n .context-gutter-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.9);\n }\n\n .context-gutter-btn.active {\n color: #c084fc;\n }\n\n .context-gutter-spacer {\n flex: 1;\n }\n\n .context-explorer-scroll {\n scrollbar-color: rgba(255, 255, 255, 0.3) #4a4a4a;\n scrollbar-width: thin;\n height: 100%;\n overflow-y: scroll;\n padding-right: 10px;\n margin-right: 30px;\n flex-grow: 1;\n }\n\n .context-explorer-bleed {\n height: 100%;\n width: 0px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar {\n width: 18px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 4px;\n }\n\n .context-explorer-scroll::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n }\n\n /* Custom scrollbar for chat area to allow content to flow behind input */\n .custom-scrollbar-container {\n position: absolute;\n top: 40px;\n bottom: var(--bottom-input-height, 60px);\n right: 4px;\n width: 10px;\n z-index: 20;\n overflow-y: auto;\n overflow-x: hidden;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar {\n width: 6px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.2);\n border-radius: 3px;\n }\n\n .custom-scrollbar-container::-webkit-scrollbar-thumb:hover {\n background: rgba(0, 0, 0, 0.4);\n }\n\n .custom-scrollbar-content {\n width: 100%;\n }\n\n .context-explorer.open {\n left: var(--context-offset);\n opacity: 1;\n pointer-events: auto;\n }\n\n .context-explorer.hidden {\n pointer-events: none !important;\n }\n\n .context-item {\n display: flex;\n align-items: flex-start;\n padding: 2px 4px;\n cursor: pointer;\n user-select: none;\n }\n\n .context-item:hover {\n background: rgba(0, 0, 0, 0.05);\n }\n\n .context-item-expandable {\n display: flex;\n align-items: center;\n }\n\n .context-expand-icon {\n width: 16px;\n display: inline-block;\n text-align: center;\n flex-shrink: 0;\n transition: transform var(--animation-time) ease;\n color: #ffffff;\n }\n\n .context-expand-icon.expanded {\n transform: rotate(90deg);\n }\n\n .context-key {\n color: #ffffff;\n flex-shrink: 0;\n margin-right: 8px;\n display: flex;\n }\n\n .context-key.has-value {\n color: #e8b5e8;\n }\n\n .context-value {\n color: #aaa;\n flex: 1;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .context-children {\n margin-left: 16px;\n }\n\n .context-copy-icon {\n opacity: 0;\n margin-left: 4px;\n transition: opacity var(--animation-time) ease;\n cursor: pointer;\n color: #ccc;\n }\n\n .context-item:hover .context-copy-icon {\n opacity: 1;\n }\n\n .context-toast {\n position: absolute;\n bottom: 60px;\n left: 50%;\n transform: translateX(-50%);\n background: #666;\n color: white;\n padding: 12px 12px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n font-size: 13px;\n z-index: 10;\n animation: slideInUp var(--animation-time) ease-out;\n }\n\n .context-toast .expression {\n color: #e8b5e8;\n font-weight: 600;\n }\n\n @keyframes slideInUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n\n .phone-top {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 10;\n cursor: grab;\n }\n .phone-notch {\n background: transparent;\n height: var(--cutout-height);\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 var(--cutout-padding);\n }\n .phone-notch::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 100%;\n background: linear-gradient(\n to bottom,\n rgba(0, 0, 0, 0.3) 0%,\n rgba(0, 0, 0, 0.2) 50%,\n transparent 100%\n );\n z-index: -1;\n }\n .dynamic-island {\n top: var(--cutout-island-top);\n left: 50%;\n\n width: var(--cutout-island-width);\n height: var(--cutout-island-height);\n background: #000;\n border-radius: calc(var(--cutout-island-height) / 1.5);\n z-index: 1;\n }\n .phone-notch .time {\n color: #000;\n font-size: var(--cutout-font-size);\n font-weight: 600;\n }\n .phone-notch .status-icons {\n display: flex;\n gap: 4px;\n align-items: center;\n }\n .phone-notch .status-icons span {\n color: #000;\n font-size: var(--cutout-font-size);\n }\n .phone-header {\n background: transparent;\n padding: 10px 15px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n cursor: move;\n user-select: none;\n border-bottom: none;\n pointer-events: all;\n }\n\n .phone-screen {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: white;\n display: flex;\n flex-direction: column;\n }\n\n temba-chat {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n --color-chat-in: #e5e5ea;\n --color-chat-out: #007aff;\n --chat-top-padding: calc(var(--cutout-height));\n --chat-bottom-padding: calc(var(--bottom-input-height, 80px) - 10px);\n }\n\n .bottom-input-container {\n position: absolute;\n bottom: 0px;\n left: 0px;\n right: 0px;\n z-index: 10;\n }\n\n .bottom-input-container::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.45);\n backdrop-filter: blur(10px);\n -webkit-mask-image: linear-gradient(to bottom, transparent, black 20px);\n mask-image: linear-gradient(to bottom, transparent, black 20px);\n z-index: -1;\n }\n\n .quick-replies-container {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 6px;\n z-index: 9;\n }\n\n .quick-reply-btn {\n padding: 4px 8px;\n border-radius: 18px;\n border: 1px solid var(--color-primary, #007aff);\n background: white;\n color: var(--color-primary, #007aff);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n }\n\n .quick-reply-btn:hover:not(:disabled) {\n background: var(--color-primary, #007aff);\n color: white;\n }\n\n .quick-reply-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .message-input {\n padding: 8px 12px;\n border-top: none;\n display: flex;\n align-items: center;\n gap: 8px;\n z-index: 10;\n }\n .message-input input {\n flex: 1;\n border: 1px solid #c6c6c857;\n border-radius: 20px;\n padding: 8px 15px;\n font-size: 15px;\n margin-bottom: 5px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n outline: none;\n }\n .message-input input::placeholder {\n color: #8e8e93;\n }\n .attachment-button {\n width: 30px;\n height: 30px;\n border-radius: 50%;\n background: #fff;\n border: 1px solid #c6c6c857;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n flex-shrink: 0;\n margin-bottom: 5px;\n transition: all var(--animation-time) ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n color: #000;\n }\n .attachment-button:hover {\n background: #f8f8f8ff;\n transform: scale(1.05);\n }\n .attachment-button:active {\n transform: scale(0.95);\n }\n .attachment-menu {\n position: absolute;\n bottom: 55px;\n left: 12px;\n background: white;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(10px);\n transition: opacity var(--animation-time) ease, transform 0.2s ease;\n z-index: 20;\n }\n .attachment-menu.open {\n opacity: 1;\n pointer-events: all;\n transform: translateY(0);\n }\n .attachment-menu-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n cursor: pointer;\n transition: background var(--animation-time) ease;\n white-space: nowrap;\n font-size: 14px;\n color: #1f2937;\n }\n .attachment-menu-item:hover {\n background: #f3f4f6;\n }\n .attachment-menu-item temba-icon {\n color: #007aff;\n }\n `;\n }\n\n @property({ type: String })\n flow = '';\n\n @property({ type: String })\n endpoint = '';\n\n @property({ type: Number })\n animationTime = 200;\n\n @fromCookie('simulator-size', 'small')\n size: 'small' | 'medium' | 'large';\n\n @property({ type: Array })\n private events: ContactEvent[] = [];\n\n private previousEventCount = 0;\n private chat: Chat = null;\n\n @property({ type: Object })\n private session: Session | null = null;\n\n @property({ type: Object })\n private context: any = null;\n\n @property({ type: Object })\n private contact: 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\n @property({ type: Boolean })\n private sprinting = false;\n\n @property({ type: String })\n private inputValue = '';\n\n @fromCookie('simulator-follow', true)\n private following: boolean;\n\n @fromCookie('simulator-context-open', false)\n private contextExplorerOpen: boolean;\n\n @property({ type: Object })\n private expandedPaths: Set<string> = new Set();\n\n @property({ type: String })\n private copiedExpression = '';\n\n @property({ type: String })\n private toastMessage = '';\n\n @property({ type: Boolean })\n private showAllKeys = true;\n\n private previousWindowWidth = 0;\n\n @property({ type: Array })\n private currentQuickReplies: any[] = [];\n\n @property({ type: Boolean })\n private isVisible = false;\n\n @property({ type: Boolean })\n private attachmentMenuOpen = false;\n\n private boundClickOutsideHandler: ((event: MouseEvent) => void) | null = null;\n\n // attachment cycling indices - initialized randomly\n private imageIndex = Math.floor(Math.random() * TEST_IMAGES.length);\n private videoIndex = Math.floor(Math.random() * TEST_VIDEOS.length);\n private audioIndex = Math.floor(Math.random() * TEST_AUDIO.length);\n private locationIndex = Math.floor(Math.random() * TEST_LOCATIONS.length);\n\n // method to reset attachment indices for testing\n public resetAttachmentIndices() {\n this.imageIndex = 2;\n this.videoIndex = 0;\n this.audioIndex = 0;\n this.locationIndex = 0;\n }\n\n private get sizeConfig(): SimulatorSize {\n return SIMULATOR_SIZES[this.size] || SIMULATOR_SIZES.medium;\n }\n\n private get windowWidth(): number {\n const config = this.sizeConfig;\n return (\n config.contextWidth +\n config.phoneWidth +\n config.optionPaneWidth +\n config.optionPaneGap +\n config.contextOffset\n );\n }\n\n private get leftBoundaryMargin(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset;\n }\n\n private get contextClosedLeft(): number {\n const config = this.sizeConfig;\n return config.contextWidth + config.contextOffset - config.phoneWidth;\n }\n\n public connectedCallback() {\n super.connectedCallback();\n }\n\n protected firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n this.chat = this.shadowRoot.querySelector('temba-chat');\n\n // if we have events that were collected before chat was ready, add them now\n if (this.chat && this.events.length > 0) {\n this.chat.addMessages(this.events, null, true);\n }\n\n this.setupCustomScrollbar();\n }\n\n private setupCustomScrollbar() {\n const chat = this.shadowRoot?.querySelector('temba-chat') as Chat;\n const scrollContainer = this.shadowRoot?.querySelector(\n '.custom-scrollbar-container'\n ) as HTMLElement;\n const scrollContent = this.shadowRoot?.querySelector(\n '.custom-scrollbar-content'\n ) as HTMLElement;\n\n if (!chat || !scrollContainer || !scrollContent) return;\n\n chat.updateComplete.then(() => {\n const chatScroll = chat.shadowRoot?.querySelector(\n '.scroll'\n ) as HTMLElement;\n if (!chatScroll) return;\n\n let ignoreScroll = false;\n\n // Sync from chat to custom scrollbar\n chatScroll.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n // Chat: 0 (bottom) ... -Max (top) (Negative scrolling)\n // Custom: Max (bottom) ... 0 (top) (Positive scrolling)\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n // Math.abs to handle negative scrollTop\n const distanceFromBottom = Math.abs(chatScroll.scrollTop);\n const newCustomScrollTop = maxScroll - distanceFromBottom;\n\n scrollContainer.scrollTop = newCustomScrollTop;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync from custom scrollbar to chat\n scrollContainer.addEventListener('scroll', () => {\n if (!ignoreScroll) {\n ignoreScroll = true;\n\n const maxScroll =\n scrollContainer.scrollHeight - scrollContainer.clientHeight;\n const distanceFromBottom = maxScroll - scrollContainer.scrollTop;\n\n // chat scrollTop should be -distanceFromBottom\n chatScroll.scrollTop = -distanceFromBottom;\n\n requestAnimationFrame(() => (ignoreScroll = false));\n }\n });\n\n // Sync height\n const syncHeight = () => {\n const chatMaxScroll = chatScroll.scrollHeight - chatScroll.clientHeight;\n const customClientHeight = scrollContainer.clientHeight;\n\n // ensure minimum height\n if (chatMaxScroll <= 0) {\n scrollContent.style.height = '100%';\n return;\n }\n\n const newHeight = chatMaxScroll + customClientHeight;\n scrollContent.style.height = `${newHeight}px`;\n\n // If we were effectively at the bottom, stay at the bottom\n // This is a heuristic, assuming if we're close enough we're \"at bottom\"\n // But the Chat component handles scrollToBottom on new messages, which fires scroll event,\n // which updates us. So we might not need to force it here unless resize happens without message.\n if (Math.abs(chatScroll.scrollTop) < 5) {\n scrollContainer.scrollTop = scrollContainer.scrollHeight;\n }\n };\n\n // Observe changes\n const observer = new MutationObserver(syncHeight);\n observer.observe(chatScroll, {\n childList: true,\n subtree: true,\n attributes: true\n });\n\n const resizeObserver = new ResizeObserver(syncHeight);\n resizeObserver.observe(chatScroll);\n\n // Initial sync\n syncHeight();\n });\n }\n\n protected updated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.updated(changes);\n\n if (\n changes.has('currentQuickReplies') ||\n changes.has('keyboardVisible') ||\n changes.has('attachmentMenuOpen')\n ) {\n this.updateBottomInputHeight();\n }\n\n if (changes.has('flow') && this.flow) {\n this.endpoint = `/flow/simulate/${this.flow}/`;\n }\n\n // handle attachment menu click outside listener\n if (changes.has('attachmentMenuOpen')) {\n if (this.attachmentMenuOpen) {\n // create bound handler if it doesn't exist\n if (!this.boundClickOutsideHandler) {\n this.boundClickOutsideHandler =\n this.handleClickOutsideAttachmentMenu.bind(this);\n }\n // add listener when menu opens\n setTimeout(() => {\n document.addEventListener('click', this.boundClickOutsideHandler);\n }, 0);\n } else {\n // remove listener when menu closes\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n }\n\n // update floating window boundaries when size changes\n if (changes.has('size')) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n // use the stored previous width since phoneWindow.width has already been updated\n const oldWidth = this.previousWindowWidth || phoneWindow.width;\n const oldRight = phoneWindow.left + oldWidth;\n\n const config = this.sizeConfig;\n const newWidth = this.windowWidth;\n\n // store current width for next size change\n this.previousWindowWidth = newWidth;\n\n // update dimensions and boundaries\n phoneWindow.width = newWidth;\n phoneWindow.leftBoundaryMargin = this.leftBoundaryMargin;\n phoneWindow.topBoundaryMargin = config.windowPadding;\n phoneWindow.bottomBoundaryMargin = config.windowPadding;\n\n // keep right edge in same position by adjusting left\n let newLeft = oldRight - newWidth;\n\n // apply same boundary logic as FloatingWindow.handleMouseMove\n const padding = 20;\n const minLeft = padding - this.leftBoundaryMargin;\n const maxLeft =\n window.innerWidth -\n newWidth -\n padding +\n phoneWindow.rightBoundaryMargin;\n\n // clamp to boundaries\n newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));\n\n phoneWindow.left = newLeft;\n\n // adjust vertical position if needed\n const windowElement = phoneWindow.shadowRoot?.querySelector(\n '.window'\n ) as HTMLElement;\n const currentHeight =\n windowElement?.offsetHeight || config.phoneTotalHeight;\n const maxTop = Math.max(\n padding - config.windowPadding,\n window.innerHeight - currentHeight - padding + config.windowPadding\n );\n\n phoneWindow.top = Math.max(\n padding - config.windowPadding,\n Math.min(phoneWindow.top, maxTop)\n );\n }\n });\n } else {\n // store initial width when first rendered\n if (!this.previousWindowWidth) {\n this.previousWindowWidth = this.windowWidth;\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n // clean up event listener when component is removed\n if (this.boundClickOutsideHandler) {\n document.removeEventListener('click', this.boundClickOutsideHandler);\n }\n }\n\n private handleShow() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.show();\n this.isVisible = true;\n getStore().getState().setSimulatorActive(true);\n\n // ensure chat component is available\n if (!this.chat) {\n this.chat = this.shadowRoot.querySelector('temba-chat');\n }\n\n // start the simulation if we haven't already\n if (!this.session) {\n this.startFlow();\n }\n }\n\n private async startFlow() {\n const now = new Date().toISOString();\n\n // set created_on to simulation start time\n this.contact = { ...this.contact, created_on: now };\n\n const body = {\n contact: this.contact,\n trigger: {\n type: 'manual',\n triggered_on: now,\n flow: { uuid: this.flow, name: 'New Chat' },\n params: {}\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n this.updateRunContext(response.json as RunContext);\n } catch (error) {\n console.error('Failed to start simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to start simulation</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n }\n }\n\n private updateRunContext(runContext: RunContext, msgInEvt?: ContactEvent) {\n const newEvents: ContactEvent[] = [];\n\n // add the user's message if provided\n if (msgInEvt) {\n // ensure it has a UUID\n if (!msgInEvt.uuid) {\n msgInEvt.uuid = generateUUIDv7();\n }\n // ensure created_on is a Date object\n if (typeof msgInEvt.created_on === 'string') {\n msgInEvt.created_on = new Date(msgInEvt.created_on);\n }\n newEvents.push(msgInEvt);\n }\n\n if (runContext.session) {\n this.session = runContext.session;\n\n // update our contact with the latest from the session\n if (runContext.contact) {\n this.contact = runContext.contact;\n }\n }\n\n // store the context from the response\n if (runContext.context) {\n this.context = runContext.context;\n }\n\n // extract quick replies from the most recent sprint\n this.currentQuickReplies = [];\n\n if (runContext.events && runContext.events.length > 0) {\n for (const rawEvent of runContext.events) {\n // skip msg_received events from the server since we already added the user's message\n if (rawEvent.type === 'msg_received') {\n continue;\n }\n\n // skip msg_created events without a proper msg property\n if (rawEvent.type === 'msg_created' && !(rawEvent as any).msg) {\n continue;\n }\n\n // convert to ContactEvent\n const event: ContactEvent = {\n ...rawEvent,\n uuid: rawEvent.uuid || generateUUIDv7(),\n created_on:\n typeof rawEvent.created_on === 'string'\n ? new Date(rawEvent.created_on)\n : rawEvent.created_on\n } as ContactEvent;\n\n // pre-render non-message events\n this.prerenderEvent(event);\n\n // extract quick replies from msg_created events\n if (event.type === 'msg_created' && (event as any).msg?.quick_replies) {\n this.currentQuickReplies = (event as any).msg.quick_replies;\n }\n\n const isMessage = event.type === 'msg_created';\n const msg = (event as any).msg;\n\n // Check if the event should be displayed.\n // 1. If it's a message, it must have text or attachments\n if (isMessage) {\n const hasText = msg.text && msg.text.trim().length > 0;\n const hasAttachments = msg.attachments && msg.attachments.length > 0;\n if (!hasText && !hasAttachments) {\n continue;\n }\n }\n // 2. If it's not a message, it must have been rendered by prerenderEvent\n else if (!event._rendered) {\n continue;\n }\n\n newEvents.push(event);\n }\n }\n\n // add all new events to chat component if it exists\n if (this.chat) {\n this.chat.addMessages(newEvents, null, true);\n } else {\n // fallback: store events and add them once chat is ready\n this.events = [...this.events, ...newEvents];\n }\n\n this.sprinting = false;\n this.requestUpdate(); // trigger re-render for quick replies\n this.scrollToBottom();\n this.updateActivity();\n }\n\n private updateActivity() {\n if (!this.session) {\n return;\n }\n\n const pathCounts: { [key: string]: number } = {};\n const nodeCounts: { [nodeUUID: string]: number } = {};\n\n // iterate through all runs to get path segment counts\n for (const run of this.session.runs) {\n if (run.path) {\n for (let i = 0; i < run.path.length - 1; i++) {\n const step = run.path[i];\n const nextStep = run.path[i + 1];\n if (step.exit_uuid && nextStep.node_uuid) {\n const key = step.exit_uuid + ':' + nextStep.node_uuid;\n pathCounts[key] = (pathCounts[key] || 0) + 1;\n }\n }\n }\n\n // set node counts on the last step of any active/waiting runs\n if (run.status === 'active' || run.status === 'waiting') {\n if (run.path && run.path.length > 0) {\n const finalStep = run.path[run.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n nodeCounts[finalStep.node_uuid] =\n (nodeCounts[finalStep.node_uuid] || 0) + 1;\n }\n }\n }\n }\n\n // Update simulator activity in the store\n getStore().getState().updateSimulatorActivity({\n segments: pathCounts,\n nodes: nodeCounts\n });\n\n // Fire follow event if following is enabled\n if (this.following) {\n this.fireFollowEvent();\n }\n }\n\n private fireFollowEvent() {\n if (!this.session || !this.session.runs || this.session.runs.length === 0) {\n return;\n }\n\n // Find the first active or waiting run\n let activeRun = this.session.runs.find(\n (run: any) => run.status === 'active' || run.status === 'waiting'\n );\n\n // If no active/waiting run and simulation has ended, use the first completed run\n if (!activeRun) {\n activeRun = this.session.runs.find(\n (run: any) => run.status === 'completed'\n );\n }\n\n if (activeRun && activeRun.path && activeRun.path.length > 0) {\n const finalStep = activeRun.path[activeRun.path.length - 1];\n if (finalStep && finalStep.node_uuid) {\n this.fireCustomEvent(CustomEventType.FollowSimulation, {\n flowUuid: activeRun.flow?.uuid || this.flow,\n nodeUuid: finalStep.node_uuid\n });\n }\n }\n }\n\n private scrollToBottom() {\n if (this.chat) {\n // chat component handles scrolling, but we still need to focus input\n this.chat.scrollToBottom();\n setTimeout(() => {\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n return;\n }\n // wait for render, then scroll to bottom\n setTimeout(() => {\n const screen = this.shadowRoot?.querySelector('.phone-screen');\n if (screen) {\n screen.scrollTop = screen.scrollHeight;\n }\n // update previous count after animation completes\n this.previousEventCount = this.events.length;\n\n // return focus to input\n const input = this.shadowRoot?.querySelector(\n '.message-input input'\n ) as HTMLInputElement;\n if (input) {\n input.focus();\n }\n }, 50);\n }\n\n private prerenderEvent(event: ContactEvent) {\n // skip if already rendered or is a message event\n if (\n event._rendered ||\n event.type === Events.MSG_CREATED ||\n event.type === Events.MSG_RECEIVED\n ) {\n return;\n }\n\n // handle simulator-specific events (errors, warnings, failures)\n if (event.type === 'error' || event.type === 'failure') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Error\n };\n return;\n }\n\n if (event.type === 'warning') {\n event._rendered = {\n html: renderEvent(event, true),\n type: MessageType.Note\n };\n return;\n }\n\n // try to render as a standard event\n const rendered = renderEvent(event, true);\n if (rendered) {\n event._rendered = {\n html: rendered,\n type: MessageType.Inline\n };\n }\n }\n\n private handleClose() {\n const phoneWindow = this.shadowRoot.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n phoneWindow.handleClose();\n this.isVisible = false;\n getStore().getState().setSimulatorActive(false);\n }\n\n private handleReset() {\n // reset simulation state\n this.events = [];\n this.session = null;\n this.context = null;\n this.inputValue = '';\n this.sprinting = false;\n this.previousEventCount = 0;\n this.currentQuickReplies = [];\n\n // reset chat component\n if (this.chat) {\n this.chat.reset();\n }\n\n // Clear simulator activity data\n getStore().getState().updateSimulatorActivity({\n segments: {},\n nodes: {}\n });\n\n // reset contact to initial state\n this.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\n // restart the flow\n this.startFlow();\n }\n\n private handleToggleFollow() {\n this.following = !this.following;\n }\n\n private handleCycleSize() {\n const sizes: Array<'small' | 'medium' | 'large'> = [\n 'small',\n 'medium',\n 'large'\n ];\n const currentIndex = sizes.indexOf(this.size);\n const nextIndex = (currentIndex + 1) % sizes.length;\n this.size = sizes[nextIndex];\n }\n\n private handleToggleContextExplorer() {\n this.contextExplorerOpen = !this.contextExplorerOpen;\n\n // if opening the context explorer, ensure it's not off-screen\n if (this.contextExplorerOpen) {\n requestAnimationFrame(() => {\n const phoneWindow = this.shadowRoot?.getElementById(\n 'phone-window'\n ) as FloatingWindow;\n if (phoneWindow) {\n const padding = 20;\n const contextExplorerLeft = this.sizeConfig.contextOffset;\n const minWindowLeft = padding - contextExplorerLeft;\n\n if (phoneWindow.left < minWindowLeft) {\n phoneWindow.left = minWindowLeft;\n }\n }\n });\n }\n }\n\n private togglePath(path: string) {\n if (this.expandedPaths.has(path)) {\n this.expandedPaths.delete(path);\n } else {\n this.expandedPaths.add(path);\n }\n this.requestUpdate();\n }\n\n private isExpandable(value: any): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n // check if object has keys other than __default__\n const keys = Object.keys(value).filter((key) => key !== '__default__');\n return keys.length > 0;\n }\n\n private renderContextValue(value: any): TemplateResult | string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'boolean')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'number')\n return html`<span class=\"context-value\">${value}</span>`;\n if (typeof value === 'string')\n return html`<span class=\"context-value\">${value}</span>`;\n if (Array.isArray(value))\n return html`<span class=\"context-value\">[${value.length}]</span>`;\n return '';\n }\n\n private buildExpression(path: string): string {\n return `@${path}`;\n }\n\n private async handleCopyExpression(\n path: string,\n event: Event\n ): Promise<void> {\n event.stopPropagation();\n const expression = this.buildExpression(path);\n try {\n await navigator.clipboard.writeText(expression);\n this.copiedExpression = expression;\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.copiedExpression = '';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy expression:', err);\n }\n }\n\n private handleToggleShowAllKeys() {\n this.showAllKeys = !this.showAllKeys;\n this.toastMessage = this.showAllKeys\n ? 'Showing all keys'\n : 'Filtering out keys without values';\n // clear the toast after 2 seconds\n setTimeout(() => {\n this.toastMessage = '';\n }, 2000);\n }\n\n private renderContextTree(\n obj: any,\n path: string = ''\n ): TemplateResult | TemplateResult[] {\n if (!obj || typeof obj !== 'object') {\n return html``;\n }\n\n let entries = Array.isArray(obj)\n ? obj.map((v, i) => [String(i), v])\n : Object.entries(obj).filter(([key]) => key !== '__default__');\n\n // filter out keys without values if showAllKeys is false\n if (!this.showAllKeys) {\n entries = entries.filter(([, value]) => {\n // keep if expandable (has children)\n if (this.isExpandable(value)) return true;\n // keep if it has a displayable value (not null/undefined)\n if (value === null || value === undefined) return false;\n // keep primitives with values\n return (\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string' ||\n Array.isArray(value)\n );\n });\n }\n\n return html`${entries.map(([key, value]) => {\n const currentPath = path ? `${path}.${key}` : key;\n const isExpanded = this.expandedPaths.has(currentPath);\n const expandable = this.isExpandable(value);\n\n // check if this object has a __default__ value\n let displayValue = value;\n\n if (\n expandable &&\n !Array.isArray(value) &&\n value !== null &&\n typeof value === 'object' &&\n '__default__' in value\n ) {\n displayValue = value.__default__;\n }\n\n return html`\n <div>\n <div\n class=\"context-item ${expandable ? 'context-item-expandable' : ''}\"\n @click=${() => expandable && this.togglePath(currentPath)}\n >\n ${expandable\n ? html`<span\n class=\"context-expand-icon ${isExpanded ? 'expanded' : ''}\"\n >›</span\n >`\n : html`<span class=\"context-expand-icon\"></span>`}\n <span class=\"context-key ${expandable ? 'has-value' : ''}\"\n >${key}\n <temba-icon\n class=\"context-copy-icon\"\n name=\"copy\"\n size=\"0.9\"\n @click=${(e: Event) =>\n this.handleCopyExpression(currentPath, e)}\n ></temba-icon>\n </span>\n ${!isExpanded ? this.renderContextValue(displayValue) : html``}\n </div>\n ${isExpanded\n ? html`<div class=\"context-children\">\n ${this.renderContextTree(value, currentPath)}\n </div>`\n : html``}\n </div>\n `;\n })}`;\n }\n\n private async resume(text: string, attachment?: string) {\n if ((!text && !attachment) || !this.session) {\n return;\n }\n\n this.sprinting = true;\n this.inputValue = '';\n this.currentQuickReplies = [];\n this.attachmentMenuOpen = false;\n\n const now = new Date().toISOString();\n\n // create the event for the API (with ISO string date)\n const msgInEvtForAPI = {\n uuid: generateUUIDv7(),\n type: 'msg_received',\n created_on: now,\n msg: {\n uuid: generateUUIDv7(),\n text: text || '',\n urn: this.contact.urns[0],\n direction: 'in',\n type: 'text',\n attachments: attachment ? [attachment] : [],\n quick_replies: [],\n channel: { uuid: generateUUIDv7(), name: 'Simulator' }\n }\n };\n\n // create the ContactEvent for display (with Date object)\n const msgInEvt = {\n ...msgInEvtForAPI,\n created_on: new Date(now)\n } as ContactEvent;\n\n // show user's message immediately via chat component\n if (this.chat) {\n this.chat.addMessages([msgInEvt], null, true);\n } else {\n this.events = [...this.events, msgInEvt];\n }\n this.requestUpdate();\n this.scrollToBottom();\n\n const body = {\n session: this.session,\n contact: this.contact,\n resume: {\n type: 'msg',\n event: msgInEvtForAPI,\n resumed_on: now\n }\n };\n\n try {\n const response = await postJSON(this.endpoint, body);\n\n // add a small delay before showing the reply to simulate typing\n await new Promise((resolve) => setTimeout(resolve, 400));\n\n // pass null for msgInEvt since we already added it\n this.updateRunContext(response.json as RunContext, null);\n } catch (error) {\n console.error('Failed to resume simulation:', error);\n const errorEvent = {\n uuid: generateUUIDv7(),\n type: 'error',\n created_on: new Date(now),\n _rendered: {\n html: html`<p>Failed to send message</p>`,\n type: MessageType.Error\n }\n } as ContactEvent;\n if (this.chat) {\n this.chat.addMessages([errorEvent], null, true);\n } else {\n this.events = [...this.events, errorEvent];\n }\n this.sprinting = false;\n }\n }\n\n private handleKeyUp(evt: KeyboardEvent) {\n if (evt.key === 'Enter') {\n const input = evt.target as HTMLInputElement;\n const text = input.value.trim();\n if (text) {\n this.resume(text);\n }\n }\n }\n\n private handleInput(evt: Event) {\n const input = evt.target as HTMLInputElement;\n this.inputValue = input.value;\n }\n\n private handleQuickReplyClick(text: string) {\n if (!this.sprinting && text) {\n this.resume(text);\n }\n }\n\n private handleToggleAttachmentMenu() {\n this.attachmentMenuOpen = !this.attachmentMenuOpen;\n }\n\n private handleClickOutsideAttachmentMenu(event: MouseEvent) {\n if (!this.attachmentMenuOpen) {\n return;\n }\n\n const menu = this.shadowRoot?.querySelector('.attachment-menu');\n const button = this.shadowRoot?.querySelector('.attachment-button');\n\n if (!menu || !button) {\n return;\n }\n\n // check if click is outside both menu and button\n const clickedInsideMenu = menu.contains(event.target as Node);\n const clickedInsideButton = button.contains(event.target as Node);\n\n if (!clickedInsideMenu && !clickedInsideButton) {\n this.attachmentMenuOpen = false;\n }\n }\n\n private handleSendAttachment(attachmentType: string) {\n let attachment = '';\n switch (attachmentType) {\n case 'image':\n attachment = `image/jpeg:${TEST_IMAGES[this.imageIndex]}`;\n this.imageIndex = (this.imageIndex + 1) % TEST_IMAGES.length;\n break;\n case 'video':\n attachment = `video/mp4:${TEST_VIDEOS[this.videoIndex]}`;\n this.videoIndex = (this.videoIndex + 1) % TEST_VIDEOS.length;\n break;\n case 'audio':\n attachment = `audio/mp3:${TEST_AUDIO[this.audioIndex]}`;\n this.audioIndex = (this.audioIndex + 1) % TEST_AUDIO.length;\n break;\n case 'location':\n attachment = TEST_LOCATIONS[this.locationIndex];\n this.locationIndex = (this.locationIndex + 1) % TEST_LOCATIONS.length;\n break;\n }\n\n if (attachment) {\n this.resume('', attachment);\n }\n }\n\n private updateBottomInputHeight() {\n requestAnimationFrame(() => {\n const bottomContainer = this.shadowRoot?.querySelector(\n '.bottom-input-container'\n ) as HTMLElement;\n if (bottomContainer) {\n const height = bottomContainer.offsetHeight;\n this.style.setProperty('--bottom-input-height', `${height}px`);\n }\n });\n }\n\n protected render(): TemplateResult {\n const config = this.sizeConfig;\n\n // set CSS custom properties dynamically based on size\n const styleVars = `\n --phone-width: ${config.phoneWidth}px;\n --phone-total-height: ${config.phoneTotalHeight}px;\n --context-width: ${config.contextWidth}px;\n --context-offset: ${config.contextOffset}px;\n --option-pane-width: ${config.optionPaneWidth}px;\n --option-pane-gap: ${config.optionPaneGap}px;\n --window-padding: ${config.windowPadding}px;\n --phone-screen-height: ${config.phoneScreenHeight}px;\n --context-height: ${config.contextHeight}px;\n --context-closed-left: ${this.contextClosedLeft}px;\n --cutout-height: ${config.cutoutHeight}px;\n --cutout-padding: ${config.cutoutPadding}px;\n --cutout-font-size: ${config.cutoutFontSize}px;\n --cutout-island-width: ${config.cutoutIslandWidth}px;\n --cutout-island-height: ${config.cutoutIslandHeight}px;\n --cutout-island-top: ${config.cutoutIslandTop}px;\n --animation-time: ${this.animationTime}ms;\n `;\n\n return html`\n <temba-floating-window\n style=\"--transition-duration: ${this.animationTime}ms\"\n id=\"phone-window\"\n width=\"${this.windowWidth}\"\n leftBoundaryMargin=\"${this.leftBoundaryMargin}\"\n bottomBoundaryMargin=\"${config.windowPadding}\"\n topBoundaryMargin=\"${config.windowPadding}\"\n height=\"${config.phoneTotalHeight}\"\n top=\"0\"\n chromeless\n >\n <div class=\"phone-simulator\" style=\"${styleVars}\">\n <div\n class=\"context-explorer ${this.contextExplorerOpen\n ? 'open'\n : ''} ${this.isVisible ? 'visible' : 'hidden'}\"\n >\n <div class=\"context-explorer-scroll\">\n ${this.context\n ? this.renderContextTree(this.context)\n : html`<div\n style=\"color: #9ca3af; padding: 8px; text-align: center;\"\n >\n No context available\n </div>`}\n </div>\n <div class=\"context-gutter\">\n <div\n class=\"context-gutter-btn ${this.showAllKeys ? '' : 'active'}\"\n @click=${this.handleToggleShowAllKeys}\n title=\"${this.showAllKeys\n ? 'Show keys with values only'\n : 'Show all keys'}\"\n >\n <temba-icon\n name=\"${this.showAllKeys ? 'filter' : 'filter'}\"\n size=\"1\"\n ></temba-icon>\n </div>\n <div class=\"context-gutter-spacer\"></div>\n <div\n class=\"context-gutter-btn\"\n @click=${this.handleToggleContextExplorer}\n title=\"Close\"\n >\n <temba-icon name=\"x\" size=\"1\"></temba-icon>\n </div>\n </div>\n ${this.copiedExpression\n ? html`<div class=\"context-toast\">\n Copied\n <span class=\"expression\">${this.copiedExpression}</span>\n to the clipboard\n </div>`\n : this.toastMessage\n ? html`<div class=\"context-toast\">${this.toastMessage}</div>`\n : html``}\n </div>\n\n <div\n class=\"phone-frame\"\n style=\"pointer-events: ${this.isVisible ? 'all' : 'none'}\"\n >\n <div class=\"phone-top drag-handle\">\n <div class=\"phone-notch\">\n <div class=\"dynamic-island\"></div>\n </div>\n </div>\n <temba-chat class=\"phone-screen\" .showTimestamps=${false}>\n </temba-chat>\n <div class=\"custom-scrollbar-container\">\n <div class=\"custom-scrollbar-content\"></div>\n </div>\n\n <div class=\"bottom-input-container\">\n ${this.currentQuickReplies.length > 0\n ? html`<div class=\"quick-replies-container\">\n ${this.currentQuickReplies.map(\n (qr) => html`\n <button\n class=\"quick-reply-btn\"\n @click=${() => this.handleQuickReplyClick(qr.text)}\n ?disabled=${this.sprinting}\n >\n ${qr.text}\n </button>\n `\n )}\n </div>`\n : null}\n <div class=\"message-input\">\n <button\n class=\"attachment-button\"\n @click=${this.handleToggleAttachmentMenu}\n ?disabled=${this.sprinting}\n >\n <temba-icon name=\"plus\" size=\"1.5\"></temba-icon>\n </button>\n <input\n type=\"text\"\n placeholder=\"Enter Message\"\n .value=${this.inputValue}\n @input=${this.handleInput}\n @keyup=${this.handleKeyUp}\n ?disabled=${this.sprinting}\n />\n <div\n class=\"attachment-menu ${this.attachmentMenuOpen\n ? 'open'\n : ''}\"\n >\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('image')}\n >\n <temba-icon name=\"attachment_image\" size=\"1.2\"></temba-icon>\n <span>Image</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('video')}\n >\n <temba-icon name=\"attachment_video\" size=\"1.2\"></temba-icon>\n <span>Video</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('audio')}\n >\n <temba-icon name=\"attachment_audio\" size=\"1.2\"></temba-icon>\n <span>Audio</span>\n </div>\n <div\n class=\"attachment-menu-item\"\n @click=${() => this.handleSendAttachment('location')}\n >\n <temba-icon\n name=\"attachment_location\"\n size=\"1.2\"\n ></temba-icon>\n <span>Location</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div\n class=\"option-pane\"\n style=\"pointer-events:${this.isVisible ? 'all' : 'none'}\"\n >\n <button class=\"option-btn\" @click=${this.handleClose} title=\"Close\">\n <temba-icon name=\"x\" size=\"1.5\"></temba-icon>\n </button>\n <button\n class=\"option-btn ${this.following ? 'active' : ''}\"\n @click=${this.handleToggleFollow}\n title=\"${this.following ? 'Following' : 'Follow'}\"\n >\n <temba-icon name=\"follow\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn ${this.contextExplorerOpen ? 'active' : ''}\"\n @click=${this.handleToggleContextExplorer}\n title=\"Context Explorer\"\n >\n <temba-icon name=\"expressions\" size=\"1.5\"></temba-icon>\n </button>\n\n <button\n class=\"option-btn\"\n @click=${this.handleCycleSize}\n title=\"Size: ${this.size}\"\n >\n ${this.size === 'small'\n ? 'S'\n : this.size === 'medium'\n ? 'M'\n : 'L'}\n </button>\n\n <button class=\"option-btn\" @click=${this.handleReset} title=\"Reset\">\n <temba-icon name=\"delete\" size=\"1.5\"></temba-icon>\n </button>\n </div>\n </div>\n </temba-floating-window>\n\n <temba-floating-tab\n id=\"phone-tab\"\n icon=\"simulator\"\n label=\"Phone Simulator\"\n color=\"#10b981\"\n .hidden=${this.isVisible}\n @temba-button-clicked=${this.handleShow}\n ></temba-floating-tab>\n `;\n }\n}\n"]}
|
|
@@ -34,6 +34,7 @@ export const zustand = createStore()(subscribeWithSelector(immer((set, get) => (
|
|
|
34
34
|
flowDefinition: null,
|
|
35
35
|
flowInfo: null,
|
|
36
36
|
isTranslating: false,
|
|
37
|
+
viewingRevision: false,
|
|
37
38
|
dirtyDate: null,
|
|
38
39
|
activity: null,
|
|
39
40
|
simulatorActivity: null,
|
|
@@ -45,6 +46,7 @@ export const zustand = createStore()(subscribeWithSelector(immer((set, get) => (
|
|
|
45
46
|
});
|
|
46
47
|
},
|
|
47
48
|
fetchRevision: async (endpoint, id = null) => {
|
|
49
|
+
const viewingRevision = !!id && id !== 'latest';
|
|
48
50
|
if (!id) {
|
|
49
51
|
id = 'latest';
|
|
50
52
|
}
|
|
@@ -53,7 +55,11 @@ export const zustand = createStore()(subscribeWithSelector(immer((set, get) => (
|
|
|
53
55
|
throw new Error('Network response was not ok');
|
|
54
56
|
}
|
|
55
57
|
const data = (await response.json());
|
|
56
|
-
set({
|
|
58
|
+
set({
|
|
59
|
+
flowInfo: data.info,
|
|
60
|
+
flowDefinition: data.definition,
|
|
61
|
+
viewingRevision
|
|
62
|
+
});
|
|
57
63
|
},
|
|
58
64
|
fetchWorkspace: async (endpoint) => {
|
|
59
65
|
const response = await fetch(endpoint);
|
|
@@ -121,7 +127,11 @@ export const zustand = createStore()(subscribeWithSelector(immer((set, get) => (
|
|
|
121
127
|
set((state) => {
|
|
122
128
|
var _a, _b, _c;
|
|
123
129
|
const flowLang = flow.definition.language;
|
|
124
|
-
|
|
130
|
+
// Clone to ensure mutable for sorting
|
|
131
|
+
state.flowDefinition = {
|
|
132
|
+
...flow.definition,
|
|
133
|
+
nodes: [...(flow.definition.nodes || [])]
|
|
134
|
+
};
|
|
125
135
|
state.flowInfo = flow.info;
|
|
126
136
|
// Reset to the flow's default language when loading a new flow
|
|
127
137
|
state.languageCode = flowLang;
|