@opengeni/react 3.3.2 → 3.4.1-canary.38960406141001
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/README.md +769 -22
- package/dist/accounts.js +2 -0
- package/dist/accounts.js.map +1 -1
- package/dist/approvals.d.ts +2 -1
- package/dist/artifacts-document.js +5 -3
- package/dist/artifacts-presentation.js +5 -3
- package/dist/artifacts-spreadsheet.d.ts +1 -1
- package/dist/artifacts-spreadsheet.js +5 -3
- package/dist/artifacts.d.ts +5 -1
- package/dist/artifacts.js +536 -42
- package/dist/artifacts.js.map +1 -1
- package/dist/browser-viewer-ZWR6MWJ7.js +19 -0
- package/dist/capability-catalog-row.d.ts +20 -0
- package/dist/capability-logo-fallback.d.ts +3 -0
- package/dist/chat-interactive-block-4EUKJXUO.js +14 -0
- package/dist/chunk-2DDJ6YH6.js +41 -0
- package/dist/chunk-2DDJ6YH6.js.map +1 -0
- package/dist/chunk-2HVLQ26H.js +183 -0
- package/dist/chunk-2HVLQ26H.js.map +1 -0
- package/dist/{chunk-XYRDDSXF.js → chunk-2I6R3GCZ.js} +4285 -3980
- package/dist/chunk-2I6R3GCZ.js.map +1 -0
- package/dist/{chunk-JAQ5K7W6.js → chunk-2SFFYIH3.js} +1178 -166
- package/dist/chunk-2SFFYIH3.js.map +1 -0
- package/dist/chunk-3PVDYTTB.js +24 -0
- package/dist/chunk-3PVDYTTB.js.map +1 -0
- package/dist/chunk-3RJKUVCA.js +14068 -0
- package/dist/chunk-3RJKUVCA.js.map +1 -0
- package/dist/chunk-3UZCWK46.js +298 -0
- package/dist/chunk-3UZCWK46.js.map +1 -0
- package/dist/chunk-47CKUXTW.js +293 -0
- package/dist/chunk-47CKUXTW.js.map +1 -0
- package/dist/chunk-4QYP6QUI.js +109 -0
- package/dist/chunk-4QYP6QUI.js.map +1 -0
- package/dist/chunk-5EY26VZ7.js +1053 -0
- package/dist/chunk-5EY26VZ7.js.map +1 -0
- package/dist/chunk-5I4VRWBB.js +56 -0
- package/dist/chunk-5I4VRWBB.js.map +1 -0
- package/dist/chunk-5WOR7UCL.js +191 -0
- package/dist/chunk-5WOR7UCL.js.map +1 -0
- package/dist/chunk-5YJLGOM5.js +51 -0
- package/dist/chunk-5YJLGOM5.js.map +1 -0
- package/dist/chunk-6JFN3OWG.js +386 -0
- package/dist/chunk-6JFN3OWG.js.map +1 -0
- package/dist/chunk-7QJT5O4S.js +35 -0
- package/dist/chunk-7QJT5O4S.js.map +1 -0
- package/dist/chunk-A55KV72M.js +402 -0
- package/dist/chunk-A55KV72M.js.map +1 -0
- package/dist/chunk-ADWCLI4G.js +2028 -0
- package/dist/chunk-ADWCLI4G.js.map +1 -0
- package/dist/chunk-B27E3V37.js +29 -0
- package/dist/chunk-B27E3V37.js.map +1 -0
- package/dist/chunk-B7TC2A33.js +83 -0
- package/dist/chunk-B7TC2A33.js.map +1 -0
- package/dist/chunk-BLL56F7R.js +385 -0
- package/dist/chunk-BLL56F7R.js.map +1 -0
- package/dist/chunk-BOFEQC6K.js +162 -0
- package/dist/chunk-BOFEQC6K.js.map +1 -0
- package/dist/chunk-CM7LVUKC.js +35 -0
- package/dist/chunk-CM7LVUKC.js.map +1 -0
- package/dist/chunk-CORUP6JB.js +122 -0
- package/dist/chunk-CORUP6JB.js.map +1 -0
- package/dist/chunk-CSX5FFKZ.js +35 -0
- package/dist/chunk-CSX5FFKZ.js.map +1 -0
- package/dist/chunk-EGVHJKGJ.js +3125 -0
- package/dist/chunk-EGVHJKGJ.js.map +1 -0
- package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
- package/dist/chunk-G76LSA76.js.map +1 -0
- package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
- package/dist/chunk-GQMRL52F.js.map +1 -0
- package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
- package/dist/chunk-GUUXOISA.js.map +1 -0
- package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
- package/dist/chunk-I7X2P4FU.js.map +1 -0
- package/dist/chunk-IGFZFLI2.js +1390 -0
- package/dist/chunk-IGFZFLI2.js.map +1 -0
- package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
- package/dist/chunk-IMSUVYQB.js.map +1 -0
- package/dist/chunk-IOYHDEP3.js +38 -0
- package/dist/chunk-IOYHDEP3.js.map +1 -0
- package/dist/chunk-IZV5FTJC.js +55 -0
- package/dist/chunk-IZV5FTJC.js.map +1 -0
- package/dist/chunk-KF33GTWN.js +343 -0
- package/dist/chunk-KF33GTWN.js.map +1 -0
- package/dist/chunk-KSGQ5ODA.js +457 -0
- package/dist/chunk-KSGQ5ODA.js.map +1 -0
- package/dist/{chunk-ZPBTI3TE.js → chunk-KZC6QRNR.js} +1513 -697
- package/dist/chunk-KZC6QRNR.js.map +1 -0
- package/dist/chunk-LJUMYUBO.js +218 -0
- package/dist/chunk-LJUMYUBO.js.map +1 -0
- package/dist/chunk-LSW2OJVV.js +380 -0
- package/dist/chunk-LSW2OJVV.js.map +1 -0
- package/dist/chunk-M357MHH3.js +2 -0
- package/dist/chunk-M357MHH3.js.map +1 -0
- package/dist/chunk-MK2TQO4Y.js +24 -0
- package/dist/chunk-MK2TQO4Y.js.map +1 -0
- package/dist/chunk-N7S72EXK.js +25 -0
- package/dist/chunk-N7S72EXK.js.map +1 -0
- package/dist/{chunk-YVCHAQZY.js → chunk-NKMYZFHA.js} +616 -621
- package/dist/chunk-NKMYZFHA.js.map +1 -0
- package/dist/chunk-NX4ADH73.js +14 -0
- package/dist/chunk-NX4ADH73.js.map +1 -0
- package/dist/chunk-O7F6UJO4.js +71 -0
- package/dist/chunk-O7F6UJO4.js.map +1 -0
- package/dist/chunk-OYQQJL3J.js +16 -0
- package/dist/chunk-OYQQJL3J.js.map +1 -0
- package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
- package/dist/chunk-P4BNUO57.js.map +1 -0
- package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
- package/dist/chunk-PEHTX3V7.js.map +1 -0
- package/dist/chunk-PMV53IMM.js +26 -0
- package/dist/chunk-PMV53IMM.js.map +1 -0
- package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
- package/dist/chunk-PYEOPA4M.js.map +1 -0
- package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
- package/dist/chunk-QHUE7E4N.js.map +1 -0
- package/dist/chunk-QV3DJVRZ.js +11 -0
- package/dist/chunk-QV3DJVRZ.js.map +1 -0
- package/dist/chunk-R5SBNG7S.js +810 -0
- package/dist/chunk-R5SBNG7S.js.map +1 -0
- package/dist/chunk-RI42H5IU.js +326 -0
- package/dist/chunk-RI42H5IU.js.map +1 -0
- package/dist/chunk-S2QH6EZ5.js +211 -0
- package/dist/chunk-S2QH6EZ5.js.map +1 -0
- package/dist/chunk-SHLZMAJN.js +304 -0
- package/dist/chunk-SHLZMAJN.js.map +1 -0
- package/dist/chunk-TGXK4BAZ.js +293 -0
- package/dist/chunk-TGXK4BAZ.js.map +1 -0
- package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
- package/dist/chunk-TNEZNMSN.js.map +1 -0
- package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
- package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
- package/dist/chunk-UNJPZGNK.js +63 -0
- package/dist/chunk-UNJPZGNK.js.map +1 -0
- package/dist/{chunk-IOLVN74D.js → chunk-V5ZUJT2T.js} +175 -42
- package/dist/chunk-V5ZUJT2T.js.map +1 -0
- package/dist/chunk-WBJY57A3.js +402 -0
- package/dist/chunk-WBJY57A3.js.map +1 -0
- package/dist/chunk-WIUKB3LD.js +1911 -0
- package/dist/chunk-WIUKB3LD.js.map +1 -0
- package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
- package/dist/chunk-WNN7NO2N.js.map +1 -0
- package/dist/{chunk-3AGBGTRT.js → chunk-X5UVUIMF.js} +1712 -1174
- package/dist/chunk-X5UVUIMF.js.map +1 -0
- package/dist/chunk-XDA5QJE7.js +402 -0
- package/dist/chunk-XDA5QJE7.js.map +1 -0
- package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
- package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
- package/dist/chunk-XHF7OYAN.js +1150 -0
- package/dist/chunk-XHF7OYAN.js.map +1 -0
- package/dist/chunk-YSRBFJMQ.js +43 -0
- package/dist/chunk-YSRBFJMQ.js.map +1 -0
- package/dist/chunk-ZOZAPAUO.js +174 -0
- package/dist/chunk-ZOZAPAUO.js.map +1 -0
- package/dist/chunk-ZQV5W7YC.js +809 -0
- package/dist/chunk-ZQV5W7YC.js.map +1 -0
- package/dist/chunk-ZUWF4NF7.js +13 -0
- package/dist/chunk-ZUWF4NF7.js.map +1 -0
- package/dist/client.d.ts +16 -7
- package/dist/clipboard.js +3 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/anthropic-mark.d.ts +3 -0
- package/dist/components/approval-surface.d.ts +19 -6
- package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
- package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
- package/dist/components/artifacts/artifact-surface.d.ts +4 -2
- package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
- package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
- package/dist/components/artifacts/document-editor.d.ts +4 -2
- package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
- package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
- package/dist/components/artifacts/editable-document.d.ts +1 -1
- package/dist/components/artifacts/editable-presentation.d.ts +2 -2
- package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
- package/dist/components/artifacts/index.d.ts +9 -2
- package/dist/components/artifacts/inline-html-document.d.ts +2 -0
- package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
- package/dist/components/artifacts/presentation-editor.d.ts +6 -2
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
- package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
- package/dist/components/artifacts/site-view.d.ts +26 -0
- package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
- package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
- package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
- package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
- package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
- package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
- package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
- package/dist/components/browser-select-control.d.ts +16 -0
- package/dist/components/browser-viewer.d.ts +11 -2
- package/dist/components/chat-composer.d.ts +21 -3
- package/dist/components/child-session-link.d.ts +9 -0
- package/dist/components/claude-mark.d.ts +3 -0
- package/dist/components/code-editor.d.ts +1 -4
- package/dist/components/composer-transcription-control.d.ts +7 -0
- package/dist/components/composer.d.ts +34 -67
- package/dist/components/computer-viewer.d.ts +1 -1
- package/dist/components/copy-button.d.ts +3 -1
- package/dist/components/desktop-viewer.d.ts +1 -1
- package/dist/components/grok-mark.d.ts +26 -0
- package/dist/components/human-input-form.d.ts +28 -32
- package/dist/components/human-input-surface.d.ts +7 -2
- package/dist/components/linkified-text.d.ts +18 -0
- package/dist/components/machine-input-display.d.ts +22 -1
- package/dist/components/machines/agent-status-icon.d.ts +6 -0
- package/dist/components/machines/machine-detail.d.ts +7 -1
- package/dist/components/machines/machine-status.d.ts +48 -0
- package/dist/components/markdown-table-layout.d.ts +18 -0
- package/dist/components/markdown.d.ts +37 -4
- package/dist/components/message-timeline.d.ts +86 -7
- package/dist/components/model-mark.d.ts +29 -0
- package/dist/components/model-policy-picker-menu.d.ts +9 -0
- package/dist/components/model-policy-picker.d.ts +35 -28
- package/dist/components/new-conversation.d.ts +32 -0
- package/dist/components/open-geni-chat.d.ts +73 -0
- package/dist/components/open-geni-links.d.ts +68 -0
- package/dist/components/openrouter-mark.d.ts +6 -0
- package/dist/components/opper-mark.d.ts +7 -0
- package/dist/components/preview-loading.d.ts +2 -0
- package/dist/components/provider-recovery-notice.d.ts +16 -0
- package/dist/components/queue-item-content.d.ts +9 -0
- package/dist/components/rehype-secret-refs.d.ts +23 -0
- package/dist/components/remark-soft-line-breaks.d.ts +38 -0
- package/dist/components/sandbox-files.d.ts +3 -1
- package/dist/components/sandbox-workspace.d.ts +18 -0
- package/dist/components/secret-question-field.d.ts +31 -0
- package/dist/components/secret-ref-chip.d.ts +35 -0
- package/dist/components/session-capability-frame.d.ts +37 -0
- package/dist/components/session-chrome.d.ts +57 -8
- package/dist/components/session-commands-panel.d.ts +6 -0
- package/dist/components/session-commands.d.ts +6 -0
- package/dist/components/session-connection-request.d.ts +8 -0
- package/dist/components/session-conversation.d.ts +157 -0
- package/dist/components/session-list.d.ts +39 -0
- package/dist/components/session-mcp-capability-card.d.ts +41 -0
- package/dist/components/session-proxy-scope.d.ts +35 -0
- package/dist/components/session-status.d.ts +4 -1
- package/dist/components/session-usage-limit-notice.d.ts +39 -0
- package/dist/components/timeline-anchor.d.ts +24 -0
- package/dist/components/timeline-annotation-chrome.d.ts +25 -0
- package/dist/components/timeline-annotation-layout.d.ts +42 -0
- package/dist/components/timeline-annotation-markers.d.ts +8 -0
- package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
- package/dist/components/timeline-annotation-shared.d.ts +31 -0
- package/dist/components/timeline-annotations-dialog.d.ts +3 -2
- package/dist/components/timeline-annotations.d.ts +13 -3
- package/dist/components/timeline-reading-progress.d.ts +11 -0
- package/dist/components/timeline-search.d.ts +34 -0
- package/dist/components/timeline-settlement.d.ts +16 -0
- package/dist/components/tool-action-review.d.ts +47 -0
- package/dist/components/tool-review-history.d.ts +25 -0
- package/dist/components/usage-limit-notice.d.ts +49 -0
- package/dist/components/usage-member-list.d.ts +91 -0
- package/dist/components/usage-meter.d.ts +73 -0
- package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
- package/dist/components/user-message-body.d.ts +10 -1
- package/dist/composer-messages.d.ts +74 -0
- package/dist/composer-messages.js +9 -0
- package/dist/composer-messages.js.map +1 -0
- package/dist/composer-voice-events.d.ts +8 -0
- package/dist/composer.d.ts +5 -4
- package/dist/composer.js +26 -13
- package/dist/computer-viewer-GMLDXPON.js +20 -0
- package/dist/computer-viewer-GMLDXPON.js.map +1 -0
- package/dist/connect-account-identity.d.ts +8 -0
- package/dist/connect-accounts.d.ts +15 -0
- package/dist/connect-chooser.d.ts +18 -0
- package/dist/connect-panel.d.ts +18 -0
- package/dist/connect-setup.d.ts +18 -0
- package/dist/connect.d.ts +21 -0
- package/dist/connect.js +2149 -0
- package/dist/connect.js.map +1 -0
- package/dist/connection-catalog.d.ts +38 -0
- package/dist/connection-discovery.d.ts +12 -0
- package/dist/connection-installed.d.ts +17 -0
- package/dist/connection-logo.d.ts +9 -0
- package/dist/connection-service-logo.d.ts +8 -0
- package/dist/connection-service-presentation.d.ts +13 -0
- package/dist/connection-skeleton.d.ts +5 -0
- package/dist/connection-type-picker.d.ts +6 -0
- package/dist/conversation-timeline.d.ts +5 -0
- package/dist/desktop.d.ts +7 -0
- package/dist/desktop.js +27 -0
- package/dist/desktop.js.map +1 -0
- package/dist/device-authorization.d.ts +23 -0
- package/dist/diffs.d.ts +8 -0
- package/dist/diffs.js +15 -0
- package/dist/diffs.js.map +1 -0
- package/dist/discovery-cache.d.ts +5 -0
- package/dist/editor.d.ts +7 -0
- package/dist/editor.js +22 -0
- package/dist/editor.js.map +1 -0
- package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
- package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
- package/dist/embedded-voice-RPHPYVBT.js +18 -0
- package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
- package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
- package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
- package/dist/hooks/latest-question.d.ts +25 -0
- package/dist/hooks/shared-machines-list.d.ts +4 -0
- package/dist/hooks/shared-query.d.ts +113 -0
- package/dist/hooks/use-attached-browsers.d.ts +1 -1
- package/dist/hooks/use-auth-runs.d.ts +1 -4
- package/dist/hooks/use-available-models.d.ts +1 -1
- package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
- package/dist/hooks/use-browser-session.d.ts +12 -1
- package/dist/hooks/use-client-config-flags.d.ts +49 -0
- package/dist/hooks/use-codex-accounts.d.ts +59 -10
- package/dist/hooks/use-composer.d.ts +24 -2
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-input-posture.d.ts +13 -0
- package/dist/hooks/use-computer-session.d.ts +4 -0
- package/dist/hooks/use-connect.d.ts +23 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-file-attachments.d.ts +12 -0
- package/dist/hooks/use-goal.d.ts +2 -1
- package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
- package/dist/hooks/use-new-conversation.d.ts +56 -0
- package/dist/hooks/use-new-session-draft.d.ts +74 -0
- package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
- package/dist/hooks/use-sandbox-files.d.ts +4 -1
- package/dist/hooks/use-session-conversation.d.ts +49 -0
- package/dist/hooks/use-session-events.d.ts +26 -5
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
- package/dist/hooks/use-session-model-account.d.ts +48 -0
- package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
- package/dist/hooks/use-terminal-stream.d.ts +11 -5
- package/dist/hooks/use-usage.d.ts +40 -0
- package/dist/hooks/use-vaults.d.ts +53 -0
- package/dist/hooks/use-voice-input.d.ts +8 -1
- package/dist/hooks/use-workspace-edit.d.ts +4 -0
- package/dist/hooks/use-workspace-sessions.d.ts +24 -5
- package/dist/human-input-model.d.ts +122 -0
- package/dist/identity-link-accounts.d.ts +11 -0
- package/dist/identity-link-consent.d.ts +18 -0
- package/dist/index.d.ts +82 -20
- package/dist/index.js +2340 -6603
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +1 -1
- package/dist/interaction.js +14 -24
- package/dist/interaction.js.map +1 -1
- package/dist/latest-question-R77KWSUP.js +118 -0
- package/dist/latest-question-R77KWSUP.js.map +1 -0
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/error-message.d.ts +7 -0
- package/dist/lib/format.d.ts +58 -4
- package/dist/lib/host-theme.d.ts +77 -0
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/lib/menu-styles.d.ts +22 -0
- package/dist/lib/notify-observer.d.ts +2 -0
- package/dist/lib/pierre-diffs-loader.d.ts +20 -0
- package/dist/lib/provider-recovery.d.ts +55 -0
- package/dist/lib/scrollbars.d.ts +11 -0
- package/dist/lib/terminal-input-readiness.d.ts +11 -0
- package/dist/lib/transient-retry.d.ts +25 -0
- package/dist/lib/workbench-peers.d.ts +36 -0
- package/dist/lib/xterm-theme.d.ts +7 -5
- package/dist/machines.js +9 -5
- package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
- package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
- package/dist/mcp-connection-status.d.ts +14 -0
- package/dist/model-mark-paths.d.ts +34 -0
- package/dist/model-mark-paths.js +16 -0
- package/dist/model-mark-paths.js.map +1 -0
- package/dist/model-picker-model.d.ts +111 -0
- package/dist/model-picker-model.js +25 -0
- package/dist/model-picker-model.js.map +1 -0
- package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
- package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
- package/dist/model-policy.d.ts +30 -3
- package/dist/model-policy.js +14 -1
- package/dist/native-previews.d.ts +28 -0
- package/dist/native-previews.js +82 -0
- package/dist/native-previews.js.map +1 -0
- package/dist/new-session-draft.d.ts +7 -0
- package/dist/new-session-draft.js +639 -0
- package/dist/new-session-draft.js.map +1 -0
- package/dist/notification-text.d.ts +27 -0
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
- package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
- package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
- package/dist/older-history.d.ts +3 -2
- package/dist/organization-model.d.ts +32 -0
- package/dist/organization-model.js +65 -0
- package/dist/organization-model.js.map +1 -0
- package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
- package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
- package/dist/plugin-details.d.ts +14 -0
- package/dist/plugin-discovery.d.ts +25 -0
- package/dist/preview-loading-paint.d.ts +20 -0
- package/dist/provider.d.ts +25 -2
- package/dist/queue-presentation-model.d.ts +72 -0
- package/dist/queue-presentation-model.js +38 -0
- package/dist/queue-presentation-model.js.map +1 -0
- package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
- package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
- package/dist/realtime/embedded-new-voice.d.ts +1 -0
- package/dist/realtime/embedded-voice.d.ts +1 -0
- package/dist/realtime/realtime-control.d.ts +4 -65
- package/dist/realtime/session-realtime.d.ts +78 -0
- package/dist/realtime.js +25 -1333
- package/dist/realtime.js.map +1 -1
- package/dist/sandbox-files-O27IPOZW.js +21 -0
- package/dist/sandbox-files-O27IPOZW.js.map +1 -0
- package/dist/sandbox-label-model.d.ts +30 -0
- package/dist/sandbox-label-model.js +20 -0
- package/dist/sandbox-label-model.js.map +1 -0
- package/dist/scrollbars.d.ts +1 -0
- package/dist/scrollbars.js +10 -0
- package/dist/scrollbars.js.map +1 -0
- package/dist/secret-reference-label.d.ts +14 -0
- package/dist/secrets-ui.d.ts +57 -0
- package/dist/session-agents-model.d.ts +10 -0
- package/dist/session-agents-model.js +25 -0
- package/dist/session-agents-model.js.map +1 -0
- package/dist/session-attention-model.d.ts +8 -0
- package/dist/session-attention-model.js +47 -0
- package/dist/session-attention-model.js.map +1 -0
- package/dist/session-auth-recommendation.d.ts +5 -0
- package/dist/session-capability-policy.d.ts +31 -0
- package/dist/session-feedback-model.d.ts +20 -0
- package/dist/session-feedback-model.js +56 -0
- package/dist/session-feedback-model.js.map +1 -0
- package/dist/session-list-model.d.ts +138 -0
- package/dist/session-list-model.js +274 -0
- package/dist/session-list-model.js.map +1 -0
- package/dist/session-realtime-7DJOIHQW.js +21 -0
- package/dist/session-realtime-7DJOIHQW.js.map +1 -0
- package/dist/session-realtime.d.ts +7 -0
- package/dist/session-realtime.js +19 -0
- package/dist/session-realtime.js.map +1 -0
- package/dist/session-status-model.d.ts +36 -0
- package/dist/session-ui.d.ts +39 -1
- package/dist/session-ui.js +126 -12
- package/dist/session-ui.js.map +1 -1
- package/dist/session.d.ts +8 -2
- package/dist/session.js +35 -20
- package/dist/site-snapshot.d.ts +14 -0
- package/dist/sites-ui.d.ts +24 -0
- package/dist/sites.d.ts +3 -0
- package/dist/sites.js +14 -0
- package/dist/sites.js.map +1 -0
- package/dist/skill-discovery.d.ts +47 -0
- package/dist/terminal.d.ts +8 -0
- package/dist/terminal.js +32 -0
- package/dist/terminal.js.map +1 -0
- package/dist/testing/session-scenarios.d.ts +10 -0
- package/dist/testing/session-scenarios.js +367 -0
- package/dist/testing/session-scenarios.js.map +1 -0
- package/dist/timeline/activity-rail.d.ts +11 -2
- package/dist/timeline/agent-identity.d.ts +30 -0
- package/dist/timeline/agent-row.d.ts +31 -0
- package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
- package/dist/timeline/compaction-copy.d.ts +46 -0
- package/dist/timeline/focus-sequence.d.ts +9 -0
- package/dist/timeline/genie-copy.d.ts +3 -0
- package/dist/timeline/genie-loading.d.ts +47 -0
- package/dist/timeline/index.d.ts +10 -5
- package/dist/timeline/knowledge-receipt.d.ts +17 -0
- package/dist/timeline/message-sender.d.ts +19 -0
- package/dist/timeline/notice-presentation.d.ts +13 -0
- package/dist/timeline/parsers.d.ts +11 -0
- package/dist/timeline/patch-apply-command.d.ts +18 -0
- package/dist/timeline/platform-activity-presentation.d.ts +21 -0
- package/dist/timeline/platform-activity-row.d.ts +1 -2
- package/dist/timeline/presented-image.d.ts +11 -0
- package/dist/timeline/projection.d.ts +31 -2
- package/dist/timeline/provider-logo.d.ts +15 -0
- package/dist/timeline/question-nav-model.d.ts +23 -0
- package/dist/timeline/registry.d.ts +12 -1
- package/dist/timeline/retained-image.d.ts +18 -0
- package/dist/timeline/retained-loaders.d.ts +27 -0
- package/dist/timeline/rolling-activity.d.ts +11 -0
- package/dist/timeline/screenshot-lightbox.d.ts +23 -1
- package/dist/timeline/session-usage-limit-row.d.ts +11 -0
- package/dist/timeline/shared.d.ts +4 -1
- package/dist/timeline/startup-dispatch-details.d.ts +5 -0
- package/dist/timeline/startup-preference.d.ts +3 -0
- package/dist/timeline/startup-timings.d.ts +4 -0
- package/dist/timeline/tool-display-name.d.ts +5 -2
- package/dist/timeline/tool-presentation.d.ts +172 -0
- package/dist/timeline/turn-summary-model.d.ts +95 -0
- package/dist/timeline/turn-summary.d.ts +20 -54
- package/dist/timeline/types.d.ts +179 -7
- package/dist/timeline/work-presentation.d.ts +60 -0
- package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
- package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
- package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
- package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
- package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
- package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
- package/dist/timeline-model.d.ts +29 -0
- package/dist/timeline-model.js +254 -0
- package/dist/timeline-model.js.map +1 -0
- package/dist/usage/allowance-copy.d.ts +25 -0
- package/dist/usage/session-usage-limit.d.ts +88 -0
- package/dist/usage/summary.d.ts +35 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +1187 -0
- package/dist/usage.js.map +1 -0
- package/dist/voice-recording-owner.d.ts +7 -0
- package/package.json +106 -7
- package/src/approvals.ts +8 -1
- package/src/artifacts-spreadsheet.ts +1 -0
- package/src/artifacts.ts +44 -0
- package/src/assets/README.md +8 -0
- package/src/assets/gmail.ico +0 -0
- package/src/assets/outlook.ico +0 -0
- package/src/capability-catalog-row.tsx +94 -0
- package/src/capability-logo-fallback.ts +22 -0
- package/src/client.ts +20 -31
- package/src/commands/registry.ts +18 -15
- package/src/commands/types.ts +2 -0
- package/src/components/anthropic-mark.tsx +10 -0
- package/src/components/approval-surface.tsx +401 -138
- package/src/components/artifacts/artifact-chrome.tsx +413 -0
- package/src/components/artifacts/artifact-sandbox.tsx +193 -0
- package/src/components/artifacts/artifact-surface.tsx +40 -20
- package/src/components/artifacts/chat-interactive-block.tsx +260 -0
- package/src/components/artifacts/deferred-chat-media.tsx +67 -0
- package/src/components/artifacts/document-editor.tsx +141 -16
- package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
- package/src/components/artifacts/editable-artifact-view.tsx +197 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
- package/src/components/artifacts/editable-document.tsx +37 -36
- package/src/components/artifacts/editable-presentation.tsx +36 -18
- package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
- package/src/components/artifacts/index.ts +45 -0
- package/src/components/artifacts/inline-html-document.ts +24 -0
- package/src/components/artifacts/latest-task-runner.ts +49 -0
- package/src/components/artifacts/presentation-editor.tsx +323 -67
- package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
- package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
- package/src/components/artifacts/site-view.tsx +121 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
- package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
- package/src/components/artifacts/spreadsheet-download.tsx +109 -0
- package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
- package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
- package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
- package/src/components/artifacts/visualization-assets/base.css +1015 -0
- package/src/components/artifacts/visualization-assets/helpers.html +349 -0
- package/src/components/artifacts/visualization-assets.gen.ts +3 -0
- package/src/components/browser-select-control.tsx +312 -0
- package/src/components/browser-viewer.tsx +778 -318
- package/src/components/chat-composer.tsx +47 -5
- package/src/components/child-session-link.tsx +36 -0
- package/src/components/claude-mark.tsx +11 -0
- package/src/components/code-editor.tsx +13 -16
- package/src/components/composer-transcription-control.tsx +128 -30
- package/src/components/composer.tsx +404 -195
- package/src/components/computer-viewer.tsx +880 -253
- package/src/components/copy-button.tsx +13 -5
- package/src/components/desktop-viewer.tsx +1 -1
- package/src/components/enrollment-consent.tsx +1 -1
- package/src/components/enrollment-device-flow.tsx +1 -1
- package/src/components/file-browser.tsx +10 -14
- package/src/components/fleet-tile.tsx +5 -3
- package/src/components/generated-video-player.tsx +4 -2
- package/src/components/grok-mark.tsx +34 -0
- package/src/components/human-input-form.tsx +590 -283
- package/src/components/human-input-surface.tsx +11 -0
- package/src/components/interaction-intervention-banner.tsx +2 -2
- package/src/components/linkified-text.tsx +79 -0
- package/src/components/machine-card.tsx +35 -78
- package/src/components/machine-dock-bar.tsx +1 -1
- package/src/components/machine-input-display.ts +197 -3
- package/src/components/machines/agent-status-icon.tsx +31 -0
- package/src/components/machines/machine-detail.tsx +200 -31
- package/src/components/machines/machine-operation-policy.tsx +1 -1
- package/src/components/machines/machine-status.ts +241 -0
- package/src/components/machines-dashboard.tsx +2 -17
- package/src/components/markdown-table-layout.ts +143 -0
- package/src/components/markdown.tsx +466 -129
- package/src/components/message-timeline.tsx +2370 -667
- package/src/components/model-mark.tsx +102 -0
- package/src/components/model-picker.tsx +15 -4
- package/src/components/model-policy-picker-menu.tsx +371 -0
- package/src/components/model-policy-picker.tsx +252 -429
- package/src/components/new-conversation.tsx +221 -0
- package/src/components/open-geni-chat.tsx +309 -0
- package/src/components/open-geni-links.tsx +179 -0
- package/src/components/openrouter-mark.tsx +13 -0
- package/src/components/opper-mark.tsx +18 -0
- package/src/components/pierre-diff.tsx +41 -16
- package/src/components/pierre-file.tsx +35 -10
- package/src/components/preview-loading.tsx +109 -0
- package/src/components/provider-recovery-notice.tsx +49 -0
- package/src/components/queue-item-content.ts +14 -0
- package/src/components/queue-surface-implementation.tsx +51 -356
- package/src/components/queue-surface-state.tsx +3 -1
- package/src/components/rehype-secret-refs.ts +98 -0
- package/src/components/remark-soft-line-breaks.ts +166 -0
- package/src/components/sandbox-files.tsx +91 -15
- package/src/components/sandbox-terminal.tsx +84 -13
- package/src/components/sandbox-workspace.tsx +147 -51
- package/src/components/secret-question-field.tsx +324 -0
- package/src/components/secret-ref-chip.tsx +185 -0
- package/src/components/session-capability-frame.tsx +197 -0
- package/src/components/session-chrome.tsx +842 -251
- package/src/components/session-commands-panel.tsx +126 -0
- package/src/components/session-commands.tsx +18 -0
- package/src/components/session-connection-request.tsx +97 -0
- package/src/components/session-conversation.tsx +876 -0
- package/src/components/session-list.tsx +257 -0
- package/src/components/session-mcp-capability-card.tsx +680 -0
- package/src/components/session-proxy-scope.tsx +153 -0
- package/src/components/session-status.tsx +26 -17
- package/src/components/session-usage-limit-notice.tsx +174 -0
- package/src/components/timeline-anchor.tsx +119 -0
- package/src/components/timeline-annotation-chrome.tsx +196 -0
- package/src/components/timeline-annotation-layout.ts +268 -0
- package/src/components/timeline-annotation-markers.tsx +185 -0
- package/src/components/timeline-annotation-reveal-context.ts +9 -0
- package/src/components/timeline-annotation-selection.tsx +106 -54
- package/src/components/timeline-annotation-shared.ts +245 -0
- package/src/components/timeline-annotations-dialog.tsx +185 -128
- package/src/components/timeline-annotations.tsx +189 -45
- package/src/components/timeline-reading-progress.ts +80 -0
- package/src/components/timeline-search.tsx +168 -0
- package/src/components/timeline-settlement.ts +60 -0
- package/src/components/tool-action-review.tsx +650 -0
- package/src/components/tool-review-history.tsx +88 -0
- package/src/components/usage-limit-notice.tsx +179 -0
- package/src/components/usage-member-list.tsx +792 -0
- package/src/components/usage-meter.tsx +382 -0
- package/src/components/use-viewer-menu-dismiss.ts +33 -0
- package/src/components/user-message-body.tsx +27 -2
- package/src/components/workspace-dock.tsx +18 -1
- package/src/composer-messages.ts +150 -0
- package/src/composer-voice-events.ts +12 -0
- package/src/composer.ts +6 -1
- package/src/connect-account-identity.tsx +34 -0
- package/src/connect-accounts.tsx +233 -0
- package/src/connect-chooser.tsx +336 -0
- package/src/connect-panel.tsx +99 -0
- package/src/connect-setup.tsx +355 -0
- package/src/connect.ts +60 -0
- package/src/connection-assets.d.ts +4 -0
- package/src/connection-catalog.tsx +162 -0
- package/src/connection-discovery.tsx +238 -0
- package/src/connection-installed.tsx +51 -0
- package/src/connection-logo.tsx +37 -0
- package/src/connection-service-logo.tsx +55 -0
- package/src/connection-service-presentation.ts +46 -0
- package/src/connection-skeleton.tsx +16 -0
- package/src/connection-type-picker.tsx +36 -0
- package/src/conversation-timeline.ts +92 -0
- package/src/desktop.ts +24 -0
- package/src/device-authorization.tsx +98 -0
- package/src/diffs.ts +16 -0
- package/src/discovery-cache.ts +42 -0
- package/src/editor.ts +13 -0
- package/src/hooks/internal.ts +3 -2
- package/src/hooks/latest-question.ts +164 -0
- package/src/hooks/shared-machines-list.ts +34 -1
- package/src/hooks/shared-query.ts +721 -0
- package/src/hooks/use-attached-browsers.ts +1 -1
- package/src/hooks/use-auth-runs.ts +0 -27
- package/src/hooks/use-available-models.ts +2 -2
- package/src/hooks/use-browser-frame-stream.ts +19 -2
- package/src/hooks/use-browser-session.ts +680 -205
- package/src/hooks/use-browser-sessions.ts +32 -1
- package/src/hooks/use-client-config-flags.ts +118 -0
- package/src/hooks/use-codex-accounts.ts +247 -47
- package/src/hooks/use-composer.ts +227 -44
- package/src/hooks/use-computer-frame-stream.ts +25 -7
- package/src/hooks/use-computer-input-posture.ts +94 -0
- package/src/hooks/use-computer-session.ts +409 -95
- package/src/hooks/use-connect.ts +23 -0
- package/src/hooks/use-desktop-stream.ts +19 -28
- package/src/hooks/use-file-attachments.ts +80 -4
- package/src/hooks/use-goal.ts +79 -9
- package/src/hooks/use-last-started-turn-policy.ts +37 -11
- package/src/hooks/use-machines.ts +4 -0
- package/src/hooks/use-new-conversation.ts +374 -0
- package/src/hooks/use-new-session-draft.ts +813 -0
- package/src/hooks/use-realtime-voice-models.ts +46 -0
- package/src/hooks/use-sandbox-files.ts +68 -20
- package/src/hooks/use-session-background-commands.ts +22 -11
- package/src/hooks/use-session-capabilities.ts +3 -2
- package/src/hooks/use-session-conversation.ts +150 -0
- package/src/hooks/use-session-events.ts +531 -335
- package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
- package/src/hooks/use-session-model-account.ts +174 -0
- package/src/hooks/use-session.ts +30 -2
- package/src/hooks/use-slash-commands.ts +6 -11
- package/src/hooks/use-supergrok-accounts.ts +22 -8
- package/src/hooks/use-terminal-stream.ts +153 -27
- package/src/hooks/use-transcription.ts +6 -0
- package/src/hooks/use-turn-queue.ts +2 -1
- package/src/hooks/use-usage.ts +100 -0
- package/src/hooks/use-vaults.ts +153 -0
- package/src/hooks/use-video-artifact-playback.ts +1 -1
- package/src/hooks/use-voice-input.ts +127 -19
- package/src/hooks/use-workspace-capture.ts +3 -2
- package/src/hooks/use-workspace-edit.ts +23 -5
- package/src/hooks/use-workspace-sessions.ts +74 -7
- package/src/human-input-model.ts +359 -0
- package/src/identity-link-accounts.tsx +148 -0
- package/src/identity-link-consent.tsx +192 -0
- package/src/index.ts +262 -16
- package/src/interaction.ts +1 -0
- package/src/lib/clipboard.ts +29 -0
- package/src/lib/error-message.ts +37 -0
- package/src/lib/format.ts +205 -10
- package/src/lib/host-theme.ts +529 -0
- package/src/lib/interaction-errors.ts +15 -0
- package/src/lib/menu-styles.ts +44 -0
- package/src/lib/notify-observer.ts +15 -0
- package/src/lib/pierre-diffs-loader.ts +53 -0
- package/src/lib/provider-recovery.ts +243 -0
- package/src/lib/scrollbars.ts +30 -0
- package/src/lib/terminal-input-readiness.ts +51 -0
- package/src/lib/transient-retry.ts +99 -0
- package/src/lib/workbench-peers.ts +62 -0
- package/src/lib/xterm-theme.ts +23 -21
- package/src/mcp-connection-status.ts +35 -0
- package/src/model-mark-paths.ts +53 -0
- package/src/model-picker-model.ts +330 -0
- package/src/model-policy.ts +299 -74
- package/src/native-previews.ts +100 -0
- package/src/new-session-draft.ts +22 -0
- package/src/notification-text.ts +81 -0
- package/src/older-history.ts +22 -4
- package/src/organization-model.ts +118 -0
- package/src/plugin-details.tsx +185 -0
- package/src/plugin-discovery.tsx +196 -0
- package/src/preview-loading-paint.ts +68 -0
- package/src/provider.tsx +74 -15
- package/src/queue-presentation-model.ts +464 -0
- package/src/realtime/dropdown-menu.tsx +19 -12
- package/src/realtime/embedded-new-voice.tsx +1 -0
- package/src/realtime/embedded-voice.tsx +3 -0
- package/src/realtime/realtime-control.tsx +138 -550
- package/src/realtime/session-realtime.ts +566 -0
- package/src/sandbox-label-model.ts +53 -0
- package/src/scrollbars.ts +3 -0
- package/src/secret-reference-label.ts +43 -0
- package/src/secrets-ui.tsx +59 -0
- package/src/session-agents-model.ts +33 -0
- package/src/session-attention-model.ts +62 -0
- package/src/session-auth-recommendation.ts +48 -0
- package/src/session-capability-policy.ts +196 -0
- package/src/session-context.ts +3 -4
- package/src/session-feedback-model.ts +95 -0
- package/src/session-list-model.ts +434 -0
- package/src/session-realtime.ts +18 -0
- package/src/session-status-model.ts +99 -0
- package/src/session-ui.ts +98 -1
- package/src/session.ts +17 -1
- package/src/site-snapshot.ts +74 -0
- package/src/sites-ui.tsx +348 -0
- package/src/sites.ts +3 -0
- package/src/skill-discovery.tsx +208 -0
- package/src/terminal.ts +26 -0
- package/src/testing/session-scenarios.ts +404 -0
- package/src/timeline/activity-rail.tsx +242 -101
- package/src/timeline/agent-identity.tsx +84 -0
- package/src/timeline/agent-row.tsx +231 -0
- package/src/timeline/allowance-exhausted-row.tsx +86 -0
- package/src/timeline/compaction-copy.ts +115 -0
- package/src/timeline/fleet-decision-projection.ts +2 -1
- package/src/timeline/fleet-decision-row.tsx +1 -0
- package/src/timeline/focus-sequence.ts +44 -0
- package/src/timeline/genie-copy.ts +19 -0
- package/src/timeline/genie-loading.tsx +143 -0
- package/src/timeline/index.ts +30 -2
- package/src/timeline/knowledge-receipt.tsx +100 -0
- package/src/timeline/message-sender.tsx +71 -0
- package/src/timeline/notice-presentation.ts +48 -0
- package/src/timeline/parsers.ts +42 -2
- package/src/timeline/patch-apply-command.tsx +135 -0
- package/src/timeline/platform-activity-presentation.ts +166 -0
- package/src/timeline/platform-activity-row.tsx +15 -90
- package/src/timeline/presented-image.ts +63 -0
- package/src/timeline/projection.ts +1742 -76
- package/src/timeline/provider-logo.tsx +53 -0
- package/src/timeline/question-nav-model.ts +28 -0
- package/src/timeline/registry.ts +26 -4
- package/src/timeline/retained-image.ts +97 -0
- package/src/timeline/retained-loaders.ts +91 -0
- package/src/timeline/rolling-activity.tsx +80 -0
- package/src/timeline/screenshot-lightbox.tsx +228 -5
- package/src/timeline/session-usage-limit-row.tsx +42 -0
- package/src/timeline/shared.tsx +42 -15
- package/src/timeline/startup-dispatch-details.tsx +36 -0
- package/src/timeline/startup-preference.ts +33 -0
- package/src/timeline/startup-timings.tsx +145 -0
- package/src/timeline/tool-display-name.ts +19 -7
- package/src/timeline/tool-presentation.ts +1316 -0
- package/src/timeline/tool-renderers.tsx +835 -1138
- package/src/timeline/turn-summary-model.ts +343 -0
- package/src/timeline/turn-summary.tsx +272 -365
- package/src/timeline/types.ts +189 -6
- package/src/timeline/work-presentation.ts +189 -0
- package/src/timeline-model.ts +143 -0
- package/src/usage/allowance-copy.ts +64 -0
- package/src/usage/session-usage-limit.ts +266 -0
- package/src/usage/summary.ts +93 -0
- package/src/usage.ts +70 -0
- package/src/voice-recording-owner.ts +22 -0
- package/styles/compiled.css +2319 -748
- package/styles/connect.css +290 -0
- package/styles/connect.d.ts +1 -0
- package/styles/effective-tokens.css +1 -0
- package/styles/index.css +309 -9
- package/styles/responsive.css +99 -7
- package/styles/session-capability.css +44 -0
- package/styles/tokens.css +134 -66
- package/dist/browser-viewer-MKKFRRRV.js +0 -14
- package/dist/chunk-2DZVYHVO.js +0 -470
- package/dist/chunk-2DZVYHVO.js.map +0 -1
- package/dist/chunk-3AGBGTRT.js.map +0 -1
- package/dist/chunk-4MDLEHXL.js.map +0 -1
- package/dist/chunk-5YK2ZDIG.js.map +0 -1
- package/dist/chunk-7EAFGICR.js +0 -302
- package/dist/chunk-7EAFGICR.js.map +0 -1
- package/dist/chunk-ELIYWBZR.js.map +0 -1
- package/dist/chunk-H5YGYNXS.js.map +0 -1
- package/dist/chunk-HUIKIDM5.js.map +0 -1
- package/dist/chunk-ICA6R6TW.js.map +0 -1
- package/dist/chunk-IOLVN74D.js.map +0 -1
- package/dist/chunk-JAQ5K7W6.js.map +0 -1
- package/dist/chunk-JVYQRRC4.js.map +0 -1
- package/dist/chunk-KCGXPP5V.js.map +0 -1
- package/dist/chunk-KZ73RL76.js.map +0 -1
- package/dist/chunk-NEXLLTP4.js.map +0 -1
- package/dist/chunk-PEI6RANI.js.map +0 -1
- package/dist/chunk-VTOREEXF.js +0 -142
- package/dist/chunk-VTOREEXF.js.map +0 -1
- package/dist/chunk-WSK7G5LE.js +0 -170
- package/dist/chunk-WSK7G5LE.js.map +0 -1
- package/dist/chunk-X4A66EWZ.js +0 -223
- package/dist/chunk-X4A66EWZ.js.map +0 -1
- package/dist/chunk-XYRDDSXF.js.map +0 -1
- package/dist/chunk-YG4QEQF5.js +0 -9557
- package/dist/chunk-YG4QEQF5.js.map +0 -1
- package/dist/chunk-YVCHAQZY.js.map +0 -1
- package/dist/chunk-ZPBTI3TE.js.map +0 -1
- package/dist/computer-viewer-FWEZISW4.js +0 -16
- package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
- package/dist/hooks/use-environments.d.ts +0 -41
- package/dist/hooks/use-packs.d.ts +0 -32
- package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
- package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
- package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
- package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
- package/src/hooks/use-environments.ts +0 -182
- package/src/hooks/use-packs.ts +0 -157
- /package/dist/{browser-viewer-MKKFRRRV.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
- /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-4EUKJXUO.js.map} +0 -0
|
@@ -1,41 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import {
|
|
2
3
|
InteractionInterventionBanner,
|
|
4
|
+
isInteractionControlUnavailable,
|
|
3
5
|
isNonRetryableInteractionError,
|
|
4
6
|
isSourcePlacementChangedError,
|
|
5
7
|
useInteractionInterventions,
|
|
6
|
-
useInteractionInvalidation
|
|
7
|
-
|
|
8
|
+
useInteractionInvalidation,
|
|
9
|
+
useViewerMenuDismiss
|
|
10
|
+
} from "./chunk-P4BNUO57.js";
|
|
11
|
+
import {
|
|
12
|
+
copyTextToClipboard
|
|
13
|
+
} from "./chunk-PEHTX3V7.js";
|
|
8
14
|
import {
|
|
9
|
-
STREAM_CLOSE_REASON_NORMAL,
|
|
10
|
-
STREAM_KIND_BROWSER,
|
|
11
|
-
STREAM_ROLE_CLIENT,
|
|
12
|
-
decodeStreamFrame,
|
|
13
|
-
decodeStreamOpenAck,
|
|
14
|
-
encodeStreamClose,
|
|
15
|
-
encodeStreamOpen,
|
|
16
15
|
interactionHostPlatform
|
|
17
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ZUWF4NF7.js";
|
|
18
17
|
import {
|
|
19
18
|
usePageLiveActivity
|
|
20
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-QHUE7E4N.js";
|
|
21
20
|
import {
|
|
22
21
|
useEmbeddedBrowserInteraction
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import {
|
|
25
|
-
copyTextToClipboard
|
|
26
|
-
} from "./chunk-JVYQRRC4.js";
|
|
22
|
+
} from "./chunk-G76LSA76.js";
|
|
27
23
|
import {
|
|
28
24
|
formatBytes
|
|
29
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-BLL56F7R.js";
|
|
26
|
+
import {
|
|
27
|
+
STREAM_CLOSE_REASON_NORMAL,
|
|
28
|
+
STREAM_KIND_BROWSER,
|
|
29
|
+
STREAM_ROLE_CLIENT,
|
|
30
|
+
decodeStreamFrame,
|
|
31
|
+
decodeStreamOpenAck,
|
|
32
|
+
encodeStreamClose,
|
|
33
|
+
encodeStreamOpen
|
|
34
|
+
} from "./chunk-TNEZNMSN.js";
|
|
30
35
|
import {
|
|
31
36
|
cn
|
|
32
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TXS65BB2.js";
|
|
33
38
|
|
|
34
39
|
// src/components/browser-viewer.tsx
|
|
35
40
|
import { interactionControlFailureFromError } from "@opengeni/sdk/interaction";
|
|
36
41
|
import {
|
|
37
42
|
BugIcon,
|
|
38
43
|
ArchiveIcon,
|
|
44
|
+
ArrowLeftIcon,
|
|
45
|
+
ArrowRightIcon,
|
|
39
46
|
CheckIcon,
|
|
40
47
|
ChevronDownIcon,
|
|
41
48
|
CircleAlertIcon,
|
|
@@ -54,11 +61,12 @@ import {
|
|
|
54
61
|
} from "lucide-react";
|
|
55
62
|
import {
|
|
56
63
|
useCallback as useCallback8,
|
|
57
|
-
useEffect as
|
|
64
|
+
useEffect as useEffect9,
|
|
58
65
|
useId,
|
|
66
|
+
useLayoutEffect as useLayoutEffect2,
|
|
59
67
|
useMemo as useMemo2,
|
|
60
|
-
useRef as
|
|
61
|
-
useState as
|
|
68
|
+
useRef as useRef9,
|
|
69
|
+
useState as useState9
|
|
62
70
|
} from "react";
|
|
63
71
|
|
|
64
72
|
// src/hooks/use-browser-frame-stream.ts
|
|
@@ -74,7 +82,8 @@ var RELAY_TAG_CLOSE = 4;
|
|
|
74
82
|
var MAX_AUTOMATIC_RECONNECTS_WITHOUT_A_FRAME = 2;
|
|
75
83
|
function useBrowserFrameStream(options) {
|
|
76
84
|
const { client, workspaceId } = useEmbeddedBrowserInteraction(options);
|
|
77
|
-
const
|
|
85
|
+
const pageLive = usePageLiveActivity();
|
|
86
|
+
const enabled = (options.enabled ?? true) && pageLive;
|
|
78
87
|
const [nonce, setNonce] = useState(0);
|
|
79
88
|
const [result, setResult] = useState({
|
|
80
89
|
state: "idle",
|
|
@@ -296,6 +305,7 @@ function useBrowserFrameStream(options) {
|
|
|
296
305
|
activeStream.kind === "relay" ? activeStream.url : browserFrameSocketUrl(activeAttachment, streamRef.current),
|
|
297
306
|
activeStream.kind === "direct_websocket" ? [...activeStream.protocols] : []
|
|
298
307
|
);
|
|
308
|
+
latestRef.current = { key: "", sequence: -1 };
|
|
299
309
|
socket = openedSocket;
|
|
300
310
|
socketHandlers = {
|
|
301
311
|
open: () => onOpen(openedSocket),
|
|
@@ -346,7 +356,9 @@ function useBrowserFrameStream(options) {
|
|
|
346
356
|
browserSessionId: attachment.browserSessionId,
|
|
347
357
|
controllerGeneration: attachment.controllerGeneration,
|
|
348
358
|
targetId: attachment.targetId,
|
|
349
|
-
expiresAt: attachment.expiresAt
|
|
359
|
+
expiresAt: attachment.expiresAt,
|
|
360
|
+
...attachment.fencedInputBatches === true ? { fencedInputBatches: true } : {},
|
|
361
|
+
...attachment.focusedInputObservations === true ? { focusedInputObservations: true } : {}
|
|
350
362
|
},
|
|
351
363
|
error: null
|
|
352
364
|
}));
|
|
@@ -855,14 +867,35 @@ function useBrowserSession(options) {
|
|
|
855
867
|
const { client, workspaceId } = useEmbeddedBrowserInteraction(options);
|
|
856
868
|
const browserSessionId = options.browserSessionId;
|
|
857
869
|
const enabled = (options.enabled ?? true) && browserSessionId !== null;
|
|
870
|
+
const sourceRef = useRef5({ client, workspaceId, browserSessionId, enabled });
|
|
871
|
+
if (sourceRef.current.client !== client || sourceRef.current.workspaceId !== workspaceId || sourceRef.current.browserSessionId !== browserSessionId || sourceRef.current.enabled !== enabled) {
|
|
872
|
+
sourceRef.current = { client, workspaceId, browserSessionId, enabled };
|
|
873
|
+
}
|
|
874
|
+
const source = sourceRef.current;
|
|
875
|
+
const semanticObservationEnabled = options.semanticObservationEnabled ?? true;
|
|
876
|
+
const semanticObservationEnabledRef = useRef5(semanticObservationEnabled);
|
|
877
|
+
semanticObservationEnabledRef.current = semanticObservationEnabled;
|
|
878
|
+
const previousSemanticObservationRef = useRef5({
|
|
879
|
+
browserSessionId,
|
|
880
|
+
enabled: semanticObservationEnabled
|
|
881
|
+
});
|
|
858
882
|
const pageLive = usePageLiveActivity();
|
|
859
883
|
const pollIntervalMs = Math.max(750, options.pollIntervalMs ?? 2e3);
|
|
860
|
-
const [state, setState] = useState5(() => emptyState4(browserSessionId, enabled));
|
|
861
|
-
const visible = state.browserSessionId === browserSessionId ? state : emptyState4(browserSessionId, enabled);
|
|
884
|
+
const [state, setState] = useState5(() => ({ ...emptyState4(browserSessionId, enabled), source }));
|
|
885
|
+
const visible = state.source === source && state.browserSessionId === browserSessionId ? state : { ...emptyState4(browserSessionId, enabled), source };
|
|
862
886
|
const refreshBlocked = isNonRetryableInteractionError(visible.error);
|
|
887
|
+
const inputFailureRef = useRef5(visible.inputFailure);
|
|
888
|
+
inputFailureRef.current = visible.inputFailure;
|
|
863
889
|
const selectedTargetIdRef = useRef5(visible.selectedTargetId);
|
|
864
890
|
selectedTargetIdRef.current = visible.selectedTargetId;
|
|
891
|
+
const selectionRevisionRef = useRef5(0);
|
|
892
|
+
const actionResultOrderRef = useRef5({ next: 0, settled: 0 });
|
|
893
|
+
const selectedTargetRef = useRef5(
|
|
894
|
+
visible.targets.find((target) => target.id === visible.selectedTargetId) ?? null
|
|
895
|
+
);
|
|
896
|
+
selectedTargetRef.current = visible.targets.find((target) => target.id === visible.selectedTargetId) ?? null;
|
|
865
897
|
const observationRef = useRef5({ browserSessionId, observation: visible.observation });
|
|
898
|
+
const lastObservationAtRef = useRef5(0);
|
|
866
899
|
if (observationRef.current.browserSessionId !== browserSessionId) {
|
|
867
900
|
observationRef.current = {
|
|
868
901
|
browserSessionId,
|
|
@@ -877,106 +910,189 @@ function useBrowserSession(options) {
|
|
|
877
910
|
});
|
|
878
911
|
const mutationRef = useRef5({
|
|
879
912
|
browserSessionId,
|
|
880
|
-
|
|
913
|
+
source,
|
|
914
|
+
count: 0,
|
|
915
|
+
needsInventoryReconcile: false
|
|
881
916
|
});
|
|
882
917
|
const mountedRef = useRef5(true);
|
|
918
|
+
const isCurrentSource = useCallback5(
|
|
919
|
+
() => mountedRef.current && sourceRef.current === source,
|
|
920
|
+
[source]
|
|
921
|
+
);
|
|
883
922
|
const invalidateRefresh = useCallback5(() => {
|
|
884
923
|
const id = requestRef.current.id + 1;
|
|
885
924
|
requestRef.current.controller?.abort();
|
|
886
925
|
requestRef.current = { id, controller: null };
|
|
887
926
|
}, []);
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
client.getBrowserSession(workspaceId, browserSessionId, {
|
|
897
|
-
signal: controller.signal
|
|
898
|
-
}),
|
|
899
|
-
client.listBrowserTargets(workspaceId, browserSessionId, {
|
|
900
|
-
signal: controller.signal
|
|
901
|
-
})
|
|
902
|
-
]);
|
|
903
|
-
if (!mountedRef.current || requestRef.current.id !== id) return;
|
|
904
|
-
const selected = chooseTarget(targetResponse.targets, selectedTargetIdRef.current);
|
|
905
|
-
selectedTargetIdRef.current = selected?.id ?? null;
|
|
906
|
-
observationRef.current = { browserSessionId, observation: null };
|
|
907
|
-
setState(
|
|
908
|
-
(current) => current.browserSessionId === browserSessionId ? {
|
|
909
|
-
...current,
|
|
910
|
-
session,
|
|
911
|
-
targets: targetResponse.targets,
|
|
912
|
-
selectedTargetId: selected?.id ?? null,
|
|
913
|
-
observation: null,
|
|
914
|
-
loading: false,
|
|
915
|
-
error: null
|
|
916
|
-
} : current
|
|
917
|
-
);
|
|
918
|
-
if (!selected) return;
|
|
927
|
+
const refreshInventory = useCallback5(
|
|
928
|
+
async (checkInput = false, observeSelectedTarget = true) => {
|
|
929
|
+
if (!enabled || !browserSessionId || !isCurrentSource()) return;
|
|
930
|
+
const checkedInputFailure = inputFailureRef.current;
|
|
931
|
+
const id = requestRef.current.id + 1;
|
|
932
|
+
requestRef.current.controller?.abort();
|
|
933
|
+
const controller = new AbortController();
|
|
934
|
+
requestRef.current = { id, controller };
|
|
919
935
|
try {
|
|
920
|
-
const
|
|
921
|
-
workspaceId,
|
|
936
|
+
const [session, targetResponse] = await Promise.all([
|
|
937
|
+
client.getBrowserSession(workspaceId, browserSessionId, {
|
|
938
|
+
signal: controller.signal
|
|
939
|
+
}),
|
|
940
|
+
client.listBrowserTargets(workspaceId, browserSessionId, {
|
|
941
|
+
signal: controller.signal
|
|
942
|
+
})
|
|
943
|
+
]);
|
|
944
|
+
if (!isCurrentSource() || requestRef.current.id !== id) return;
|
|
945
|
+
const selected = chooseTarget(targetResponse.targets, selectedTargetIdRef.current);
|
|
946
|
+
selectedTargetIdRef.current = selected?.id ?? null;
|
|
947
|
+
selectedTargetRef.current = selected;
|
|
948
|
+
const previousObservation = observationRef.current.browserSessionId === browserSessionId ? observationRef.current.observation : null;
|
|
949
|
+
const retainedObservation = selected && previousObservation && sameObservationTarget(previousObservation, selected) ? previousObservation : null;
|
|
950
|
+
observationRef.current = {
|
|
922
951
|
browserSessionId,
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
);
|
|
926
|
-
if (!mountedRef.current || requestRef.current.id !== id) return;
|
|
927
|
-
observationRef.current = { browserSessionId, observation };
|
|
952
|
+
observation: retainedObservation
|
|
953
|
+
};
|
|
928
954
|
setState(
|
|
929
|
-
(current) => current.
|
|
955
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
956
|
+
...current,
|
|
957
|
+
session,
|
|
958
|
+
targets: targetResponse.targets,
|
|
959
|
+
selectedTargetId: selected?.id ?? null,
|
|
960
|
+
observation: retainedObservation,
|
|
961
|
+
loading: false,
|
|
962
|
+
error: null,
|
|
963
|
+
// Media and background polling cannot confirm an input outcome.
|
|
964
|
+
// Only an explicit fresh check clears the notice it began with.
|
|
965
|
+
inputFailure: checkInput && session.id === browserSessionId && targetResponse.browserSessionId === browserSessionId && current.inputFailure === checkedInputFailure ? null : current.inputFailure
|
|
966
|
+
} : current
|
|
930
967
|
);
|
|
968
|
+
if (!selected || !observeSelectedTarget || !semanticObservationEnabledRef.current) return;
|
|
969
|
+
try {
|
|
970
|
+
const observation = await client.observeBrowserTarget(
|
|
971
|
+
workspaceId,
|
|
972
|
+
browserSessionId,
|
|
973
|
+
selected.id,
|
|
974
|
+
{ signal: controller.signal }
|
|
975
|
+
);
|
|
976
|
+
if (!isCurrentSource() || requestRef.current.id !== id) return;
|
|
977
|
+
const currentSelected = selectedTargetRef.current;
|
|
978
|
+
if (observationRef.current.browserSessionId !== browserSessionId || currentSelected?.id !== selected.id || observation.browserSessionId !== browserSessionId || observation.target.id !== selected.id || observation.target.controllerGeneration !== currentSelected.controllerGeneration || observation.target.targetGeneration !== currentSelected.targetGeneration)
|
|
979
|
+
return;
|
|
980
|
+
selectedTargetRef.current = observation.target;
|
|
981
|
+
observationRef.current = { browserSessionId, observation };
|
|
982
|
+
lastObservationAtRef.current = Date.now();
|
|
983
|
+
setState(
|
|
984
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId && current.selectedTargetId === observation.target.id ? {
|
|
985
|
+
...current,
|
|
986
|
+
observation,
|
|
987
|
+
targets: replaceTarget(current.targets, observation.target)
|
|
988
|
+
} : current
|
|
989
|
+
);
|
|
990
|
+
} catch (cause) {
|
|
991
|
+
if (controller.signal.aborted || !isCurrentSource() || requestRef.current.id !== id)
|
|
992
|
+
return;
|
|
993
|
+
void cause;
|
|
994
|
+
}
|
|
931
995
|
} catch (cause) {
|
|
932
|
-
if (controller.signal.aborted || !
|
|
933
|
-
|
|
934
|
-
|
|
996
|
+
if (controller.signal.aborted || !isCurrentSource() || requestRef.current.id !== id) return;
|
|
997
|
+
setState(
|
|
998
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
999
|
+
...current,
|
|
1000
|
+
loading: false,
|
|
1001
|
+
error: cause instanceof Error ? cause : new Error(String(cause))
|
|
1002
|
+
} : current
|
|
1003
|
+
);
|
|
1004
|
+
} finally {
|
|
1005
|
+
if (requestRef.current.id === id) {
|
|
1006
|
+
requestRef.current = { id, controller: null };
|
|
1007
|
+
}
|
|
935
1008
|
}
|
|
936
|
-
}
|
|
937
|
-
|
|
1009
|
+
},
|
|
1010
|
+
[browserSessionId, client, enabled, isCurrentSource, source, workspaceId]
|
|
1011
|
+
);
|
|
1012
|
+
const refresh = useCallback5(async () => await refreshInventory(true), [refreshInventory]);
|
|
1013
|
+
const refreshSemantic = useCallback5(async () => {
|
|
1014
|
+
if (!enabled || !browserSessionId || !isCurrentSource()) return;
|
|
1015
|
+
const target = selectedTargetRef.current;
|
|
1016
|
+
if (!target) return;
|
|
1017
|
+
const id = requestRef.current.id + 1;
|
|
1018
|
+
requestRef.current.controller?.abort();
|
|
1019
|
+
const controller = new AbortController();
|
|
1020
|
+
requestRef.current = { id, controller };
|
|
1021
|
+
try {
|
|
1022
|
+
const observation = await client.observeBrowserTarget(
|
|
1023
|
+
workspaceId,
|
|
1024
|
+
browserSessionId,
|
|
1025
|
+
target.id,
|
|
1026
|
+
{ signal: controller.signal }
|
|
1027
|
+
);
|
|
1028
|
+
if (!isCurrentSource() || requestRef.current.id !== id) return;
|
|
1029
|
+
if (!sameObservationTarget(observation, selectedTargetRef.current)) return;
|
|
1030
|
+
observationRef.current = { browserSessionId, observation };
|
|
1031
|
+
lastObservationAtRef.current = Date.now();
|
|
938
1032
|
setState(
|
|
939
|
-
(current) => current.browserSessionId === browserSessionId ? {
|
|
940
|
-
...current,
|
|
941
|
-
loading: false,
|
|
942
|
-
error: cause instanceof Error ? cause : new Error(String(cause))
|
|
943
|
-
} : current
|
|
1033
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId && current.selectedTargetId === target.id ? { ...current, observation } : current
|
|
944
1034
|
);
|
|
1035
|
+
} catch {
|
|
945
1036
|
} finally {
|
|
946
|
-
if (requestRef.current.id === id) {
|
|
947
|
-
requestRef.current = { id, controller: null };
|
|
948
|
-
}
|
|
1037
|
+
if (requestRef.current.id === id) requestRef.current = { id, controller: null };
|
|
949
1038
|
}
|
|
950
|
-
}, [browserSessionId, client, enabled, workspaceId]);
|
|
1039
|
+
}, [browserSessionId, client, enabled, isCurrentSource, source, workspaceId]);
|
|
951
1040
|
useEffect5(() => {
|
|
952
1041
|
mountedRef.current = true;
|
|
953
1042
|
if (!enabled) {
|
|
954
1043
|
invalidateRefresh();
|
|
955
|
-
setState(emptyState4(browserSessionId, false));
|
|
1044
|
+
setState({ ...emptyState4(browserSessionId, false), source });
|
|
956
1045
|
return;
|
|
957
1046
|
}
|
|
958
1047
|
setState(
|
|
959
|
-
(current) => current.browserSessionId === browserSessionId ? { ...current, loading: true } : emptyState4(browserSessionId, true)
|
|
1048
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId ? { ...current, loading: true } : { ...emptyState4(browserSessionId, true), source }
|
|
960
1049
|
);
|
|
961
|
-
void
|
|
1050
|
+
void refreshInventory();
|
|
962
1051
|
return () => {
|
|
963
1052
|
mountedRef.current = false;
|
|
964
1053
|
invalidateRefresh();
|
|
965
1054
|
};
|
|
966
|
-
}, [browserSessionId, enabled, invalidateRefresh,
|
|
1055
|
+
}, [browserSessionId, enabled, invalidateRefresh, isCurrentSource, refreshInventory, source]);
|
|
1056
|
+
useEffect5(() => {
|
|
1057
|
+
const previous = previousSemanticObservationRef.current;
|
|
1058
|
+
previousSemanticObservationRef.current = {
|
|
1059
|
+
browserSessionId,
|
|
1060
|
+
enabled: semanticObservationEnabled
|
|
1061
|
+
};
|
|
1062
|
+
if (enabled && semanticObservationEnabled && previous.browserSessionId === browserSessionId && !previous.enabled) {
|
|
1063
|
+
const currentObservation = observationRef.current.observation;
|
|
1064
|
+
if (currentObservation && sameObservationTarget(currentObservation, selectedTargetRef.current) && Date.now() - lastObservationAtRef.current < pollIntervalMs) {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
observationRef.current = { browserSessionId, observation: null };
|
|
1068
|
+
setState(
|
|
1069
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === browserSessionId ? { ...current, observation: null } : current
|
|
1070
|
+
);
|
|
1071
|
+
void refreshSemantic();
|
|
1072
|
+
}
|
|
1073
|
+
}, [
|
|
1074
|
+
browserSessionId,
|
|
1075
|
+
enabled,
|
|
1076
|
+
isCurrentSource,
|
|
1077
|
+
pollIntervalMs,
|
|
1078
|
+
refreshSemantic,
|
|
1079
|
+
semanticObservationEnabled,
|
|
1080
|
+
source
|
|
1081
|
+
]);
|
|
967
1082
|
useEffect5(() => {
|
|
968
1083
|
if (!enabled || !pageLive || visible.mutating || refreshBlocked) return;
|
|
969
1084
|
const timer = setInterval(() => {
|
|
970
|
-
if (!requestRef.current.controller) void
|
|
1085
|
+
if (!requestRef.current.controller) void refreshInventory();
|
|
971
1086
|
}, pollIntervalMs);
|
|
972
1087
|
return () => clearInterval(timer);
|
|
973
|
-
}, [enabled, pageLive, pollIntervalMs,
|
|
1088
|
+
}, [enabled, pageLive, pollIntervalMs, refreshInventory, refreshBlocked, visible.mutating]);
|
|
974
1089
|
useEffect5(() => {
|
|
975
1090
|
if (!enabled || !browserSessionId || !pageLive || refreshBlocked) return;
|
|
976
1091
|
let disposed = false;
|
|
977
1092
|
const heartbeat = () => {
|
|
1093
|
+
if (!isCurrentSource()) return;
|
|
978
1094
|
void client.heartbeatBrowserSession(workspaceId, browserSessionId).catch(() => {
|
|
979
|
-
if (!disposed) void
|
|
1095
|
+
if (!disposed) void refreshInventory();
|
|
980
1096
|
});
|
|
981
1097
|
};
|
|
982
1098
|
const timer = setInterval(heartbeat, 3e4);
|
|
@@ -984,148 +1100,216 @@ function useBrowserSession(options) {
|
|
|
984
1100
|
disposed = true;
|
|
985
1101
|
clearInterval(timer);
|
|
986
1102
|
};
|
|
987
|
-
}, [
|
|
1103
|
+
}, [
|
|
1104
|
+
browserSessionId,
|
|
1105
|
+
client,
|
|
1106
|
+
enabled,
|
|
1107
|
+
isCurrentSource,
|
|
1108
|
+
pageLive,
|
|
1109
|
+
refreshInventory,
|
|
1110
|
+
refreshBlocked,
|
|
1111
|
+
workspaceId
|
|
1112
|
+
]);
|
|
988
1113
|
const runMutation = useCallback5(
|
|
989
|
-
async (scopeBrowserSessionId, operation) => {
|
|
1114
|
+
async (scopeBrowserSessionId, operation, selectionRead = false, changesInventory = false) => {
|
|
1115
|
+
if (!enabled || !isCurrentSource()) {
|
|
1116
|
+
throw new Error("The browser source is no longer selected.");
|
|
1117
|
+
}
|
|
1118
|
+
const selectionRevision = ++selectionRevisionRef.current;
|
|
990
1119
|
invalidateRefresh();
|
|
991
|
-
|
|
1120
|
+
const readRequestId = requestRef.current.id;
|
|
1121
|
+
if (mutationRef.current.browserSessionId !== scopeBrowserSessionId || mutationRef.current.source !== source) {
|
|
992
1122
|
mutationRef.current = {
|
|
993
1123
|
browserSessionId: scopeBrowserSessionId,
|
|
994
|
-
|
|
1124
|
+
source,
|
|
1125
|
+
count: 0,
|
|
1126
|
+
needsInventoryReconcile: false
|
|
995
1127
|
};
|
|
996
1128
|
}
|
|
997
1129
|
mutationRef.current.count += 1;
|
|
998
1130
|
setState(
|
|
999
|
-
(current) => current.browserSessionId === scopeBrowserSessionId ? { ...current, mutating: true, error: null } : current
|
|
1131
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === scopeBrowserSessionId ? { ...current, mutating: true, error: null } : current
|
|
1000
1132
|
);
|
|
1001
1133
|
try {
|
|
1002
|
-
return await operation();
|
|
1134
|
+
return await operation(selectionRevision, readRequestId);
|
|
1003
1135
|
} catch (cause) {
|
|
1004
1136
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
1005
|
-
|
|
1006
|
-
(
|
|
1007
|
-
|
|
1137
|
+
if (!selectionRead || requestRef.current.id === readRequestId) {
|
|
1138
|
+
setState(
|
|
1139
|
+
(current) => isCurrentSource() && selectionRevisionRef.current === selectionRevision && current.source === source && current.browserSessionId === scopeBrowserSessionId ? { ...current, error } : current
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1008
1142
|
throw error;
|
|
1009
1143
|
} finally {
|
|
1010
|
-
if (mutationRef.current.browserSessionId === scopeBrowserSessionId) {
|
|
1144
|
+
if (mutationRef.current.browserSessionId === scopeBrowserSessionId && mutationRef.current.source === source) {
|
|
1145
|
+
if (changesInventory && (selectionRevisionRef.current !== selectionRevision || requestRef.current.id !== readRequestId)) {
|
|
1146
|
+
mutationRef.current.needsInventoryReconcile = true;
|
|
1147
|
+
}
|
|
1011
1148
|
mutationRef.current.count = Math.max(0, mutationRef.current.count - 1);
|
|
1012
1149
|
const mutating = mutationRef.current.count > 0;
|
|
1013
1150
|
setState(
|
|
1014
|
-
(current) => current.browserSessionId === scopeBrowserSessionId ? { ...current, mutating } : current
|
|
1151
|
+
(current) => isCurrentSource() && current.source === source && current.browserSessionId === scopeBrowserSessionId ? { ...current, mutating } : current
|
|
1015
1152
|
);
|
|
1153
|
+
if (!mutating && mutationRef.current.needsInventoryReconcile && isCurrentSource()) {
|
|
1154
|
+
mutationRef.current.needsInventoryReconcile = false;
|
|
1155
|
+
void refreshInventory(false, false);
|
|
1156
|
+
}
|
|
1016
1157
|
}
|
|
1017
1158
|
}
|
|
1018
1159
|
},
|
|
1019
|
-
[invalidateRefresh]
|
|
1160
|
+
[enabled, invalidateRefresh, isCurrentSource, refreshInventory, source]
|
|
1020
1161
|
);
|
|
1021
1162
|
const selectTarget = useCallback5(
|
|
1022
1163
|
async (targetId) => {
|
|
1023
1164
|
if (!browserSessionId) throw new Error("No BrowserSession is selected.");
|
|
1024
|
-
return await runMutation(
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1165
|
+
return await runMutation(
|
|
1166
|
+
browserSessionId,
|
|
1167
|
+
async (selectionRevision, readRequestId) => {
|
|
1168
|
+
const isCurrentSelection = () => isCurrentSource() && selectionRevisionRef.current === selectionRevision;
|
|
1169
|
+
const isCurrentSelectionRead = () => isCurrentSelection() && requestRef.current.id === readRequestId;
|
|
1170
|
+
let targets = visible.targets;
|
|
1171
|
+
let target;
|
|
1172
|
+
let observation;
|
|
1173
|
+
try {
|
|
1174
|
+
observation = await client.selectBrowserTarget(workspaceId, browserSessionId, targetId);
|
|
1175
|
+
target = observation.target;
|
|
1176
|
+
} catch (cause) {
|
|
1177
|
+
if (!isCurrentSelectionRead() || !isMissingBrowserTarget(cause)) throw cause;
|
|
1178
|
+
const response = await client.listBrowserTargets(workspaceId, browserSessionId);
|
|
1179
|
+
if (!isCurrentSelectionRead()) throw cause;
|
|
1180
|
+
targets = response.targets;
|
|
1181
|
+
const fallback = chooseTarget(targets, null);
|
|
1182
|
+
if (!fallback) {
|
|
1183
|
+
selectedTargetIdRef.current = null;
|
|
1184
|
+
selectedTargetRef.current = null;
|
|
1185
|
+
observationRef.current = { browserSessionId, observation: null };
|
|
1186
|
+
setState(
|
|
1187
|
+
(current) => isCurrentSelection() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
1188
|
+
...current,
|
|
1189
|
+
targets,
|
|
1190
|
+
selectedTargetId: null,
|
|
1191
|
+
observation: null
|
|
1192
|
+
} : current
|
|
1193
|
+
);
|
|
1194
|
+
throw cause;
|
|
1195
|
+
}
|
|
1196
|
+
observation = await client.selectBrowserTarget(
|
|
1197
|
+
workspaceId,
|
|
1198
|
+
browserSessionId,
|
|
1199
|
+
fallback.id
|
|
1046
1200
|
);
|
|
1047
|
-
|
|
1201
|
+
target = observation.target;
|
|
1048
1202
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1203
|
+
if (!isCurrentSelectionRead()) return target;
|
|
1204
|
+
selectedTargetIdRef.current = target.id;
|
|
1205
|
+
selectedTargetRef.current = target;
|
|
1206
|
+
observationRef.current = { browserSessionId, observation };
|
|
1207
|
+
lastObservationAtRef.current = Date.now();
|
|
1208
|
+
setState(
|
|
1209
|
+
(current) => isCurrentSelection() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
1210
|
+
...current,
|
|
1211
|
+
targets: replaceTarget(targets, target).map((candidate) => ({
|
|
1212
|
+
...candidate,
|
|
1213
|
+
selected: candidate.id === target.id
|
|
1214
|
+
})),
|
|
1215
|
+
selectedTargetId: target.id,
|
|
1216
|
+
observation
|
|
1217
|
+
} : current
|
|
1053
1218
|
);
|
|
1054
|
-
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
setState(
|
|
1059
|
-
(current) => current.browserSessionId === browserSessionId ? {
|
|
1060
|
-
...current,
|
|
1061
|
-
targets: targets.map((candidate) => ({
|
|
1062
|
-
...candidate,
|
|
1063
|
-
selected: candidate.id === target.id
|
|
1064
|
-
})),
|
|
1065
|
-
selectedTargetId: target.id,
|
|
1066
|
-
observation
|
|
1067
|
-
} : current
|
|
1068
|
-
);
|
|
1069
|
-
return target;
|
|
1070
|
-
});
|
|
1219
|
+
return target;
|
|
1220
|
+
},
|
|
1221
|
+
true
|
|
1222
|
+
);
|
|
1071
1223
|
},
|
|
1072
|
-
[browserSessionId, client, runMutation, visible.targets, workspaceId]
|
|
1224
|
+
[browserSessionId, client, isCurrentSource, runMutation, source, visible.targets, workspaceId]
|
|
1073
1225
|
);
|
|
1074
1226
|
const openTarget = useCallback5(
|
|
1075
1227
|
async (url) => {
|
|
1076
1228
|
if (!browserSessionId) throw new Error("No BrowserSession is selected.");
|
|
1077
|
-
return await runMutation(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1229
|
+
return await runMutation(
|
|
1230
|
+
browserSessionId,
|
|
1231
|
+
async (selectionRevision, readRequestId) => {
|
|
1232
|
+
const isCurrentSelection = () => isCurrentSource() && selectionRevisionRef.current === selectionRevision;
|
|
1233
|
+
const isCurrentSelectionRead = () => isCurrentSelection() && requestRef.current.id === readRequestId;
|
|
1234
|
+
const observation = await client.openBrowserTarget(
|
|
1235
|
+
workspaceId,
|
|
1236
|
+
browserSessionId,
|
|
1237
|
+
url === void 0 ? {} : { url }
|
|
1238
|
+
);
|
|
1239
|
+
const target = observation.target;
|
|
1240
|
+
if (!isCurrentSource()) return target;
|
|
1241
|
+
if (!isCurrentSelectionRead()) return target;
|
|
1242
|
+
selectedTargetIdRef.current = target.id;
|
|
1243
|
+
selectedTargetRef.current = target;
|
|
1244
|
+
observationRef.current = { browserSessionId, observation };
|
|
1245
|
+
lastObservationAtRef.current = Date.now();
|
|
1246
|
+
setState(
|
|
1247
|
+
(current) => isCurrentSelection() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
1248
|
+
...current,
|
|
1249
|
+
targets: [
|
|
1250
|
+
...current.targets.map((candidate) => ({
|
|
1251
|
+
...candidate,
|
|
1252
|
+
selected: false
|
|
1253
|
+
})),
|
|
1254
|
+
target
|
|
1255
|
+
],
|
|
1256
|
+
selectedTargetId: target.id,
|
|
1257
|
+
observation
|
|
1258
|
+
} : current
|
|
1259
|
+
);
|
|
1260
|
+
return target;
|
|
1261
|
+
},
|
|
1262
|
+
false,
|
|
1263
|
+
true
|
|
1264
|
+
);
|
|
1102
1265
|
},
|
|
1103
|
-
[browserSessionId, client, runMutation, workspaceId]
|
|
1266
|
+
[browserSessionId, client, isCurrentSource, runMutation, source, workspaceId]
|
|
1104
1267
|
);
|
|
1105
1268
|
const closeTarget = useCallback5(
|
|
1106
1269
|
async (targetId) => {
|
|
1107
1270
|
if (!browserSessionId) throw new Error("No BrowserSession is selected.");
|
|
1108
|
-
await runMutation(
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1271
|
+
await runMutation(
|
|
1272
|
+
browserSessionId,
|
|
1273
|
+
async (selectionRevision, readRequestId) => {
|
|
1274
|
+
const isCurrentSelection = () => isCurrentSource() && selectionRevisionRef.current === selectionRevision;
|
|
1275
|
+
const isCurrentSelectionRead = () => isCurrentSelection() && requestRef.current.id === readRequestId;
|
|
1276
|
+
const response = await client.closeBrowserTarget(workspaceId, browserSessionId, targetId);
|
|
1277
|
+
if (!isCurrentSource()) return;
|
|
1278
|
+
if (!isCurrentSelectionRead()) return;
|
|
1279
|
+
const selected = chooseTarget(response.targets, selectedTargetIdRef.current);
|
|
1280
|
+
const observed = selected ? await client.observeBrowserTarget(workspaceId, browserSessionId, selected.id) : null;
|
|
1281
|
+
if (!isCurrentSource()) return;
|
|
1282
|
+
if (!isCurrentSelectionRead()) return;
|
|
1283
|
+
const observation = observed && selected && observed.browserSessionId === browserSessionId && observed.target.id === selected.id && observed.target.controllerGeneration === selected.controllerGeneration && observed.target.targetGeneration === selected.targetGeneration ? observed : null;
|
|
1284
|
+
const currentTarget = observation?.target ?? selected;
|
|
1285
|
+
selectedTargetIdRef.current = currentTarget?.id ?? null;
|
|
1286
|
+
selectedTargetRef.current = currentTarget;
|
|
1287
|
+
observationRef.current = { browserSessionId, observation };
|
|
1288
|
+
if (observation) lastObservationAtRef.current = Date.now();
|
|
1289
|
+
setState(
|
|
1290
|
+
(current) => isCurrentSelection() && current.source === source && current.browserSessionId === browserSessionId ? {
|
|
1291
|
+
...current,
|
|
1292
|
+
targets: currentTarget ? replaceTarget(response.targets, currentTarget) : response.targets,
|
|
1293
|
+
selectedTargetId: currentTarget?.id ?? null,
|
|
1294
|
+
observation
|
|
1295
|
+
} : current
|
|
1296
|
+
);
|
|
1297
|
+
},
|
|
1298
|
+
false,
|
|
1299
|
+
true
|
|
1300
|
+
);
|
|
1123
1301
|
},
|
|
1124
|
-
[browserSessionId, client, runMutation, workspaceId]
|
|
1302
|
+
[browserSessionId, client, isCurrentSource, runMutation, source, workspaceId]
|
|
1125
1303
|
);
|
|
1126
1304
|
const dispatchAction = useCallback5(
|
|
1127
|
-
async (action, operationId, frame) => {
|
|
1305
|
+
async (action, operationId, frame, observationMode = "none") => {
|
|
1128
1306
|
if (!browserSessionId) throw new Error("No BrowserSession is selected.");
|
|
1307
|
+
if (!enabled || !isCurrentSource()) {
|
|
1308
|
+
throw new Error("The browser source is no longer selected.");
|
|
1309
|
+
}
|
|
1310
|
+
if (!selectedTargetRef.current) {
|
|
1311
|
+
throw new Error("The browser page is not ready for input.");
|
|
1312
|
+
}
|
|
1129
1313
|
if (frame && frame.browserSessionId !== browserSessionId) {
|
|
1130
1314
|
throw new Error("The displayed browser frame belongs to another BrowserSession.");
|
|
1131
1315
|
}
|
|
@@ -1135,7 +1319,7 @@ function useBrowserSession(options) {
|
|
|
1135
1319
|
expectedTargetGeneration: frame.targetGeneration,
|
|
1136
1320
|
expectedDocumentGeneration: frame.documentGeneration,
|
|
1137
1321
|
expectedFrameId: frame.frameId
|
|
1138
|
-
} : currentObservation ? {
|
|
1322
|
+
} : currentObservation && sameObservationTarget(currentObservation, selectedTargetRef.current) ? {
|
|
1139
1323
|
targetId: currentObservation.target.id,
|
|
1140
1324
|
expectedTargetGeneration: currentObservation.target.targetGeneration,
|
|
1141
1325
|
expectedDocumentGeneration: currentObservation.target.documentGeneration,
|
|
@@ -1144,47 +1328,113 @@ function useBrowserSession(options) {
|
|
|
1144
1328
|
if (!fence) {
|
|
1145
1329
|
throw new Error("The browser page is not ready for input.");
|
|
1146
1330
|
}
|
|
1331
|
+
const expectedControllerGeneration = frame?.controllerGeneration ?? currentObservation.target.controllerGeneration;
|
|
1332
|
+
const selectionRevision = selectionRevisionRef.current;
|
|
1333
|
+
const resultOrder = ++actionResultOrderRef.current.next;
|
|
1334
|
+
let resultDocumentGeneration = fence.expectedDocumentGeneration;
|
|
1335
|
+
const isCurrentResultView = () => {
|
|
1336
|
+
const selected = selectedTargetRef.current;
|
|
1337
|
+
return isCurrentSource() && selectionRevisionRef.current === selectionRevision && selected?.browserSessionId === browserSessionId && selected.id === fence.targetId && selected.controllerGeneration === expectedControllerGeneration && selected.targetGeneration === fence.expectedTargetGeneration && (selected.documentGeneration === fence.expectedDocumentGeneration || selected.documentGeneration === resultDocumentGeneration);
|
|
1338
|
+
};
|
|
1339
|
+
const canProjectResult = () => isCurrentResultView() && resultOrder >= actionResultOrderRef.current.settled;
|
|
1340
|
+
const settleResult = () => {
|
|
1341
|
+
if (!canProjectResult()) return false;
|
|
1342
|
+
actionResultOrderRef.current.settled = resultOrder;
|
|
1343
|
+
invalidateRefresh();
|
|
1344
|
+
return true;
|
|
1345
|
+
};
|
|
1147
1346
|
try {
|
|
1148
1347
|
const receipt = await client.actInBrowser(workspaceId, browserSessionId, {
|
|
1149
1348
|
operationId,
|
|
1150
1349
|
...fence,
|
|
1151
|
-
observationMode
|
|
1350
|
+
observationMode,
|
|
1152
1351
|
action
|
|
1153
1352
|
});
|
|
1154
|
-
|
|
1353
|
+
resultDocumentGeneration = receipt.observation?.target.documentGeneration ?? fence.expectedDocumentGeneration;
|
|
1354
|
+
const settled = receipt.state === "completed" || receipt.state === "failed" || receipt.state === "outcome_unknown";
|
|
1355
|
+
if (!canProjectResult() || settled && !settleResult()) return receipt;
|
|
1356
|
+
const receivedObservation = receipt.observation;
|
|
1357
|
+
const selectedTarget = selectedTargetRef.current;
|
|
1358
|
+
let projectedObservation = null;
|
|
1359
|
+
if (settled && receivedObservation && canProjectResult() && receipt.browserSessionId === browserSessionId && receipt.controllerGeneration === expectedControllerGeneration && receipt.targetId === fence.targetId && observationRef.current.browserSessionId === browserSessionId && receivedObservation.browserSessionId === browserSessionId && selectedTarget?.browserSessionId === browserSessionId && selectedTarget.id === fence.targetId && receivedObservation.target.id === fence.targetId && selectedTarget.controllerGeneration === expectedControllerGeneration && receivedObservation.target.controllerGeneration === expectedControllerGeneration && selectedTarget.targetGeneration === fence.expectedTargetGeneration && receivedObservation.target.targetGeneration === fence.expectedTargetGeneration && (selectedTarget.documentGeneration === fence.expectedDocumentGeneration || selectedTarget.documentGeneration === receivedObservation.target.documentGeneration)) {
|
|
1360
|
+
projectedObservation = receivedObservation;
|
|
1155
1361
|
observationRef.current = {
|
|
1156
1362
|
browserSessionId,
|
|
1157
|
-
observation:
|
|
1363
|
+
observation: receivedObservation
|
|
1158
1364
|
};
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
...current,
|
|
1162
|
-
observation: receipt.observation,
|
|
1163
|
-
targets: replaceTarget(current.targets, receipt.observation.target)
|
|
1164
|
-
} : current
|
|
1165
|
-
);
|
|
1365
|
+
selectedTargetRef.current = receivedObservation.target;
|
|
1366
|
+
lastObservationAtRef.current = Date.now();
|
|
1166
1367
|
}
|
|
1368
|
+
setState(
|
|
1369
|
+
(current) => isCurrentResultView() && current.source === source && current.browserSessionId === browserSessionId && current.actionResultOrder <= resultOrder ? {
|
|
1370
|
+
...current,
|
|
1371
|
+
actionResultOrder: settled ? resultOrder : current.actionResultOrder,
|
|
1372
|
+
error: receipt.state === "completed" ? null : current.error,
|
|
1373
|
+
inputFailure: receipt.state === "completed" ? current.inputFailure : {
|
|
1374
|
+
operationId: receipt.operationId,
|
|
1375
|
+
state: receipt.state,
|
|
1376
|
+
error: receipt.error
|
|
1377
|
+
},
|
|
1378
|
+
...projectedObservation ? {
|
|
1379
|
+
observation: projectedObservation,
|
|
1380
|
+
targets: replaceTarget(current.targets, projectedObservation.target)
|
|
1381
|
+
} : {}
|
|
1382
|
+
} : current
|
|
1383
|
+
);
|
|
1167
1384
|
return receipt;
|
|
1168
1385
|
} catch (cause) {
|
|
1169
1386
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
1170
|
-
|
|
1171
|
-
(
|
|
1172
|
-
|
|
1387
|
+
if (settleResult()) {
|
|
1388
|
+
setState(
|
|
1389
|
+
(current) => isCurrentResultView() && current.source === source && current.browserSessionId === browserSessionId && current.actionResultOrder <= resultOrder ? { ...current, error, actionResultOrder: resultOrder } : current
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1173
1392
|
throw error;
|
|
1174
1393
|
}
|
|
1175
1394
|
},
|
|
1176
|
-
[browserSessionId, client, workspaceId]
|
|
1395
|
+
[browserSessionId, client, enabled, invalidateRefresh, isCurrentSource, source, workspaceId]
|
|
1177
1396
|
);
|
|
1178
1397
|
const act = useCallback5(
|
|
1179
1398
|
async (action, operationId = crypto.randomUUID()) => await dispatchAction(action, operationId, null),
|
|
1180
1399
|
[dispatchAction]
|
|
1181
1400
|
);
|
|
1182
1401
|
const actFromFrame = useCallback5(
|
|
1183
|
-
async (action, frame, operationId = crypto.randomUUID()) => await dispatchAction(action, operationId, frame),
|
|
1402
|
+
async (action, frame, operationId = crypto.randomUUID(), observationMode = "none") => await dispatchAction(action, operationId, frame, observationMode),
|
|
1403
|
+
[dispatchAction]
|
|
1404
|
+
);
|
|
1405
|
+
const observeForInput = useCallback5(async () => {
|
|
1406
|
+
const target = selectedTargetRef.current;
|
|
1407
|
+
if (!enabled || !isCurrentSource()) {
|
|
1408
|
+
throw new Error("The browser source is no longer selected.");
|
|
1409
|
+
}
|
|
1410
|
+
if (!browserSessionId || !target) throw new Error("No browser tab is selected.");
|
|
1411
|
+
const observation = await client.observeBrowserTarget(workspaceId, browserSessionId, target.id);
|
|
1412
|
+
if (!isCurrentSource() || observation.browserSessionId !== browserSessionId || !sameObservationTarget(observation, selectedTargetRef.current)) {
|
|
1413
|
+
throw new Error("The browser page changed. Open the options again.");
|
|
1414
|
+
}
|
|
1415
|
+
return observation;
|
|
1416
|
+
}, [browserSessionId, client, enabled, isCurrentSource, workspaceId]);
|
|
1417
|
+
const actFromObservation = useCallback5(
|
|
1418
|
+
async (action, observation) => {
|
|
1419
|
+
if (!sameObservationTarget(observation, selectedTargetRef.current)) {
|
|
1420
|
+
throw new Error("The browser page changed. Open the options again.");
|
|
1421
|
+
}
|
|
1422
|
+
return await dispatchAction(action, crypto.randomUUID(), {
|
|
1423
|
+
browserSessionId: observation.browserSessionId,
|
|
1424
|
+
controllerGeneration: observation.target.controllerGeneration,
|
|
1425
|
+
targetId: observation.target.id,
|
|
1426
|
+
targetGeneration: observation.target.targetGeneration,
|
|
1427
|
+
documentGeneration: observation.target.documentGeneration,
|
|
1428
|
+
frameId: observation.frameId
|
|
1429
|
+
});
|
|
1430
|
+
},
|
|
1184
1431
|
[dispatchAction]
|
|
1185
1432
|
);
|
|
1186
1433
|
const diagnostics = useCallback5(
|
|
1187
1434
|
async (diagnosticOptions = {}) => {
|
|
1435
|
+
if (!enabled || !isCurrentSource()) {
|
|
1436
|
+
throw new Error("The browser source is no longer selected.");
|
|
1437
|
+
}
|
|
1188
1438
|
const targetId = selectedTargetIdRef.current;
|
|
1189
1439
|
if (!browserSessionId || !targetId) {
|
|
1190
1440
|
throw new Error("No browser tab is selected.");
|
|
@@ -1196,16 +1446,19 @@ function useBrowserSession(options) {
|
|
|
1196
1446
|
diagnosticOptions
|
|
1197
1447
|
);
|
|
1198
1448
|
},
|
|
1199
|
-
[browserSessionId, client, workspaceId]
|
|
1449
|
+
[browserSessionId, client, enabled, isCurrentSource, workspaceId]
|
|
1200
1450
|
);
|
|
1201
1451
|
const readClipboard = useCallback5(async () => {
|
|
1452
|
+
if (!enabled || !isCurrentSource()) {
|
|
1453
|
+
throw new Error("The browser source is no longer selected.");
|
|
1454
|
+
}
|
|
1202
1455
|
if (!browserSessionId) throw new Error("No BrowserSession is selected.");
|
|
1203
1456
|
const clipboard = await client.readBrowserClipboard(workspaceId, browserSessionId);
|
|
1204
|
-
if (clipboard.browserSessionId !== browserSessionId) {
|
|
1457
|
+
if (!isCurrentSource() || clipboard.browserSessionId !== browserSessionId) {
|
|
1205
1458
|
throw new Error("Browser clipboard belongs to another BrowserSession.");
|
|
1206
1459
|
}
|
|
1207
1460
|
return clipboard;
|
|
1208
|
-
}, [browserSessionId, client, workspaceId]);
|
|
1461
|
+
}, [browserSessionId, client, enabled, isCurrentSource, workspaceId]);
|
|
1209
1462
|
return {
|
|
1210
1463
|
session: visible.session,
|
|
1211
1464
|
targets: visible.targets,
|
|
@@ -1214,7 +1467,10 @@ function useBrowserSession(options) {
|
|
|
1214
1467
|
loading: visible.loading,
|
|
1215
1468
|
mutating: visible.mutating,
|
|
1216
1469
|
error: visible.error,
|
|
1470
|
+
inputFailure: visible.inputFailure,
|
|
1217
1471
|
refresh,
|
|
1472
|
+
observeForInput,
|
|
1473
|
+
actFromObservation,
|
|
1218
1474
|
selectTarget,
|
|
1219
1475
|
openTarget,
|
|
1220
1476
|
closeTarget,
|
|
@@ -1233,7 +1489,9 @@ function emptyState4(browserSessionId, loading) {
|
|
|
1233
1489
|
observation: null,
|
|
1234
1490
|
loading,
|
|
1235
1491
|
mutating: false,
|
|
1236
|
-
error: null
|
|
1492
|
+
error: null,
|
|
1493
|
+
inputFailure: null,
|
|
1494
|
+
actionResultOrder: 0
|
|
1237
1495
|
};
|
|
1238
1496
|
}
|
|
1239
1497
|
function chooseTarget(targets, preferredId) {
|
|
@@ -1244,6 +1502,9 @@ function replaceTarget(targets, target) {
|
|
|
1244
1502
|
next.push(target);
|
|
1245
1503
|
return next.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
1246
1504
|
}
|
|
1505
|
+
function sameObservationTarget(observation, target) {
|
|
1506
|
+
return target !== null && observation.browserSessionId === target.browserSessionId && observation.target.id === target.id && observation.target.controllerGeneration === target.controllerGeneration && observation.target.targetGeneration === target.targetGeneration && observation.target.documentGeneration === target.documentGeneration;
|
|
1507
|
+
}
|
|
1247
1508
|
function isMissingBrowserTarget(error) {
|
|
1248
1509
|
return error instanceof OpenGeniApiError && error.code === "target_not_found";
|
|
1249
1510
|
}
|
|
@@ -1264,14 +1525,16 @@ function useBrowserSessions(options = {}) {
|
|
|
1264
1525
|
id: 0,
|
|
1265
1526
|
controller: null
|
|
1266
1527
|
});
|
|
1528
|
+
const loadQueueRef = useRef6(null);
|
|
1267
1529
|
const mountedRef = useRef6(true);
|
|
1268
1530
|
const visibleState = state.workspaceId === workspaceId ? state : emptyState5(workspaceId, enabled);
|
|
1269
1531
|
const cancelLoad = useCallback6(() => {
|
|
1532
|
+
loadQueueRef.current = null;
|
|
1270
1533
|
const id = requestRef.current.id + 1;
|
|
1271
1534
|
requestRef.current.controller?.abort();
|
|
1272
1535
|
requestRef.current = { id, controller: null };
|
|
1273
1536
|
}, []);
|
|
1274
|
-
const
|
|
1537
|
+
const loadOnce = useCallback6(
|
|
1275
1538
|
async (foreground) => {
|
|
1276
1539
|
if (!enabled) return;
|
|
1277
1540
|
const id = requestRef.current.id + 1;
|
|
@@ -1317,6 +1580,30 @@ function useBrowserSessions(options = {}) {
|
|
|
1317
1580
|
},
|
|
1318
1581
|
[client, enabled, workspaceId]
|
|
1319
1582
|
);
|
|
1583
|
+
const load = useCallback6(
|
|
1584
|
+
(foreground) => {
|
|
1585
|
+
const current = loadQueueRef.current;
|
|
1586
|
+
if (current) {
|
|
1587
|
+
current.pending = true;
|
|
1588
|
+
return current.promise;
|
|
1589
|
+
}
|
|
1590
|
+
const queue = { pending: false, promise: Promise.resolve() };
|
|
1591
|
+
loadQueueRef.current = queue;
|
|
1592
|
+
queue.promise = Promise.resolve().then(async () => {
|
|
1593
|
+
while (loadQueueRef.current === queue) {
|
|
1594
|
+
queue.pending = false;
|
|
1595
|
+
await loadOnce(foreground);
|
|
1596
|
+
foreground = false;
|
|
1597
|
+
if (!queue.pending) break;
|
|
1598
|
+
}
|
|
1599
|
+
if (loadQueueRef.current === queue) loadQueueRef.current = null;
|
|
1600
|
+
}).finally(() => {
|
|
1601
|
+
if (loadQueueRef.current === queue) loadQueueRef.current = null;
|
|
1602
|
+
});
|
|
1603
|
+
return queue.promise;
|
|
1604
|
+
},
|
|
1605
|
+
[loadOnce]
|
|
1606
|
+
);
|
|
1320
1607
|
const refresh = useCallback6(async () => await load(false), [load]);
|
|
1321
1608
|
useEffect6(() => {
|
|
1322
1609
|
mountedRef.current = true;
|
|
@@ -1644,11 +1931,270 @@ function browserKey(event, hostPlatform = interactionHostPlatform()) {
|
|
|
1644
1931
|
return parts.join("+");
|
|
1645
1932
|
}
|
|
1646
1933
|
|
|
1647
|
-
// src/components/browser-
|
|
1934
|
+
// src/components/browser-select-control.tsx
|
|
1935
|
+
import { useEffect as useEffect8, useLayoutEffect, useRef as useRef8, useState as useState8 } from "react";
|
|
1648
1936
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1937
|
+
function focusedSelect(observation) {
|
|
1938
|
+
if (observation.semantic?.kind !== "snapshot") return null;
|
|
1939
|
+
const pending = [...observation.semantic.roots];
|
|
1940
|
+
while (pending.length) {
|
|
1941
|
+
const node = pending.pop();
|
|
1942
|
+
if (node.children) pending.push(...node.children);
|
|
1943
|
+
if (node.ref !== observation.focusedRef || !node.actions.includes("select") || node.native?.platform !== "dom")
|
|
1944
|
+
continue;
|
|
1945
|
+
const data = node.native.data;
|
|
1946
|
+
if (!data || data.kind !== "native-select" || typeof data.multiple !== "boolean" || typeof data.disabled !== "boolean" || !Array.isArray(data.options) || data.options.length > 200)
|
|
1947
|
+
return null;
|
|
1948
|
+
if (data.options.some(
|
|
1949
|
+
(option) => !option || typeof option.value !== "string" || typeof option.label !== "string" || typeof option.selected !== "boolean" || typeof option.disabled !== "boolean"
|
|
1950
|
+
))
|
|
1951
|
+
return null;
|
|
1952
|
+
return { node, control: data };
|
|
1953
|
+
}
|
|
1954
|
+
return null;
|
|
1955
|
+
}
|
|
1956
|
+
function BrowserSelectControl(props) {
|
|
1957
|
+
const [snapshot, setSnapshot] = useState8(null);
|
|
1958
|
+
const [open, setOpen] = useState8(false);
|
|
1959
|
+
const [busy, setBusy] = useState8(false);
|
|
1960
|
+
const [error, setError] = useState8(null);
|
|
1961
|
+
const [values, setValues] = useState8([]);
|
|
1962
|
+
const [anchor, setAnchor] = useState8(null);
|
|
1963
|
+
const popupRef = useRef8(null);
|
|
1964
|
+
const [position, setPosition] = useState8(null);
|
|
1965
|
+
const panelRef = useRef8(null);
|
|
1966
|
+
const request = useRef8(0);
|
|
1967
|
+
const optionKeys = useRef8(/* @__PURE__ */ new WeakMap());
|
|
1968
|
+
const nextOptionKey = useRef8(0);
|
|
1969
|
+
const optionKey = (option) => {
|
|
1970
|
+
let key = optionKeys.current.get(option);
|
|
1971
|
+
if (key === void 0) {
|
|
1972
|
+
key = ++nextOptionKey.current;
|
|
1973
|
+
optionKeys.current.set(option, key);
|
|
1974
|
+
}
|
|
1975
|
+
return key;
|
|
1976
|
+
};
|
|
1977
|
+
useEffect8(
|
|
1978
|
+
() => () => {
|
|
1979
|
+
request.current += 1;
|
|
1980
|
+
},
|
|
1981
|
+
[]
|
|
1982
|
+
);
|
|
1983
|
+
useEffect8(() => {
|
|
1984
|
+
if (props.activation === void 0) return;
|
|
1985
|
+
++request.current;
|
|
1986
|
+
const observation = props.activation?.observation;
|
|
1987
|
+
const selected2 = observation ? focusedSelect(observation) : null;
|
|
1988
|
+
setSnapshot(selected2 && observation ? observation : null);
|
|
1989
|
+
setAnchor(selected2 ? props.activation.anchor : null);
|
|
1990
|
+
setOpen(Boolean(selected2));
|
|
1991
|
+
setBusy(false);
|
|
1992
|
+
setError(null);
|
|
1993
|
+
setValues(
|
|
1994
|
+
selected2?.control.options.filter((option) => option.selected).map((option) => option.value) ?? []
|
|
1995
|
+
);
|
|
1996
|
+
}, [props.activation]);
|
|
1997
|
+
useEffect8(() => {
|
|
1998
|
+
if (open && !busy) panelRef.current?.focus({ preventScroll: true });
|
|
1999
|
+
}, [open, busy]);
|
|
2000
|
+
useLayoutEffect(() => {
|
|
2001
|
+
if (!anchor || !open) {
|
|
2002
|
+
setPosition(null);
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
const place = () => {
|
|
2006
|
+
const popup = popupRef.current;
|
|
2007
|
+
const parent = popup?.parentElement;
|
|
2008
|
+
if (!popup || !parent) return;
|
|
2009
|
+
setPosition({
|
|
2010
|
+
x: Math.max(12, Math.min(anchor.x, parent.clientWidth - popup.offsetWidth - 12)),
|
|
2011
|
+
y: Math.max(12, Math.min(anchor.y, parent.clientHeight - popup.offsetHeight - 12)),
|
|
2012
|
+
height: Math.max(48, parent.clientHeight - 60)
|
|
2013
|
+
});
|
|
2014
|
+
};
|
|
2015
|
+
place();
|
|
2016
|
+
const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(place);
|
|
2017
|
+
if (popupRef.current?.parentElement) observer?.observe(popupRef.current.parentElement);
|
|
2018
|
+
if (popupRef.current) observer?.observe(popupRef.current);
|
|
2019
|
+
return () => observer?.disconnect();
|
|
2020
|
+
}, [anchor, open, busy, snapshot, error]);
|
|
2021
|
+
const selected = snapshot ? focusedSelect(snapshot) : null;
|
|
2022
|
+
const ambiguousValue = (value) => (selected?.control.options.filter((option) => option.value === value || option.label === value).length ?? 0) !== 1;
|
|
2023
|
+
const load = async () => {
|
|
2024
|
+
const current = ++request.current;
|
|
2025
|
+
setOpen(true);
|
|
2026
|
+
setBusy(true);
|
|
2027
|
+
setSnapshot(null);
|
|
2028
|
+
setError(null);
|
|
2029
|
+
setAnchor(null);
|
|
2030
|
+
try {
|
|
2031
|
+
const observation = await props.observe();
|
|
2032
|
+
if (current !== request.current) return;
|
|
2033
|
+
setSnapshot(observation);
|
|
2034
|
+
setValues(
|
|
2035
|
+
focusedSelect(observation)?.control.options.filter((option) => option.selected).map((option) => option.value) ?? []
|
|
2036
|
+
);
|
|
2037
|
+
} catch (cause) {
|
|
2038
|
+
if (current === request.current)
|
|
2039
|
+
setError(cause instanceof Error ? cause.message : "Could not read options.");
|
|
2040
|
+
} finally {
|
|
2041
|
+
if (current === request.current) setBusy(false);
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
const apply = async (next) => {
|
|
2045
|
+
if (!snapshot || !selected || busy) return;
|
|
2046
|
+
const current = ++request.current;
|
|
2047
|
+
setBusy(true);
|
|
2048
|
+
setError(null);
|
|
2049
|
+
try {
|
|
2050
|
+
const receipt = await props.act(
|
|
2051
|
+
{ type: "select", locator: { kind: "ref", ref: selected.node.ref }, values: next },
|
|
2052
|
+
snapshot
|
|
2053
|
+
);
|
|
2054
|
+
if (receipt.state !== "completed")
|
|
2055
|
+
throw new Error(receipt.error?.message ?? "Selection did not complete.");
|
|
2056
|
+
if (current === request.current) {
|
|
2057
|
+
setOpen(false);
|
|
2058
|
+
setSnapshot(null);
|
|
2059
|
+
props.onDismiss?.();
|
|
2060
|
+
}
|
|
2061
|
+
} catch (cause) {
|
|
2062
|
+
if (current === request.current) {
|
|
2063
|
+
setError(
|
|
2064
|
+
cause instanceof Error ? cause.message : "Selection failed. Read the options again."
|
|
2065
|
+
);
|
|
2066
|
+
setSnapshot(null);
|
|
2067
|
+
}
|
|
2068
|
+
} finally {
|
|
2069
|
+
if (current === request.current) setBusy(false);
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
if (props.manualFallback === false && !open) return null;
|
|
2073
|
+
return /* @__PURE__ */ jsxs(
|
|
2074
|
+
"div",
|
|
2075
|
+
{
|
|
2076
|
+
ref: popupRef,
|
|
2077
|
+
className: "absolute z-10 max-w-[calc(100%-1.5rem)] text-og-control",
|
|
2078
|
+
style: anchor && open ? {
|
|
2079
|
+
left: position?.x ?? anchor.x,
|
|
2080
|
+
top: position?.y ?? anchor.y
|
|
2081
|
+
} : { bottom: 12, left: 12 },
|
|
2082
|
+
children: [
|
|
2083
|
+
props.manualFallback !== false && (!anchor || !open) || error ? /* @__PURE__ */ jsx(
|
|
2084
|
+
"button",
|
|
2085
|
+
{
|
|
2086
|
+
type: "button",
|
|
2087
|
+
className: "rounded-og-sm border border-og-border bg-og-bg px-2 py-1 text-og-fg",
|
|
2088
|
+
disabled: busy,
|
|
2089
|
+
onClick: () => void load(),
|
|
2090
|
+
"aria-expanded": open,
|
|
2091
|
+
children: "Choose option"
|
|
2092
|
+
}
|
|
2093
|
+
) : null,
|
|
2094
|
+
open ? /* @__PURE__ */ jsxs(
|
|
2095
|
+
"section",
|
|
2096
|
+
{
|
|
2097
|
+
ref: panelRef,
|
|
2098
|
+
tabIndex: -1,
|
|
2099
|
+
"aria-label": "Page selection options",
|
|
2100
|
+
style: position ? { maxHeight: Math.min(288, position.height) } : void 0,
|
|
2101
|
+
onKeyDown: (event) => {
|
|
2102
|
+
if (event.key !== "Escape") return;
|
|
2103
|
+
event.preventDefault();
|
|
2104
|
+
event.stopPropagation();
|
|
2105
|
+
++request.current;
|
|
2106
|
+
setOpen(false);
|
|
2107
|
+
setSnapshot(null);
|
|
2108
|
+
setBusy(false);
|
|
2109
|
+
props.onDismiss?.();
|
|
2110
|
+
},
|
|
2111
|
+
className: "mt-1 max-h-72 w-72 max-w-full overflow-auto rounded-og-sm border border-og-border bg-og-bg p-3 text-og-fg shadow-lg",
|
|
2112
|
+
children: [
|
|
2113
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2114
|
+
/* @__PURE__ */ jsx("strong", { children: selected?.node.name || "Page options" }),
|
|
2115
|
+
/* @__PURE__ */ jsx(
|
|
2116
|
+
"button",
|
|
2117
|
+
{
|
|
2118
|
+
type: "button",
|
|
2119
|
+
disabled: busy,
|
|
2120
|
+
onClick: () => {
|
|
2121
|
+
++request.current;
|
|
2122
|
+
setOpen(false);
|
|
2123
|
+
setSnapshot(null);
|
|
2124
|
+
props.onDismiss?.();
|
|
2125
|
+
},
|
|
2126
|
+
"aria-label": "Close page options",
|
|
2127
|
+
children: "Close"
|
|
2128
|
+
}
|
|
2129
|
+
)
|
|
2130
|
+
] }),
|
|
2131
|
+
busy ? /* @__PURE__ */ jsx("p", { role: "status", children: "Loading\u2026" }) : error ? /* @__PURE__ */ jsx("p", { role: "alert", children: error }) : !selected ? /* @__PURE__ */ jsx("p", { children: "Click a dropdown in the page, then choose \u201CChoose option\u201D." }) : selected.control.disabled ? /* @__PURE__ */ jsx("p", { children: "This control is disabled." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2132
|
+
selected.control.options.map((option) => {
|
|
2133
|
+
const ambiguous = ambiguousValue(option.value);
|
|
2134
|
+
const disabled = busy || option.disabled || ambiguous;
|
|
2135
|
+
return selected.control.multiple ? /* @__PURE__ */ jsxs("label", { className: "my-1 flex items-center gap-2", children: [
|
|
2136
|
+
/* @__PURE__ */ jsx(
|
|
2137
|
+
"input",
|
|
2138
|
+
{
|
|
2139
|
+
type: "checkbox",
|
|
2140
|
+
disabled,
|
|
2141
|
+
checked: values.includes(option.value),
|
|
2142
|
+
onChange: (event) => setValues(
|
|
2143
|
+
event.target.checked ? [...values, option.value] : values.filter((value) => value !== option.value)
|
|
2144
|
+
)
|
|
2145
|
+
}
|
|
2146
|
+
),
|
|
2147
|
+
option.label || "(empty)",
|
|
2148
|
+
ambiguous ? " (ambiguous value)" : ""
|
|
2149
|
+
] }, optionKey(option)) : /* @__PURE__ */ jsxs(
|
|
2150
|
+
"button",
|
|
2151
|
+
{
|
|
2152
|
+
type: "button",
|
|
2153
|
+
disabled,
|
|
2154
|
+
"aria-pressed": option.selected,
|
|
2155
|
+
className: "my-1 block w-full rounded-og-sm border border-og-border px-2 py-1 text-left disabled:opacity-50",
|
|
2156
|
+
onClick: () => void apply([option.value]),
|
|
2157
|
+
children: [
|
|
2158
|
+
option.label || "(empty)",
|
|
2159
|
+
option.selected ? " \u2713" : "",
|
|
2160
|
+
ambiguous ? " (ambiguous value)" : ""
|
|
2161
|
+
]
|
|
2162
|
+
},
|
|
2163
|
+
optionKey(option)
|
|
2164
|
+
);
|
|
2165
|
+
}),
|
|
2166
|
+
selected.control.multiple ? /* @__PURE__ */ jsx(
|
|
2167
|
+
"button",
|
|
2168
|
+
{
|
|
2169
|
+
type: "button",
|
|
2170
|
+
disabled: busy || values.some(ambiguousValue),
|
|
2171
|
+
onClick: () => void apply(values),
|
|
2172
|
+
children: "Apply selection"
|
|
2173
|
+
}
|
|
2174
|
+
) : null
|
|
2175
|
+
] })
|
|
2176
|
+
]
|
|
2177
|
+
}
|
|
2178
|
+
) : null
|
|
2179
|
+
]
|
|
2180
|
+
}
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
// src/components/browser-viewer.tsx
|
|
2185
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2186
|
+
var STALE_BROWSER_END_MAX_ATTEMPTS = 3;
|
|
2187
|
+
var STALE_BROWSER_END_RETRY_BASE_MS = 5e3;
|
|
2188
|
+
function staleBrowserEndRetryDelayMs(cause, failedAttempts) {
|
|
2189
|
+
const status = cause?.status;
|
|
2190
|
+
if (typeof status === "number" && status >= 400 && status < 500) return null;
|
|
2191
|
+
if (failedAttempts >= STALE_BROWSER_END_MAX_ATTEMPTS) return null;
|
|
2192
|
+
return STALE_BROWSER_END_RETRY_BASE_MS * 2 ** (failedAttempts - 1);
|
|
2193
|
+
}
|
|
1649
2194
|
function BrowserViewer({
|
|
1650
2195
|
sessionId,
|
|
1651
2196
|
enabled = true,
|
|
2197
|
+
active = true,
|
|
1652
2198
|
className,
|
|
1653
2199
|
onNotify,
|
|
1654
2200
|
webSocketFactory,
|
|
@@ -1682,9 +2228,10 @@ function BrowserViewer({
|
|
|
1682
2228
|
() => attachedChromeGenerationLoss(registry.sessions),
|
|
1683
2229
|
[registry.sessions]
|
|
1684
2230
|
);
|
|
1685
|
-
const endedGenerationLossRef =
|
|
2231
|
+
const endedGenerationLossRef = useRef9(/* @__PURE__ */ new Set());
|
|
2232
|
+
const endStaleBrowserAttemptsRef = useRef9(/* @__PURE__ */ new Map());
|
|
1686
2233
|
const endStaleBrowser = registry.end;
|
|
1687
|
-
|
|
2234
|
+
useEffect9(() => {
|
|
1688
2235
|
if (!enabled) return;
|
|
1689
2236
|
for (const session of registry.sessions) {
|
|
1690
2237
|
if (session.lifecycle !== "lost" || session.failureCode !== "controller_transition_expired" || session.placement.kind !== "attached_device") {
|
|
@@ -1692,20 +2239,22 @@ function BrowserViewer({
|
|
|
1692
2239
|
}
|
|
1693
2240
|
if (endedGenerationLossRef.current.has(session.id)) continue;
|
|
1694
2241
|
endedGenerationLossRef.current.add(session.id);
|
|
1695
|
-
void endStaleBrowser(session.id).catch(() => {
|
|
1696
|
-
|
|
2242
|
+
void endStaleBrowser(session.id).catch((cause) => {
|
|
2243
|
+
const attempts = (endStaleBrowserAttemptsRef.current.get(session.id) ?? 0) + 1;
|
|
2244
|
+
endStaleBrowserAttemptsRef.current.set(session.id, attempts);
|
|
2245
|
+
const delay = staleBrowserEndRetryDelayMs(cause, attempts);
|
|
2246
|
+
if (delay === null) return;
|
|
2247
|
+
setTimeout(() => endedGenerationLossRef.current.delete(session.id), delay);
|
|
1697
2248
|
});
|
|
1698
2249
|
}
|
|
1699
2250
|
}, [enabled, endStaleBrowser, registry.sessions]);
|
|
1700
|
-
const replacementChromeDevice = useMemo2(() => {
|
|
1701
|
-
if (!attachedGenerationLoss) return null;
|
|
1702
|
-
return attached.devices.find((candidate) => candidate.id === attachedGenerationLoss.deviceId) ?? null;
|
|
1703
|
-
}, [attached.devices, attachedGenerationLoss]);
|
|
1704
2251
|
const relevant = useMemo2(
|
|
1705
2252
|
() => registry.relevantSessions.filter((session) => isLiveBrowser2(session)),
|
|
1706
2253
|
[registry.relevantSessions]
|
|
1707
2254
|
);
|
|
1708
|
-
const
|
|
2255
|
+
const latestRelevantBrowser = registry.relevantSessions[0];
|
|
2256
|
+
const unavailableBrowser = latestRelevantBrowser?.lifecycle === "lost" || latestRelevantBrowser?.lifecycle === "failed" ? latestRelevantBrowser : void 0;
|
|
2257
|
+
const [selection, setSelection] = useState9(
|
|
1709
2258
|
() => initialBrowserSessionId ? { sessionId: initialBrowserSessionId, pinned: true } : null
|
|
1710
2259
|
);
|
|
1711
2260
|
const selectBrowserSession = useCallback8(
|
|
@@ -1720,16 +2269,17 @@ function BrowserViewer({
|
|
|
1720
2269
|
enabled,
|
|
1721
2270
|
resourceKind: "browser_session"
|
|
1722
2271
|
});
|
|
1723
|
-
const [creating, setCreating] =
|
|
1724
|
-
const [savingProfile, setSavingProfile] =
|
|
1725
|
-
const [baseRevisionOrdinal, setBaseRevisionOrdinal] =
|
|
1726
|
-
const [profileHistory, setProfileHistory] =
|
|
1727
|
-
const [resumeAttempt, setResumeAttempt] =
|
|
1728
|
-
const resumeAttemptsRef =
|
|
1729
|
-
const previousSessionIdRef =
|
|
1730
|
-
const seenInterventionIdsRef =
|
|
1731
|
-
const diagnosticRequestRef =
|
|
1732
|
-
const
|
|
2272
|
+
const [creating, setCreating] = useState9(false);
|
|
2273
|
+
const [savingProfile, setSavingProfile] = useState9(false);
|
|
2274
|
+
const [baseRevisionOrdinal, setBaseRevisionOrdinal] = useState9(null);
|
|
2275
|
+
const [profileHistory, setProfileHistory] = useState9(null);
|
|
2276
|
+
const [resumeAttempt, setResumeAttempt] = useState9(null);
|
|
2277
|
+
const resumeAttemptsRef = useRef9(/* @__PURE__ */ new Map());
|
|
2278
|
+
const previousSessionIdRef = useRef9(sessionId);
|
|
2279
|
+
const seenInterventionIdsRef = useRef9(/* @__PURE__ */ new Set());
|
|
2280
|
+
const diagnosticRequestRef = useRef9(0);
|
|
2281
|
+
const viewportFocusHandoffRef = useRef9(null);
|
|
2282
|
+
const [diagnosticsView, setDiagnosticsView] = useState9(null);
|
|
1733
2283
|
const notifyError = useCallback8(
|
|
1734
2284
|
(cause, fallback) => {
|
|
1735
2285
|
const message = cause instanceof Error ? cause.message : fallback;
|
|
@@ -1737,7 +2287,7 @@ function BrowserViewer({
|
|
|
1737
2287
|
},
|
|
1738
2288
|
[onNotify]
|
|
1739
2289
|
);
|
|
1740
|
-
|
|
2290
|
+
useEffect9(() => {
|
|
1741
2291
|
if (previousSessionIdRef.current !== sessionId) {
|
|
1742
2292
|
previousSessionIdRef.current = sessionId;
|
|
1743
2293
|
setSelection(
|
|
@@ -1745,7 +2295,7 @@ function BrowserViewer({
|
|
|
1745
2295
|
);
|
|
1746
2296
|
}
|
|
1747
2297
|
}, [initialBrowserSessionId, sessionId]);
|
|
1748
|
-
|
|
2298
|
+
useEffect9(() => {
|
|
1749
2299
|
if (!enabled || registry.loading) return;
|
|
1750
2300
|
const selectedStillLive = liveSessions.some((session) => session.id === selection?.sessionId);
|
|
1751
2301
|
if (selection?.pinned && selectedStillLive) return;
|
|
@@ -1776,6 +2326,7 @@ function BrowserViewer({
|
|
|
1776
2326
|
);
|
|
1777
2327
|
const controllerReady = selectedRegistrySession?.lifecycle === "active";
|
|
1778
2328
|
const resumeSession = registry.resume;
|
|
2329
|
+
const [hasLiveFrame, setHasLiveFrame] = useState9(false);
|
|
1779
2330
|
const wakeBrowser = useCallback8(
|
|
1780
2331
|
async (session, retry = false) => {
|
|
1781
2332
|
const current = resumeAttemptsRef.current.get(session.id);
|
|
@@ -1814,25 +2365,22 @@ function BrowserViewer({
|
|
|
1814
2365
|
},
|
|
1815
2366
|
[notifyError, resumeSession]
|
|
1816
2367
|
);
|
|
1817
|
-
|
|
2368
|
+
useEffect9(() => {
|
|
1818
2369
|
if (!selectedRegistrySession) return;
|
|
1819
2370
|
if (selectedRegistrySession.lifecycle === "active") {
|
|
1820
2371
|
resumeAttemptsRef.current.delete(selectedRegistrySession.id);
|
|
1821
2372
|
setResumeAttempt(
|
|
1822
2373
|
(visible) => visible?.sessionId === selectedRegistrySession.id ? null : visible
|
|
1823
2374
|
);
|
|
1824
|
-
return;
|
|
1825
2375
|
}
|
|
1826
|
-
|
|
1827
|
-
void wakeBrowser(selectedRegistrySession);
|
|
1828
|
-
}
|
|
1829
|
-
}, [selectedRegistrySession, wakeBrowser]);
|
|
2376
|
+
}, [selectedRegistrySession]);
|
|
1830
2377
|
const browser = useBrowserSession({
|
|
1831
2378
|
...override,
|
|
1832
2379
|
browserSessionId: selection?.sessionId ?? null,
|
|
1833
|
-
enabled: enabled && selection !== null && controllerReady
|
|
2380
|
+
enabled: enabled && selection !== null && controllerReady,
|
|
2381
|
+
semanticObservationEnabled: active && !hasLiveFrame
|
|
1834
2382
|
});
|
|
1835
|
-
|
|
2383
|
+
useEffect9(() => {
|
|
1836
2384
|
if (!isSourcePlacementChangedError(browser.error, "browser_session")) return;
|
|
1837
2385
|
void refreshRegistry();
|
|
1838
2386
|
}, [browser.error, refreshRegistry]);
|
|
@@ -1842,7 +2390,7 @@ function BrowserViewer({
|
|
|
1842
2390
|
enabled: enabled && diagnosticsView !== null && controllerReady && browser.session?.capabilities.downloads === true
|
|
1843
2391
|
});
|
|
1844
2392
|
const loadBrowserDiagnostics = browser.diagnostics;
|
|
1845
|
-
|
|
2393
|
+
useEffect9(() => {
|
|
1846
2394
|
for (const intervention of interventions.interventions) {
|
|
1847
2395
|
if (seenInterventionIdsRef.current.has(intervention.id)) continue;
|
|
1848
2396
|
seenInterventionIdsRef.current.add(intervention.id);
|
|
@@ -1874,13 +2422,26 @@ function BrowserViewer({
|
|
|
1874
2422
|
stream: { format: "jpeg", quality: 76, maxWidth: 1920, maxHeight: 1200 },
|
|
1875
2423
|
...webSocketFactory ? { webSocketFactory } : {}
|
|
1876
2424
|
});
|
|
1877
|
-
const
|
|
2425
|
+
const receivedFrame = frameMatchesSelectedTarget(
|
|
1878
2426
|
frames.frame,
|
|
1879
2427
|
browser.session,
|
|
1880
2428
|
browser.selectedTarget
|
|
1881
2429
|
) ? frames.frame : null;
|
|
1882
|
-
const
|
|
1883
|
-
|
|
2430
|
+
const displayedFrame = useMemo2(
|
|
2431
|
+
() => receivedFrame ? { ...receivedFrame, data: receivedFrame.data.slice().buffer } : null,
|
|
2432
|
+
[receivedFrame]
|
|
2433
|
+
);
|
|
2434
|
+
const frameIsLive = frames.state === "live" && displayedFrame !== null;
|
|
2435
|
+
useEffect9(() => {
|
|
2436
|
+
setHasLiveFrame(frameIsLive);
|
|
2437
|
+
}, [frameIsLive]);
|
|
2438
|
+
const supportsLiveFrames = (browser.session ?? selectedRegistrySession)?.capabilities.liveFrames === true;
|
|
2439
|
+
const controlUnavailable = isInteractionControlUnavailable(browser.error);
|
|
2440
|
+
const connectionError = controlUnavailable ? browser.error : frames.error ?? browser.error;
|
|
2441
|
+
const selectedPlacement = (browser.session ?? selectedRegistrySession)?.placement;
|
|
2442
|
+
const selectedChromeGenerationLoss = selectedPlacement?.kind === "attached_device" && isAttachedChromeGenerationLossError(connectionError);
|
|
2443
|
+
const replacementChromeDevice = selectedChromeGenerationLoss && selectedPlacement.kind === "attached_device" ? attached.devices.find((candidate) => candidate.id === selectedPlacement.deviceId) : null;
|
|
2444
|
+
const displayConnectionState = connectionError && (!frameIsLive || controlUnavailable) ? "error" : !browser.session ? "connecting" : supportsLiveFrames ? frames.state === "live" && !displayedFrame ? "connecting" : frames.state : "semantic";
|
|
1884
2445
|
const selectedProfile = useMemo2(
|
|
1885
2446
|
() => profiles.identities.find(
|
|
1886
2447
|
(identity) => identity.id === (browser.session?.identityId ?? selectedRegistrySession?.identityId)
|
|
@@ -1893,7 +2454,7 @@ function BrowserViewer({
|
|
|
1893
2454
|
) : [],
|
|
1894
2455
|
[selectedProfile, siteAuth.connections]
|
|
1895
2456
|
);
|
|
1896
|
-
|
|
2457
|
+
useEffect9(() => {
|
|
1897
2458
|
diagnosticRequestRef.current += 1;
|
|
1898
2459
|
setDiagnosticsView(null);
|
|
1899
2460
|
}, [browser.session?.id, browser.selectedTarget?.id]);
|
|
@@ -1943,7 +2504,7 @@ function BrowserViewer({
|
|
|
1943
2504
|
},
|
|
1944
2505
|
[downloads, onNotify]
|
|
1945
2506
|
);
|
|
1946
|
-
|
|
2507
|
+
useEffect9(() => {
|
|
1947
2508
|
const identityId = browser.session?.identityId ?? selectedRegistrySession?.identityId;
|
|
1948
2509
|
const revisionId = browser.session?.baseRevisionId ?? selectedRegistrySession?.baseRevisionId;
|
|
1949
2510
|
if (!identityId) {
|
|
@@ -2126,26 +2687,29 @@ function BrowserViewer({
|
|
|
2126
2687
|
);
|
|
2127
2688
|
if (!enabled) return null;
|
|
2128
2689
|
if (registry.loading && liveSessions.length === 0) {
|
|
2129
|
-
return /* @__PURE__ */
|
|
2690
|
+
return /* @__PURE__ */ jsx2(
|
|
2130
2691
|
BrowserNotice,
|
|
2131
2692
|
{
|
|
2132
|
-
icon: /* @__PURE__ */
|
|
2693
|
+
icon: /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "animate-spin" }),
|
|
2133
2694
|
text: "Finding browsers\u2026",
|
|
2134
2695
|
...className ? { className } : {}
|
|
2135
2696
|
}
|
|
2136
2697
|
);
|
|
2137
2698
|
}
|
|
2138
2699
|
if (liveSessions.length === 0) {
|
|
2139
|
-
if (renderEmpty
|
|
2140
|
-
|
|
2700
|
+
if (renderEmpty && !unavailableBrowser)
|
|
2701
|
+
return /* @__PURE__ */ jsx2(Fragment2, { children: renderEmpty(() => createBrowser(), creating) });
|
|
2702
|
+
return /* @__PURE__ */ jsx2(
|
|
2141
2703
|
"div",
|
|
2142
2704
|
{
|
|
2143
2705
|
className: cn("flex h-full min-h-0 items-center justify-center bg-og-bg p-6", className),
|
|
2144
|
-
children: /* @__PURE__ */
|
|
2145
|
-
/* @__PURE__ */
|
|
2146
|
-
/* @__PURE__ */
|
|
2147
|
-
|
|
2148
|
-
|
|
2706
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "max-w-sm text-center", children: [
|
|
2707
|
+
/* @__PURE__ */ jsx2("span", { className: "mx-auto grid size-10 place-items-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted", children: /* @__PURE__ */ jsx2(Globe2Icon, { className: "size-4.5" }) }),
|
|
2708
|
+
unavailableBrowser && !attachedGenerationLoss ? /* @__PURE__ */ jsx2(BrowserUnavailableNotice, { session: unavailableBrowser }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2709
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-3 text-og-menu font-medium text-og-fg", children: attachedGenerationLoss ? "Chrome reconnected\u2014open a fresh browser/desktop." : "No browser open" }),
|
|
2710
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-og-control leading-5 text-og-fg-muted", children: attachedGenerationLoss ? "This Chrome profile is live again, but the previous browser cannot move to the new connection. Use Browser \u2192 New browser \u2192 Connected Chrome." : "A browser appears here when this agent\u2014or another agent in the workspace\u2014opens one." })
|
|
2711
|
+
] }),
|
|
2712
|
+
/* @__PURE__ */ jsx2(
|
|
2149
2713
|
BrowserLaunchMenu,
|
|
2150
2714
|
{
|
|
2151
2715
|
attachedBridges: onlineAttachedBridges,
|
|
@@ -2159,17 +2723,17 @@ function BrowserViewer({
|
|
|
2159
2723
|
prominent: true
|
|
2160
2724
|
}
|
|
2161
2725
|
),
|
|
2162
|
-
registry.error ? /* @__PURE__ */
|
|
2726
|
+
registry.error ? /* @__PURE__ */ jsx2("p", { className: "mt-3 text-og-control text-og-danger", children: registry.error.message }) : null
|
|
2163
2727
|
] })
|
|
2164
2728
|
}
|
|
2165
2729
|
);
|
|
2166
2730
|
}
|
|
2167
|
-
return /* @__PURE__ */
|
|
2731
|
+
return /* @__PURE__ */ jsxs2(
|
|
2168
2732
|
"div",
|
|
2169
2733
|
{
|
|
2170
2734
|
className: cn("relative flex h-full min-h-0 flex-col overflow-hidden bg-og-bg", className),
|
|
2171
2735
|
children: [
|
|
2172
|
-
/* @__PURE__ */
|
|
2736
|
+
/* @__PURE__ */ jsx2(
|
|
2173
2737
|
BrowserToolbar,
|
|
2174
2738
|
{
|
|
2175
2739
|
sessions: liveSessions,
|
|
@@ -2199,7 +2763,7 @@ function BrowserViewer({
|
|
|
2199
2763
|
setupUrl: browserExtensionSetupUrl
|
|
2200
2764
|
}
|
|
2201
2765
|
),
|
|
2202
|
-
/* @__PURE__ */
|
|
2766
|
+
/* @__PURE__ */ jsx2(
|
|
2203
2767
|
InteractionInterventionBanner,
|
|
2204
2768
|
{
|
|
2205
2769
|
interventions: selectedInterventions,
|
|
@@ -2209,22 +2773,23 @@ function BrowserViewer({
|
|
|
2209
2773
|
onResolve: resolveIntervention
|
|
2210
2774
|
}
|
|
2211
2775
|
),
|
|
2212
|
-
!selectedRegistrySession ? /* @__PURE__ */
|
|
2776
|
+
!selectedRegistrySession ? /* @__PURE__ */ jsx2(
|
|
2213
2777
|
BrowserUnselectedPanel,
|
|
2214
2778
|
{
|
|
2779
|
+
unavailableBrowser,
|
|
2215
2780
|
peerCount: liveSessions.length,
|
|
2216
2781
|
creating,
|
|
2217
2782
|
onCreate: () => createBrowser()
|
|
2218
2783
|
}
|
|
2219
|
-
) : !controllerReady ? /* @__PURE__ */
|
|
2784
|
+
) : !controllerReady ? /* @__PURE__ */ jsx2(
|
|
2220
2785
|
BrowserLifecyclePanel,
|
|
2221
2786
|
{
|
|
2222
2787
|
session: selectedRegistrySession,
|
|
2223
2788
|
attempt: resumeAttempt?.sessionId === selectedRegistrySession.id ? resumeAttempt.attempt : null,
|
|
2224
2789
|
onResume: () => void wakeBrowser(selectedRegistrySession, true)
|
|
2225
2790
|
}
|
|
2226
|
-
) : /* @__PURE__ */
|
|
2227
|
-
/* @__PURE__ */
|
|
2791
|
+
) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2792
|
+
/* @__PURE__ */ jsx2(
|
|
2228
2793
|
BrowserTabs,
|
|
2229
2794
|
{
|
|
2230
2795
|
targets: browser.targets,
|
|
@@ -2236,12 +2801,28 @@ function BrowserViewer({
|
|
|
2236
2801
|
onOpen: () => void browser.openTarget(HUMAN_BROWSER_HOME_URL).catch((cause) => notifyError(cause, "Could not open a tab."))
|
|
2237
2802
|
}
|
|
2238
2803
|
),
|
|
2239
|
-
/* @__PURE__ */
|
|
2804
|
+
/* @__PURE__ */ jsx2(
|
|
2240
2805
|
BrowserAddressBar,
|
|
2241
2806
|
{
|
|
2242
2807
|
target: browser.selectedTarget,
|
|
2243
2808
|
loading: browser.loading || browser.mutating || savingProfile,
|
|
2244
2809
|
onNavigate: (url) => void browser.act({ type: "navigate", url }).catch((cause) => notifyError(cause, "Could not navigate.")),
|
|
2810
|
+
onHistory: async (direction) => {
|
|
2811
|
+
try {
|
|
2812
|
+
const action = { type: "history", direction };
|
|
2813
|
+
if (receivedFrame) await browser.actFromFrame(action, receivedFrame);
|
|
2814
|
+
else {
|
|
2815
|
+
if (!browser.observation)
|
|
2816
|
+
throw new Error("The browser page is not ready for input.");
|
|
2817
|
+
await browser.actFromObservation(action, browser.observation);
|
|
2818
|
+
}
|
|
2819
|
+
} catch (cause) {
|
|
2820
|
+
notifyError(
|
|
2821
|
+
cause,
|
|
2822
|
+
direction === "back" ? "Could not go back." : "Could not go forward."
|
|
2823
|
+
);
|
|
2824
|
+
}
|
|
2825
|
+
},
|
|
2245
2826
|
onReload: () => {
|
|
2246
2827
|
const url = browser.selectedTarget?.url;
|
|
2247
2828
|
if (url)
|
|
@@ -2249,42 +2830,116 @@ function BrowserViewer({
|
|
|
2249
2830
|
}
|
|
2250
2831
|
}
|
|
2251
2832
|
),
|
|
2252
|
-
/* @__PURE__ */
|
|
2253
|
-
|
|
2833
|
+
browser.inputFailure ? /* @__PURE__ */ jsxs2(
|
|
2834
|
+
"div",
|
|
2254
2835
|
{
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
}
|
|
2275
|
-
} : frames.reconnect,
|
|
2276
|
-
reconnectLabel: (attachedGenerationLoss || isAttachedChromeGenerationLossError(frames.error)) && replacementChromeDevice ? "Open a fresh Connected Chrome" : void 0,
|
|
2277
|
-
reconnectMessage: attachedGenerationLoss || isAttachedChromeGenerationLossError(frames.error) ? "Chrome reconnected\u2014open a fresh browser/desktop." : void 0,
|
|
2278
|
-
onError: (cause) => notifyError(cause, "Browser input failed.")
|
|
2836
|
+
role: "alert",
|
|
2837
|
+
"aria-label": "Browser input status",
|
|
2838
|
+
className: "flex shrink-0 items-center gap-2 border-t border-og-border bg-og-surface-1 px-3 py-2 text-og-xs",
|
|
2839
|
+
children: [
|
|
2840
|
+
/* @__PURE__ */ jsx2(CircleAlertIcon, { className: "size-4 shrink-0 text-og-status-failed" }),
|
|
2841
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
|
|
2842
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium", children: browser.inputFailure.state === "failed" ? "Browser input failed" : "Input result unknown" }),
|
|
2843
|
+
/* @__PURE__ */ jsx2("p", { className: "text-og-fg-subtle", children: browser.inputFailure.error?.message ?? "Inspect the page before continuing." })
|
|
2844
|
+
] }),
|
|
2845
|
+
/* @__PURE__ */ jsx2(
|
|
2846
|
+
"button",
|
|
2847
|
+
{
|
|
2848
|
+
type: "button",
|
|
2849
|
+
onClick: () => void browser.refresh(),
|
|
2850
|
+
className: "shrink-0 rounded border border-og-border px-2 py-1 transition hover:bg-og-surface-2",
|
|
2851
|
+
children: "Check browser"
|
|
2852
|
+
}
|
|
2853
|
+
)
|
|
2854
|
+
]
|
|
2279
2855
|
}
|
|
2280
|
-
),
|
|
2281
|
-
/* @__PURE__ */
|
|
2856
|
+
) : null,
|
|
2857
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative flex min-h-0 min-w-0 flex-1 overflow-hidden", children: [
|
|
2858
|
+
/* @__PURE__ */ jsx2(
|
|
2859
|
+
BrowserViewport,
|
|
2860
|
+
{
|
|
2861
|
+
focusHandoffRef: viewportFocusHandoffRef,
|
|
2862
|
+
focusScope: JSON.stringify([
|
|
2863
|
+
selection?.sessionId,
|
|
2864
|
+
browser.selectedTarget?.id,
|
|
2865
|
+
browser.selectedTarget?.targetGeneration
|
|
2866
|
+
]),
|
|
2867
|
+
frame: displayedFrame,
|
|
2868
|
+
connectionState: displayConnectionState,
|
|
2869
|
+
supportsLiveFrames,
|
|
2870
|
+
connectionError,
|
|
2871
|
+
controlUnavailable,
|
|
2872
|
+
observation: browser.observation,
|
|
2873
|
+
mutating: browser.mutating || savingProfile,
|
|
2874
|
+
activityLabel: savingProfile ? "Saving browser version\u2026" : void 0,
|
|
2875
|
+
clipboardEnabled: browser.session?.capabilities.clipboard === true,
|
|
2876
|
+
inputBatchAttachment: frames.attachment,
|
|
2877
|
+
onAction: async (action, frame) => {
|
|
2878
|
+
const focusedInput = frame && action.type === "pointer" && action.action === "click" && (action.button === void 0 || action.button === "left") && frames.attachment?.focusedInputObservations === true && frames.attachment.browserSessionId === frame.browserSessionId && frames.attachment.controllerGeneration === frame.controllerGeneration && frames.attachment.targetId === frame.targetId && Date.parse(frames.attachment.expiresAt) > Date.now();
|
|
2879
|
+
const receipt = frame ? await browser.actFromFrame(
|
|
2880
|
+
action,
|
|
2881
|
+
frame,
|
|
2882
|
+
void 0,
|
|
2883
|
+
focusedInput ? "input" : "none"
|
|
2884
|
+
) : await browser.act(action);
|
|
2885
|
+
if (receipt.state !== "completed") {
|
|
2886
|
+
throw new Error(receipt.error?.message ?? "Browser input did not complete.");
|
|
2887
|
+
}
|
|
2888
|
+
return receipt;
|
|
2889
|
+
},
|
|
2890
|
+
onReadClipboard: browser.readClipboard,
|
|
2891
|
+
onObserveForInput: browser.observeForInput,
|
|
2892
|
+
onSelectFromObservation: browser.actFromObservation,
|
|
2893
|
+
onReconnect: selectedChromeGenerationLoss ? () => {
|
|
2894
|
+
if (replacementChromeDevice) {
|
|
2895
|
+
createBrowser({ kind: "attached", device: replacementChromeDevice });
|
|
2896
|
+
}
|
|
2897
|
+
} : () => {
|
|
2898
|
+
void browser.refresh();
|
|
2899
|
+
frames.reconnect();
|
|
2900
|
+
},
|
|
2901
|
+
reconnectLabel: selectedChromeGenerationLoss && replacementChromeDevice ? "Open a fresh Connected Chrome" : void 0,
|
|
2902
|
+
reconnectMessage: selectedChromeGenerationLoss ? "Chrome reconnected\u2014open a fresh browser/desktop." : void 0,
|
|
2903
|
+
onError: (cause) => notifyError(cause, "Browser input failed.")
|
|
2904
|
+
},
|
|
2905
|
+
JSON.stringify([
|
|
2906
|
+
selection?.sessionId,
|
|
2907
|
+
browser.selectedTarget?.id,
|
|
2908
|
+
browser.selectedTarget?.targetGeneration,
|
|
2909
|
+
browser.selectedTarget?.documentGeneration,
|
|
2910
|
+
frames.attachment?.controllerGeneration
|
|
2911
|
+
])
|
|
2912
|
+
),
|
|
2913
|
+
diagnosticsView ? /* @__PURE__ */ jsx2(
|
|
2914
|
+
BrowserDiagnosticsDrawer,
|
|
2915
|
+
{
|
|
2916
|
+
session: browser.session,
|
|
2917
|
+
profile: selectedProfile,
|
|
2918
|
+
target: browser.selectedTarget,
|
|
2919
|
+
observation: browser.observation,
|
|
2920
|
+
baseRevisionOrdinal,
|
|
2921
|
+
state: diagnosticsView,
|
|
2922
|
+
downloads: downloads.downloads,
|
|
2923
|
+
downloadsEnabled: browser.session?.capabilities.downloads === true,
|
|
2924
|
+
downloadsLoading: downloads.loading,
|
|
2925
|
+
downloadsRefreshing: downloads.refreshing,
|
|
2926
|
+
downloadsError: downloads.error,
|
|
2927
|
+
savingDownloadIds: downloads.savingDownloadIds,
|
|
2928
|
+
onSaveDownload: saveDownload,
|
|
2929
|
+
onRefreshDownloads: () => void downloads.refresh(),
|
|
2930
|
+
onRefresh: refreshDiagnostics,
|
|
2931
|
+
onClose: closeDiagnostics
|
|
2932
|
+
}
|
|
2933
|
+
) : null
|
|
2934
|
+
] }),
|
|
2935
|
+
/* @__PURE__ */ jsx2(
|
|
2282
2936
|
BrowserStatusBar,
|
|
2283
2937
|
{
|
|
2284
2938
|
session: browser.session,
|
|
2285
2939
|
profile: selectedProfile,
|
|
2286
2940
|
target: browser.selectedTarget,
|
|
2287
2941
|
observation: browser.observation,
|
|
2942
|
+
inputFailure: browser.inputFailure,
|
|
2288
2943
|
connectionState: displayConnectionState,
|
|
2289
2944
|
refreshing: registry.refreshing,
|
|
2290
2945
|
diagnosticsOpen: diagnosticsView !== null,
|
|
@@ -2295,28 +2950,7 @@ function BrowserViewer({
|
|
|
2295
2950
|
onDiagnostics: diagnosticsView ? closeDiagnostics : loadDiagnostics
|
|
2296
2951
|
}
|
|
2297
2952
|
)
|
|
2298
|
-
] })
|
|
2299
|
-
diagnosticsView ? /* @__PURE__ */ jsx(
|
|
2300
|
-
BrowserDiagnosticsDrawer,
|
|
2301
|
-
{
|
|
2302
|
-
session: browser.session,
|
|
2303
|
-
profile: selectedProfile,
|
|
2304
|
-
target: browser.selectedTarget,
|
|
2305
|
-
observation: browser.observation,
|
|
2306
|
-
baseRevisionOrdinal,
|
|
2307
|
-
state: diagnosticsView,
|
|
2308
|
-
downloads: downloads.downloads,
|
|
2309
|
-
downloadsEnabled: browser.session?.capabilities.downloads === true,
|
|
2310
|
-
downloadsLoading: downloads.loading,
|
|
2311
|
-
downloadsRefreshing: downloads.refreshing,
|
|
2312
|
-
downloadsError: downloads.error,
|
|
2313
|
-
savingDownloadIds: downloads.savingDownloadIds,
|
|
2314
|
-
onSaveDownload: saveDownload,
|
|
2315
|
-
onRefreshDownloads: () => void downloads.refresh(),
|
|
2316
|
-
onRefresh: refreshDiagnostics,
|
|
2317
|
-
onClose: closeDiagnostics
|
|
2318
|
-
}
|
|
2319
|
-
) : null
|
|
2953
|
+
] })
|
|
2320
2954
|
]
|
|
2321
2955
|
}
|
|
2322
2956
|
);
|
|
@@ -2325,23 +2959,23 @@ function BrowserLifecyclePanel(props) {
|
|
|
2325
2959
|
const failed = props.attempt?.error ?? null;
|
|
2326
2960
|
const label = failed ? "Browser could not reopen" : props.session.lifecycle === "suspending" ? "Saving browser state\u2026" : props.session.lifecycle === "restoring" || props.attempt?.running ? "Opening browser\u2026" : props.session.lifecycle === "starting" ? "Starting browser\u2026" : "Browser is sleeping";
|
|
2327
2961
|
const detail = failed ? failed.message : props.session.lifecycle === "suspended" ? "Its private state is saved. Opening it creates a fresh, isolated browser process." : "The browser will reconnect here when it is ready.";
|
|
2328
|
-
return /* @__PURE__ */
|
|
2329
|
-
/* @__PURE__ */
|
|
2330
|
-
/* @__PURE__ */
|
|
2331
|
-
/* @__PURE__ */
|
|
2332
|
-
failed || props.session.lifecycle === "suspended" && !props.attempt?.running ? /* @__PURE__ */
|
|
2962
|
+
return /* @__PURE__ */ jsx2("div", { className: "grid min-h-0 flex-1 place-items-center bg-og-bg p-6 text-center", children: /* @__PURE__ */ jsxs2("div", { className: "max-w-sm", children: [
|
|
2963
|
+
/* @__PURE__ */ jsx2("span", { className: "mx-auto grid size-10 place-items-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted", children: failed ? /* @__PURE__ */ jsx2(CircleAlertIcon, { className: "size-4.5 text-og-danger" }) : /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-4.5 animate-spin" }) }),
|
|
2964
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-3 text-og-menu font-medium text-og-fg", children: label }),
|
|
2965
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-og-control leading-5 text-og-fg-muted", children: detail }),
|
|
2966
|
+
failed || props.session.lifecycle === "suspended" && !props.attempt?.running ? /* @__PURE__ */ jsx2(
|
|
2333
2967
|
"button",
|
|
2334
2968
|
{
|
|
2335
2969
|
type: "button",
|
|
2336
2970
|
onClick: props.onResume,
|
|
2337
|
-
className: "mt-4 inline-flex h-8 items-center rounded-og-sm border border-og-border bg-og-
|
|
2971
|
+
className: "mt-4 inline-flex h-8 items-center rounded-og-sm border border-og-primary-border bg-og-primary px-3 text-og-control font-medium text-og-primary-fg transition hover:bg-og-primary-hover",
|
|
2338
2972
|
children: "Open browser"
|
|
2339
2973
|
}
|
|
2340
2974
|
) : null
|
|
2341
2975
|
] }) });
|
|
2342
2976
|
}
|
|
2343
2977
|
function BrowserToolbar(props) {
|
|
2344
|
-
const detailsRef =
|
|
2978
|
+
const detailsRef = useViewerMenuDismiss();
|
|
2345
2979
|
const selected = props.sessions.find((session) => session.id === props.selectedSessionId);
|
|
2346
2980
|
const current = props.sessions.filter((session) => props.relevantSessionIds.has(session.id));
|
|
2347
2981
|
const others = props.sessions.filter((session) => !props.relevantSessionIds.has(session.id));
|
|
@@ -2349,48 +2983,50 @@ function BrowserToolbar(props) {
|
|
|
2349
2983
|
props.onSelect(id);
|
|
2350
2984
|
detailsRef.current?.removeAttribute("open");
|
|
2351
2985
|
};
|
|
2352
|
-
return /* @__PURE__ */
|
|
2353
|
-
/* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2355
|
-
/* @__PURE__ */
|
|
2356
|
-
/* @__PURE__ */
|
|
2357
|
-
(props.interventionCounts.get(selected?.id ?? "") ?? 0) > 0 ? /* @__PURE__ */
|
|
2358
|
-
/* @__PURE__ */
|
|
2986
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex h-10 shrink-0 items-center gap-1.5 border-b border-og-border bg-og-surface-1 px-2", children: [
|
|
2987
|
+
/* @__PURE__ */ jsxs2("details", { ref: detailsRef, className: "min-w-0", children: [
|
|
2988
|
+
/* @__PURE__ */ jsxs2("summary", { className: "flex h-7 max-w-52 cursor-pointer list-none items-center gap-2 rounded-og-sm px-2 text-og-control text-og-fg transition hover:bg-og-surface-2 [&::-webkit-details-marker]:hidden", children: [
|
|
2989
|
+
/* @__PURE__ */ jsx2(Globe2Icon, { className: "size-3.5 shrink-0 text-og-fg-muted" }),
|
|
2990
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate font-medium", children: selected?.name ?? "Browser" }),
|
|
2991
|
+
(props.interventionCounts.get(selected?.id ?? "") ?? 0) > 0 ? /* @__PURE__ */ jsx2("span", { className: "size-1.5 shrink-0 rounded-full bg-og-status-waiting" }) : null,
|
|
2992
|
+
/* @__PURE__ */ jsx2(ChevronDownIcon, { className: "size-3 shrink-0 text-og-fg-subtle" })
|
|
2359
2993
|
] }),
|
|
2360
|
-
/* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2994
|
+
/* @__PURE__ */ jsxs2("div", { className: "absolute left-2 top-10 z-30 flex max-h-[calc(100%-3rem)] w-72 max-w-[calc(100%-1rem)] flex-col overflow-hidden rounded-og-md border border-og-border bg-og-surface-1 p-1 shadow-xl", children: [
|
|
2995
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-h-0 max-h-96 overflow-y-auto overscroll-contain", children: [
|
|
2996
|
+
/* @__PURE__ */ jsx2(
|
|
2997
|
+
BrowserSessionGroup,
|
|
2998
|
+
{
|
|
2999
|
+
label: "Current agent",
|
|
3000
|
+
sessions: current,
|
|
3001
|
+
identities: props.identities,
|
|
3002
|
+
selectedId: props.selectedSessionId,
|
|
3003
|
+
interventionCounts: props.interventionCounts,
|
|
3004
|
+
onSelect: choose
|
|
3005
|
+
}
|
|
3006
|
+
),
|
|
3007
|
+
/* @__PURE__ */ jsx2(
|
|
3008
|
+
BrowserSessionGroup,
|
|
3009
|
+
{
|
|
3010
|
+
label: "Workspace browsers",
|
|
3011
|
+
sessions: others,
|
|
3012
|
+
identities: props.identities,
|
|
3013
|
+
selectedId: props.selectedSessionId,
|
|
3014
|
+
interventionCounts: props.interventionCounts,
|
|
3015
|
+
onSelect: choose
|
|
3016
|
+
}
|
|
3017
|
+
)
|
|
3018
|
+
] }),
|
|
3019
|
+
/* @__PURE__ */ jsxs2("div", { className: "mt-1 flex shrink-0 gap-1 border-t border-og-border pt-1", children: [
|
|
3020
|
+
current.length > 0 ? /* @__PURE__ */ jsx2(MenuButton, { onClick: props.onFollow, children: "Follow agent" }) : null,
|
|
3021
|
+
/* @__PURE__ */ jsxs2(MenuButton, { onClick: () => props.onCreate(), disabled: props.creating, children: [
|
|
3022
|
+
/* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5" }),
|
|
2387
3023
|
" New browser"
|
|
2388
3024
|
] })
|
|
2389
3025
|
] })
|
|
2390
3026
|
] })
|
|
2391
3027
|
] }),
|
|
2392
|
-
/* @__PURE__ */
|
|
2393
|
-
/* @__PURE__ */
|
|
3028
|
+
/* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate text-og-xs text-og-fg-subtle", children: placementLabel(selected) }),
|
|
3029
|
+
/* @__PURE__ */ jsx2(
|
|
2394
3030
|
BrowserProfileMenu,
|
|
2395
3031
|
{
|
|
2396
3032
|
session: selected ?? null,
|
|
@@ -2404,17 +3040,17 @@ function BrowserToolbar(props) {
|
|
|
2404
3040
|
onOpenVersion: props.onOpenProfileVersion
|
|
2405
3041
|
}
|
|
2406
3042
|
),
|
|
2407
|
-
/* @__PURE__ */
|
|
3043
|
+
/* @__PURE__ */ jsx2(
|
|
2408
3044
|
"button",
|
|
2409
3045
|
{
|
|
2410
3046
|
type: "button",
|
|
2411
3047
|
onClick: props.onRefresh,
|
|
2412
|
-
className: "grid size-7 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg",
|
|
3048
|
+
className: "grid size-7 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg",
|
|
2413
3049
|
"aria-label": "Refresh browsers",
|
|
2414
|
-
children: /* @__PURE__ */
|
|
3050
|
+
children: /* @__PURE__ */ jsx2(RefreshCwIcon, { className: cn("size-3.5", props.refreshing && "animate-spin") })
|
|
2415
3051
|
}
|
|
2416
3052
|
),
|
|
2417
|
-
/* @__PURE__ */
|
|
3053
|
+
/* @__PURE__ */ jsx2(
|
|
2418
3054
|
BrowserLaunchMenu,
|
|
2419
3055
|
{
|
|
2420
3056
|
attachedBridges: props.attachedBridges,
|
|
@@ -2430,43 +3066,57 @@ function BrowserToolbar(props) {
|
|
|
2430
3066
|
] });
|
|
2431
3067
|
}
|
|
2432
3068
|
function BrowserUnselectedPanel(props) {
|
|
2433
|
-
return /* @__PURE__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2435
|
-
/* @__PURE__ */
|
|
2436
|
-
/* @__PURE__ */
|
|
2437
|
-
/* @__PURE__ */
|
|
3069
|
+
return /* @__PURE__ */ jsx2("div", { className: "grid min-h-0 flex-1 place-items-center bg-og-bg p-6 text-center", children: /* @__PURE__ */ jsxs2("div", { className: "max-w-sm", children: [
|
|
3070
|
+
/* @__PURE__ */ jsx2("span", { className: "mx-auto grid size-10 place-items-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted", children: /* @__PURE__ */ jsx2(Globe2Icon, { className: "size-4.5" }) }),
|
|
3071
|
+
props.unavailableBrowser ? /* @__PURE__ */ jsx2(BrowserUnavailableNotice, { session: props.unavailableBrowser }) : /* @__PURE__ */ jsx2("p", { className: "mt-3 text-og-menu font-medium text-og-fg", children: "No browser for this agent" }),
|
|
3072
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-og-control leading-5 text-og-fg-muted", children: props.peerCount === 1 ? "One workspace browser is available from the browser menu." : `${props.peerCount} workspace browsers are available from the browser menu.` }),
|
|
3073
|
+
/* @__PURE__ */ jsxs2(
|
|
2438
3074
|
"button",
|
|
2439
3075
|
{
|
|
2440
3076
|
type: "button",
|
|
2441
3077
|
disabled: props.creating,
|
|
2442
3078
|
onClick: props.onCreate,
|
|
2443
|
-
className: "mt-4 inline-flex h-8 items-center gap-1.5 rounded-og-sm border border-og-border bg-og-
|
|
3079
|
+
className: "mt-4 inline-flex h-8 items-center gap-1.5 rounded-og-sm border border-og-primary-border bg-og-primary px-3 text-og-control font-medium text-og-primary-fg transition hover:bg-og-primary-hover disabled:cursor-not-allowed disabled:opacity-50",
|
|
2444
3080
|
children: [
|
|
2445
|
-
/* @__PURE__ */
|
|
3081
|
+
/* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5" }),
|
|
2446
3082
|
props.creating ? "Opening\u2026" : "New browser"
|
|
2447
3083
|
]
|
|
2448
3084
|
}
|
|
2449
3085
|
)
|
|
2450
3086
|
] }) });
|
|
2451
3087
|
}
|
|
3088
|
+
function BrowserUnavailableNotice({ session }) {
|
|
3089
|
+
const reason = session.failureCode === "provider_deadline_rotation" ? "The computer running it reached its time limit." : session.failureCode === "source_placement_changed" ? "This chat moved to another computer." : session.failureCode === "idle_released" ? "It stopped after it went unused." : session.lifecycle === "failed" ? "It stopped unexpectedly." : "The connection to it was lost.";
|
|
3090
|
+
return /* @__PURE__ */ jsxs2("div", { role: "status", children: [
|
|
3091
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-3 text-og-menu font-medium text-og-fg", children: "Browser unavailable" }),
|
|
3092
|
+
/* @__PURE__ */ jsxs2("p", { className: "mt-1 break-words text-og-control leading-5 text-og-fg-muted", children: [
|
|
3093
|
+
session.name,
|
|
3094
|
+
". ",
|
|
3095
|
+
reason,
|
|
3096
|
+
" Open a new browser to continue."
|
|
3097
|
+
] })
|
|
3098
|
+
] });
|
|
3099
|
+
}
|
|
2452
3100
|
function BrowserSessionGroup(props) {
|
|
2453
3101
|
if (props.sessions.length === 0) return null;
|
|
2454
|
-
return /* @__PURE__ */
|
|
2455
|
-
/* @__PURE__ */
|
|
3102
|
+
return /* @__PURE__ */ jsxs2("div", { className: "py-1", children: [
|
|
3103
|
+
/* @__PURE__ */ jsx2("p", { className: "px-2 pb-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-fg-subtle", children: props.label }),
|
|
2456
3104
|
props.sessions.map((session) => {
|
|
2457
3105
|
const identity = props.identities.find((candidate) => candidate.id === session.identityId);
|
|
2458
3106
|
const interventionCount = props.interventionCounts.get(session.id) ?? 0;
|
|
2459
|
-
return /* @__PURE__ */
|
|
3107
|
+
return /* @__PURE__ */ jsxs2(
|
|
2460
3108
|
"button",
|
|
2461
3109
|
{
|
|
2462
3110
|
type: "button",
|
|
3111
|
+
"aria-label": `${session.name}${identity ? ` \xB7 ${identity.name}` : ""} \xB7 ${placementLabel(session)}`,
|
|
3112
|
+
"aria-pressed": session.id === props.selectedId,
|
|
2463
3113
|
onClick: () => props.onSelect(session.id),
|
|
2464
3114
|
className: cn(
|
|
2465
3115
|
"flex w-full items-center gap-2 rounded-og-sm px-2 py-1.5 text-left transition hover:bg-og-surface-2",
|
|
2466
3116
|
session.id === props.selectedId && "bg-og-surface-2"
|
|
2467
3117
|
),
|
|
2468
3118
|
children: [
|
|
2469
|
-
/* @__PURE__ */
|
|
3119
|
+
/* @__PURE__ */ jsx2(
|
|
2470
3120
|
"span",
|
|
2471
3121
|
{
|
|
2472
3122
|
className: cn(
|
|
@@ -2475,14 +3125,14 @@ function BrowserSessionGroup(props) {
|
|
|
2475
3125
|
)
|
|
2476
3126
|
}
|
|
2477
3127
|
),
|
|
2478
|
-
/* @__PURE__ */
|
|
2479
|
-
/* @__PURE__ */
|
|
2480
|
-
/* @__PURE__ */
|
|
3128
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3129
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: session.name }),
|
|
3130
|
+
/* @__PURE__ */ jsxs2("span", { className: "block truncate text-og-xs text-og-fg-subtle", children: [
|
|
2481
3131
|
identity ? `${identity.name} \xB7 ` : "",
|
|
2482
3132
|
placementLabel(session)
|
|
2483
3133
|
] })
|
|
2484
3134
|
] }),
|
|
2485
|
-
interventionCount > 0 ? /* @__PURE__ */
|
|
3135
|
+
interventionCount > 0 ? /* @__PURE__ */ jsx2("span", { className: "rounded-full bg-og-status-waiting/12 px-1.5 py-0.5 text-[10px] font-medium text-og-status-waiting", children: interventionCount }) : null
|
|
2486
3136
|
]
|
|
2487
3137
|
},
|
|
2488
3138
|
session.id
|
|
@@ -2491,7 +3141,7 @@ function BrowserSessionGroup(props) {
|
|
|
2491
3141
|
] });
|
|
2492
3142
|
}
|
|
2493
3143
|
function BrowserLaunchMenu(props) {
|
|
2494
|
-
const detailsRef =
|
|
3144
|
+
const detailsRef = useViewerMenuDismiss();
|
|
2495
3145
|
const choose = (choice) => {
|
|
2496
3146
|
detailsRef.current?.removeAttribute("open");
|
|
2497
3147
|
props.onCreate(choice);
|
|
@@ -2502,47 +3152,47 @@ function BrowserLaunchMenu(props) {
|
|
|
2502
3152
|
const busy = props.creating || props.mutatingProfile;
|
|
2503
3153
|
const activeIdentities = props.identities.filter((identity) => identity.status === "active");
|
|
2504
3154
|
const archivedIdentities = props.identities.filter((identity) => identity.status === "archived");
|
|
2505
|
-
return /* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
3155
|
+
return /* @__PURE__ */ jsxs2("details", { ref: detailsRef, className: cn(props.prominent && "mt-4 inline-block"), children: [
|
|
3156
|
+
/* @__PURE__ */ jsxs2(
|
|
2507
3157
|
"summary",
|
|
2508
3158
|
{
|
|
2509
3159
|
onClick: (event) => {
|
|
2510
3160
|
if (busy) event.preventDefault();
|
|
2511
3161
|
},
|
|
2512
3162
|
className: cn(
|
|
2513
|
-
"cursor-pointer list-none items-center justify-center gap-1.5 text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg [&::-webkit-details-marker]:hidden",
|
|
3163
|
+
"cursor-pointer list-none items-center justify-center gap-1.5 text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg [&::-webkit-details-marker]:hidden",
|
|
2514
3164
|
props.prominent ? "inline-flex h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-3 text-og-control font-medium text-og-fg" : "grid size-7 place-items-center rounded-og-sm",
|
|
2515
3165
|
busy && "pointer-events-none opacity-50"
|
|
2516
3166
|
),
|
|
2517
3167
|
"aria-label": "New browser",
|
|
2518
3168
|
children: [
|
|
2519
|
-
busy ? /* @__PURE__ */
|
|
3169
|
+
busy ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5" }),
|
|
2520
3170
|
props.prominent ? "New browser" : null,
|
|
2521
|
-
props.prominent ? /* @__PURE__ */
|
|
3171
|
+
props.prominent ? /* @__PURE__ */ jsx2(ChevronDownIcon, { className: "size-3" }) : null
|
|
2522
3172
|
]
|
|
2523
3173
|
}
|
|
2524
3174
|
),
|
|
2525
|
-
/* @__PURE__ */
|
|
3175
|
+
/* @__PURE__ */ jsxs2(
|
|
2526
3176
|
"div",
|
|
2527
3177
|
{
|
|
2528
3178
|
className: cn(
|
|
2529
|
-
"absolute z-40 w-72 overflow-
|
|
2530
|
-
props.prominent ? "left-1/2 top-
|
|
3179
|
+
"absolute z-40 max-h-[calc(100%-3rem)] w-72 max-w-[calc(100%-1rem)] overflow-y-auto rounded-og-md border border-og-border bg-og-surface-1 p-1 text-left shadow-xl",
|
|
3180
|
+
props.prominent ? "left-1/2 top-2 -translate-x-1/2" : "right-2 top-10"
|
|
2531
3181
|
),
|
|
2532
3182
|
children: [
|
|
2533
|
-
props.attachedDevices.length > 0 || props.attachedBridges.length > 0 ? /* @__PURE__ */
|
|
2534
|
-
/* @__PURE__ */
|
|
2535
|
-
props.attachedDevices.map((device) => /* @__PURE__ */
|
|
3183
|
+
props.attachedDevices.length > 0 || props.attachedBridges.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "pb-1", children: [
|
|
3184
|
+
/* @__PURE__ */ jsx2("p", { className: "px-2 pb-1 pt-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-fg-subtle", children: "Connected Chrome" }),
|
|
3185
|
+
props.attachedDevices.map((device) => /* @__PURE__ */ jsxs2(
|
|
2536
3186
|
"button",
|
|
2537
3187
|
{
|
|
2538
3188
|
type: "button",
|
|
2539
3189
|
onClick: () => choose({ kind: "attached", device }),
|
|
2540
3190
|
className: "flex w-full items-center gap-2 rounded-og-sm px-2 py-2 text-left transition hover:bg-og-surface-2",
|
|
2541
3191
|
children: [
|
|
2542
|
-
/* @__PURE__ */
|
|
2543
|
-
/* @__PURE__ */
|
|
2544
|
-
/* @__PURE__ */
|
|
2545
|
-
/* @__PURE__ */
|
|
3192
|
+
/* @__PURE__ */ jsx2(MonitorIcon, { className: "size-3.5 shrink-0 text-og-fg-muted" }),
|
|
3193
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3194
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: device.profileLabel ?? device.name }),
|
|
3195
|
+
/* @__PURE__ */ jsxs2("span", { className: "block truncate text-og-xs text-og-fg-subtle", children: [
|
|
2546
3196
|
device.browserName,
|
|
2547
3197
|
" \xB7 ",
|
|
2548
3198
|
device.tabCount,
|
|
@@ -2551,12 +3201,12 @@ function BrowserLaunchMenu(props) {
|
|
|
2551
3201
|
device.tabCount === 1 ? "tab" : "tabs"
|
|
2552
3202
|
] })
|
|
2553
3203
|
] }),
|
|
2554
|
-
/* @__PURE__ */
|
|
3204
|
+
/* @__PURE__ */ jsx2("span", { className: "size-1.5 shrink-0 rounded-full bg-og-status-running" })
|
|
2555
3205
|
]
|
|
2556
3206
|
},
|
|
2557
3207
|
device.id
|
|
2558
3208
|
)),
|
|
2559
|
-
props.attachedBridges.length > 0 ? props.setupUrl ? /* @__PURE__ */
|
|
3209
|
+
props.attachedBridges.length > 0 ? props.setupUrl ? /* @__PURE__ */ jsxs2(
|
|
2560
3210
|
"a",
|
|
2561
3211
|
{
|
|
2562
3212
|
href: props.setupUrl,
|
|
@@ -2565,70 +3215,70 @@ function BrowserLaunchMenu(props) {
|
|
|
2565
3215
|
onClick: () => detailsRef.current?.removeAttribute("open"),
|
|
2566
3216
|
className: "flex w-full items-center gap-2 rounded-og-sm px-2 py-2 text-left transition hover:bg-og-surface-2",
|
|
2567
3217
|
children: [
|
|
2568
|
-
/* @__PURE__ */
|
|
2569
|
-
/* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
3218
|
+
/* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5 shrink-0 text-og-fg-muted" }),
|
|
3219
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3220
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: props.attachedDevices.length > 0 ? "Connect another Chrome profile" : "Connect this Chrome profile" }),
|
|
3221
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-xs text-og-fg-subtle", children: "Machine connected \xB7 Chrome extension missing" })
|
|
2572
3222
|
] })
|
|
2573
3223
|
]
|
|
2574
3224
|
}
|
|
2575
|
-
) : /* @__PURE__ */
|
|
2576
|
-
/* @__PURE__ */
|
|
2577
|
-
/* @__PURE__ */
|
|
2578
|
-
/* @__PURE__ */
|
|
2579
|
-
/* @__PURE__ */
|
|
3225
|
+
) : /* @__PURE__ */ jsxs2("div", { className: "flex w-full items-center gap-2 px-2 py-2 text-left", children: [
|
|
3226
|
+
/* @__PURE__ */ jsx2(MonitorIcon, { className: "size-3.5 shrink-0 text-og-fg-muted" }),
|
|
3227
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3228
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: "Chrome connection ready" }),
|
|
3229
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-xs leading-4 text-og-fg-subtle", children: "Install the Opengeni Browser extension in the profile you want to use." })
|
|
2580
3230
|
] })
|
|
2581
3231
|
] }) : null
|
|
2582
3232
|
] }) : null,
|
|
2583
|
-
/* @__PURE__ */
|
|
3233
|
+
/* @__PURE__ */ jsx2(
|
|
2584
3234
|
"p",
|
|
2585
3235
|
{
|
|
2586
3236
|
className: cn(
|
|
2587
|
-
"px-2 pb-1 pt-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-subtle",
|
|
3237
|
+
"px-2 pb-1 pt-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-fg-subtle",
|
|
2588
3238
|
(props.attachedDevices.length > 0 || props.attachedBridges.length > 0) && "border-t border-og-border"
|
|
2589
3239
|
),
|
|
2590
3240
|
children: "Open isolated browser"
|
|
2591
3241
|
}
|
|
2592
3242
|
),
|
|
2593
|
-
/* @__PURE__ */
|
|
3243
|
+
/* @__PURE__ */ jsxs2(
|
|
2594
3244
|
"button",
|
|
2595
3245
|
{
|
|
2596
3246
|
type: "button",
|
|
2597
3247
|
onClick: () => choose({ kind: "clean" }),
|
|
2598
3248
|
className: "flex w-full items-center gap-2 rounded-og-sm px-2 py-2 text-left transition hover:bg-og-surface-2",
|
|
2599
3249
|
children: [
|
|
2600
|
-
/* @__PURE__ */
|
|
2601
|
-
/* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
2603
|
-
/* @__PURE__ */
|
|
3250
|
+
/* @__PURE__ */ jsx2(Globe2Icon, { className: "size-3.5 text-og-fg-muted" }),
|
|
3251
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
3252
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-control text-og-fg", children: "Fresh browser" }),
|
|
3253
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-xs text-og-fg-subtle", children: "Visual browser \xB7 no saved state" })
|
|
2604
3254
|
] })
|
|
2605
3255
|
]
|
|
2606
3256
|
}
|
|
2607
3257
|
),
|
|
2608
|
-
activeIdentities.length > 0 ? /* @__PURE__ */
|
|
3258
|
+
activeIdentities.length > 0 ? /* @__PURE__ */ jsx2("div", { className: "mt-1 border-t border-og-border pt-1", children: activeIdentities.map((identity) => /* @__PURE__ */ jsxs2(
|
|
2609
3259
|
"button",
|
|
2610
3260
|
{
|
|
2611
3261
|
type: "button",
|
|
2612
3262
|
onClick: () => choose({ kind: "profile", identityId: identity.id }),
|
|
2613
3263
|
className: "flex w-full items-center gap-2 rounded-og-sm px-2 py-2 text-left transition hover:bg-og-surface-2",
|
|
2614
3264
|
children: [
|
|
2615
|
-
/* @__PURE__ */
|
|
2616
|
-
/* @__PURE__ */
|
|
2617
|
-
/* @__PURE__ */
|
|
2618
|
-
/* @__PURE__ */
|
|
3265
|
+
/* @__PURE__ */ jsx2(UserRoundIcon, { className: "size-3.5 text-og-fg-muted" }),
|
|
3266
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
|
|
3267
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: identity.name }),
|
|
3268
|
+
/* @__PURE__ */ jsx2("span", { className: "block text-og-xs text-og-fg-subtle", children: identity.defaultRevisionId ? `${identity.revisionCount} saved version${identity.revisionCount === 1 ? "" : "s"}` : "Ready for first sign-in" })
|
|
2619
3269
|
] })
|
|
2620
3270
|
]
|
|
2621
3271
|
},
|
|
2622
3272
|
identity.id
|
|
2623
3273
|
)) }) : null,
|
|
2624
|
-
archivedIdentities.length > 0 ? /* @__PURE__ */
|
|
2625
|
-
/* @__PURE__ */
|
|
2626
|
-
/* @__PURE__ */
|
|
3274
|
+
archivedIdentities.length > 0 ? /* @__PURE__ */ jsxs2("details", { className: "mt-1 border-t border-og-border pt-1", children: [
|
|
3275
|
+
/* @__PURE__ */ jsxs2("summary", { className: "flex cursor-pointer list-none items-center gap-1.5 rounded-og-sm px-2 py-1.5 text-og-xs text-og-fg-subtle transition hover:bg-og-surface-2 hover:text-og-fg [&::-webkit-details-marker]:hidden", children: [
|
|
3276
|
+
/* @__PURE__ */ jsx2(ArchiveIcon, { className: "size-3" }),
|
|
2627
3277
|
" Hidden profiles \xB7 ",
|
|
2628
3278
|
archivedIdentities.length,
|
|
2629
|
-
/* @__PURE__ */
|
|
3279
|
+
/* @__PURE__ */ jsx2(ChevronDownIcon, { className: "ml-auto size-3" })
|
|
2630
3280
|
] }),
|
|
2631
|
-
archivedIdentities.map((identity) => /* @__PURE__ */
|
|
3281
|
+
archivedIdentities.map((identity) => /* @__PURE__ */ jsxs2(
|
|
2632
3282
|
"button",
|
|
2633
3283
|
{
|
|
2634
3284
|
type: "button",
|
|
@@ -2636,8 +3286,8 @@ function BrowserLaunchMenu(props) {
|
|
|
2636
3286
|
onClick: () => void restore(identity),
|
|
2637
3287
|
className: "flex w-full items-center gap-2 rounded-og-sm px-2 py-2 text-left transition hover:bg-og-surface-2 disabled:opacity-50",
|
|
2638
3288
|
children: [
|
|
2639
|
-
/* @__PURE__ */
|
|
2640
|
-
/* @__PURE__ */
|
|
3289
|
+
/* @__PURE__ */ jsx2(RotateCcwIcon, { className: "size-3.5 text-og-fg-muted" }),
|
|
3290
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1 truncate text-og-control text-og-fg", children: [
|
|
2641
3291
|
"Restore ",
|
|
2642
3292
|
identity.name
|
|
2643
3293
|
] })
|
|
@@ -2652,9 +3302,9 @@ function BrowserLaunchMenu(props) {
|
|
|
2652
3302
|
] });
|
|
2653
3303
|
}
|
|
2654
3304
|
function BrowserProfileMenu(props) {
|
|
2655
|
-
const detailsRef =
|
|
3305
|
+
const detailsRef = useViewerMenuDismiss();
|
|
2656
3306
|
const nameInputId = useId();
|
|
2657
|
-
const [name, setName] =
|
|
3307
|
+
const [name, setName] = useState9("");
|
|
2658
3308
|
const attached = props.session?.placement.kind === "attached_device";
|
|
2659
3309
|
const canSave = (props.session?.capabilities.identityPublication ?? false) && props.identity?.status !== "archived";
|
|
2660
3310
|
const revisions = props.identity && props.history?.identityId === props.identity.id ? [...props.history.revisions].sort((left, right) => right.ordinal - left.ordinal) : [];
|
|
@@ -2669,36 +3319,36 @@ function BrowserProfileMenu(props) {
|
|
|
2669
3319
|
props.onOpenVersion(identityId, baseRevisionId);
|
|
2670
3320
|
};
|
|
2671
3321
|
const versionLabel = attached ? "live" : props.identity ? props.baseRevisionOrdinal ? `v${props.baseRevisionOrdinal}` : props.session?.baseRevisionId ? "saved" : "unsaved" : "temporary";
|
|
2672
|
-
return /* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2674
|
-
props.saving ? /* @__PURE__ */
|
|
2675
|
-
/* @__PURE__ */
|
|
2676
|
-
attached || props.identity ? /* @__PURE__ */
|
|
3322
|
+
return /* @__PURE__ */ jsxs2("details", { ref: detailsRef, className: "min-w-0", children: [
|
|
3323
|
+
/* @__PURE__ */ jsxs2("summary", { className: "flex h-7 max-w-40 cursor-pointer list-none items-center gap-1.5 rounded-og-sm px-2 text-og-xs text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg [&::-webkit-details-marker]:hidden", children: [
|
|
3324
|
+
props.saving ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx2(MonitorIcon, { className: "size-3" }) : /* @__PURE__ */ jsx2(UserRoundIcon, { className: "size-3" }),
|
|
3325
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: attached ? props.session?.name : props.identity?.name ?? "Temporary" }),
|
|
3326
|
+
attached || props.identity ? /* @__PURE__ */ jsxs2("span", { className: "shrink-0 text-og-fg-subtle", children: [
|
|
2677
3327
|
"\xB7 ",
|
|
2678
3328
|
versionLabel
|
|
2679
3329
|
] }) : null,
|
|
2680
|
-
/* @__PURE__ */
|
|
3330
|
+
/* @__PURE__ */ jsx2(ChevronDownIcon, { className: "size-3 shrink-0 text-og-fg-subtle" })
|
|
2681
3331
|
] }),
|
|
2682
|
-
/* @__PURE__ */
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
/* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
/* @__PURE__ */
|
|
2687
|
-
/* @__PURE__ */
|
|
3332
|
+
/* @__PURE__ */ jsxs2("div", { className: "absolute right-2 top-10 z-40 max-h-[calc(100%-3rem)] w-72 max-w-[calc(100%-1rem)] overflow-y-auto rounded-og-md border border-og-border bg-og-surface-1 p-3 shadow-xl", children: [
|
|
3333
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-2", children: [
|
|
3334
|
+
/* @__PURE__ */ jsx2("span", { className: "grid size-7 shrink-0 place-items-center rounded-og-sm bg-og-surface-2 text-og-fg-muted", children: attached ? /* @__PURE__ */ jsx2(MonitorIcon, { className: "size-3.5" }) : /* @__PURE__ */ jsx2(UserRoundIcon, { className: "size-3.5" }) }),
|
|
3335
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
3336
|
+
/* @__PURE__ */ jsx2("p", { className: "truncate text-og-control font-medium text-og-fg", children: attached ? props.session?.name : props.identity?.name ?? "Temporary browser" }),
|
|
3337
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-og-xs leading-4 text-og-fg-subtle", children: attached ? "This session drives the existing Chrome profile and its current login state." : props.identity?.status === "archived" ? "Hidden from new browsers. This already-open browser is unchanged." : props.identity ? props.baseRevisionOrdinal ? `Started from version ${props.baseRevisionOrdinal}.` : "Not saved yet." : "This browser is not reusable yet." })
|
|
2688
3338
|
] })
|
|
2689
3339
|
] }),
|
|
2690
|
-
props.identity && revisions.length > 0 ? /* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
2692
|
-
/* @__PURE__ */
|
|
3340
|
+
props.identity && revisions.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "mt-3 border-t border-og-border pt-2", children: [
|
|
3341
|
+
/* @__PURE__ */ jsx2("p", { className: "px-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-fg-subtle", children: "Saved versions" }),
|
|
3342
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-1 max-h-40 overflow-y-auto", children: revisions.map((revision) => {
|
|
2693
3343
|
const isDefault = revision.id === props.identity?.defaultRevisionId;
|
|
2694
3344
|
const isCurrent = revision.ordinal === props.baseRevisionOrdinal;
|
|
2695
3345
|
const materialization = revisionMaterializationSummary(revision);
|
|
2696
|
-
return /* @__PURE__ */
|
|
3346
|
+
return /* @__PURE__ */ jsxs2(
|
|
2697
3347
|
"div",
|
|
2698
3348
|
{
|
|
2699
3349
|
className: "flex w-full items-center gap-1 rounded-og-sm transition hover:bg-og-surface-2",
|
|
2700
3350
|
children: [
|
|
2701
|
-
/* @__PURE__ */
|
|
3351
|
+
/* @__PURE__ */ jsxs2(
|
|
2702
3352
|
"button",
|
|
2703
3353
|
{
|
|
2704
3354
|
type: "button",
|
|
@@ -2707,19 +3357,19 @@ function BrowserProfileMenu(props) {
|
|
|
2707
3357
|
onClick: () => openVersion(props.identity.id, revision.id),
|
|
2708
3358
|
className: "flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left disabled:opacity-50",
|
|
2709
3359
|
children: [
|
|
2710
|
-
/* @__PURE__ */
|
|
2711
|
-
/* @__PURE__ */
|
|
2712
|
-
/* @__PURE__ */
|
|
3360
|
+
/* @__PURE__ */ jsx2("span", { className: "grid size-4 place-items-center text-og-fg-muted", children: isCurrent ? /* @__PURE__ */ jsx2(CheckIcon, { className: "size-3.5 text-og-accent" }) : null }),
|
|
3361
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3362
|
+
/* @__PURE__ */ jsxs2("span", { className: "block text-og-control text-og-fg", children: [
|
|
2713
3363
|
"Version ",
|
|
2714
3364
|
revision.ordinal
|
|
2715
3365
|
] }),
|
|
2716
|
-
/* @__PURE__ */
|
|
3366
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-[10px] text-og-fg-subtle", children: materialization.label })
|
|
2717
3367
|
] }),
|
|
2718
|
-
isCurrent ? /* @__PURE__ */
|
|
3368
|
+
isCurrent ? /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-og-fg-subtle", children: "Current" }) : null
|
|
2719
3369
|
]
|
|
2720
3370
|
}
|
|
2721
3371
|
),
|
|
2722
|
-
/* @__PURE__ */
|
|
3372
|
+
/* @__PURE__ */ jsx2(
|
|
2723
3373
|
"button",
|
|
2724
3374
|
{
|
|
2725
3375
|
type: "button",
|
|
@@ -2727,7 +3377,7 @@ function BrowserProfileMenu(props) {
|
|
|
2727
3377
|
"aria-label": isDefault ? `${props.identity.name} version ${revision.ordinal} is the default` : `Use ${props.identity.name} version ${revision.ordinal} by default`,
|
|
2728
3378
|
title: isDefault ? "Default version" : "Use by default",
|
|
2729
3379
|
onClick: () => void props.onUpdate(props.identity, { defaultRevisionId: revision.id }),
|
|
2730
|
-
className: "mr-1 shrink-0 rounded-og-sm px-2 py-1 text-[10px] text-og-subtle transition hover:bg-og-surface-3 hover:text-og-fg disabled:cursor-default disabled:opacity-70",
|
|
3380
|
+
className: "mr-1 shrink-0 rounded-og-sm px-2 py-1 text-[10px] text-og-fg-subtle transition hover:bg-og-surface-3 hover:text-og-fg disabled:cursor-default disabled:opacity-70",
|
|
2731
3381
|
children: isDefault ? "Default" : "Make default"
|
|
2732
3382
|
}
|
|
2733
3383
|
)
|
|
@@ -2736,24 +3386,24 @@ function BrowserProfileMenu(props) {
|
|
|
2736
3386
|
revision.id
|
|
2737
3387
|
);
|
|
2738
3388
|
}) }),
|
|
2739
|
-
/* @__PURE__ */
|
|
2740
|
-
] }) : props.identity && props.history?.identityId === props.identity.id && props.history.loading ? /* @__PURE__ */
|
|
2741
|
-
/* @__PURE__ */
|
|
3389
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 px-2 text-[10px] leading-4 text-og-fg-subtle", children: "Changing the default affects only browsers opened later. Saved browser data can be copied; a website may still expire or re-verify its own session." })
|
|
3390
|
+
] }) : props.identity && props.history?.identityId === props.identity.id && props.history.loading ? /* @__PURE__ */ jsxs2("p", { className: "mt-3 flex items-center gap-1.5 border-t border-og-border px-2 pt-2 text-og-xs text-og-fg-subtle", children: [
|
|
3391
|
+
/* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3 animate-spin" }),
|
|
2742
3392
|
" Loading saved versions\u2026"
|
|
2743
3393
|
] }) : null,
|
|
2744
|
-
props.identity && props.authConnections.length > 0 ? /* @__PURE__ */
|
|
2745
|
-
/* @__PURE__ */
|
|
2746
|
-
/* @__PURE__ */
|
|
3394
|
+
props.identity && props.authConnections.length > 0 ? /* @__PURE__ */ jsxs2("div", { className: "mt-3 border-t border-og-border pt-2", children: [
|
|
3395
|
+
/* @__PURE__ */ jsx2("p", { className: "px-1 text-[10px] font-medium uppercase tracking-[0.12em] text-og-fg-subtle", children: "Login health" }),
|
|
3396
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-1 space-y-1", children: props.authConnections.map((connection) => {
|
|
2747
3397
|
const health = siteAuthHealth(connection);
|
|
2748
|
-
return /* @__PURE__ */
|
|
3398
|
+
return /* @__PURE__ */ jsxs2(
|
|
2749
3399
|
"div",
|
|
2750
3400
|
{
|
|
2751
3401
|
className: "flex items-start gap-2 rounded-og-sm px-2 py-1.5",
|
|
2752
3402
|
children: [
|
|
2753
|
-
/* @__PURE__ */
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
/* @__PURE__ */
|
|
2756
|
-
/* @__PURE__ */
|
|
3403
|
+
/* @__PURE__ */ jsx2("span", { className: cn("mt-1 size-1.5 shrink-0 rounded-full", health.dotClass) }),
|
|
3404
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
3405
|
+
/* @__PURE__ */ jsx2("span", { className: "block truncate text-og-control text-og-fg", children: connection.name }),
|
|
3406
|
+
/* @__PURE__ */ jsxs2("span", { className: "block truncate text-[10px] text-og-fg-subtle", children: [
|
|
2757
3407
|
connection.accountLabel,
|
|
2758
3408
|
" \xB7 ",
|
|
2759
3409
|
health.label
|
|
@@ -2765,7 +3415,7 @@ function BrowserProfileMenu(props) {
|
|
|
2765
3415
|
);
|
|
2766
3416
|
}) })
|
|
2767
3417
|
] }) : null,
|
|
2768
|
-
canSave ? props.identity ? /* @__PURE__ */
|
|
3418
|
+
canSave ? props.identity ? /* @__PURE__ */ jsxs2(
|
|
2769
3419
|
"button",
|
|
2770
3420
|
{
|
|
2771
3421
|
type: "button",
|
|
@@ -2773,11 +3423,11 @@ function BrowserProfileMenu(props) {
|
|
|
2773
3423
|
disabled: props.saving,
|
|
2774
3424
|
className: "mt-3 flex h-8 w-full items-center justify-center gap-1.5 rounded-og-sm border border-og-border bg-og-surface-2 px-3 text-og-control font-medium text-og-fg transition hover:bg-og-surface-3 disabled:opacity-50",
|
|
2775
3425
|
children: [
|
|
2776
|
-
props.saving ? /* @__PURE__ */
|
|
3426
|
+
props.saving ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx2(SaveIcon, { className: "size-3.5" }),
|
|
2777
3427
|
props.saving ? "Saving browser version\u2026" : "Save new version"
|
|
2778
3428
|
]
|
|
2779
3429
|
}
|
|
2780
|
-
) : /* @__PURE__ */
|
|
3430
|
+
) : /* @__PURE__ */ jsxs2(
|
|
2781
3431
|
"form",
|
|
2782
3432
|
{
|
|
2783
3433
|
className: "mt-3",
|
|
@@ -2786,9 +3436,9 @@ function BrowserProfileMenu(props) {
|
|
|
2786
3436
|
if (name.trim()) void save(name);
|
|
2787
3437
|
},
|
|
2788
3438
|
children: [
|
|
2789
|
-
/* @__PURE__ */
|
|
2790
|
-
/* @__PURE__ */
|
|
2791
|
-
/* @__PURE__ */
|
|
3439
|
+
/* @__PURE__ */ jsx2("label", { className: "text-og-xs font-medium text-og-fg-muted", htmlFor: nameInputId, children: "Profile name" }),
|
|
3440
|
+
/* @__PURE__ */ jsxs2("div", { className: "mt-1 flex gap-1.5", children: [
|
|
3441
|
+
/* @__PURE__ */ jsx2(
|
|
2792
3442
|
"input",
|
|
2793
3443
|
{
|
|
2794
3444
|
id: nameInputId,
|
|
@@ -2796,17 +3446,17 @@ function BrowserProfileMenu(props) {
|
|
|
2796
3446
|
onInput: (event) => setName(event.currentTarget.value),
|
|
2797
3447
|
maxLength: 200,
|
|
2798
3448
|
placeholder: "Work",
|
|
2799
|
-
className: "h-8 min-w-0 flex-1 rounded-og-sm border border-og-border bg-og-bg px-2 text-og-control text-og-fg placeholder:text-og-subtle focus:border-og-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
3449
|
+
className: "h-8 min-w-0 flex-1 rounded-og-sm border border-og-border bg-og-bg px-2 text-og-control text-og-fg placeholder:text-og-fg-subtle focus:border-og-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent"
|
|
2800
3450
|
}
|
|
2801
3451
|
),
|
|
2802
|
-
/* @__PURE__ */
|
|
3452
|
+
/* @__PURE__ */ jsxs2(
|
|
2803
3453
|
"button",
|
|
2804
3454
|
{
|
|
2805
3455
|
type: "submit",
|
|
2806
3456
|
disabled: !name.trim() || props.saving,
|
|
2807
|
-
className: "inline-flex h-8 items-center gap-1 rounded-og-sm bg-og-
|
|
3457
|
+
className: "inline-flex h-8 items-center gap-1 rounded-og-sm border border-og-primary-border bg-og-primary text-og-primary-fg px-2.5 text-og-control font-medium transition hover:bg-og-primary-hover disabled:opacity-50",
|
|
2808
3458
|
children: [
|
|
2809
|
-
props.saving ? /* @__PURE__ */
|
|
3459
|
+
props.saving ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx2(SaveIcon, { className: "size-3.5" }),
|
|
2810
3460
|
"Save"
|
|
2811
3461
|
]
|
|
2812
3462
|
}
|
|
@@ -2814,8 +3464,8 @@ function BrowserProfileMenu(props) {
|
|
|
2814
3464
|
] })
|
|
2815
3465
|
]
|
|
2816
3466
|
}
|
|
2817
|
-
) : /* @__PURE__ */
|
|
2818
|
-
!attached && props.identity ? /* @__PURE__ */
|
|
3467
|
+
) : /* @__PURE__ */ jsx2("p", { className: "mt-3 rounded-og-sm bg-og-surface-2 px-2.5 py-2 text-og-xs text-og-fg-subtle", children: attached ? "Chrome keeps this profile's state directly; Opengeni does not copy it automatically." : props.identity?.status === "archived" ? "Restore this profile before saving another version." : "This browser cannot save reusable profile state." }),
|
|
3468
|
+
!attached && props.identity ? /* @__PURE__ */ jsxs2(
|
|
2819
3469
|
"button",
|
|
2820
3470
|
{
|
|
2821
3471
|
type: "button",
|
|
@@ -2823,14 +3473,14 @@ function BrowserProfileMenu(props) {
|
|
|
2823
3473
|
onClick: () => void props.onUpdate(props.identity, {
|
|
2824
3474
|
status: props.identity.status === "active" ? "archived" : "active"
|
|
2825
3475
|
}),
|
|
2826
|
-
className: "mt-2 flex h-8 w-full items-center justify-center gap-1.5 rounded-og-sm px-3 text-og-control text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50",
|
|
3476
|
+
className: "mt-2 flex h-8 w-full items-center justify-center gap-1.5 rounded-og-sm px-3 text-og-control text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50",
|
|
2827
3477
|
children: [
|
|
2828
|
-
props.identity.status === "active" ? /* @__PURE__ */
|
|
3478
|
+
props.identity.status === "active" ? /* @__PURE__ */ jsx2(ArchiveIcon, { className: "size-3.5" }) : /* @__PURE__ */ jsx2(RotateCcwIcon, { className: "size-3.5" }),
|
|
2829
3479
|
props.identity.status === "active" ? "Hide from new browsers" : "Restore profile"
|
|
2830
3480
|
]
|
|
2831
3481
|
}
|
|
2832
3482
|
) : null,
|
|
2833
|
-
canSave ? /* @__PURE__ */
|
|
3483
|
+
canSave ? /* @__PURE__ */ jsx2("p", { className: "mt-2 text-[10px] leading-4 text-og-fg-subtle", children: "Saving restarts this browser. Save unfinished work on its pages first; unsaved form entries may be lost. Other open browsers are unchanged." }) : null
|
|
2834
3484
|
] })
|
|
2835
3485
|
] });
|
|
2836
3486
|
}
|
|
@@ -2867,29 +3517,29 @@ function siteAuthHealth(connection) {
|
|
|
2867
3517
|
}
|
|
2868
3518
|
}
|
|
2869
3519
|
function MenuButton(props) {
|
|
2870
|
-
return /* @__PURE__ */
|
|
3520
|
+
return /* @__PURE__ */ jsx2(
|
|
2871
3521
|
"button",
|
|
2872
3522
|
{
|
|
2873
3523
|
type: "button",
|
|
2874
3524
|
onClick: props.onClick,
|
|
2875
3525
|
disabled: props.disabled,
|
|
2876
|
-
className: "flex h-7 flex-1 items-center justify-center gap-1 rounded-og-sm px-2 text-og-control text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50",
|
|
3526
|
+
className: "flex h-7 flex-1 items-center justify-center gap-1 rounded-og-sm px-2 text-og-control text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50",
|
|
2877
3527
|
children: props.children
|
|
2878
3528
|
}
|
|
2879
3529
|
);
|
|
2880
3530
|
}
|
|
2881
3531
|
function BrowserTabs(props) {
|
|
2882
3532
|
const pages = props.targets.filter((target) => target.kind === "page" || target.kind === "popup");
|
|
2883
|
-
return /* @__PURE__ */
|
|
2884
|
-
pages.map((target) => /* @__PURE__ */
|
|
3533
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex h-9 shrink-0 items-end gap-px overflow-x-auto border-b border-og-border bg-og-surface-1 px-1 pt-1", children: [
|
|
3534
|
+
pages.map((target) => /* @__PURE__ */ jsxs2(
|
|
2885
3535
|
"div",
|
|
2886
3536
|
{
|
|
2887
3537
|
className: cn(
|
|
2888
3538
|
"group flex h-8 min-w-24 max-w-48 items-center rounded-t-og-sm border border-b-0 border-transparent px-2",
|
|
2889
|
-
target.id === props.selectedTargetId ? "border-og-border bg-og-bg text-og-fg" : "text-og-muted hover:bg-og-surface-1"
|
|
3539
|
+
target.id === props.selectedTargetId ? "border-og-border bg-og-bg text-og-fg" : "text-og-fg-muted hover:bg-og-surface-1"
|
|
2890
3540
|
),
|
|
2891
3541
|
children: [
|
|
2892
|
-
/* @__PURE__ */
|
|
3542
|
+
/* @__PURE__ */ jsx2(
|
|
2893
3543
|
"button",
|
|
2894
3544
|
{
|
|
2895
3545
|
type: "button",
|
|
@@ -2898,7 +3548,7 @@ function BrowserTabs(props) {
|
|
|
2898
3548
|
children: target.title || shortUrl(target.url)
|
|
2899
3549
|
}
|
|
2900
3550
|
),
|
|
2901
|
-
props.tabControl ? /* @__PURE__ */
|
|
3551
|
+
props.tabControl ? /* @__PURE__ */ jsx2(
|
|
2902
3552
|
"button",
|
|
2903
3553
|
{
|
|
2904
3554
|
type: "button",
|
|
@@ -2906,57 +3556,94 @@ function BrowserTabs(props) {
|
|
|
2906
3556
|
disabled: props.mutating,
|
|
2907
3557
|
className: "ml-1 grid size-4 shrink-0 place-items-center rounded opacity-0 transition hover:bg-og-surface-3 group-hover:opacity-100 focus:opacity-100 disabled:opacity-30",
|
|
2908
3558
|
"aria-label": `Close ${target.title || "tab"}`,
|
|
2909
|
-
children: /* @__PURE__ */
|
|
3559
|
+
children: /* @__PURE__ */ jsx2(XIcon, { className: "size-3" })
|
|
2910
3560
|
}
|
|
2911
3561
|
) : null
|
|
2912
3562
|
]
|
|
2913
3563
|
},
|
|
2914
3564
|
target.id
|
|
2915
3565
|
)),
|
|
2916
|
-
props.tabControl ? /* @__PURE__ */
|
|
3566
|
+
props.tabControl ? /* @__PURE__ */ jsx2(
|
|
2917
3567
|
"button",
|
|
2918
3568
|
{
|
|
2919
3569
|
type: "button",
|
|
2920
3570
|
onClick: props.onOpen,
|
|
2921
3571
|
disabled: props.mutating,
|
|
2922
|
-
className: "mb-1 grid size-6 shrink-0 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-40",
|
|
3572
|
+
className: "mb-1 grid size-6 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-40",
|
|
2923
3573
|
"aria-label": "New tab",
|
|
2924
|
-
children: /* @__PURE__ */
|
|
3574
|
+
children: /* @__PURE__ */ jsx2(PlusIcon, { className: "size-3.5" })
|
|
2925
3575
|
}
|
|
2926
3576
|
) : null
|
|
2927
3577
|
] });
|
|
2928
3578
|
}
|
|
2929
3579
|
function BrowserAddressBar(props) {
|
|
2930
|
-
const [draft, setDraft] =
|
|
2931
|
-
const focusedRef =
|
|
2932
|
-
|
|
3580
|
+
const [draft, setDraft] = useState9(props.target?.url ?? "");
|
|
3581
|
+
const focusedRef = useRef9(false);
|
|
3582
|
+
const historyPendingRef = useRef9(false);
|
|
3583
|
+
const [historyPending, setHistoryPending] = useState9(false);
|
|
3584
|
+
useEffect9(() => {
|
|
2933
3585
|
if (!focusedRef.current) setDraft(props.target?.url ?? "");
|
|
2934
3586
|
}, [props.target?.id, props.target?.url]);
|
|
2935
3587
|
const submit = (event) => {
|
|
2936
3588
|
event.preventDefault();
|
|
3589
|
+
if (historyPendingRef.current) return;
|
|
2937
3590
|
const normalized = normalizeBrowserAddress(draft);
|
|
2938
3591
|
if (normalized) props.onNavigate(normalized);
|
|
2939
3592
|
};
|
|
2940
|
-
|
|
3593
|
+
const navigateHistory = async (direction) => {
|
|
3594
|
+
if (!props.target || props.loading || historyPendingRef.current) return;
|
|
3595
|
+
historyPendingRef.current = true;
|
|
3596
|
+
setHistoryPending(true);
|
|
3597
|
+
try {
|
|
3598
|
+
await props.onHistory(direction);
|
|
3599
|
+
} finally {
|
|
3600
|
+
historyPendingRef.current = false;
|
|
3601
|
+
setHistoryPending(false);
|
|
3602
|
+
}
|
|
3603
|
+
};
|
|
3604
|
+
return /* @__PURE__ */ jsxs2(
|
|
2941
3605
|
"form",
|
|
2942
3606
|
{
|
|
2943
3607
|
onSubmit: submit,
|
|
3608
|
+
"aria-busy": historyPending || void 0,
|
|
2944
3609
|
className: "flex h-10 shrink-0 items-center gap-1.5 border-b border-og-border bg-og-bg px-2",
|
|
2945
3610
|
children: [
|
|
2946
|
-
/* @__PURE__ */
|
|
3611
|
+
["back", "forward"].map((direction) => /* @__PURE__ */ jsx2(
|
|
2947
3612
|
"button",
|
|
2948
3613
|
{
|
|
2949
3614
|
type: "button",
|
|
2950
|
-
onClick:
|
|
3615
|
+
onClick: () => void navigateHistory(direction),
|
|
2951
3616
|
disabled: !props.target || props.loading,
|
|
2952
|
-
|
|
3617
|
+
"aria-disabled": historyPending || void 0,
|
|
3618
|
+
className: cn(
|
|
3619
|
+
"grid size-7 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:opacity-35",
|
|
3620
|
+
historyPending && "opacity-50"
|
|
3621
|
+
),
|
|
3622
|
+
"aria-label": direction === "back" ? "Back" : "Forward",
|
|
3623
|
+
title: direction === "back" ? "Back" : "Forward",
|
|
3624
|
+
children: direction === "back" ? /* @__PURE__ */ jsx2(ArrowLeftIcon, { className: "size-3.5" }) : /* @__PURE__ */ jsx2(ArrowRightIcon, { className: "size-3.5" })
|
|
3625
|
+
},
|
|
3626
|
+
direction
|
|
3627
|
+
)),
|
|
3628
|
+
/* @__PURE__ */ jsx2(
|
|
3629
|
+
"button",
|
|
3630
|
+
{
|
|
3631
|
+
type: "button",
|
|
3632
|
+
onClick: props.onReload,
|
|
3633
|
+
disabled: !props.target || props.loading || historyPending,
|
|
3634
|
+
className: "grid size-7 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-35",
|
|
2953
3635
|
"aria-label": "Reload",
|
|
2954
|
-
children: /* @__PURE__ */
|
|
3636
|
+
children: /* @__PURE__ */ jsx2(
|
|
3637
|
+
RefreshCwIcon,
|
|
3638
|
+
{
|
|
3639
|
+
className: cn("size-3.5", (props.loading || historyPending) && "animate-spin")
|
|
3640
|
+
}
|
|
3641
|
+
)
|
|
2955
3642
|
}
|
|
2956
3643
|
),
|
|
2957
|
-
/* @__PURE__ */
|
|
2958
|
-
/* @__PURE__ */
|
|
2959
|
-
/* @__PURE__ */
|
|
3644
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex h-7 min-w-0 flex-1 items-center gap-2 rounded-og-sm border border-og-border bg-og-surface-1 px-2 focus-within:border-og-accent/60", children: [
|
|
3645
|
+
/* @__PURE__ */ jsx2(Globe2Icon, { className: "size-3 shrink-0 text-og-fg-subtle" }),
|
|
3646
|
+
/* @__PURE__ */ jsx2(
|
|
2960
3647
|
"input",
|
|
2961
3648
|
{
|
|
2962
3649
|
value: draft,
|
|
@@ -2970,11 +3657,12 @@ function BrowserAddressBar(props) {
|
|
|
2970
3657
|
onKeyDown: (event) => {
|
|
2971
3658
|
if (event.key !== "Enter") return;
|
|
2972
3659
|
event.preventDefault();
|
|
3660
|
+
if (historyPendingRef.current) return;
|
|
2973
3661
|
const normalized = normalizeBrowserAddress(draft);
|
|
2974
3662
|
if (normalized) props.onNavigate(normalized);
|
|
2975
3663
|
},
|
|
2976
3664
|
disabled: !props.target,
|
|
2977
|
-
className: "min-w-0 flex-1 bg-transparent text-og-control text-og-fg placeholder:text-og-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:opacity-50",
|
|
3665
|
+
className: "min-w-0 flex-1 bg-transparent text-og-control text-og-fg placeholder:text-og-fg-subtle focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:opacity-50",
|
|
2978
3666
|
"aria-label": "Address",
|
|
2979
3667
|
spellCheck: false,
|
|
2980
3668
|
placeholder: "Search or enter address"
|
|
@@ -2986,24 +3674,48 @@ function BrowserAddressBar(props) {
|
|
|
2986
3674
|
);
|
|
2987
3675
|
}
|
|
2988
3676
|
function BrowserViewport(props) {
|
|
2989
|
-
const canvasRef =
|
|
2990
|
-
const inputRef =
|
|
2991
|
-
const
|
|
2992
|
-
const
|
|
2993
|
-
const
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
const
|
|
2998
|
-
const
|
|
2999
|
-
const
|
|
3000
|
-
const
|
|
3001
|
-
const
|
|
3002
|
-
const
|
|
3003
|
-
const
|
|
3677
|
+
const canvasRef = useRef9(null);
|
|
3678
|
+
const inputRef = useRef9(null);
|
|
3679
|
+
const [selectPopup, setSelectPopup] = useState9(null);
|
|
3680
|
+
const inputSequenceRef = useRef9(0);
|
|
3681
|
+
const dismissSelectPopup = useCallback8(() => {
|
|
3682
|
+
inputSequenceRef.current += 1;
|
|
3683
|
+
setSelectPopup({ observation: null, anchor: null });
|
|
3684
|
+
}, []);
|
|
3685
|
+
const composingRef = useRef9(false);
|
|
3686
|
+
const pointerStartRef = useRef9(null);
|
|
3687
|
+
const lastClickRef = useRef9(null);
|
|
3688
|
+
const wheelRef = useRef9(null);
|
|
3689
|
+
const pendingTextRef = useRef9(null);
|
|
3690
|
+
const actionRef = useRef9(props.onAction);
|
|
3691
|
+
const readClipboardRef = useRef9(props.onReadClipboard);
|
|
3692
|
+
const observeInputRef = useRef9(props.onObserveForInput);
|
|
3693
|
+
const errorRef = useRef9(props.onError);
|
|
3694
|
+
const actionTailRef = useRef9(Promise.resolve());
|
|
3695
|
+
const actionQueueEpochRef = useRef9(0);
|
|
3696
|
+
const queuedTypingRef = useRef9(null);
|
|
3697
|
+
const queuedFrameRef = useRef9(null);
|
|
3698
|
+
const currentFrameRef = useRef9(props.frame);
|
|
3699
|
+
const paintedFrameRef = useRef9(null);
|
|
3700
|
+
const [paintedFrame, setPaintedFrame] = useState9(null);
|
|
3701
|
+
const decodingFrameRef = useRef9(false);
|
|
3702
|
+
const mountedRef = useRef9(true);
|
|
3004
3703
|
actionRef.current = props.onAction;
|
|
3005
3704
|
readClipboardRef.current = props.onReadClipboard;
|
|
3705
|
+
observeInputRef.current = props.onObserveForInput;
|
|
3006
3706
|
errorRef.current = props.onError;
|
|
3707
|
+
const clearBufferedInput = useCallback8(() => {
|
|
3708
|
+
dismissSelectPopup();
|
|
3709
|
+
if (wheelRef.current?.timer) clearTimeout(wheelRef.current.timer);
|
|
3710
|
+
if (pendingTextRef.current?.timer) clearTimeout(pendingTextRef.current.timer);
|
|
3711
|
+
wheelRef.current = null;
|
|
3712
|
+
pendingTextRef.current = null;
|
|
3713
|
+
queuedTypingRef.current = null;
|
|
3714
|
+
pointerStartRef.current = null;
|
|
3715
|
+
lastClickRef.current = null;
|
|
3716
|
+
composingRef.current = false;
|
|
3717
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
3718
|
+
}, [dismissSelectPopup]);
|
|
3007
3719
|
const paintQueuedFrames = useCallback8(() => {
|
|
3008
3720
|
if (decodingFrameRef.current) return;
|
|
3009
3721
|
decodingFrameRef.current = true;
|
|
@@ -3015,15 +3727,17 @@ function BrowserViewport(props) {
|
|
|
3015
3727
|
if (!frame) break;
|
|
3016
3728
|
let objectUrl = null;
|
|
3017
3729
|
try {
|
|
3018
|
-
const blob = new Blob([frame.data
|
|
3730
|
+
const blob = new Blob([frame.data], {
|
|
3019
3731
|
type: frame.mediaType
|
|
3020
3732
|
});
|
|
3021
3733
|
if (typeof createImageBitmap === "function") {
|
|
3022
3734
|
const bitmap = await createImageBitmap(blob);
|
|
3023
3735
|
try {
|
|
3024
3736
|
const canvas2 = canvasRef.current;
|
|
3025
|
-
if (mountedRef.current && canvas2) {
|
|
3737
|
+
if (mountedRef.current && canvas2 && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current)) {
|
|
3026
3738
|
paintCanvas(canvas2, bitmap, frame.width, frame.height);
|
|
3739
|
+
paintedFrameRef.current = frame;
|
|
3740
|
+
setPaintedFrame(frame);
|
|
3027
3741
|
}
|
|
3028
3742
|
} finally {
|
|
3029
3743
|
bitmap.close();
|
|
@@ -3033,11 +3747,14 @@ function BrowserViewport(props) {
|
|
|
3033
3747
|
objectUrl = URL.createObjectURL(blob);
|
|
3034
3748
|
const image = await loadImage(objectUrl);
|
|
3035
3749
|
const canvas = canvasRef.current;
|
|
3036
|
-
if (mountedRef.current && canvas) {
|
|
3750
|
+
if (mountedRef.current && canvas && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current)) {
|
|
3037
3751
|
paintCanvas(canvas, image, frame.width, frame.height);
|
|
3752
|
+
paintedFrameRef.current = frame;
|
|
3753
|
+
setPaintedFrame(frame);
|
|
3038
3754
|
}
|
|
3039
3755
|
} catch (cause) {
|
|
3040
|
-
if (mountedRef.current
|
|
3756
|
+
if (mountedRef.current && currentFrameRef.current && sameBrowserDocument(frame, currentFrameRef.current))
|
|
3757
|
+
errorRef.current(cause);
|
|
3041
3758
|
} finally {
|
|
3042
3759
|
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
3043
3760
|
}
|
|
@@ -3048,38 +3765,83 @@ function BrowserViewport(props) {
|
|
|
3048
3765
|
}
|
|
3049
3766
|
})();
|
|
3050
3767
|
}, []);
|
|
3051
|
-
|
|
3768
|
+
useLayoutEffect2(() => {
|
|
3769
|
+
const keyboardInput = inputRef.current;
|
|
3770
|
+
const focusHandoff = props.focusHandoffRef;
|
|
3052
3771
|
mountedRef.current = true;
|
|
3772
|
+
if (focusHandoff.current === props.focusScope) {
|
|
3773
|
+
keyboardInput?.focus({ preventScroll: true });
|
|
3774
|
+
}
|
|
3775
|
+
focusHandoff.current = null;
|
|
3053
3776
|
return () => {
|
|
3777
|
+
if (document.activeElement === keyboardInput) {
|
|
3778
|
+
focusHandoff.current = props.focusScope;
|
|
3779
|
+
}
|
|
3054
3780
|
mountedRef.current = false;
|
|
3781
|
+
actionQueueEpochRef.current += 1;
|
|
3055
3782
|
queuedFrameRef.current = null;
|
|
3783
|
+
clearBufferedInput();
|
|
3056
3784
|
};
|
|
3057
|
-
}, []);
|
|
3058
|
-
|
|
3059
|
-
if (!props.frame)
|
|
3785
|
+
}, [clearBufferedInput, props.focusHandoffRef, props.focusScope]);
|
|
3786
|
+
useLayoutEffect2(() => {
|
|
3787
|
+
if (currentFrameRef.current && !props.frame) {
|
|
3788
|
+
actionQueueEpochRef.current += 1;
|
|
3789
|
+
clearBufferedInput();
|
|
3790
|
+
}
|
|
3791
|
+
currentFrameRef.current = props.frame;
|
|
3792
|
+
if (!props.frame) {
|
|
3793
|
+
queuedFrameRef.current = null;
|
|
3794
|
+
paintedFrameRef.current = null;
|
|
3795
|
+
setPaintedFrame(null);
|
|
3796
|
+
return;
|
|
3797
|
+
}
|
|
3060
3798
|
queuedFrameRef.current = props.frame;
|
|
3061
3799
|
paintQueuedFrames();
|
|
3062
|
-
}, [paintQueuedFrames, props.frame]);
|
|
3063
|
-
useEffect8(
|
|
3064
|
-
() => () => {
|
|
3065
|
-
if (wheelRef.current?.timer) clearTimeout(wheelRef.current.timer);
|
|
3066
|
-
if (pendingTextRef.current?.timer) clearTimeout(pendingTextRef.current.timer);
|
|
3067
|
-
},
|
|
3068
|
-
[]
|
|
3069
|
-
);
|
|
3800
|
+
}, [clearBufferedInput, paintQueuedFrames, props.frame]);
|
|
3070
3801
|
const enqueue = useCallback8(
|
|
3071
|
-
(action, frame, after) => {
|
|
3802
|
+
(action, frame, after, selectAnchor) => {
|
|
3803
|
+
const inputSequence = ++inputSequenceRef.current;
|
|
3804
|
+
setSelectPopup({ observation: null, anchor: null });
|
|
3805
|
+
frame = frame ? {
|
|
3806
|
+
browserSessionId: frame.browserSessionId,
|
|
3807
|
+
controllerGeneration: frame.controllerGeneration,
|
|
3808
|
+
targetId: frame.targetId,
|
|
3809
|
+
targetGeneration: frame.targetGeneration,
|
|
3810
|
+
documentGeneration: frame.documentGeneration,
|
|
3811
|
+
frameId: frame.frameId
|
|
3812
|
+
} : null;
|
|
3072
3813
|
const epoch = actionQueueEpochRef.current;
|
|
3814
|
+
const attachment = props.inputBatchAttachment;
|
|
3815
|
+
const canBatchTyping = action.type === "type" && !after && frame && attachment?.fencedInputBatches === true && attachment.browserSessionId === frame.browserSessionId && attachment.controllerGeneration === frame.controllerGeneration && attachment.targetId === frame.targetId && Date.parse(attachment.expiresAt) > Date.now();
|
|
3816
|
+
const previous = queuedTypingRef.current;
|
|
3817
|
+
if (canBatchTyping && frame && previous && previous.epoch === epoch && sameFrameFence(previous.frame, frame) && previous.actions.length < 16) {
|
|
3818
|
+
previous.actions.push(action);
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
const typing = canBatchTyping && frame ? { actions: [action], frame, epoch } : null;
|
|
3822
|
+
queuedTypingRef.current = typing;
|
|
3073
3823
|
actionTailRef.current = actionTailRef.current.catch(() => void 0).then(async () => {
|
|
3074
|
-
if (epoch !== actionQueueEpochRef.current) return;
|
|
3075
|
-
|
|
3824
|
+
if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
|
|
3825
|
+
if (queuedTypingRef.current === typing) queuedTypingRef.current = null;
|
|
3826
|
+
const dispatchedAction = typing && typing.actions.length > 1 ? { type: "batch", actions: typing.actions, fenceEachAction: true } : action;
|
|
3827
|
+
const receipt = await actionRef.current(dispatchedAction, frame);
|
|
3828
|
+
if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
|
|
3829
|
+
const keyboardSelect = dispatchedAction.type === "press" && dispatchedAction.key === "Alt+ArrowDown";
|
|
3830
|
+
if ((selectAnchor || keyboardSelect) && inputSequence === inputSequenceRef.current) {
|
|
3831
|
+
const observation = keyboardSelect ? await observeInputRef.current() : receipt.observation;
|
|
3832
|
+
if (mountedRef.current && epoch === actionQueueEpochRef.current && inputSequence === inputSequenceRef.current && observation) {
|
|
3833
|
+
setSelectPopup({ observation, anchor: selectAnchor ?? null });
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3076
3836
|
await after?.(receipt);
|
|
3077
3837
|
}).catch((cause) => {
|
|
3838
|
+
if (!mountedRef.current || epoch !== actionQueueEpochRef.current) return;
|
|
3078
3839
|
actionQueueEpochRef.current += 1;
|
|
3840
|
+
clearBufferedInput();
|
|
3079
3841
|
errorRef.current(cause);
|
|
3080
3842
|
});
|
|
3081
3843
|
},
|
|
3082
|
-
[]
|
|
3844
|
+
[clearBufferedInput, props.inputBatchAttachment]
|
|
3083
3845
|
);
|
|
3084
3846
|
const point = useCallback8(
|
|
3085
3847
|
(frame, clientX, clientY) => browserPoint(canvasRef.current, frame, clientX, clientY),
|
|
@@ -3095,15 +3857,35 @@ function BrowserViewport(props) {
|
|
|
3095
3857
|
const flushPendingClick = useCallback8(() => {
|
|
3096
3858
|
lastClickRef.current = null;
|
|
3097
3859
|
}, []);
|
|
3860
|
+
const flushPendingWheel = useCallback8(() => {
|
|
3861
|
+
const batch = wheelRef.current;
|
|
3862
|
+
if (!batch) return;
|
|
3863
|
+
if (batch.timer) clearTimeout(batch.timer);
|
|
3864
|
+
wheelRef.current = null;
|
|
3865
|
+
enqueue(
|
|
3866
|
+
{
|
|
3867
|
+
type: "pointer",
|
|
3868
|
+
action: "scroll",
|
|
3869
|
+
x: batch.x,
|
|
3870
|
+
y: batch.y,
|
|
3871
|
+
deltaX: batch.deltaX,
|
|
3872
|
+
deltaY: batch.deltaY
|
|
3873
|
+
},
|
|
3874
|
+
batch.frame
|
|
3875
|
+
);
|
|
3876
|
+
}, [enqueue]);
|
|
3098
3877
|
const pointerDown = (event) => {
|
|
3099
|
-
|
|
3878
|
+
const frame = paintedFrameRef.current;
|
|
3879
|
+
if (!frame || event.button !== 0) return;
|
|
3100
3880
|
event.preventDefault();
|
|
3881
|
+
dismissSelectPopup();
|
|
3882
|
+
flushPendingWheel();
|
|
3101
3883
|
flushPendingText();
|
|
3102
3884
|
pointerStartRef.current = {
|
|
3103
3885
|
x: event.clientX,
|
|
3104
3886
|
y: event.clientY,
|
|
3105
3887
|
pointerId: event.pointerId,
|
|
3106
|
-
frame
|
|
3888
|
+
frame
|
|
3107
3889
|
};
|
|
3108
3890
|
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
3109
3891
|
inputRef.current?.focus({ preventScroll: true });
|
|
@@ -3138,52 +3920,54 @@ function BrowserViewport(props) {
|
|
|
3138
3920
|
return;
|
|
3139
3921
|
}
|
|
3140
3922
|
lastClickRef.current = { at: now, x: to.x, y: to.y, frame: start.frame };
|
|
3141
|
-
|
|
3923
|
+
const viewportBounds = canvasRef.current?.parentElement?.getBoundingClientRect();
|
|
3924
|
+
enqueue(
|
|
3925
|
+
{ type: "pointer", action: "click", x: to.x, y: to.y },
|
|
3926
|
+
start.frame,
|
|
3927
|
+
void 0,
|
|
3928
|
+
viewportBounds ? { x: event.clientX - viewportBounds.left, y: event.clientY - viewportBounds.top + 8 } : void 0
|
|
3929
|
+
);
|
|
3142
3930
|
};
|
|
3143
3931
|
const contextMenu = (event) => {
|
|
3144
3932
|
event.preventDefault();
|
|
3145
|
-
const frame =
|
|
3933
|
+
const frame = paintedFrameRef.current;
|
|
3146
3934
|
if (!frame) return;
|
|
3935
|
+
flushPendingWheel();
|
|
3147
3936
|
flushPendingText();
|
|
3148
3937
|
flushPendingClick();
|
|
3149
3938
|
const at = point(frame, event.clientX, event.clientY);
|
|
3150
3939
|
if (at) enqueue({ type: "pointer", action: "click", x: at.x, y: at.y, button: "right" }, frame);
|
|
3151
3940
|
};
|
|
3152
3941
|
const wheel = (event) => {
|
|
3153
|
-
|
|
3942
|
+
dismissSelectPopup();
|
|
3943
|
+
const frame = paintedFrameRef.current;
|
|
3154
3944
|
if (!frame) return;
|
|
3155
3945
|
const at = point(frame, event.clientX, event.clientY);
|
|
3156
3946
|
if (!at) return;
|
|
3157
3947
|
flushPendingText();
|
|
3158
3948
|
flushPendingClick();
|
|
3159
3949
|
event.preventDefault();
|
|
3160
|
-
|
|
3161
|
-
if (pending
|
|
3950
|
+
let pending = wheelRef.current;
|
|
3951
|
+
if (pending && (!sameBrowserDocument(pending.frame, frame) || Math.hypot(pending.x - at.x, pending.y - at.y) > 6)) {
|
|
3952
|
+
flushPendingWheel();
|
|
3953
|
+
pending = null;
|
|
3954
|
+
}
|
|
3162
3955
|
wheelRef.current = {
|
|
3163
3956
|
x: at.x,
|
|
3164
3957
|
y: at.y,
|
|
3165
|
-
deltaX: (pending
|
|
3166
|
-
deltaY: (pending
|
|
3958
|
+
deltaX: (pending?.deltaX ?? 0) + event.deltaX,
|
|
3959
|
+
deltaY: (pending?.deltaY ?? 0) + event.deltaY,
|
|
3167
3960
|
frame,
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
wheelRef.current = null;
|
|
3171
|
-
if (batch)
|
|
3172
|
-
enqueue(
|
|
3173
|
-
{
|
|
3174
|
-
type: "pointer",
|
|
3175
|
-
action: "scroll",
|
|
3176
|
-
x: batch.x,
|
|
3177
|
-
y: batch.y,
|
|
3178
|
-
deltaX: batch.deltaX,
|
|
3179
|
-
deltaY: batch.deltaY
|
|
3180
|
-
},
|
|
3181
|
-
batch.frame
|
|
3182
|
-
);
|
|
3183
|
-
}, 45)
|
|
3961
|
+
// Retain the first event's deadline so a continuous gesture keeps moving.
|
|
3962
|
+
timer: pending?.timer ?? setTimeout(flushPendingWheel, 45)
|
|
3184
3963
|
};
|
|
3185
3964
|
};
|
|
3186
3965
|
const keyDown = (event) => {
|
|
3966
|
+
if (composingRef.current || event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229) {
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
dismissSelectPopup();
|
|
3970
|
+
flushPendingWheel();
|
|
3187
3971
|
const command = event.metaKey || event.ctrlKey;
|
|
3188
3972
|
if (props.clipboardEnabled && command && !event.altKey && ["c", "v"].includes(event.key.toLowerCase())) {
|
|
3189
3973
|
flushPendingText();
|
|
@@ -3194,24 +3978,28 @@ function BrowserViewport(props) {
|
|
|
3194
3978
|
event.preventDefault();
|
|
3195
3979
|
flushPendingText();
|
|
3196
3980
|
flushPendingClick();
|
|
3197
|
-
enqueue({ type: "press", key },
|
|
3981
|
+
enqueue({ type: "press", key }, paintedFrameRef.current);
|
|
3198
3982
|
};
|
|
3983
|
+
const finishCopy = useCallback8(async () => {
|
|
3984
|
+
const clipboard = await readClipboardRef.current();
|
|
3985
|
+
if (!mountedRef.current) return;
|
|
3986
|
+
if (clipboard.text.length === 0) return;
|
|
3987
|
+
if (!await copyTextToClipboard(clipboard.text)) {
|
|
3988
|
+
throw new Error("Browser text could not be copied to the local clipboard");
|
|
3989
|
+
}
|
|
3990
|
+
}, []);
|
|
3199
3991
|
const copy = (event) => {
|
|
3200
3992
|
if (!props.clipboardEnabled) return;
|
|
3201
3993
|
event.preventDefault();
|
|
3994
|
+
flushPendingWheel();
|
|
3202
3995
|
flushPendingText();
|
|
3203
3996
|
flushPendingClick();
|
|
3204
|
-
enqueue({ type: "clipboard", operation: "copy" },
|
|
3205
|
-
const clipboard = await readClipboardRef.current();
|
|
3206
|
-
if (clipboard.text.length === 0) return;
|
|
3207
|
-
if (!await copyTextToClipboard(clipboard.text)) {
|
|
3208
|
-
throw new Error("Browser text could not be copied to the local clipboard");
|
|
3209
|
-
}
|
|
3210
|
-
});
|
|
3997
|
+
enqueue({ type: "clipboard", operation: "copy" }, paintedFrameRef.current, finishCopy);
|
|
3211
3998
|
};
|
|
3212
3999
|
const paste = (event) => {
|
|
3213
4000
|
if (!props.clipboardEnabled) return;
|
|
3214
4001
|
event.preventDefault();
|
|
4002
|
+
flushPendingWheel();
|
|
3215
4003
|
flushPendingText();
|
|
3216
4004
|
flushPendingClick();
|
|
3217
4005
|
enqueue(
|
|
@@ -3220,15 +4008,17 @@ function BrowserViewport(props) {
|
|
|
3220
4008
|
operation: "paste",
|
|
3221
4009
|
text: event.clipboardData.getData("text/plain")
|
|
3222
4010
|
},
|
|
3223
|
-
|
|
4011
|
+
paintedFrameRef.current
|
|
3224
4012
|
);
|
|
3225
4013
|
};
|
|
3226
4014
|
const input = (value, nativeComposing = false) => {
|
|
4015
|
+
dismissSelectPopup();
|
|
3227
4016
|
if (composingRef.current || nativeComposing) return;
|
|
3228
4017
|
if (!value) return;
|
|
4018
|
+
flushPendingWheel();
|
|
3229
4019
|
flushPendingClick();
|
|
3230
4020
|
const pending = pendingTextRef.current;
|
|
3231
|
-
if (pending && sameOptionalBrowserFrame(pending.frame,
|
|
4021
|
+
if (pending && sameOptionalBrowserFrame(pending.frame, paintedFrameRef.current)) {
|
|
3232
4022
|
clearTimeout(pending.timer);
|
|
3233
4023
|
pending.text += value;
|
|
3234
4024
|
pending.timer = setTimeout(flushPendingText, 16);
|
|
@@ -3236,7 +4026,7 @@ function BrowserViewport(props) {
|
|
|
3236
4026
|
flushPendingText();
|
|
3237
4027
|
pendingTextRef.current = {
|
|
3238
4028
|
text: value,
|
|
3239
|
-
frame:
|
|
4029
|
+
frame: paintedFrameRef.current,
|
|
3240
4030
|
timer: setTimeout(flushPendingText, 16)
|
|
3241
4031
|
};
|
|
3242
4032
|
}
|
|
@@ -3249,9 +4039,9 @@ function BrowserViewport(props) {
|
|
|
3249
4039
|
composingRef.current = false;
|
|
3250
4040
|
input(event.currentTarget.value || event.data);
|
|
3251
4041
|
};
|
|
3252
|
-
const showCanvas = props.frame !== null;
|
|
3253
|
-
return /* @__PURE__ */
|
|
3254
|
-
/* @__PURE__ */
|
|
4042
|
+
const showCanvas = !props.controlUnavailable && props.frame !== null && paintedFrame !== null && sameBrowserDocument(props.frame, paintedFrame);
|
|
4043
|
+
return /* @__PURE__ */ jsxs2("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-black", children: [
|
|
4044
|
+
/* @__PURE__ */ jsx2(
|
|
3255
4045
|
"canvas",
|
|
3256
4046
|
{
|
|
3257
4047
|
ref: canvasRef,
|
|
@@ -3269,10 +4059,11 @@ function BrowserViewport(props) {
|
|
|
3269
4059
|
"aria-label": "Interactive browser page"
|
|
3270
4060
|
}
|
|
3271
4061
|
),
|
|
3272
|
-
/* @__PURE__ */
|
|
4062
|
+
/* @__PURE__ */ jsx2(
|
|
3273
4063
|
"textarea",
|
|
3274
4064
|
{
|
|
3275
4065
|
ref: inputRef,
|
|
4066
|
+
disabled: props.controlUnavailable,
|
|
3276
4067
|
defaultValue: "",
|
|
3277
4068
|
onInput: (event) => input(event.currentTarget.value, event.nativeEvent.isComposing),
|
|
3278
4069
|
onCompositionStart: compositionStart,
|
|
@@ -3282,26 +4073,44 @@ function BrowserViewport(props) {
|
|
|
3282
4073
|
onPaste: paste,
|
|
3283
4074
|
className: "pointer-events-none absolute left-1/2 top-1/2 size-px resize-none overflow-hidden opacity-0",
|
|
3284
4075
|
"aria-label": "Browser keyboard input",
|
|
4076
|
+
"aria-keyshortcuts": "Alt+ArrowDown",
|
|
3285
4077
|
autoCapitalize: "off",
|
|
3286
4078
|
autoCorrect: "off",
|
|
3287
4079
|
spellCheck: false
|
|
3288
4080
|
}
|
|
3289
4081
|
),
|
|
3290
|
-
!showCanvas ? /* @__PURE__ */
|
|
4082
|
+
!showCanvas ? /* @__PURE__ */ jsx2(
|
|
3291
4083
|
SemanticBrowserFallback,
|
|
3292
4084
|
{
|
|
3293
4085
|
observation: props.observation,
|
|
3294
4086
|
connectionState: props.connectionState,
|
|
3295
4087
|
supportsLiveFrames: props.supportsLiveFrames,
|
|
3296
4088
|
error: props.connectionError,
|
|
4089
|
+
controlUnavailable: props.controlUnavailable,
|
|
3297
4090
|
onAction: (action) => enqueue(action, null),
|
|
3298
4091
|
onReconnect: props.onReconnect,
|
|
3299
4092
|
reconnectLabel: props.reconnectLabel,
|
|
3300
4093
|
reconnectMessage: props.reconnectMessage
|
|
3301
4094
|
}
|
|
3302
4095
|
) : null,
|
|
3303
|
-
|
|
3304
|
-
|
|
4096
|
+
showCanvas ? /* @__PURE__ */ jsx2(
|
|
4097
|
+
BrowserSelectControl,
|
|
4098
|
+
{
|
|
4099
|
+
manualFallback: props.inputBatchAttachment?.focusedInputObservations !== true,
|
|
4100
|
+
activation: selectPopup,
|
|
4101
|
+
onDismiss: () => inputRef.current?.focus({ preventScroll: true }),
|
|
4102
|
+
observe: async () => {
|
|
4103
|
+
flushPendingText();
|
|
4104
|
+
flushPendingWheel();
|
|
4105
|
+
await actionTailRef.current;
|
|
4106
|
+
if (!mountedRef.current) throw new Error("The browser page changed.");
|
|
4107
|
+
return await props.onObserveForInput();
|
|
4108
|
+
},
|
|
4109
|
+
act: props.onSelectFromObservation
|
|
4110
|
+
}
|
|
4111
|
+
) : null,
|
|
4112
|
+
props.mutating ? /* @__PURE__ */ jsxs2("div", { className: "pointer-events-none absolute right-3 top-3 flex items-center gap-1.5 rounded-full border border-white/10 bg-black/65 px-2.5 py-1 text-[11px] text-white/80 backdrop-blur", children: [
|
|
4113
|
+
/* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3 animate-spin" }),
|
|
3305
4114
|
" ",
|
|
3306
4115
|
props.activityLabel ?? "Acting"
|
|
3307
4116
|
] }) : null
|
|
@@ -3309,20 +4118,21 @@ function BrowserViewport(props) {
|
|
|
3309
4118
|
}
|
|
3310
4119
|
function SemanticBrowserFallback(props) {
|
|
3311
4120
|
const controlFailure = interactionControlFailureFromError(props.error);
|
|
3312
|
-
const
|
|
4121
|
+
const { controlUnavailable } = props;
|
|
4122
|
+
const generationLoss = Boolean(props.reconnectMessage);
|
|
3313
4123
|
const nodes = semanticNodes(
|
|
3314
4124
|
props.observation?.semantic?.kind === "snapshot" ? props.observation.semantic.roots : []
|
|
3315
4125
|
);
|
|
3316
4126
|
const interactive = nodes.filter((node) => node.actions.includes("click")).slice(0, 8);
|
|
3317
|
-
return /* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
props.error ? /* @__PURE__ */
|
|
3320
|
-
/* @__PURE__ */
|
|
4127
|
+
return /* @__PURE__ */ jsx2("div", { className: "absolute inset-0 grid place-items-center bg-og-bg p-6", children: /* @__PURE__ */ jsxs2("div", { className: "w-full max-w-md rounded-og-lg border border-og-border bg-og-surface-1 p-4 shadow-lg", children: [
|
|
4128
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
4129
|
+
props.error ? /* @__PURE__ */ jsx2(CircleAlertIcon, { className: "size-4 text-og-danger" }) : props.connectionState === "semantic" ? /* @__PURE__ */ jsx2(ZapIcon, { className: "size-4 text-og-fg-muted" }) : /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-4 animate-spin text-og-fg-muted" }),
|
|
4130
|
+
/* @__PURE__ */ jsx2("p", { className: "text-og-menu font-medium text-og-fg", children: generationLoss ? "Chrome reconnected\u2014open a fresh browser/desktop." : controlUnavailable ? "Browser controls unavailable" : props.error ? props.supportsLiveFrames ? "Live view disconnected" : "Browser unavailable" : props.connectionState === "semantic" ? "Semantic browser" : browserConnectionLabel(props.connectionState) })
|
|
3321
4131
|
] }),
|
|
3322
|
-
props.error || props.reconnectMessage ? /* @__PURE__ */
|
|
3323
|
-
interactive.length > 0 ? /* @__PURE__ */
|
|
3324
|
-
/* @__PURE__ */
|
|
3325
|
-
/* @__PURE__ */
|
|
4132
|
+
props.error || props.reconnectMessage ? /* @__PURE__ */ jsx2("p", { className: "mt-2 text-og-control leading-5 text-og-fg-muted", children: props.reconnectMessage ?? controlFailure?.message ?? props.error?.message }) : null,
|
|
4133
|
+
interactive.length > 0 && !controlUnavailable ? /* @__PURE__ */ jsxs2("div", { className: "mt-3 border-t border-og-border pt-3", children: [
|
|
4134
|
+
/* @__PURE__ */ jsx2("p", { className: "mb-2 text-og-xs text-og-fg-subtle", children: props.supportsLiveFrames ? "Page controls remain available" : "Available page controls" }),
|
|
4135
|
+
/* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-1.5", children: interactive.map((node) => /* @__PURE__ */ jsx2(
|
|
3326
4136
|
"button",
|
|
3327
4137
|
{
|
|
3328
4138
|
type: "button",
|
|
@@ -3336,12 +4146,12 @@ function SemanticBrowserFallback(props) {
|
|
|
3336
4146
|
node.ref
|
|
3337
4147
|
)) })
|
|
3338
4148
|
] }) : null,
|
|
3339
|
-
props.error &&
|
|
4149
|
+
props.error && (!generationLoss || props.reconnectLabel) ? /* @__PURE__ */ jsx2(
|
|
3340
4150
|
"button",
|
|
3341
4151
|
{
|
|
3342
4152
|
type: "button",
|
|
3343
4153
|
onClick: props.onReconnect,
|
|
3344
|
-
className: "mt-3 text-og-control font-medium
|
|
4154
|
+
className: "mt-3 text-og-control font-medium og-link",
|
|
3345
4155
|
children: props.reconnectLabel ?? (controlFailure?.retryable === false ? "Try again" : "Reconnect")
|
|
3346
4156
|
}
|
|
3347
4157
|
) : null
|
|
@@ -3350,8 +4160,8 @@ function SemanticBrowserFallback(props) {
|
|
|
3350
4160
|
function BrowserStatusBar(props) {
|
|
3351
4161
|
const errors = (props.observation?.diagnostics.consoleErrorCount ?? 0) + (props.observation?.diagnostics.pageErrorCount ?? 0);
|
|
3352
4162
|
const failed = props.observation?.diagnostics.failedRequestCount ?? 0;
|
|
3353
|
-
return /* @__PURE__ */
|
|
3354
|
-
/* @__PURE__ */
|
|
4163
|
+
return /* @__PURE__ */ jsxs2("div", { className: "flex h-7 shrink-0 items-center gap-2 border-t border-og-border bg-og-surface-1 px-2 text-og-xs text-og-fg-subtle", children: [
|
|
4164
|
+
/* @__PURE__ */ jsx2(
|
|
3355
4165
|
"span",
|
|
3356
4166
|
{
|
|
3357
4167
|
className: cn(
|
|
@@ -3360,11 +4170,12 @@ function BrowserStatusBar(props) {
|
|
|
3360
4170
|
)
|
|
3361
4171
|
}
|
|
3362
4172
|
),
|
|
3363
|
-
/* @__PURE__ */
|
|
3364
|
-
/* @__PURE__ */
|
|
3365
|
-
/* @__PURE__ */
|
|
3366
|
-
|
|
3367
|
-
props.
|
|
4173
|
+
/* @__PURE__ */ jsx2("span", { children: props.connectionState === "live" ? "Live" : props.connectionState === "semantic" ? "Semantic" : browserConnectionLabel(props.connectionState) }),
|
|
4174
|
+
props.inputFailure ? /* @__PURE__ */ jsx2("span", { className: "text-og-status-failed", children: props.inputFailure.state === "failed" ? "Input failed" : "Input result unknown" }) : null,
|
|
4175
|
+
/* @__PURE__ */ jsx2("span", { children: props.profile?.name ?? "Temporary browser" }),
|
|
4176
|
+
/* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate", children: props.target?.title }),
|
|
4177
|
+
props.refreshing ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3 animate-spin" }) : null,
|
|
4178
|
+
props.onOpenComputer ? /* @__PURE__ */ jsxs2(
|
|
3368
4179
|
"button",
|
|
3369
4180
|
{
|
|
3370
4181
|
type: "button",
|
|
@@ -3372,12 +4183,12 @@ function BrowserStatusBar(props) {
|
|
|
3372
4183
|
className: "flex items-center gap-1 rounded px-1.5 py-0.5 transition hover:bg-og-surface-2 hover:text-og-fg",
|
|
3373
4184
|
"aria-label": "Open this browser window in Desktop",
|
|
3374
4185
|
children: [
|
|
3375
|
-
/* @__PURE__ */
|
|
4186
|
+
/* @__PURE__ */ jsx2(MonitorIcon, { className: "size-3" }),
|
|
3376
4187
|
"Desktop"
|
|
3377
4188
|
]
|
|
3378
4189
|
}
|
|
3379
4190
|
) : null,
|
|
3380
|
-
/* @__PURE__ */
|
|
4191
|
+
/* @__PURE__ */ jsxs2(
|
|
3381
4192
|
"button",
|
|
3382
4193
|
{
|
|
3383
4194
|
type: "button",
|
|
@@ -3389,7 +4200,7 @@ function BrowserStatusBar(props) {
|
|
|
3389
4200
|
props.diagnosticsOpen && "bg-og-surface-2 text-og-fg"
|
|
3390
4201
|
),
|
|
3391
4202
|
children: [
|
|
3392
|
-
/* @__PURE__ */
|
|
4203
|
+
/* @__PURE__ */ jsx2(BugIcon, { className: "size-3" }),
|
|
3393
4204
|
errors + failed > 0 ? errors + failed : "Debug"
|
|
3394
4205
|
]
|
|
3395
4206
|
}
|
|
@@ -3400,101 +4211,102 @@ function BrowserDiagnosticsDrawer(props) {
|
|
|
3400
4211
|
const session = props.session;
|
|
3401
4212
|
const diagnostics = props.observation?.diagnostics;
|
|
3402
4213
|
const semanticMode = props.observation?.semantic ? "Semantic page structure available" : props.observation?.screenshot ? "Visual fallback in use" : "Waiting for page observation";
|
|
3403
|
-
return /* @__PURE__ */
|
|
4214
|
+
return /* @__PURE__ */ jsxs2(
|
|
3404
4215
|
"aside",
|
|
3405
4216
|
{
|
|
3406
4217
|
id: "browser-diagnostics-drawer",
|
|
3407
4218
|
role: "region",
|
|
3408
4219
|
"aria-label": "Browser diagnostics",
|
|
3409
|
-
className: "absolute
|
|
4220
|
+
className: "absolute inset-y-0 right-0 z-40 flex min-h-0 w-full max-w-md flex-col border-l border-og-border bg-og-surface-1 shadow-2xl",
|
|
3410
4221
|
children: [
|
|
3411
|
-
/* @__PURE__ */
|
|
3412
|
-
/* @__PURE__ */
|
|
3413
|
-
/* @__PURE__ */
|
|
3414
|
-
/* @__PURE__ */
|
|
3415
|
-
/* @__PURE__ */
|
|
4222
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex min-h-11 shrink-0 items-center gap-2 border-b border-og-border px-3 py-2", children: [
|
|
4223
|
+
/* @__PURE__ */ jsx2(BugIcon, { className: "size-4 shrink-0 text-og-fg-muted" }),
|
|
4224
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
|
|
4225
|
+
/* @__PURE__ */ jsx2("p", { className: "text-og-control font-semibold text-og-fg", children: "Browser diagnostics" }),
|
|
4226
|
+
/* @__PURE__ */ jsx2("p", { className: "truncate text-og-xs text-og-fg-subtle", children: props.target?.title || shortUrl(props.target?.url ?? "") || "Current tab" })
|
|
3416
4227
|
] }),
|
|
3417
|
-
/* @__PURE__ */
|
|
4228
|
+
/* @__PURE__ */ jsx2(
|
|
3418
4229
|
"button",
|
|
3419
4230
|
{
|
|
3420
4231
|
type: "button",
|
|
3421
4232
|
onClick: props.onRefresh,
|
|
3422
4233
|
disabled: props.state.loading,
|
|
3423
|
-
className: "grid size-7 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-40",
|
|
4234
|
+
className: "grid size-7 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-40",
|
|
3424
4235
|
"aria-label": "Refresh browser diagnostics",
|
|
3425
|
-
children: /* @__PURE__ */
|
|
4236
|
+
children: /* @__PURE__ */ jsx2(RefreshCwIcon, { className: cn("size-3.5", props.state.loading && "animate-spin") })
|
|
3426
4237
|
}
|
|
3427
4238
|
),
|
|
3428
|
-
/* @__PURE__ */
|
|
4239
|
+
/* @__PURE__ */ jsx2(
|
|
3429
4240
|
"button",
|
|
3430
4241
|
{
|
|
3431
4242
|
type: "button",
|
|
3432
4243
|
onClick: props.onClose,
|
|
3433
|
-
className: "grid size-7 place-items-center rounded-og-sm text-og-muted transition hover:bg-og-surface-2 hover:text-og-fg",
|
|
4244
|
+
className: "grid size-7 shrink-0 place-items-center rounded-og-sm text-og-fg-muted transition hover:bg-og-surface-2 hover:text-og-fg",
|
|
3434
4245
|
"aria-label": "Close browser diagnostics",
|
|
3435
|
-
children: /* @__PURE__ */
|
|
4246
|
+
children: /* @__PURE__ */ jsx2(XIcon, { className: "size-3.5" })
|
|
3436
4247
|
}
|
|
3437
4248
|
)
|
|
3438
4249
|
] }),
|
|
3439
|
-
/* @__PURE__ */
|
|
3440
|
-
/* @__PURE__ */
|
|
3441
|
-
/* @__PURE__ */
|
|
4250
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-h-0 flex-1 overflow-y-auto", children: [
|
|
4251
|
+
/* @__PURE__ */ jsxs2("section", { className: "border-b border-og-border p-3", "aria-labelledby": "browser-runtime-title", children: [
|
|
4252
|
+
/* @__PURE__ */ jsx2(
|
|
3442
4253
|
"h3",
|
|
3443
4254
|
{
|
|
3444
4255
|
id: "browser-runtime-title",
|
|
3445
|
-
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-subtle",
|
|
4256
|
+
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-fg-subtle",
|
|
3446
4257
|
children: "Runtime"
|
|
3447
4258
|
}
|
|
3448
4259
|
),
|
|
3449
|
-
/* @__PURE__ */
|
|
3450
|
-
/* @__PURE__ */
|
|
3451
|
-
/* @__PURE__ */
|
|
3452
|
-
/* @__PURE__ */
|
|
3453
|
-
/* @__PURE__ */
|
|
4260
|
+
/* @__PURE__ */ jsxs2("dl", { className: "mt-2 grid grid-cols-[7rem_minmax(0,1fr)] gap-x-3 gap-y-1.5 text-og-xs", children: [
|
|
4261
|
+
/* @__PURE__ */ jsx2(DiagnosticFact, { label: "Engine", value: browserEngineLabel(session) }),
|
|
4262
|
+
/* @__PURE__ */ jsx2(DiagnosticFact, { label: "Driver", value: session?.driverId ?? "Unavailable" }),
|
|
4263
|
+
/* @__PURE__ */ jsx2(DiagnosticFact, { label: "Placement", value: placementLabel(session ?? void 0) }),
|
|
4264
|
+
/* @__PURE__ */ jsx2(
|
|
3454
4265
|
DiagnosticFact,
|
|
3455
4266
|
{
|
|
3456
4267
|
label: "Profile",
|
|
3457
4268
|
value: props.profile ? `${props.profile.name}${props.baseRevisionOrdinal ? ` \xB7 v${props.baseRevisionOrdinal}` : ""}` : "Temporary"
|
|
3458
4269
|
}
|
|
3459
4270
|
),
|
|
3460
|
-
/* @__PURE__ */
|
|
4271
|
+
/* @__PURE__ */ jsx2(
|
|
3461
4272
|
DiagnosticFact,
|
|
3462
4273
|
{
|
|
3463
4274
|
label: "Controller",
|
|
3464
4275
|
value: shortGeneration(session?.controller?.controllerGeneration)
|
|
3465
4276
|
}
|
|
3466
4277
|
),
|
|
3467
|
-
/* @__PURE__ */
|
|
4278
|
+
/* @__PURE__ */ jsx2(
|
|
3468
4279
|
DiagnosticFact,
|
|
3469
4280
|
{
|
|
3470
4281
|
label: "Network",
|
|
3471
4282
|
value: session?.networkRouteId ? "Custom route" : "Placement default"
|
|
3472
4283
|
}
|
|
3473
4284
|
),
|
|
3474
|
-
/* @__PURE__ */
|
|
4285
|
+
/* @__PURE__ */ jsx2(DiagnosticFact, { label: "Observation", value: semanticMode })
|
|
3475
4286
|
] })
|
|
3476
4287
|
] }),
|
|
3477
|
-
/* @__PURE__ */
|
|
3478
|
-
/* @__PURE__ */
|
|
4288
|
+
/* @__PURE__ */ jsxs2("section", { className: "border-b border-og-border p-3", "aria-labelledby": "browser-page-title", children: [
|
|
4289
|
+
/* @__PURE__ */ jsx2(
|
|
3479
4290
|
"h3",
|
|
3480
4291
|
{
|
|
3481
4292
|
id: "browser-page-title",
|
|
3482
|
-
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-subtle",
|
|
3483
|
-
children: "
|
|
4293
|
+
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-fg-subtle",
|
|
4294
|
+
children: "Tab diagnostics"
|
|
3484
4295
|
}
|
|
3485
4296
|
),
|
|
3486
|
-
/* @__PURE__ */
|
|
3487
|
-
|
|
3488
|
-
/* @__PURE__ */
|
|
3489
|
-
/* @__PURE__ */
|
|
3490
|
-
/* @__PURE__ */
|
|
4297
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-og-xs text-og-fg-subtle", children: "Includes earlier pages in this tab." }),
|
|
4298
|
+
/* @__PURE__ */ jsxs2("dl", { className: "mt-2 grid grid-cols-2 gap-2", children: [
|
|
4299
|
+
/* @__PURE__ */ jsx2(DiagnosticCount, { label: "Console errors", value: diagnostics?.consoleErrorCount }),
|
|
4300
|
+
/* @__PURE__ */ jsx2(DiagnosticCount, { label: "Page errors", value: diagnostics?.pageErrorCount }),
|
|
4301
|
+
/* @__PURE__ */ jsx2(DiagnosticCount, { label: "Failed requests", value: diagnostics?.failedRequestCount }),
|
|
4302
|
+
/* @__PURE__ */ jsx2(DiagnosticCount, { label: "Downloads", value: diagnostics?.downloadCount })
|
|
3491
4303
|
] }),
|
|
3492
|
-
session?.failureCode ? /* @__PURE__ */
|
|
4304
|
+
session?.failureCode ? /* @__PURE__ */ jsxs2("p", { className: "mt-2 rounded-og-sm border border-og-status-error/30 bg-og-status-error/5 px-2.5 py-2 text-og-xs text-og-danger", children: [
|
|
3493
4305
|
"Browser state: ",
|
|
3494
4306
|
session.failureCode
|
|
3495
4307
|
] }) : null
|
|
3496
4308
|
] }),
|
|
3497
|
-
props.downloadsEnabled ? /* @__PURE__ */
|
|
4309
|
+
props.downloadsEnabled ? /* @__PURE__ */ jsx2(
|
|
3498
4310
|
BrowserDownloadsPanel,
|
|
3499
4311
|
{
|
|
3500
4312
|
downloads: props.downloads,
|
|
@@ -3506,39 +4318,39 @@ function BrowserDiagnosticsDrawer(props) {
|
|
|
3506
4318
|
onRefresh: props.onRefreshDownloads
|
|
3507
4319
|
}
|
|
3508
4320
|
) : null,
|
|
3509
|
-
/* @__PURE__ */
|
|
3510
|
-
/* @__PURE__ */
|
|
3511
|
-
/* @__PURE__ */
|
|
4321
|
+
/* @__PURE__ */ jsxs2("section", { className: "p-3", "aria-labelledby": "browser-events-title", children: [
|
|
4322
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-2", children: [
|
|
4323
|
+
/* @__PURE__ */ jsx2(
|
|
3512
4324
|
"h3",
|
|
3513
4325
|
{
|
|
3514
4326
|
id: "browser-events-title",
|
|
3515
|
-
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-subtle",
|
|
4327
|
+
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-fg-subtle",
|
|
3516
4328
|
children: "Recent events"
|
|
3517
4329
|
}
|
|
3518
4330
|
),
|
|
3519
|
-
props.state.batch?.truncated ? /* @__PURE__ */
|
|
4331
|
+
props.state.batch?.truncated ? /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-og-fg-subtle", children: "Newest 100" }) : null
|
|
3520
4332
|
] }),
|
|
3521
|
-
props.state.loading && !props.state.batch ? /* @__PURE__ */
|
|
3522
|
-
/* @__PURE__ */
|
|
4333
|
+
props.state.loading && !props.state.batch ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 py-6 text-og-control text-og-fg-muted", children: [
|
|
4334
|
+
/* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3.5 animate-spin" }),
|
|
3523
4335
|
" Loading diagnostics\u2026"
|
|
3524
|
-
] }) : props.state.error ? /* @__PURE__ */
|
|
3525
|
-
/* @__PURE__ */
|
|
3526
|
-
/* @__PURE__ */
|
|
4336
|
+
] }) : props.state.error ? /* @__PURE__ */ jsxs2("div", { className: "py-5", children: [
|
|
4337
|
+
/* @__PURE__ */ jsx2("p", { className: "text-og-control text-og-danger", children: props.state.error.message }),
|
|
4338
|
+
/* @__PURE__ */ jsx2(
|
|
3527
4339
|
"button",
|
|
3528
4340
|
{
|
|
3529
4341
|
type: "button",
|
|
3530
4342
|
onClick: props.onRefresh,
|
|
3531
|
-
className: "mt-2 text-og-control font-medium
|
|
4343
|
+
className: "mt-2 text-og-control font-medium og-link",
|
|
3532
4344
|
children: "Try again"
|
|
3533
4345
|
}
|
|
3534
4346
|
)
|
|
3535
|
-
] }) : props.state.batch?.entries.length ? /* @__PURE__ */
|
|
4347
|
+
] }) : props.state.batch?.entries.length ? /* @__PURE__ */ jsx2("ol", { className: "mt-2 space-y-2", children: props.state.batch.entries.map((entry) => /* @__PURE__ */ jsxs2(
|
|
3536
4348
|
"li",
|
|
3537
4349
|
{
|
|
3538
4350
|
className: "rounded-og-sm border border-og-border bg-og-bg p-2.5",
|
|
3539
4351
|
children: [
|
|
3540
|
-
/* @__PURE__ */
|
|
3541
|
-
/* @__PURE__ */
|
|
4352
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-[10px] text-og-fg-subtle", children: [
|
|
4353
|
+
/* @__PURE__ */ jsx2(
|
|
3542
4354
|
"span",
|
|
3543
4355
|
{
|
|
3544
4356
|
className: cn(
|
|
@@ -3548,14 +4360,14 @@ function BrowserDiagnosticsDrawer(props) {
|
|
|
3548
4360
|
children: diagnosticKindLabel(entry.kind)
|
|
3549
4361
|
}
|
|
3550
4362
|
),
|
|
3551
|
-
/* @__PURE__ */
|
|
4363
|
+
/* @__PURE__ */ jsx2("span", { className: "ml-auto", children: formatDiagnosticTime(entry.occurredAt) })
|
|
3552
4364
|
] }),
|
|
3553
|
-
/* @__PURE__ */
|
|
3554
|
-
entry.url || entry.filename || entry.method || entry.status ? /* @__PURE__ */
|
|
4365
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 whitespace-pre-wrap break-words text-og-xs leading-5 text-og-fg", children: entry.message }),
|
|
4366
|
+
entry.url || entry.filename || entry.method || entry.status ? /* @__PURE__ */ jsx2("p", { className: "mt-1 truncate font-og-mono text-[10px] text-og-fg-subtle", children: [entry.method, entry.status, entry.filename, entry.url].filter((value) => value !== null).join(" \xB7 ") }) : null
|
|
3555
4367
|
]
|
|
3556
4368
|
},
|
|
3557
4369
|
entry.sequence
|
|
3558
|
-
)) }) : /* @__PURE__ */
|
|
4370
|
+
)) }) : /* @__PURE__ */ jsx2("p", { className: "py-6 text-og-control text-og-fg-muted", children: "No diagnostics for this tab." })
|
|
3559
4371
|
] })
|
|
3560
4372
|
] })
|
|
3561
4373
|
]
|
|
@@ -3563,10 +4375,10 @@ function BrowserDiagnosticsDrawer(props) {
|
|
|
3563
4375
|
);
|
|
3564
4376
|
}
|
|
3565
4377
|
function BrowserDownloadsPanel(props) {
|
|
3566
|
-
const [paths, setPaths] =
|
|
3567
|
-
const [overwrite, setOverwrite] =
|
|
3568
|
-
const [savedPaths, setSavedPaths] =
|
|
3569
|
-
const [errors, setErrors] =
|
|
4378
|
+
const [paths, setPaths] = useState9({});
|
|
4379
|
+
const [overwrite, setOverwrite] = useState9({});
|
|
4380
|
+
const [savedPaths, setSavedPaths] = useState9({});
|
|
4381
|
+
const [errors, setErrors] = useState9({});
|
|
3570
4382
|
const saving = useMemo2(() => new Set(props.savingDownloadIds), [props.savingDownloadIds]);
|
|
3571
4383
|
const save = (download) => {
|
|
3572
4384
|
const destinationPath = (paths[download.id] ?? defaultDownloadDestination(download)).trim();
|
|
@@ -3581,46 +4393,46 @@ function BrowserDownloadsPanel(props) {
|
|
|
3581
4393
|
}));
|
|
3582
4394
|
});
|
|
3583
4395
|
};
|
|
3584
|
-
return /* @__PURE__ */
|
|
3585
|
-
/* @__PURE__ */
|
|
3586
|
-
/* @__PURE__ */
|
|
3587
|
-
/* @__PURE__ */
|
|
4396
|
+
return /* @__PURE__ */ jsxs2("section", { className: "border-b border-og-border p-3", "aria-labelledby": "browser-downloads-title", children: [
|
|
4397
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
4398
|
+
/* @__PURE__ */ jsx2(DownloadIcon, { className: "size-3.5 text-og-fg-muted" }),
|
|
4399
|
+
/* @__PURE__ */ jsx2(
|
|
3588
4400
|
"h3",
|
|
3589
4401
|
{
|
|
3590
4402
|
id: "browser-downloads-title",
|
|
3591
|
-
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-subtle",
|
|
4403
|
+
className: "text-[10px] font-semibold uppercase tracking-[0.14em] text-og-fg-subtle",
|
|
3592
4404
|
children: "Downloads"
|
|
3593
4405
|
}
|
|
3594
4406
|
),
|
|
3595
|
-
props.refreshing ? /* @__PURE__ */
|
|
4407
|
+
props.refreshing ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "ml-auto size-3 animate-spin text-og-fg-muted" }) : null
|
|
3596
4408
|
] }),
|
|
3597
|
-
props.loading ? /* @__PURE__ */
|
|
3598
|
-
/* @__PURE__ */
|
|
4409
|
+
props.loading ? /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 py-5 text-og-control text-og-fg-muted", children: [
|
|
4410
|
+
/* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3.5 animate-spin" }),
|
|
3599
4411
|
" Loading downloads\u2026"
|
|
3600
|
-
] }) : props.error ? /* @__PURE__ */
|
|
3601
|
-
/* @__PURE__ */
|
|
3602
|
-
/* @__PURE__ */
|
|
4412
|
+
] }) : props.error ? /* @__PURE__ */ jsxs2("div", { className: "py-4", children: [
|
|
4413
|
+
/* @__PURE__ */ jsx2("p", { className: "text-og-control text-og-danger", children: props.error.message }),
|
|
4414
|
+
/* @__PURE__ */ jsx2(
|
|
3603
4415
|
"button",
|
|
3604
4416
|
{
|
|
3605
4417
|
type: "button",
|
|
3606
4418
|
onClick: props.onRefresh,
|
|
3607
|
-
className: "mt-2 text-og-control font-medium
|
|
4419
|
+
className: "mt-2 text-og-control font-medium og-link",
|
|
3608
4420
|
children: "Try again"
|
|
3609
4421
|
}
|
|
3610
4422
|
)
|
|
3611
|
-
] }) : props.downloads.length === 0 ? /* @__PURE__ */
|
|
4423
|
+
] }) : props.downloads.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "py-4 text-og-control text-og-fg-muted", children: "No files downloaded yet." }) : /* @__PURE__ */ jsx2("ol", { className: "mt-2 space-y-2", children: props.downloads.map((download) => {
|
|
3612
4424
|
const destinationPath = paths[download.id] ?? defaultDownloadDestination(download);
|
|
3613
4425
|
const isSaving = saving.has(download.id);
|
|
3614
4426
|
const isSaved = savedPaths[download.id] === destinationPath;
|
|
3615
|
-
return /* @__PURE__ */
|
|
4427
|
+
return /* @__PURE__ */ jsxs2(
|
|
3616
4428
|
"li",
|
|
3617
4429
|
{
|
|
3618
4430
|
className: "rounded-og-sm border border-og-border bg-og-bg p-2.5",
|
|
3619
4431
|
children: [
|
|
3620
|
-
/* @__PURE__ */
|
|
3621
|
-
/* @__PURE__ */
|
|
3622
|
-
/* @__PURE__ */
|
|
3623
|
-
/* @__PURE__ */
|
|
4432
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-start gap-2", children: [
|
|
4433
|
+
/* @__PURE__ */ jsx2("span", { className: "mt-0.5 grid size-6 shrink-0 place-items-center rounded bg-og-surface-2 text-og-fg-muted", children: isSaved ? /* @__PURE__ */ jsx2(FileCheck2Icon, { className: "size-3.5 text-og-status-idle" }) : /* @__PURE__ */ jsx2(DownloadIcon, { className: "size-3.5" }) }),
|
|
4434
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
|
|
4435
|
+
/* @__PURE__ */ jsx2(
|
|
3624
4436
|
"p",
|
|
3625
4437
|
{
|
|
3626
4438
|
className: "truncate text-og-xs font-medium text-og-fg",
|
|
@@ -3628,12 +4440,12 @@ function BrowserDownloadsPanel(props) {
|
|
|
3628
4440
|
children: download.filename
|
|
3629
4441
|
}
|
|
3630
4442
|
),
|
|
3631
|
-
/* @__PURE__ */
|
|
4443
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-[10px] text-og-fg-subtle", children: downloadStatusLabel(download) })
|
|
3632
4444
|
] })
|
|
3633
4445
|
] }),
|
|
3634
|
-
download.status === "completed" ? /* @__PURE__ */
|
|
3635
|
-
/* @__PURE__ */
|
|
3636
|
-
/* @__PURE__ */
|
|
4446
|
+
download.status === "completed" ? /* @__PURE__ */ jsxs2("div", { className: "mt-2", children: [
|
|
4447
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-1.5", children: [
|
|
4448
|
+
/* @__PURE__ */ jsx2(
|
|
3637
4449
|
"input",
|
|
3638
4450
|
{
|
|
3639
4451
|
type: "text",
|
|
@@ -3648,10 +4460,10 @@ function BrowserDownloadsPanel(props) {
|
|
|
3648
4460
|
},
|
|
3649
4461
|
disabled: isSaving,
|
|
3650
4462
|
"aria-label": `Workspace path for ${download.filename}`,
|
|
3651
|
-
className: "h-7 min-w-0 flex-1 rounded-og-sm border border-og-border bg-og-surface-
|
|
4463
|
+
className: "h-7 min-w-0 flex-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-og-mono text-[10px] text-og-fg transition focus:border-og-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:opacity-50"
|
|
3652
4464
|
}
|
|
3653
4465
|
),
|
|
3654
|
-
/* @__PURE__ */
|
|
4466
|
+
/* @__PURE__ */ jsxs2(
|
|
3655
4467
|
"button",
|
|
3656
4468
|
{
|
|
3657
4469
|
type: "button",
|
|
@@ -3659,14 +4471,14 @@ function BrowserDownloadsPanel(props) {
|
|
|
3659
4471
|
disabled: isSaving || !destinationPath.trim() || isSaved && !overwrite[download.id],
|
|
3660
4472
|
className: "inline-flex h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-[10px] font-medium text-og-fg transition hover:bg-og-surface-2 disabled:opacity-40",
|
|
3661
4473
|
children: [
|
|
3662
|
-
isSaving ? /* @__PURE__ */
|
|
4474
|
+
isSaving ? /* @__PURE__ */ jsx2(LoaderCircleIcon, { className: "size-3 animate-spin" }) : /* @__PURE__ */ jsx2(SaveIcon, { className: "size-3" }),
|
|
3663
4475
|
isSaving ? "Saving" : isSaved ? "Saved" : overwrite[download.id] ? "Replace" : "Save"
|
|
3664
4476
|
]
|
|
3665
4477
|
}
|
|
3666
4478
|
)
|
|
3667
4479
|
] }),
|
|
3668
|
-
/* @__PURE__ */
|
|
3669
|
-
/* @__PURE__ */
|
|
4480
|
+
/* @__PURE__ */ jsxs2("label", { className: "mt-1.5 flex w-fit items-center gap-1.5 text-[10px] text-og-fg-subtle", children: [
|
|
4481
|
+
/* @__PURE__ */ jsx2(
|
|
3670
4482
|
"input",
|
|
3671
4483
|
{
|
|
3672
4484
|
type: "checkbox",
|
|
@@ -3684,7 +4496,7 @@ function BrowserDownloadsPanel(props) {
|
|
|
3684
4496
|
),
|
|
3685
4497
|
"Replace an existing workspace file"
|
|
3686
4498
|
] }),
|
|
3687
|
-
errors[download.id] ? /* @__PURE__ */
|
|
4499
|
+
errors[download.id] ? /* @__PURE__ */ jsx2("p", { className: "mt-1.5 break-words text-[10px] text-og-danger", children: errors[download.id] }) : null
|
|
3688
4500
|
] }) : null
|
|
3689
4501
|
]
|
|
3690
4502
|
},
|
|
@@ -3712,22 +4524,22 @@ function defaultDownloadDestination(download) {
|
|
|
3712
4524
|
return portable;
|
|
3713
4525
|
}
|
|
3714
4526
|
function DiagnosticFact(props) {
|
|
3715
|
-
return /* @__PURE__ */
|
|
3716
|
-
/* @__PURE__ */
|
|
3717
|
-
/* @__PURE__ */
|
|
4527
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
4528
|
+
/* @__PURE__ */ jsx2("dt", { className: "text-og-fg-subtle", children: props.label }),
|
|
4529
|
+
/* @__PURE__ */ jsx2("dd", { className: "min-w-0 truncate text-og-fg", title: props.value, children: props.value })
|
|
3718
4530
|
] });
|
|
3719
4531
|
}
|
|
3720
4532
|
function DiagnosticCount(props) {
|
|
3721
|
-
return /* @__PURE__ */
|
|
3722
|
-
/* @__PURE__ */
|
|
3723
|
-
/* @__PURE__ */
|
|
4533
|
+
return /* @__PURE__ */ jsxs2("div", { className: "rounded-og-sm border border-og-border bg-og-bg px-2.5 py-2", children: [
|
|
4534
|
+
/* @__PURE__ */ jsx2("dt", { className: "text-[10px] text-og-fg-subtle", children: props.label }),
|
|
4535
|
+
/* @__PURE__ */ jsx2(
|
|
3724
4536
|
"dd",
|
|
3725
4537
|
{
|
|
3726
4538
|
className: cn(
|
|
3727
4539
|
"mt-0.5 text-og-sm font-semibold",
|
|
3728
|
-
props.value ? "text-og-fg" : "text-og-muted"
|
|
4540
|
+
props.value ? "text-og-fg" : "text-og-fg-muted"
|
|
3729
4541
|
),
|
|
3730
|
-
children: props.value
|
|
4542
|
+
children: props.value ?? "Unavailable"
|
|
3731
4543
|
}
|
|
3732
4544
|
)
|
|
3733
4545
|
] });
|
|
@@ -3754,23 +4566,23 @@ function diagnosticKindLabel(kind) {
|
|
|
3754
4566
|
}
|
|
3755
4567
|
}
|
|
3756
4568
|
function diagnosticTone(level) {
|
|
3757
|
-
if (level === "error") return "text-og-
|
|
4569
|
+
if (level === "error") return "text-og-danger";
|
|
3758
4570
|
if (level === "warning") return "text-og-status-waiting";
|
|
3759
|
-
return "text-og-muted";
|
|
4571
|
+
return "text-og-fg-muted";
|
|
3760
4572
|
}
|
|
3761
4573
|
function formatDiagnosticTime(value) {
|
|
3762
4574
|
const date = new Date(value);
|
|
3763
4575
|
return Number.isNaN(date.getTime()) ? "" : date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
3764
4576
|
}
|
|
3765
4577
|
function BrowserNotice(props) {
|
|
3766
|
-
return /* @__PURE__ */
|
|
4578
|
+
return /* @__PURE__ */ jsx2(
|
|
3767
4579
|
"div",
|
|
3768
4580
|
{
|
|
3769
4581
|
className: cn(
|
|
3770
|
-
"grid h-full place-items-center bg-og-bg text-og-control text-og-muted",
|
|
4582
|
+
"grid h-full place-items-center bg-og-bg text-og-control text-og-fg-muted",
|
|
3771
4583
|
props.className
|
|
3772
4584
|
),
|
|
3773
|
-
children: /* @__PURE__ */
|
|
4585
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
3774
4586
|
props.icon,
|
|
3775
4587
|
props.text
|
|
3776
4588
|
] })
|
|
@@ -3819,7 +4631,10 @@ function frameMatchesSelectedTarget(frame, session, target) {
|
|
|
3819
4631
|
);
|
|
3820
4632
|
}
|
|
3821
4633
|
function sameFrameFence(left, right) {
|
|
3822
|
-
return left
|
|
4634
|
+
return sameBrowserDocument(left, right) && left.frameId === right.frameId;
|
|
4635
|
+
}
|
|
4636
|
+
function sameBrowserDocument(left, right) {
|
|
4637
|
+
return left.browserSessionId === right.browserSessionId && left.controllerGeneration === right.controllerGeneration && left.targetId === right.targetId && left.targetGeneration === right.targetGeneration && left.documentGeneration === right.documentGeneration;
|
|
3823
4638
|
}
|
|
3824
4639
|
function sameOptionalBrowserFrame(left, right) {
|
|
3825
4640
|
return left === null || right === null ? left === right : sameFrameFence(left, right);
|
|
@@ -3895,13 +4710,14 @@ function shortUrl(value) {
|
|
|
3895
4710
|
}
|
|
3896
4711
|
|
|
3897
4712
|
export {
|
|
3898
|
-
|
|
4713
|
+
useSiteAuthConnections,
|
|
3899
4714
|
useAttachedBrowsers,
|
|
4715
|
+
useBrowserSessions,
|
|
3900
4716
|
useBrowserIdentities,
|
|
3901
|
-
useBrowserDownloads,
|
|
3902
4717
|
useBrowserSession,
|
|
3903
|
-
|
|
3904
|
-
|
|
4718
|
+
useBrowserDownloads,
|
|
4719
|
+
useBrowserFrameStream,
|
|
4720
|
+
staleBrowserEndRetryDelayMs,
|
|
3905
4721
|
BrowserViewer
|
|
3906
4722
|
};
|
|
3907
|
-
//# sourceMappingURL=chunk-
|
|
4723
|
+
//# sourceMappingURL=chunk-KZC6QRNR.js.map
|