@opengeni/react 6.7.0 → 6.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/app-state.js +9 -9
- package/dist/app/components/Composer.js +20 -20
- package/dist/app/components/agent/agent-capability-picker.js +6 -6
- package/dist/app/components/artifacts/artifact-browse-controls.js +2 -2
- package/dist/app/components/artifacts/artifact-library.js +13 -13
- package/dist/app/components/artifacts/artifact-viewer.js +21 -21
- package/dist/app/components/artifacts/chat-interactive-block.js +14 -14
- package/dist/app/components/artifacts/copy-artifact-link.js +2 -2
- package/dist/app/components/artifacts/file-reach-dialog.js +7 -7
- package/dist/app/components/artifacts/inline-chat-image.js +22 -22
- package/dist/app/components/artifacts/retained-file-preview.js +23 -23
- package/dist/app/components/artifacts/retained-text-preview.js +3 -3
- package/dist/app/components/artifacts/site-actions.d.ts +43 -0
- package/dist/app/components/artifacts/site-actions.js +38 -0
- package/dist/app/components/artifacts/site-audience.js +5 -5
- package/dist/app/components/artifacts/site-conversations.js +13 -13
- package/dist/app/components/artifacts/site-data.js +14 -14
- package/dist/app/components/artifacts/site-publishing-page.js +31 -31
- package/dist/app/components/artifacts/site-publishing.js +25 -25
- package/dist/app/components/artifacts/site-settings.js +30 -30
- package/dist/app/components/artifacts/site-version-menu.js +3 -3
- package/dist/app/components/billing-class-mark.js +3 -3
- package/dist/app/components/bots/bot-launch-strip.js +23 -23
- package/dist/app/components/bots/bot-template-dialog.js +30 -30
- package/dist/app/components/bots/bot-template-shortcuts.js +23 -23
- package/dist/app/components/bots/bot-templates-page.js +37 -37
- package/dist/app/components/capabilities/capability-detail-sheet.js +9 -9
- package/dist/app/components/capabilities/capability-logo-source.js +14 -15
- package/dist/app/components/capabilities/connection-ownership-selector.js +4 -4
- package/dist/app/components/capabilities/connector-tool-permissions.js +4 -4
- package/dist/app/components/capabilities/detail-dialog.js +3 -3
- package/dist/app/components/capabilities/native-connect-setup.js +16 -17
- package/dist/app/components/capabilities/native-connect-setup.js.map +1 -1
- package/dist/app/components/capabilities/own-logins-shared-heads-up.js +3 -3
- package/dist/app/components/capabilities/prepared-mcp-setup-card.js +16 -17
- package/dist/app/components/capabilities/session-capability-card.js +49 -50
- package/dist/app/components/capabilities/session-capability-card.js.map +1 -1
- package/dist/app/components/capabilities/session-chrome-card.js +24 -25
- package/dist/app/components/capabilities/session-custom-mcp-card.js +17 -18
- package/dist/app/components/capabilities/session-github-card.js +17 -18
- package/dist/app/components/capabilities/session-machine-card.js +23 -24
- package/dist/app/components/capabilities/session-personal-github-card.js +15 -16
- package/dist/app/components/capabilities/session-plugin-card.js +9 -10
- package/dist/app/components/capabilities/use-connection-accounts.js +2 -2
- package/dist/app/components/command-menu/chat-status.js +19 -19
- package/dist/app/components/command-menu/chat-switcher.js +35 -35
- package/dist/app/components/command-menu/command-menu.js +42 -42
- package/dist/app/components/command-menu/shortcut-sheet.js +11 -11
- package/dist/app/components/composer-capabilities-menu-body.js +4 -4
- package/dist/app/components/composer-mobile-plus-panel.js +10 -10
- package/dist/app/components/composer-mobile-plus.js +3 -3
- package/dist/app/components/credit-required-gate.js +1 -1
- package/dist/app/components/credit-required-prompt.js +4 -4
- package/dist/app/components/credits/checkout-credits-celebration.js +3 -3
- package/dist/app/components/credits/checkout-return.js +3 -3
- package/dist/app/components/credits/credit-refusal-notice.js +2 -2
- package/dist/app/components/desktop/app-shots.js +6 -6
- package/dist/app/components/desktop/computer-use.js +2 -2
- package/dist/app/components/desktop/this-computer.js +5 -5
- package/dist/app/components/feedback.js +5 -5
- package/dist/app/components/github-app-connect-launcher.js +1 -1
- package/dist/app/components/machines/connect-machine-dialog.js +14 -14
- package/dist/app/components/markdown.js +7 -7
- package/dist/app/components/models/models-ui.js +6 -6
- package/dist/app/components/my-things.js +6 -6
- package/dist/app/components/own-where-it-works.js +5 -5
- package/dist/app/components/personal-resource-attachment-surface.js +4 -4
- package/dist/app/components/pickers.js +5 -5
- package/dist/app/components/rail/channel-create-dialog.js +5 -5
- package/dist/app/components/rail/project-glyph.js +23 -23
- package/dist/app/components/rail/project-profile.js +32 -32
- package/dist/app/components/rail/rail-context.js +1 -1
- package/dist/app/components/rail/rail-sections.js +70 -61
- package/dist/app/components/rail/session-header.js +54 -53
- package/dist/app/components/rail/session-list.js +68 -59
- package/dist/app/components/rail/session-row-content.js +4 -4
- package/dist/app/components/rail/session-row-hover-details.js +18 -18
- package/dist/app/components/rail/session-shell.js +89 -80
- package/dist/app/components/rail/site-session-group-heading.js +29 -12
- package/dist/app/components/session/agent-configuration-panel.js +14 -14
- package/dist/app/components/session/artifact-session-page.js +5 -5
- package/dist/app/components/session/banners.js +9 -9
- package/dist/app/components/session/console-new-conversation.js +43 -44
- package/dist/app/components/session/descendant-requests.js +39 -40
- package/dist/app/components/session/descendant-requests.js.map +1 -1
- package/dist/app/components/session/editable-artifacts-workspace.js +27 -27
- package/dist/app/components/session/failed-session-banner.js +9 -9
- package/dist/app/components/session/failure-recovery-boundary.js +3 -3
- package/dist/app/components/session/human-input-delegation-record.js +2 -2
- package/dist/app/components/session/human-input.js +37 -38
- package/dist/app/components/session/inspector.js +47 -48
- package/dist/app/components/session/inspector.js.map +1 -1
- package/dist/app/components/session/message-actions.js +5 -5
- package/dist/app/components/session/message-resource-attachments.js +13 -13
- package/dist/app/components/session/model-recovery-notice.js +3 -3
- package/dist/app/components/session/new-session-settings-menu.js +6 -6
- package/dist/app/components/session/new-session-setup-strip.js +24 -24
- package/dist/app/components/session/sandbox-recovery-actions.js +5 -5
- package/dist/app/components/session/sandbox-switcher.js +8 -8
- package/dist/app/components/session/sandbox-workspace.js +52 -53
- package/dist/app/components/session/search-markdown-highlight.js +8 -8
- package/dist/app/components/session/search-results-view.js +9 -9
- package/dist/app/components/session/session-admin-access.js +5 -5
- package/dist/app/components/session/session-admission-notice.js +4 -4
- package/dist/app/components/session/session-avatar-picker.js +24 -24
- package/dist/app/components/session/session-avatar.js +22 -22
- package/dist/app/components/session/session-machine-access-notice.js +4 -4
- package/dist/app/components/session/session-profile-dialog.js +29 -29
- package/dist/app/components/session/session-profile-editor.js +30 -30
- package/dist/app/components/session/session-retention.js +3 -3
- package/dist/app/components/session/session-search-dialog.js +11 -11
- package/dist/app/components/session/session-tenancy-control.js +4 -4
- package/dist/app/components/session/session-usage-limit-section.js +4 -4
- package/dist/app/components/session/share-chat-dialog.js +7 -7
- package/dist/app/components/session/subagents.js +12 -12
- package/dist/app/components/session/subscription-account-indicator.js +6 -6
- package/dist/app/components/settings/row-select.js +4 -4
- package/dist/app/components/transcription-settings.js +6 -6
- package/dist/app/components/ui/destructive-confirm.js +7 -7
- package/dist/app/components/usage/usage-entry.js +3 -3
- package/dist/app/components/window-bar.d.ts +3 -1
- package/dist/app/components/window-bar.js +13 -11
- package/dist/app/components/workspace-composer-plus.js +19 -20
- package/dist/app/components/workspace-reach.js +4 -4
- package/dist/app/embed/session-app.js +173 -167
- package/dist/app/lib/actions/actions-provider.js +9 -9
- package/dist/app/lib/agent-capabilities.js +3 -3
- package/dist/app/lib/codex-usage-query.js +2 -2
- package/dist/app/lib/composer-connectors.js +15 -16
- package/dist/app/lib/composer-send-blocking.d.ts +135 -1
- package/dist/app/lib/composer-send-blocking.js +30 -3
- package/dist/app/lib/console-site.js +2 -2
- package/dist/app/lib/console-text.js +2 -2
- package/dist/app/lib/copy-link.d.ts +2 -0
- package/dist/app/lib/events.js +15 -15
- package/dist/app/lib/failed-session-copy.js +4 -4
- package/dist/app/lib/model-access-onboarding.js +3 -3
- package/dist/app/lib/model-access.js +2 -2
- package/dist/app/lib/move-chat-to-machine.js +3 -3
- package/dist/app/lib/session-branch-cache.js +12 -12
- package/dist/app/lib/session-composer-readiness.d.ts +2 -2
- package/dist/app/lib/session-create.js +4 -4
- package/dist/app/lib/session-group-pagination.js +12 -12
- package/dist/app/lib/session-hover-facts.js +17 -17
- package/dist/app/lib/session-model.js +2 -2
- package/dist/app/lib/session-rail.js +9 -9
- package/dist/app/lib/session-rename.js +3 -3
- package/dist/app/lib/sessions-group.js +11 -11
- package/dist/app/lib/site-sidebar-bridge.d.ts +24 -0
- package/dist/app/lib/site-tool-consent-dialog.js +9 -10
- package/dist/app/lib/site-tool-consent-dialog.js.map +1 -1
- package/dist/app/lib/site-tool-consent.js +1 -1
- package/dist/app/lib/turn-failure-analytics.js +5 -5
- package/dist/app/lib/use-follow-up-repositories.js +5 -5
- package/dist/app/lib/use-workspace-machines.js +5 -5
- package/dist/app/lib/use-workspace-model-catalog.js +3 -3
- package/dist/app/lib/use-workspace-rigs.js +2 -2
- package/dist/app/lib/workspace-navigation-preference.js +4 -4
- package/dist/app/lib/workspace-scope-context.js +3 -3
- package/dist/app/routes/artifacts.js +69 -69
- package/dist/app/routes/retained-artifact.js +48 -48
- package/dist/app/routes/session.js +100 -101
- package/dist/app/routes/sessions-index-hydration.js +5 -5
- package/dist/app/routes/sessions-index.js +85 -85
- package/dist/app/routes/site-view.js +177 -85
- package/dist/app/routes/site-view.js.map +1 -1
- package/dist/artifacts-document.js +4 -4
- package/dist/artifacts-presentation.js +4 -4
- package/dist/artifacts-spreadsheet.js +4 -4
- package/dist/artifacts.js +13 -13
- package/dist/automations.js +12 -12
- package/dist/{browser-viewer-TC27OCIP.js → browser-viewer-ZHQDVHZ2.js} +5 -5
- package/dist/{chat-interactive-block-RWPQBHVS.js → chat-interactive-block-VSDD6X3M.js} +5 -5
- package/dist/{chunk-5MOJZORA.js → chunk-2EA4IRIP.js} +34 -3
- package/dist/chunk-2EA4IRIP.js.map +1 -0
- package/dist/{chunk-C43KRXGA.js → chunk-2GCHGWNE.js} +3 -3
- package/dist/{chunk-XLH7QY2R.js → chunk-2J77TWGH.js} +3 -3
- package/dist/{chunk-77WAKEAH.js → chunk-2OXSB2OL.js} +2 -2
- package/dist/{chunk-H3T7IWNA.js → chunk-2VJOSU4H.js} +2 -2
- package/dist/{chunk-N6AACDUW.js → chunk-34NV52R3.js} +4 -4
- package/dist/{chunk-L7YTNTIK.js → chunk-3CDJSKDW.js} +3 -3
- package/dist/{chunk-EWSOC6WF.js → chunk-3DRLCX5V.js} +2 -2
- package/dist/{chunk-JEUPAVYY.js → chunk-3L465FBR.js} +6 -6
- package/dist/{chunk-5NWEKLDZ.js → chunk-3NNAC43A.js} +2 -2
- package/dist/{chunk-EDI6SJ2N.js → chunk-3OK7Y6ES.js} +2 -2
- package/dist/{chunk-AWKES45Y.js → chunk-3PM3M2Q6.js} +2 -2
- package/dist/{chunk-I7XIZRFD.js → chunk-3PZ3LRPV.js} +3 -3
- package/dist/{chunk-AW2MQB37.js → chunk-44JWVYJB.js} +2 -2
- package/dist/{chunk-2M3J7ZWQ.js → chunk-467WDSOK.js} +2 -2
- package/dist/{chunk-UTIAXH52.js → chunk-477DTTMH.js} +3 -3
- package/dist/{chunk-J5F5HPPW.js → chunk-4BWMAGJJ.js} +3 -3
- package/dist/{chunk-YSJEAAOL.js → chunk-4F3AEJI6.js} +4 -4
- package/dist/{chunk-LHPNABDH.js → chunk-4JXPLTWV.js} +2 -2
- package/dist/{chunk-RQKLF42C.js → chunk-4K64EKM7.js} +4 -4
- package/dist/{chunk-NUNZS36W.js → chunk-4O2XWOLZ.js} +3 -3
- package/dist/{chunk-QB2KMIDP.js → chunk-4SJAEPM2.js} +2 -2
- package/dist/{chunk-6JHU2UBS.js → chunk-4Z5X7PLC.js} +3 -3
- package/dist/{chunk-2STUPWEL.js → chunk-54U6ZBEX.js} +3 -3
- package/dist/{chunk-XXSOHN35.js → chunk-5FLYHX5R.js} +2 -2
- package/dist/{chunk-MIYFS2XN.js → chunk-5MHMCE2G.js} +3 -3
- package/dist/{chunk-YWVI6ZMK.js → chunk-5MIBQ4P5.js} +2 -2
- package/dist/chunk-6B73WNLR.js +173 -0
- package/dist/chunk-6B73WNLR.js.map +1 -0
- package/dist/{chunk-5O2FCCHZ.js → chunk-6QK65ZWM.js} +3 -3
- package/dist/{chunk-RPVREAU7.js → chunk-736RUNIA.js} +4 -4
- package/dist/{chunk-2KALVELR.js → chunk-74CBR5YE.js} +3 -3
- package/dist/{chunk-5IE76VCY.js → chunk-752WXSDN.js} +2 -2
- package/dist/{chunk-OPJJSKUK.js → chunk-77B6UCNK.js} +6 -6
- package/dist/{chunk-SEO7TICN.js → chunk-77BHKC43.js} +1 -1
- package/dist/{chunk-ZUA3JMI6.js → chunk-77SYIH6O.js} +2 -2
- package/dist/{chunk-ILDXWY37.js → chunk-7AI4E7PV.js} +2 -2
- package/dist/{chunk-C372BFOV.js → chunk-7NLF35YL.js} +4 -4
- package/dist/{chunk-IFB3WJ36.js → chunk-7YTR3UFO.js} +4 -4
- package/dist/{chunk-BMICEQZQ.js → chunk-7Z76QP64.js} +3 -3
- package/dist/{chunk-YWIFM7D7.js → chunk-AAS7OWV6.js} +3 -3
- package/dist/{chunk-5QAY6K77.js → chunk-AB5IW227.js} +3 -3
- package/dist/{chunk-ZBIXBQNI.js → chunk-ABJZDRW2.js} +2 -2
- package/dist/{chunk-4DVJ6ONS.js → chunk-AH3DGOTK.js} +2 -2
- package/dist/{chunk-HGKTHF2U.js → chunk-AJBDAVX3.js} +8 -8
- package/dist/{chunk-5YKW2K6I.js → chunk-AJDGP2N4.js} +20 -20
- package/dist/{chunk-HD5X76TP.js → chunk-AQQT2FIC.js} +5 -5
- package/dist/chunk-AQQT2FIC.js.map +1 -0
- package/dist/{chunk-SC6RRD2D.js → chunk-ARTEEI2E.js} +11 -2
- package/dist/{chunk-SC6RRD2D.js.map → chunk-ARTEEI2E.js.map} +1 -1
- package/dist/{chunk-IXPTECSC.js → chunk-AVXDIRRW.js} +2 -2
- package/dist/{chunk-QK5EFEUT.js → chunk-BASI553K.js} +4 -4
- package/dist/{chunk-CRU35QQH.js → chunk-BFFNINCC.js} +108 -66
- package/dist/chunk-BFFNINCC.js.map +1 -0
- package/dist/{chunk-Z4FMAFNH.js → chunk-BQYRZIZ7.js} +2 -2
- package/dist/{chunk-DZXEDSQI.js → chunk-CEMSIU4Z.js} +5 -5
- package/dist/{chunk-FZC5N55X.js → chunk-CH4UQ4NO.js} +5 -5
- package/dist/{chunk-7X6SDK2C.js → chunk-CHU3RDV4.js} +3 -3
- package/dist/{chunk-Y4OBB2VN.js → chunk-CV4VVLPZ.js} +2 -2
- package/dist/{chunk-JQL7ZH6C.js → chunk-CXAN2FHF.js} +7 -7
- package/dist/{chunk-F2OPHAUN.js → chunk-CYDXCILL.js} +7 -7
- package/dist/{chunk-3PZ7JZI2.js → chunk-D3PTVN2I.js} +2 -2
- package/dist/{chunk-FPXASDG5.js → chunk-D5TIVCXG.js} +2 -2
- package/dist/{chunk-7W37NS3I.js → chunk-D74Z2N4K.js} +2 -2
- package/dist/{chunk-MNZG4OHU.js → chunk-DCEQCGVN.js} +2 -2
- package/dist/{chunk-ND2BXV3P.js → chunk-DEHLWZSI.js} +4 -4
- package/dist/{chunk-2YUOVM3G.js → chunk-DIP7YALH.js} +2 -2
- package/dist/{chunk-6PZ7OBYU.js → chunk-DLVIRJGK.js} +4 -4
- package/dist/{chunk-KLEUWIMZ.js → chunk-DQPIEQGP.js} +2 -2
- package/dist/{chunk-T2QX3FDP.js → chunk-DWJ6J3YW.js} +4 -4
- package/dist/{chunk-3CPWWGNK.js → chunk-E5KOWRDU.js} +2 -2
- package/dist/{chunk-6WGRDRMA.js → chunk-EBIVTDEG.js} +2 -2
- package/dist/{chunk-KUDGXAF7.js → chunk-EBTUPRRQ.js} +10 -10
- package/dist/{chunk-5CPEEAFD.js → chunk-EDDKPIIV.js} +2 -2
- package/dist/{chunk-TX3VECZU.js → chunk-EGKARC53.js} +2 -2
- package/dist/{chunk-JEA3QDX7.js → chunk-EKJHOWTZ.js} +4 -4
- package/dist/{chunk-UVN5TMHU.js → chunk-ESXAECZ3.js} +2 -2
- package/dist/{chunk-3SOIESJM.js → chunk-EWZ2RLNG.js} +2 -2
- package/dist/{chunk-CMKGILJK.js → chunk-FBA2NXYH.js} +4 -4
- package/dist/{chunk-O6N4ABCA.js → chunk-FER6EVIY.js} +2 -2
- package/dist/{chunk-DF5EAHDN.js → chunk-FLWQJDJ5.js} +5 -5
- package/dist/{chunk-PTAG4PDC.js → chunk-FNXCFIPW.js} +2 -2
- package/dist/chunk-FPSS23S4.js +36 -0
- package/dist/chunk-FPSS23S4.js.map +1 -0
- package/dist/{chunk-BJEJFISW.js → chunk-FSDQQQIA.js} +3 -3
- package/dist/{chunk-PTF5B7TJ.js → chunk-G5UQBTXY.js} +2 -2
- package/dist/{chunk-4E3ZJRTZ.js → chunk-G6ICCGJ3.js} +2 -2
- package/dist/{chunk-NRTE7DNV.js → chunk-GIWFLWXG.js} +4 -4
- package/dist/{chunk-MM4FNWI4.js → chunk-GMHIOYB7.js} +4 -4
- package/dist/{chunk-6DK6Z4UN.js → chunk-GOCODNQS.js} +3 -3
- package/dist/{chunk-TPQTRNER.js → chunk-GSCGKJNK.js} +2 -2
- package/dist/{chunk-7VMZGLYI.js → chunk-GTHCHCWW.js} +3 -3
- package/dist/{chunk-SQJIKMN3.js → chunk-GTRAH4FG.js} +2 -2
- package/dist/{chunk-ZYAZUPPV.js → chunk-GU7T2S5N.js} +3 -3
- package/dist/{chunk-JKHKLL5W.js → chunk-H6BX6WOW.js} +3 -3
- package/dist/{chunk-IMZCQBOT.js → chunk-H6MJFMHZ.js} +3 -3
- package/dist/{chunk-HSOXMJOT.js → chunk-HEGV4QMS.js} +2 -2
- package/dist/chunk-HROITVQJ.js +85 -0
- package/dist/chunk-HROITVQJ.js.map +1 -0
- package/dist/{chunk-OF4TIKYC.js → chunk-HTMQGS63.js} +17 -9
- package/dist/chunk-HTMQGS63.js.map +1 -0
- package/dist/{chunk-NC7PVOEK.js → chunk-HWVPLFIW.js} +2 -2
- package/dist/{chunk-IMDQUHBJ.js → chunk-HYEIA25Y.js} +2 -2
- package/dist/{chunk-ECJBYNLJ.js → chunk-ICAMYP5M.js} +2 -2
- package/dist/{chunk-DJAXC5OK.js → chunk-IFSXVU2S.js} +2 -2
- package/dist/{chunk-I4MRDSUF.js → chunk-IJR6VOLU.js} +3 -3
- package/dist/{chunk-YCVD6CI3.js → chunk-IN3VQFKS.js} +2 -2
- package/dist/{chunk-BJFH6JI5.js → chunk-IZXYFWA4.js} +13 -13
- package/dist/{chunk-MFROMEKA.js → chunk-J2BTILRR.js} +3 -3
- package/dist/{chunk-NCYMNCJO.js → chunk-J2WY42FA.js} +2 -2
- package/dist/{chunk-DGMR6JEJ.js → chunk-J4XSTXZP.js} +2 -2
- package/dist/{chunk-ZTPXACWB.js → chunk-JKL5S7UQ.js} +6 -6
- package/dist/{chunk-P77WNZDY.js → chunk-JMHEFZOB.js} +2 -2
- package/dist/{chunk-IDANQPRH.js → chunk-JV3UI7BH.js} +3 -3
- package/dist/{chunk-NW53H5RW.js → chunk-JV5ULONH.js} +166 -65
- package/dist/chunk-JV5ULONH.js.map +1 -0
- package/dist/{chunk-FVXBNBHO.js → chunk-K3D7IQQP.js} +6 -6
- package/dist/{chunk-XEQMZB3C.js → chunk-K4DQS2ML.js} +24 -6
- package/dist/chunk-K4DQS2ML.js.map +1 -0
- package/dist/{chunk-GKVJIDHF.js → chunk-KFNZZ2N6.js} +2 -2
- package/dist/{chunk-I4QEJ62Y.js → chunk-KI46GKMD.js} +7 -7
- package/dist/{chunk-SIRLACNZ.js → chunk-KO3OHHY2.js} +3 -3
- package/dist/{chunk-NULUNM7H.js → chunk-KUE5BOQE.js} +5 -5
- package/dist/{chunk-O3LKCBP5.js → chunk-LIJNVIT3.js} +3 -3
- package/dist/{chunk-JWB44UGJ.js → chunk-LIJPDVYP.js} +2 -2
- package/dist/{chunk-KYS77RPN.js → chunk-LPKJ77EK.js} +2 -2
- package/dist/{chunk-RMFKVOM7.js → chunk-LQKVNREV.js} +4 -4
- package/dist/{chunk-E7XERZWC.js → chunk-LTJFV2JI.js} +2 -2
- package/dist/{chunk-INXGSG3J.js → chunk-LVDNY5RC.js} +2 -2
- package/dist/{chunk-2INLDVK3.js → chunk-LVELUUK6.js} +2 -2
- package/dist/{chunk-TAT5USZN.js → chunk-M3FDGRB4.js} +3 -3
- package/dist/{chunk-5EWSRZ2Y.js → chunk-M3HGBO2Y.js} +1 -1
- package/dist/{chunk-J3DY5HWQ.js → chunk-M5IQVMLR.js} +4 -4
- package/dist/{chunk-53AGXXZM.js → chunk-MKDFYE2E.js} +2 -2
- package/dist/{chunk-4SAWSRAA.js → chunk-MRECRNVU.js} +5 -5
- package/dist/{chunk-2I7HDP53.js → chunk-MT2R57SF.js} +2 -2
- package/dist/{chunk-Z7Y523PS.js → chunk-MV2CLIO6.js} +6 -6
- package/dist/{chunk-JZ4NLCAP.js → chunk-MZY3VKKM.js} +2 -2
- package/dist/{chunk-YENLNISG.js → chunk-N3FM4BNA.js} +2 -2
- package/dist/{chunk-DZWARC4M.js → chunk-NFCS5WYC.js} +3 -3
- package/dist/{chunk-I5QZJODL.js → chunk-NQ2CPQJF.js} +3 -3
- package/dist/{chunk-6DVCC7QS.js → chunk-OBGOLHCP.js} +164 -43
- package/dist/chunk-OBGOLHCP.js.map +1 -0
- package/dist/{chunk-CUIWCGMA.js → chunk-OCXEY7HE.js} +2 -2
- package/dist/{chunk-VTTAJOQ7.js → chunk-OCXTTKVA.js} +2 -2
- package/dist/{chunk-KRDR5RJD.js → chunk-OGU73VUN.js} +2 -2
- package/dist/{chunk-YIRVLKAX.js → chunk-OI6VI6SU.js} +9 -9
- package/dist/{chunk-BHNSJVBC.js → chunk-OJWDNNW3.js} +5 -5
- package/dist/{chunk-X6KAJI3V.js → chunk-OK7BQMCI.js} +9 -9
- package/dist/{chunk-I5B5L6Q4.js → chunk-OOOSGPJL.js} +1 -1
- package/dist/chunk-OP2GD6QW.js +166 -0
- package/dist/chunk-OP2GD6QW.js.map +1 -0
- package/dist/{chunk-TUIN4MB7.js → chunk-ORV7EFSL.js} +4 -4
- package/dist/{chunk-JDTGRRNU.js → chunk-OSJ366KR.js} +49 -31
- package/dist/chunk-OSJ366KR.js.map +1 -0
- package/dist/{chunk-3IK6UYO6.js → chunk-OTW25A6I.js} +3 -3
- package/dist/{chunk-NPGISCU6.js → chunk-OWET7EY2.js} +16 -16
- package/dist/{chunk-CRAOSVHC.js → chunk-OXQ2SXVC.js} +2 -2
- package/dist/{chunk-3ED2U6XE.js → chunk-OYCK4JRS.js} +2 -2
- package/dist/{chunk-YQXTDZSU.js → chunk-OYOFPNLC.js} +4 -4
- package/dist/{chunk-4NQHXYMW.js → chunk-PD7NWM7V.js} +2 -2
- package/dist/{chunk-4YCA2Y73.js → chunk-PF2WU2IL.js} +3 -3
- package/dist/{chunk-Z654FWNU.js → chunk-PLYVGZIN.js} +2 -2
- package/dist/{chunk-MVW6HNPI.js → chunk-PRT4J2DL.js} +2 -2
- package/dist/{chunk-TXLIEOJX.js → chunk-PSM3CU7N.js} +111 -80
- package/dist/chunk-PSM3CU7N.js.map +1 -0
- package/dist/{chunk-OPWCMA4D.js → chunk-PUUEI4W3.js} +6 -6
- package/dist/{chunk-RLBKLAEY.js → chunk-PVB4YVDP.js} +2 -2
- package/dist/{chunk-NXCMHIKI.js → chunk-PWUSSSSL.js} +2 -2
- package/dist/{chunk-MJUCFQMS.js → chunk-PYB4BFEC.js} +3 -3
- package/dist/{chunk-2FSBSCZJ.js → chunk-PZKHST7A.js} +2 -2
- package/dist/{chunk-QZAAUQRN.js → chunk-Q5EZNBPI.js} +3 -3
- package/dist/{chunk-ZHDFQITM.js → chunk-Q5K2J5GG.js} +2 -2
- package/dist/{chunk-7T2ZE3VT.js → chunk-QPQ7R77C.js} +8 -1
- package/dist/chunk-QPQ7R77C.js.map +1 -0
- package/dist/{chunk-6BCXNDEI.js → chunk-QQIZMVAJ.js} +74 -60
- package/dist/chunk-QQIZMVAJ.js.map +1 -0
- package/dist/{chunk-OV6QJRT4.js → chunk-QRECBCJM.js} +2 -2
- package/dist/{chunk-3GZA4BUW.js → chunk-QURYQFDN.js} +2 -2
- package/dist/{chunk-VS7AHPCZ.js → chunk-R33SBMB7.js} +3 -3
- package/dist/{chunk-KCBMFSMS.js → chunk-R4JA5JFI.js} +3 -3
- package/dist/{chunk-HC4JFZVU.js → chunk-R5QAL43H.js} +2 -2
- package/dist/{chunk-QPSGCC5D.js → chunk-RGR57NYY.js} +2 -2
- package/dist/{chunk-XWFAMUZQ.js → chunk-RHXYO4H2.js} +2 -2
- package/dist/{chunk-Y4BB2KS2.js → chunk-RISUROBM.js} +7 -7
- package/dist/{chunk-U3DN4HEY.js → chunk-RMCLFSMX.js} +2 -2
- package/dist/{chunk-YK7756IF.js → chunk-RTZANSSC.js} +3 -3
- package/dist/{chunk-ZEG4VPBL.js → chunk-S27VZ5DO.js} +6 -6
- package/dist/{chunk-54YW6SZZ.js → chunk-SBXSKRFA.js} +3 -3
- package/dist/{chunk-HAX4LCR5.js → chunk-SFIXTOOJ.js} +3 -3
- package/dist/{chunk-QIOQ2NPQ.js → chunk-SGH7I7OY.js} +2 -2
- package/dist/{chunk-K2A5PXQ5.js → chunk-SJYTQLN3.js} +3 -3
- package/dist/{chunk-2Z3NQNTM.js → chunk-SK5S2PCK.js} +15 -15
- package/dist/{chunk-X3MWB2QU.js → chunk-SN2WENRP.js} +3 -3
- package/dist/{chunk-OSY5K7L7.js → chunk-SP44O3OU.js} +2 -2
- package/dist/{chunk-OZCBM3UC.js → chunk-SSR4ZX52.js} +2 -2
- package/dist/{chunk-QCSJ4CWE.js → chunk-SXGJL7UT.js} +14 -14
- package/dist/{chunk-NC55IFN3.js → chunk-T67LTMSW.js} +10 -10
- package/dist/{chunk-AXHZYXUV.js → chunk-TDTD66BK.js} +2 -2
- package/dist/{chunk-NGJJJPZZ.js → chunk-TK5FWVZR.js} +3 -3
- package/dist/{chunk-YPWU5KPE.js → chunk-TKQL7EDB.js} +56 -19
- package/dist/chunk-TKQL7EDB.js.map +1 -0
- package/dist/{chunk-2OP6WLGV.js → chunk-TNSJFZ6Q.js} +4 -4
- package/dist/{chunk-O732GAFC.js → chunk-U4LTPFD2.js} +2 -2
- package/dist/{chunk-4DVNUCRR.js → chunk-U5UGM5XD.js} +6 -6
- package/dist/{chunk-UJK53QFL.js → chunk-UBRQ3PQD.js} +2 -2
- package/dist/{chunk-SODC7T6L.js → chunk-UMX6DZME.js} +2 -2
- package/dist/{chunk-YLS6QE5G.js → chunk-UO35OEOX.js} +4 -4
- package/dist/{chunk-SHHJCL7X.js → chunk-UTRNLNCW.js} +3 -3
- package/dist/{chunk-HEFPPMBQ.js → chunk-UU5FBVRX.js} +2 -2
- package/dist/{chunk-GQXZPKK7.js → chunk-V6UOVHW3.js} +2 -2
- package/dist/{chunk-GVN5SZLX.js → chunk-VATYK3JQ.js} +3 -3
- package/dist/{chunk-7TIX2UAR.js → chunk-VCJQQYRE.js} +4 -4
- package/dist/{chunk-6WD2INST.js → chunk-WDASYY4S.js} +7 -7
- package/dist/{chunk-DXBYWSL5.js → chunk-WIFDNUKD.js} +3 -3
- package/dist/{chunk-RT7CJMER.js → chunk-WIXHUBQN.js} +2 -2
- package/dist/{chunk-57AZS3IE.js → chunk-WRMUXZ7C.js} +3 -3
- package/dist/{chunk-2CLNIEK4.js → chunk-WTSQUCHB.js} +3 -3
- package/dist/{chunk-OVKYVZMW.js → chunk-WXF2RTS4.js} +2 -2
- package/dist/{chunk-MIHN76LX.js → chunk-WYGTAQMX.js} +3 -3
- package/dist/{chunk-2RG7NIAS.js → chunk-X2QJXDE4.js} +10 -10
- package/dist/{chunk-GAVYGBFI.js → chunk-XMBOLFFS.js} +2 -2
- package/dist/{chunk-T7OXJZCX.js → chunk-XOIDUM2H.js} +1 -1
- package/dist/{chunk-ORJPS5VN.js → chunk-XUOYNJPB.js} +97 -37
- package/dist/chunk-XUOYNJPB.js.map +1 -0
- package/dist/{chunk-XHIQ5I6N.js → chunk-XVLEBB4Y.js} +2 -2
- package/dist/{chunk-Q3DPEYX4.js → chunk-XZCCEKPW.js} +7 -7
- package/dist/{chunk-T3OWFVMS.js → chunk-Y3XZEKDQ.js} +2 -2
- package/dist/{chunk-KODELWYT.js → chunk-YJSCLGAW.js} +3 -3
- package/dist/{chunk-ROKQU7WG.js → chunk-YMI27QPF.js} +2 -2
- package/dist/{chunk-U7XM7CB4.js → chunk-YNTLWCF4.js} +4 -4
- package/dist/{chunk-ZQCND77P.js → chunk-YRYF76OE.js} +2 -2
- package/dist/{chunk-2BDT3UZQ.js → chunk-ZAX4XQLN.js} +3 -3
- package/dist/{chunk-DXR5PDFP.js → chunk-ZBHGNE2J.js} +3 -3
- package/dist/{chunk-I7ITSXSJ.js → chunk-ZR5EKJT6.js} +2 -2
- package/dist/{chunk-IZXHMZQ6.js → chunk-ZW5YTIH3.js} +4 -4
- package/dist/components/artifacts/artifact-sandbox.d.ts +6 -1
- package/dist/components/artifacts/site-view.d.ts +4 -2
- package/dist/components/timeline-anchor.d.ts +8 -3
- package/dist/components/timeline-reading-progress.d.ts +1 -1
- package/dist/components/timeline-settlement.d.ts +1 -1
- package/dist/composer-messages.js +2 -2
- package/dist/composer.js +10 -10
- package/dist/{computer-viewer-TDDO25AV.js → computer-viewer-5LKRCEVQ.js} +5 -5
- package/dist/connect.js +13 -14
- package/dist/desktop-dictation.js +7 -7
- package/dist/desktop.js +2 -2
- package/dist/editor.js +2 -2
- package/dist/{embedded-new-voice-2G3VLPVQ.js → embedded-new-voice-GHJRY3YL.js} +5 -5
- package/dist/{embedded-voice-T5IWOWGD.js → embedded-voice-ASQXBSTX.js} +5 -5
- package/dist/{fleet-decision-row-WM64KXP3.js → fleet-decision-row-U7LDVBEM.js} +2 -2
- package/dist/in-chat-connect-model.js +5 -5
- package/dist/index.js +62 -63
- package/dist/interaction.js +6 -6
- package/dist/{latest-question-OX56OVQ5.js → latest-question-RNVF262Q.js} +5 -5
- package/dist/lib/format.d.ts +10 -0
- package/dist/machines.js +4 -4
- package/dist/meetings-recorder.js +1 -1
- package/dist/meetings.js +24 -24
- package/dist/messages/en.d.ts +7 -0
- package/dist/messages.js +1 -1
- package/dist/{model-policy-picker-menu-SMC6J6QN.js → model-policy-picker-menu-E6XKMFTA.js} +4 -4
- package/dist/{payment-page-card-G4U63KUV.js → payment-page-card-DJDKV2LW.js} +6 -5
- package/dist/{payment-page-card-G4U63KUV.js.map → payment-page-card-DJDKV2LW.js.map} +1 -1
- package/dist/{platform-activity-row-BUZGZAKZ.js → platform-activity-row-MSDCSMET.js} +17 -7
- package/dist/platform-activity-row-MSDCSMET.js.map +1 -0
- package/dist/{queue-surface-implementation-4KUZ4PJV.js → queue-surface-implementation-GUAIG6TK.js} +5 -5
- package/dist/realtime.js +4 -4
- package/dist/{recorder-host-WF2RRR56.js → recorder-host-2MYDJPQW.js} +4 -4
- package/dist/recordings.js +3 -3
- package/dist/{sandbox-files-ESDMOFSD.js → sandbox-files-W5W2LW4K.js} +6 -6
- package/dist/session-app.js +173 -167
- package/dist/{session-connect-cards-Q53KMMYY.js → session-connect-cards-HPH7JOZP.js} +9 -10
- package/dist/session-list-model.js +2 -2
- package/dist/{session-realtime-CF3I35WJ.js → session-realtime-SDTKFFIR.js} +3 -3
- package/dist/session-realtime-SDTKFFIR.js.map +1 -0
- package/dist/session-realtime.js +2 -2
- package/dist/session-ui.js +37 -38
- package/dist/session.js +9 -9
- package/dist/sites.js +2 -2
- package/dist/terminal.js +2 -2
- package/dist/this-computer.js +3 -3
- package/dist/timeline/shared.d.ts +2 -0
- package/dist/{timeline-annotation-markers-CJK4RYZ4.js → timeline-annotation-markers-FNILLWNU.js} +2 -2
- package/dist/{timeline-annotation-selection-67GF5H26.js → timeline-annotation-selection-MBCIDO2Q.js} +2 -2
- package/dist/{timeline-annotations-dialog-ONJPQDJQ.js → timeline-annotations-dialog-JPNKLOTE.js} +3 -3
- package/dist/timeline-model.js +6 -6
- package/dist/ui/access-list.js +6 -6
- package/dist/ui/cadence-picker.js +4 -4
- package/dist/ui/choice-cards.js +3 -3
- package/dist/ui/confirm-dialog.js +4 -4
- package/dist/ui/copy-field.js +3 -3
- package/dist/ui/detail-page.js +5 -5
- package/dist/ui/detail-sheet.js +4 -4
- package/dist/ui/dialog.js +2 -2
- package/dist/ui/disclosure.js +5 -5
- package/dist/ui/email-chips-input.js +3 -3
- package/dist/ui/field.js +2 -2
- package/dist/ui/flush-form-page.js +4 -4
- package/dist/ui/form-dialog.js +3 -3
- package/dist/ui/list-row.js +3 -3
- package/dist/ui/page-header.js +2 -2
- package/dist/ui/relative-time.js +2 -2
- package/dist/ui/revision-history.js +4 -4
- package/dist/ui/role-select.js +6 -6
- package/dist/ui/select-menu.js +3 -3
- package/dist/ui/sheet.js +2 -2
- package/dist/ui/usage-meter.js +3 -3
- package/dist/ui/window-bar-title.d.ts +7 -3
- package/dist/ui/window-bar-title.js +1 -1
- package/dist/usage.js +2 -2
- package/dist/workbench.js +4 -4
- package/package.json +4 -4
- package/src/app/components/artifacts/site-actions.tsx +105 -0
- package/src/app/components/rail/session-header-copy.test.tsx +172 -0
- package/src/app/components/rail/session-header.tsx +68 -12
- package/src/app/components/rail/session-list.tsx +20 -0
- package/src/app/components/rail/site-session-group-heading.test.tsx +210 -0
- package/src/app/components/rail/site-session-group-heading.tsx +119 -60
- package/src/app/components/session/failed-session-actions.test.tsx +4 -0
- package/src/app/components/window-bar.tsx +63 -15
- package/src/app/lib/composer-send-blocking.tsx +312 -1
- package/src/app/lib/copy-link.ts +10 -0
- package/src/app/lib/session-composer-readiness.ts +4 -3
- package/src/app/lib/site-sidebar-bridge.test.tsx +67 -0
- package/src/app/lib/site-sidebar-bridge.ts +57 -0
- package/src/app/routes/session.tsx +45 -12
- package/src/app/routes/sessions-index.tsx +164 -105
- package/src/app/routes/site-view.test.tsx +74 -6
- package/src/app/routes/site-view.tsx +135 -14
- package/src/components/approval-surface.tsx +78 -3
- package/src/components/artifacts/artifact-sandbox.tsx +27 -2
- package/src/components/artifacts/site-view.tsx +13 -1
- package/src/components/message-timeline.tsx +25 -52
- package/src/components/session-capability-frame.tsx +2 -30
- package/src/components/timeline-anchor.tsx +19 -14
- package/src/components/timeline-reading-progress.ts +1 -2
- package/src/components/timeline-settlement.ts +3 -3
- package/src/lib/format.ts +46 -1
- package/src/messages/en.ts +11 -0
- package/src/timeline/platform-activity-row.tsx +20 -8
- package/src/timeline/shared.tsx +203 -32
- package/src/ui/window-bar-title.test.tsx +37 -0
- package/src/ui/window-bar-title.tsx +13 -6
- package/styles/compiled.css +5 -0
- package/dist/chunk-5MOJZORA.js.map +0 -1
- package/dist/chunk-6BCXNDEI.js.map +0 -1
- package/dist/chunk-6DVCC7QS.js.map +0 -1
- package/dist/chunk-7T2ZE3VT.js.map +0 -1
- package/dist/chunk-AFRGP2VP.js +0 -17
- package/dist/chunk-AFRGP2VP.js.map +0 -1
- package/dist/chunk-CRU35QQH.js.map +0 -1
- package/dist/chunk-FO4LYKJL.js +0 -197
- package/dist/chunk-FO4LYKJL.js.map +0 -1
- package/dist/chunk-HD5X76TP.js.map +0 -1
- package/dist/chunk-JDTGRRNU.js.map +0 -1
- package/dist/chunk-NW53H5RW.js.map +0 -1
- package/dist/chunk-OF4TIKYC.js.map +0 -1
- package/dist/chunk-ORJPS5VN.js.map +0 -1
- package/dist/chunk-TXLIEOJX.js.map +0 -1
- package/dist/chunk-VBUVBHFJ.js +0 -16
- package/dist/chunk-VBUVBHFJ.js.map +0 -1
- package/dist/chunk-XEQMZB3C.js.map +0 -1
- package/dist/chunk-YPWU5KPE.js.map +0 -1
- package/dist/components/timeline-answer-follow.d.ts +0 -8
- package/dist/platform-activity-row-BUZGZAKZ.js.map +0 -1
- package/src/components/timeline-answer-follow.ts +0 -15
- /package/dist/{browser-viewer-TC27OCIP.js.map → app/components/artifacts/site-actions.js.map} +0 -0
- /package/dist/{chat-interactive-block-RWPQBHVS.js.map → browser-viewer-ZHQDVHZ2.js.map} +0 -0
- /package/dist/{computer-viewer-TDDO25AV.js.map → chat-interactive-block-VSDD6X3M.js.map} +0 -0
- /package/dist/{chunk-C43KRXGA.js.map → chunk-2GCHGWNE.js.map} +0 -0
- /package/dist/{chunk-XLH7QY2R.js.map → chunk-2J77TWGH.js.map} +0 -0
- /package/dist/{chunk-77WAKEAH.js.map → chunk-2OXSB2OL.js.map} +0 -0
- /package/dist/{chunk-H3T7IWNA.js.map → chunk-2VJOSU4H.js.map} +0 -0
- /package/dist/{chunk-N6AACDUW.js.map → chunk-34NV52R3.js.map} +0 -0
- /package/dist/{chunk-L7YTNTIK.js.map → chunk-3CDJSKDW.js.map} +0 -0
- /package/dist/{chunk-EWSOC6WF.js.map → chunk-3DRLCX5V.js.map} +0 -0
- /package/dist/{chunk-JEUPAVYY.js.map → chunk-3L465FBR.js.map} +0 -0
- /package/dist/{chunk-5NWEKLDZ.js.map → chunk-3NNAC43A.js.map} +0 -0
- /package/dist/{chunk-EDI6SJ2N.js.map → chunk-3OK7Y6ES.js.map} +0 -0
- /package/dist/{chunk-AWKES45Y.js.map → chunk-3PM3M2Q6.js.map} +0 -0
- /package/dist/{chunk-I7XIZRFD.js.map → chunk-3PZ3LRPV.js.map} +0 -0
- /package/dist/{chunk-AW2MQB37.js.map → chunk-44JWVYJB.js.map} +0 -0
- /package/dist/{chunk-2M3J7ZWQ.js.map → chunk-467WDSOK.js.map} +0 -0
- /package/dist/{chunk-UTIAXH52.js.map → chunk-477DTTMH.js.map} +0 -0
- /package/dist/{chunk-J5F5HPPW.js.map → chunk-4BWMAGJJ.js.map} +0 -0
- /package/dist/{chunk-YSJEAAOL.js.map → chunk-4F3AEJI6.js.map} +0 -0
- /package/dist/{chunk-LHPNABDH.js.map → chunk-4JXPLTWV.js.map} +0 -0
- /package/dist/{chunk-RQKLF42C.js.map → chunk-4K64EKM7.js.map} +0 -0
- /package/dist/{chunk-NUNZS36W.js.map → chunk-4O2XWOLZ.js.map} +0 -0
- /package/dist/{chunk-QB2KMIDP.js.map → chunk-4SJAEPM2.js.map} +0 -0
- /package/dist/{chunk-6JHU2UBS.js.map → chunk-4Z5X7PLC.js.map} +0 -0
- /package/dist/{chunk-2STUPWEL.js.map → chunk-54U6ZBEX.js.map} +0 -0
- /package/dist/{chunk-XXSOHN35.js.map → chunk-5FLYHX5R.js.map} +0 -0
- /package/dist/{chunk-MIYFS2XN.js.map → chunk-5MHMCE2G.js.map} +0 -0
- /package/dist/{chunk-YWVI6ZMK.js.map → chunk-5MIBQ4P5.js.map} +0 -0
- /package/dist/{chunk-5O2FCCHZ.js.map → chunk-6QK65ZWM.js.map} +0 -0
- /package/dist/{chunk-RPVREAU7.js.map → chunk-736RUNIA.js.map} +0 -0
- /package/dist/{chunk-2KALVELR.js.map → chunk-74CBR5YE.js.map} +0 -0
- /package/dist/{chunk-5IE76VCY.js.map → chunk-752WXSDN.js.map} +0 -0
- /package/dist/{chunk-OPJJSKUK.js.map → chunk-77B6UCNK.js.map} +0 -0
- /package/dist/{chunk-SEO7TICN.js.map → chunk-77BHKC43.js.map} +0 -0
- /package/dist/{chunk-ZUA3JMI6.js.map → chunk-77SYIH6O.js.map} +0 -0
- /package/dist/{chunk-ILDXWY37.js.map → chunk-7AI4E7PV.js.map} +0 -0
- /package/dist/{chunk-C372BFOV.js.map → chunk-7NLF35YL.js.map} +0 -0
- /package/dist/{chunk-IFB3WJ36.js.map → chunk-7YTR3UFO.js.map} +0 -0
- /package/dist/{chunk-BMICEQZQ.js.map → chunk-7Z76QP64.js.map} +0 -0
- /package/dist/{chunk-YWIFM7D7.js.map → chunk-AAS7OWV6.js.map} +0 -0
- /package/dist/{chunk-5QAY6K77.js.map → chunk-AB5IW227.js.map} +0 -0
- /package/dist/{chunk-ZBIXBQNI.js.map → chunk-ABJZDRW2.js.map} +0 -0
- /package/dist/{chunk-4DVJ6ONS.js.map → chunk-AH3DGOTK.js.map} +0 -0
- /package/dist/{chunk-HGKTHF2U.js.map → chunk-AJBDAVX3.js.map} +0 -0
- /package/dist/{chunk-5YKW2K6I.js.map → chunk-AJDGP2N4.js.map} +0 -0
- /package/dist/{chunk-IXPTECSC.js.map → chunk-AVXDIRRW.js.map} +0 -0
- /package/dist/{chunk-QK5EFEUT.js.map → chunk-BASI553K.js.map} +0 -0
- /package/dist/{chunk-Z4FMAFNH.js.map → chunk-BQYRZIZ7.js.map} +0 -0
- /package/dist/{chunk-DZXEDSQI.js.map → chunk-CEMSIU4Z.js.map} +0 -0
- /package/dist/{chunk-FZC5N55X.js.map → chunk-CH4UQ4NO.js.map} +0 -0
- /package/dist/{chunk-7X6SDK2C.js.map → chunk-CHU3RDV4.js.map} +0 -0
- /package/dist/{chunk-Y4OBB2VN.js.map → chunk-CV4VVLPZ.js.map} +0 -0
- /package/dist/{chunk-JQL7ZH6C.js.map → chunk-CXAN2FHF.js.map} +0 -0
- /package/dist/{chunk-F2OPHAUN.js.map → chunk-CYDXCILL.js.map} +0 -0
- /package/dist/{chunk-3PZ7JZI2.js.map → chunk-D3PTVN2I.js.map} +0 -0
- /package/dist/{chunk-FPXASDG5.js.map → chunk-D5TIVCXG.js.map} +0 -0
- /package/dist/{chunk-7W37NS3I.js.map → chunk-D74Z2N4K.js.map} +0 -0
- /package/dist/{chunk-MNZG4OHU.js.map → chunk-DCEQCGVN.js.map} +0 -0
- /package/dist/{chunk-ND2BXV3P.js.map → chunk-DEHLWZSI.js.map} +0 -0
- /package/dist/{chunk-2YUOVM3G.js.map → chunk-DIP7YALH.js.map} +0 -0
- /package/dist/{chunk-6PZ7OBYU.js.map → chunk-DLVIRJGK.js.map} +0 -0
- /package/dist/{chunk-KLEUWIMZ.js.map → chunk-DQPIEQGP.js.map} +0 -0
- /package/dist/{chunk-T2QX3FDP.js.map → chunk-DWJ6J3YW.js.map} +0 -0
- /package/dist/{chunk-3CPWWGNK.js.map → chunk-E5KOWRDU.js.map} +0 -0
- /package/dist/{chunk-6WGRDRMA.js.map → chunk-EBIVTDEG.js.map} +0 -0
- /package/dist/{chunk-KUDGXAF7.js.map → chunk-EBTUPRRQ.js.map} +0 -0
- /package/dist/{chunk-5CPEEAFD.js.map → chunk-EDDKPIIV.js.map} +0 -0
- /package/dist/{chunk-TX3VECZU.js.map → chunk-EGKARC53.js.map} +0 -0
- /package/dist/{chunk-JEA3QDX7.js.map → chunk-EKJHOWTZ.js.map} +0 -0
- /package/dist/{chunk-UVN5TMHU.js.map → chunk-ESXAECZ3.js.map} +0 -0
- /package/dist/{chunk-3SOIESJM.js.map → chunk-EWZ2RLNG.js.map} +0 -0
- /package/dist/{chunk-CMKGILJK.js.map → chunk-FBA2NXYH.js.map} +0 -0
- /package/dist/{chunk-O6N4ABCA.js.map → chunk-FER6EVIY.js.map} +0 -0
- /package/dist/{chunk-DF5EAHDN.js.map → chunk-FLWQJDJ5.js.map} +0 -0
- /package/dist/{chunk-PTAG4PDC.js.map → chunk-FNXCFIPW.js.map} +0 -0
- /package/dist/{chunk-BJEJFISW.js.map → chunk-FSDQQQIA.js.map} +0 -0
- /package/dist/{chunk-PTF5B7TJ.js.map → chunk-G5UQBTXY.js.map} +0 -0
- /package/dist/{chunk-4E3ZJRTZ.js.map → chunk-G6ICCGJ3.js.map} +0 -0
- /package/dist/{chunk-NRTE7DNV.js.map → chunk-GIWFLWXG.js.map} +0 -0
- /package/dist/{chunk-MM4FNWI4.js.map → chunk-GMHIOYB7.js.map} +0 -0
- /package/dist/{chunk-6DK6Z4UN.js.map → chunk-GOCODNQS.js.map} +0 -0
- /package/dist/{chunk-TPQTRNER.js.map → chunk-GSCGKJNK.js.map} +0 -0
- /package/dist/{chunk-7VMZGLYI.js.map → chunk-GTHCHCWW.js.map} +0 -0
- /package/dist/{chunk-SQJIKMN3.js.map → chunk-GTRAH4FG.js.map} +0 -0
- /package/dist/{chunk-ZYAZUPPV.js.map → chunk-GU7T2S5N.js.map} +0 -0
- /package/dist/{chunk-JKHKLL5W.js.map → chunk-H6BX6WOW.js.map} +0 -0
- /package/dist/{chunk-IMZCQBOT.js.map → chunk-H6MJFMHZ.js.map} +0 -0
- /package/dist/{chunk-HSOXMJOT.js.map → chunk-HEGV4QMS.js.map} +0 -0
- /package/dist/{chunk-NC7PVOEK.js.map → chunk-HWVPLFIW.js.map} +0 -0
- /package/dist/{chunk-IMDQUHBJ.js.map → chunk-HYEIA25Y.js.map} +0 -0
- /package/dist/{chunk-ECJBYNLJ.js.map → chunk-ICAMYP5M.js.map} +0 -0
- /package/dist/{chunk-DJAXC5OK.js.map → chunk-IFSXVU2S.js.map} +0 -0
- /package/dist/{chunk-I4MRDSUF.js.map → chunk-IJR6VOLU.js.map} +0 -0
- /package/dist/{chunk-YCVD6CI3.js.map → chunk-IN3VQFKS.js.map} +0 -0
- /package/dist/{chunk-BJFH6JI5.js.map → chunk-IZXYFWA4.js.map} +0 -0
- /package/dist/{chunk-MFROMEKA.js.map → chunk-J2BTILRR.js.map} +0 -0
- /package/dist/{chunk-NCYMNCJO.js.map → chunk-J2WY42FA.js.map} +0 -0
- /package/dist/{chunk-DGMR6JEJ.js.map → chunk-J4XSTXZP.js.map} +0 -0
- /package/dist/{chunk-ZTPXACWB.js.map → chunk-JKL5S7UQ.js.map} +0 -0
- /package/dist/{chunk-P77WNZDY.js.map → chunk-JMHEFZOB.js.map} +0 -0
- /package/dist/{chunk-IDANQPRH.js.map → chunk-JV3UI7BH.js.map} +0 -0
- /package/dist/{chunk-FVXBNBHO.js.map → chunk-K3D7IQQP.js.map} +0 -0
- /package/dist/{chunk-GKVJIDHF.js.map → chunk-KFNZZ2N6.js.map} +0 -0
- /package/dist/{chunk-I4QEJ62Y.js.map → chunk-KI46GKMD.js.map} +0 -0
- /package/dist/{chunk-SIRLACNZ.js.map → chunk-KO3OHHY2.js.map} +0 -0
- /package/dist/{chunk-NULUNM7H.js.map → chunk-KUE5BOQE.js.map} +0 -0
- /package/dist/{chunk-O3LKCBP5.js.map → chunk-LIJNVIT3.js.map} +0 -0
- /package/dist/{chunk-JWB44UGJ.js.map → chunk-LIJPDVYP.js.map} +0 -0
- /package/dist/{chunk-KYS77RPN.js.map → chunk-LPKJ77EK.js.map} +0 -0
- /package/dist/{chunk-RMFKVOM7.js.map → chunk-LQKVNREV.js.map} +0 -0
- /package/dist/{chunk-E7XERZWC.js.map → chunk-LTJFV2JI.js.map} +0 -0
- /package/dist/{chunk-INXGSG3J.js.map → chunk-LVDNY5RC.js.map} +0 -0
- /package/dist/{chunk-2INLDVK3.js.map → chunk-LVELUUK6.js.map} +0 -0
- /package/dist/{chunk-TAT5USZN.js.map → chunk-M3FDGRB4.js.map} +0 -0
- /package/dist/{chunk-5EWSRZ2Y.js.map → chunk-M3HGBO2Y.js.map} +0 -0
- /package/dist/{chunk-J3DY5HWQ.js.map → chunk-M5IQVMLR.js.map} +0 -0
- /package/dist/{chunk-53AGXXZM.js.map → chunk-MKDFYE2E.js.map} +0 -0
- /package/dist/{chunk-4SAWSRAA.js.map → chunk-MRECRNVU.js.map} +0 -0
- /package/dist/{chunk-2I7HDP53.js.map → chunk-MT2R57SF.js.map} +0 -0
- /package/dist/{chunk-Z7Y523PS.js.map → chunk-MV2CLIO6.js.map} +0 -0
- /package/dist/{chunk-JZ4NLCAP.js.map → chunk-MZY3VKKM.js.map} +0 -0
- /package/dist/{chunk-YENLNISG.js.map → chunk-N3FM4BNA.js.map} +0 -0
- /package/dist/{chunk-DZWARC4M.js.map → chunk-NFCS5WYC.js.map} +0 -0
- /package/dist/{chunk-I5QZJODL.js.map → chunk-NQ2CPQJF.js.map} +0 -0
- /package/dist/{chunk-CUIWCGMA.js.map → chunk-OCXEY7HE.js.map} +0 -0
- /package/dist/{chunk-VTTAJOQ7.js.map → chunk-OCXTTKVA.js.map} +0 -0
- /package/dist/{chunk-KRDR5RJD.js.map → chunk-OGU73VUN.js.map} +0 -0
- /package/dist/{chunk-YIRVLKAX.js.map → chunk-OI6VI6SU.js.map} +0 -0
- /package/dist/{chunk-BHNSJVBC.js.map → chunk-OJWDNNW3.js.map} +0 -0
- /package/dist/{chunk-X6KAJI3V.js.map → chunk-OK7BQMCI.js.map} +0 -0
- /package/dist/{chunk-I5B5L6Q4.js.map → chunk-OOOSGPJL.js.map} +0 -0
- /package/dist/{chunk-TUIN4MB7.js.map → chunk-ORV7EFSL.js.map} +0 -0
- /package/dist/{chunk-3IK6UYO6.js.map → chunk-OTW25A6I.js.map} +0 -0
- /package/dist/{chunk-NPGISCU6.js.map → chunk-OWET7EY2.js.map} +0 -0
- /package/dist/{chunk-CRAOSVHC.js.map → chunk-OXQ2SXVC.js.map} +0 -0
- /package/dist/{chunk-3ED2U6XE.js.map → chunk-OYCK4JRS.js.map} +0 -0
- /package/dist/{chunk-YQXTDZSU.js.map → chunk-OYOFPNLC.js.map} +0 -0
- /package/dist/{chunk-4NQHXYMW.js.map → chunk-PD7NWM7V.js.map} +0 -0
- /package/dist/{chunk-4YCA2Y73.js.map → chunk-PF2WU2IL.js.map} +0 -0
- /package/dist/{chunk-Z654FWNU.js.map → chunk-PLYVGZIN.js.map} +0 -0
- /package/dist/{chunk-MVW6HNPI.js.map → chunk-PRT4J2DL.js.map} +0 -0
- /package/dist/{chunk-OPWCMA4D.js.map → chunk-PUUEI4W3.js.map} +0 -0
- /package/dist/{chunk-RLBKLAEY.js.map → chunk-PVB4YVDP.js.map} +0 -0
- /package/dist/{chunk-NXCMHIKI.js.map → chunk-PWUSSSSL.js.map} +0 -0
- /package/dist/{chunk-MJUCFQMS.js.map → chunk-PYB4BFEC.js.map} +0 -0
- /package/dist/{chunk-2FSBSCZJ.js.map → chunk-PZKHST7A.js.map} +0 -0
- /package/dist/{chunk-QZAAUQRN.js.map → chunk-Q5EZNBPI.js.map} +0 -0
- /package/dist/{chunk-ZHDFQITM.js.map → chunk-Q5K2J5GG.js.map} +0 -0
- /package/dist/{chunk-OV6QJRT4.js.map → chunk-QRECBCJM.js.map} +0 -0
- /package/dist/{chunk-3GZA4BUW.js.map → chunk-QURYQFDN.js.map} +0 -0
- /package/dist/{chunk-VS7AHPCZ.js.map → chunk-R33SBMB7.js.map} +0 -0
- /package/dist/{chunk-KCBMFSMS.js.map → chunk-R4JA5JFI.js.map} +0 -0
- /package/dist/{chunk-HC4JFZVU.js.map → chunk-R5QAL43H.js.map} +0 -0
- /package/dist/{chunk-QPSGCC5D.js.map → chunk-RGR57NYY.js.map} +0 -0
- /package/dist/{chunk-XWFAMUZQ.js.map → chunk-RHXYO4H2.js.map} +0 -0
- /package/dist/{chunk-Y4BB2KS2.js.map → chunk-RISUROBM.js.map} +0 -0
- /package/dist/{chunk-U3DN4HEY.js.map → chunk-RMCLFSMX.js.map} +0 -0
- /package/dist/{chunk-YK7756IF.js.map → chunk-RTZANSSC.js.map} +0 -0
- /package/dist/{chunk-ZEG4VPBL.js.map → chunk-S27VZ5DO.js.map} +0 -0
- /package/dist/{chunk-54YW6SZZ.js.map → chunk-SBXSKRFA.js.map} +0 -0
- /package/dist/{chunk-HAX4LCR5.js.map → chunk-SFIXTOOJ.js.map} +0 -0
- /package/dist/{chunk-QIOQ2NPQ.js.map → chunk-SGH7I7OY.js.map} +0 -0
- /package/dist/{chunk-K2A5PXQ5.js.map → chunk-SJYTQLN3.js.map} +0 -0
- /package/dist/{chunk-2Z3NQNTM.js.map → chunk-SK5S2PCK.js.map} +0 -0
- /package/dist/{chunk-X3MWB2QU.js.map → chunk-SN2WENRP.js.map} +0 -0
- /package/dist/{chunk-OSY5K7L7.js.map → chunk-SP44O3OU.js.map} +0 -0
- /package/dist/{chunk-OZCBM3UC.js.map → chunk-SSR4ZX52.js.map} +0 -0
- /package/dist/{chunk-QCSJ4CWE.js.map → chunk-SXGJL7UT.js.map} +0 -0
- /package/dist/{chunk-NC55IFN3.js.map → chunk-T67LTMSW.js.map} +0 -0
- /package/dist/{chunk-AXHZYXUV.js.map → chunk-TDTD66BK.js.map} +0 -0
- /package/dist/{chunk-NGJJJPZZ.js.map → chunk-TK5FWVZR.js.map} +0 -0
- /package/dist/{chunk-2OP6WLGV.js.map → chunk-TNSJFZ6Q.js.map} +0 -0
- /package/dist/{chunk-O732GAFC.js.map → chunk-U4LTPFD2.js.map} +0 -0
- /package/dist/{chunk-4DVNUCRR.js.map → chunk-U5UGM5XD.js.map} +0 -0
- /package/dist/{chunk-UJK53QFL.js.map → chunk-UBRQ3PQD.js.map} +0 -0
- /package/dist/{chunk-SODC7T6L.js.map → chunk-UMX6DZME.js.map} +0 -0
- /package/dist/{chunk-YLS6QE5G.js.map → chunk-UO35OEOX.js.map} +0 -0
- /package/dist/{chunk-SHHJCL7X.js.map → chunk-UTRNLNCW.js.map} +0 -0
- /package/dist/{chunk-HEFPPMBQ.js.map → chunk-UU5FBVRX.js.map} +0 -0
- /package/dist/{chunk-GQXZPKK7.js.map → chunk-V6UOVHW3.js.map} +0 -0
- /package/dist/{chunk-GVN5SZLX.js.map → chunk-VATYK3JQ.js.map} +0 -0
- /package/dist/{chunk-7TIX2UAR.js.map → chunk-VCJQQYRE.js.map} +0 -0
- /package/dist/{chunk-6WD2INST.js.map → chunk-WDASYY4S.js.map} +0 -0
- /package/dist/{chunk-DXBYWSL5.js.map → chunk-WIFDNUKD.js.map} +0 -0
- /package/dist/{chunk-RT7CJMER.js.map → chunk-WIXHUBQN.js.map} +0 -0
- /package/dist/{chunk-57AZS3IE.js.map → chunk-WRMUXZ7C.js.map} +0 -0
- /package/dist/{chunk-2CLNIEK4.js.map → chunk-WTSQUCHB.js.map} +0 -0
- /package/dist/{chunk-OVKYVZMW.js.map → chunk-WXF2RTS4.js.map} +0 -0
- /package/dist/{chunk-MIHN76LX.js.map → chunk-WYGTAQMX.js.map} +0 -0
- /package/dist/{chunk-2RG7NIAS.js.map → chunk-X2QJXDE4.js.map} +0 -0
- /package/dist/{chunk-GAVYGBFI.js.map → chunk-XMBOLFFS.js.map} +0 -0
- /package/dist/{chunk-T7OXJZCX.js.map → chunk-XOIDUM2H.js.map} +0 -0
- /package/dist/{chunk-XHIQ5I6N.js.map → chunk-XVLEBB4Y.js.map} +0 -0
- /package/dist/{chunk-Q3DPEYX4.js.map → chunk-XZCCEKPW.js.map} +0 -0
- /package/dist/{chunk-T3OWFVMS.js.map → chunk-Y3XZEKDQ.js.map} +0 -0
- /package/dist/{chunk-KODELWYT.js.map → chunk-YJSCLGAW.js.map} +0 -0
- /package/dist/{chunk-ROKQU7WG.js.map → chunk-YMI27QPF.js.map} +0 -0
- /package/dist/{chunk-U7XM7CB4.js.map → chunk-YNTLWCF4.js.map} +0 -0
- /package/dist/{chunk-ZQCND77P.js.map → chunk-YRYF76OE.js.map} +0 -0
- /package/dist/{chunk-2BDT3UZQ.js.map → chunk-ZAX4XQLN.js.map} +0 -0
- /package/dist/{chunk-DXR5PDFP.js.map → chunk-ZBHGNE2J.js.map} +0 -0
- /package/dist/{chunk-I7ITSXSJ.js.map → chunk-ZR5EKJT6.js.map} +0 -0
- /package/dist/{chunk-IZXHMZQ6.js.map → chunk-ZW5YTIH3.js.map} +0 -0
- /package/dist/{embedded-new-voice-2G3VLPVQ.js.map → computer-viewer-5LKRCEVQ.js.map} +0 -0
- /package/dist/{embedded-voice-T5IWOWGD.js.map → embedded-new-voice-GHJRY3YL.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-SMC6J6QN.js.map → embedded-voice-ASQXBSTX.js.map} +0 -0
- /package/dist/{fleet-decision-row-WM64KXP3.js.map → fleet-decision-row-U7LDVBEM.js.map} +0 -0
- /package/dist/{latest-question-OX56OVQ5.js.map → latest-question-RNVF262Q.js.map} +0 -0
- /package/dist/{sandbox-files-ESDMOFSD.js.map → model-policy-picker-menu-E6XKMFTA.js.map} +0 -0
- /package/dist/{queue-surface-implementation-4KUZ4PJV.js.map → queue-surface-implementation-GUAIG6TK.js.map} +0 -0
- /package/dist/{recorder-host-WF2RRR56.js.map → recorder-host-2MYDJPQW.js.map} +0 -0
- /package/dist/{session-connect-cards-Q53KMMYY.js.map → sandbox-files-W5W2LW4K.js.map} +0 -0
- /package/dist/{session-realtime-CF3I35WJ.js.map → session-connect-cards-HPH7JOZP.js.map} +0 -0
- /package/dist/{timeline-annotation-markers-CJK4RYZ4.js.map → timeline-annotation-markers-FNILLWNU.js.map} +0 -0
- /package/dist/{timeline-annotation-selection-67GF5H26.js.map → timeline-annotation-selection-MBCIDO2Q.js.map} +0 -0
- /package/dist/{timeline-annotations-dialog-ONJPQDJQ.js.map → timeline-annotations-dialog-JPNKLOTE.js.map} +0 -0
|
@@ -3,14 +3,22 @@
|
|
|
3
3
|
// traffic lights, and the bar's row, the page's title line. The bar itself is
|
|
4
4
|
// drawn by the app's stylesheet (`html[data-desktop]::before`), as are the
|
|
5
5
|
// rules that lift a row into it (`[data-window-bar-row] > [data-titlebar]`).
|
|
6
|
-
import { ChevronsLeftIcon, ChevronsRightIcon, PanelLeftIcon } from "lucide-react";
|
|
7
|
-
import { useMemo, useState, type ReactNode, type RefObject } from "react";
|
|
6
|
+
import { ChevronsLeftIcon, ChevronsRightIcon, CopyIcon, PanelLeftIcon } from "lucide-react";
|
|
7
|
+
import { useMemo, useRef, useState, type ReactNode, type RefObject } from "react";
|
|
8
8
|
import { createPortal } from "react-dom";
|
|
9
9
|
|
|
10
10
|
import { Button } from "../../ui/button";
|
|
11
|
+
import { cn } from "../../lib/cn";
|
|
12
|
+
import {
|
|
13
|
+
ContextMenu,
|
|
14
|
+
ContextMenuContent,
|
|
15
|
+
ContextMenuItem,
|
|
16
|
+
ContextMenuTrigger,
|
|
17
|
+
} from "../../ui/context-menu";
|
|
11
18
|
import { PageHeaderWindowBarContext } from "../../ui/window-bar-title";
|
|
12
19
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip";
|
|
13
20
|
import { useActionShortcut } from "../lib/actions/actions-provider";
|
|
21
|
+
import { copyTitle } from "../lib/copy-link";
|
|
14
22
|
import { desktopPlatform } from "../lib/desktop";
|
|
15
23
|
import { useWindowBarRowLeft } from "../lib/window-bar-row";
|
|
16
24
|
import { TooltipWithKeys } from "./command-menu/keycaps";
|
|
@@ -121,7 +129,17 @@ export function SidebarToggleButton({
|
|
|
121
129
|
* repeat. Render it as the canvas's first child, with `data-window-bar-row`
|
|
122
130
|
* on the canvas (`useWindowBarRow`).
|
|
123
131
|
*/
|
|
124
|
-
export function WindowBarTitle({
|
|
132
|
+
export function WindowBarTitle({
|
|
133
|
+
copyable = false,
|
|
134
|
+
children,
|
|
135
|
+
}: {
|
|
136
|
+
/** A title worth copying (a Site's): right-click it for Copy title. */
|
|
137
|
+
copyable?: boolean;
|
|
138
|
+
children: ReactNode;
|
|
139
|
+
}) {
|
|
140
|
+
const text = useRef<HTMLSpanElement>(null);
|
|
141
|
+
const className =
|
|
142
|
+
"min-w-0 truncate text-[15px] font-semibold leading-6 tracking-[-0.01em] text-fg";
|
|
125
143
|
return (
|
|
126
144
|
<header
|
|
127
145
|
data-window-drag
|
|
@@ -130,12 +148,34 @@ export function WindowBarTitle({ children }: { children: ReactNode }) {
|
|
|
130
148
|
className="flex min-w-0 shrink-0 items-center gap-1 pl-[max(clamp(0.5rem,2.5vw,1.25rem),env(safe-area-inset-left))] pr-[max(clamp(0.5rem,2.5vw,1.25rem),env(safe-area-inset-right))]"
|
|
131
149
|
>
|
|
132
150
|
{/* The page's own header keeps the page's heading for assistive tech. */}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
{copyable ? (
|
|
152
|
+
// A copyable title's words leave the drag region, so they can be
|
|
153
|
+
// right-clicked; the rest of the bar still drags the window.
|
|
154
|
+
<ContextMenu>
|
|
155
|
+
<ContextMenuTrigger asChild>
|
|
156
|
+
<span
|
|
157
|
+
ref={text}
|
|
158
|
+
aria-hidden="true"
|
|
159
|
+
data-window-bar-title-text=""
|
|
160
|
+
className={cn(className, "[-webkit-app-region:no-drag] [app-region:no-drag]")}
|
|
161
|
+
>
|
|
162
|
+
{children}
|
|
163
|
+
</span>
|
|
164
|
+
</ContextMenuTrigger>
|
|
165
|
+
<ContextMenuContent className="min-w-40">
|
|
166
|
+
<ContextMenuItem
|
|
167
|
+
onSelect={() => void copyTitle(text.current?.textContent?.trim() ?? "")}
|
|
168
|
+
>
|
|
169
|
+
<CopyIcon className="size-4" />
|
|
170
|
+
Copy title
|
|
171
|
+
</ContextMenuItem>
|
|
172
|
+
</ContextMenuContent>
|
|
173
|
+
</ContextMenu>
|
|
174
|
+
) : (
|
|
175
|
+
<span aria-hidden="true" data-window-bar-title-text="" className={className}>
|
|
176
|
+
{children}
|
|
177
|
+
</span>
|
|
178
|
+
)}
|
|
139
179
|
</header>
|
|
140
180
|
);
|
|
141
181
|
}
|
|
@@ -173,16 +213,22 @@ export function WindowBarPageTitle({
|
|
|
173
213
|
// In the order the headers mounted (the page's order); a header keeps its
|
|
174
214
|
// place while its title is briefly empty.
|
|
175
215
|
const [claims, setClaims] = useState<
|
|
176
|
-
readonly { id: string; title: string | null; fallback: boolean }[]
|
|
216
|
+
readonly { id: string; title: string | null; fallback: boolean; copyable: boolean }[]
|
|
177
217
|
>([]);
|
|
178
218
|
const [registry] = useState(() => ({
|
|
179
|
-
set(id: string, title: string | null, fallback = false) {
|
|
219
|
+
set(id: string, title: string | null, fallback = false, copyable = false) {
|
|
180
220
|
setClaims((current) => {
|
|
181
221
|
const existing = current.find((claim) => claim.id === id);
|
|
182
|
-
if (
|
|
222
|
+
if (
|
|
223
|
+
existing?.title === title &&
|
|
224
|
+
existing.fallback === fallback &&
|
|
225
|
+
existing.copyable === copyable
|
|
226
|
+
)
|
|
227
|
+
return current;
|
|
228
|
+
const claim = { id, title, fallback, copyable };
|
|
183
229
|
return existing
|
|
184
|
-
? current.map((
|
|
185
|
-
: [...current,
|
|
230
|
+
? current.map((other) => (other.id === id ? claim : other))
|
|
231
|
+
: [...current, claim];
|
|
186
232
|
});
|
|
187
233
|
},
|
|
188
234
|
release(id: string) {
|
|
@@ -200,7 +246,9 @@ export function WindowBarPageTitle({
|
|
|
200
246
|
);
|
|
201
247
|
return (
|
|
202
248
|
<PageHeaderWindowBarContext.Provider value={value}>
|
|
203
|
-
{enabled && title != null && title !== "" ?
|
|
249
|
+
{enabled && title != null && title !== "" ? (
|
|
250
|
+
<WindowBarTitle copyable={owner?.copyable ?? false}>{title}</WindowBarTitle>
|
|
251
|
+
) : null}
|
|
204
252
|
{children}
|
|
205
253
|
</PageHeaderWindowBarContext.Provider>
|
|
206
254
|
);
|
|
@@ -1,16 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { Button } from "../../ui/button";
|
|
3
|
+
import { Notice } from "../../ui/notice";
|
|
4
|
+
import type { LatencyMode, ReasoningEffort } from "@opengeni/sdk";
|
|
5
|
+
import {
|
|
6
|
+
effortOptionsForModel,
|
|
7
|
+
runnableLatencyModesForModel,
|
|
8
|
+
type PickerModelRow,
|
|
9
|
+
} from "../../model-policy";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Why Send cannot run right now: the one source of truth shared by the new
|
|
13
|
+
* chat and open chat composers. Every blocker either shows one short visible
|
|
14
|
+
* line (composerSendBlockerNotice) or is explained by a surface the host
|
|
15
|
+
* already renders. A disabled Send button is never the only signal.
|
|
16
|
+
*/
|
|
1
17
|
export type ComposerSendBlocker =
|
|
2
18
|
| "upload"
|
|
3
19
|
| "repository"
|
|
4
20
|
| "policy"
|
|
5
21
|
| "personal_decision"
|
|
6
22
|
| "machine_permission"
|
|
7
|
-
| "personal_loading"
|
|
23
|
+
| "personal_loading"
|
|
24
|
+
/** Something Send needs is still loading; an early Send waits for it. */
|
|
25
|
+
| "loading"
|
|
26
|
+
| "model_catalog"
|
|
27
|
+
| "no_model"
|
|
28
|
+
| "model_not_connected"
|
|
29
|
+
| "model_unavailable"
|
|
30
|
+
| "private_session"
|
|
31
|
+
| "accounts"
|
|
32
|
+
/** The person may not read the chat's connected accounts; an admin must grant it. */
|
|
33
|
+
| "accounts_denied"
|
|
34
|
+
/** Opengeni is briefly unreachable; the page reconnects on its own. */
|
|
35
|
+
| "updating"
|
|
36
|
+
| "account_choice"
|
|
37
|
+
| "resources"
|
|
38
|
+
| "compute";
|
|
39
|
+
|
|
8
40
|
export function getComposerSendBlocker(input: {
|
|
9
41
|
uploadPending: boolean;
|
|
10
42
|
repositoryError: string | null;
|
|
11
43
|
policyValid: boolean;
|
|
12
44
|
personalDecision: boolean;
|
|
13
45
|
personalLoading: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Something Send needs failed to load (the chat's connected accounts):
|
|
48
|
+
* a failure Retry may fix, a permission denial, or a brief outage the page
|
|
49
|
+
* reconnects from by itself.
|
|
50
|
+
*/
|
|
51
|
+
loadFailed?: false | "failed" | "denied" | "updating" | undefined;
|
|
14
52
|
machineAccessDenied?: boolean | undefined;
|
|
15
53
|
}): ComposerSendBlocker | null {
|
|
16
54
|
if (input.uploadPending) return "upload";
|
|
@@ -19,5 +57,278 @@ export function getComposerSendBlocker(input: {
|
|
|
19
57
|
if (input.machineAccessDenied) return "machine_permission";
|
|
20
58
|
if (input.personalDecision) return "personal_decision";
|
|
21
59
|
if (input.personalLoading) return "personal_loading";
|
|
60
|
+
if (input.loadFailed === "denied") return "accounts_denied";
|
|
61
|
+
if (input.loadFailed === "updating") return "updating";
|
|
62
|
+
if (input.loadFailed) return "accounts";
|
|
22
63
|
return null;
|
|
23
64
|
}
|
|
65
|
+
|
|
66
|
+
/** Whether a model choice can run: the row is selectable and offers the effort and speed. */
|
|
67
|
+
export function pickerPolicyRunnable(
|
|
68
|
+
row: PickerModelRow | null | undefined,
|
|
69
|
+
effort: ReasoningEffort,
|
|
70
|
+
latencyMode: LatencyMode,
|
|
71
|
+
): boolean {
|
|
72
|
+
return Boolean(
|
|
73
|
+
row?.selectable &&
|
|
74
|
+
effortOptionsForModel(row.catalog).includes(effort) &&
|
|
75
|
+
(latencyMode === "standard" || runnableLatencyModesForModel(row.catalog).includes(latencyMode)),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Everything the new-chat composer's Send depends on, apart from the text. */
|
|
80
|
+
export type NewSessionSendState = {
|
|
81
|
+
/** A failed create left a session to retry into. */
|
|
82
|
+
created: boolean;
|
|
83
|
+
/** A voice launch does not bind connected-tool accounts. */
|
|
84
|
+
voice?: boolean | undefined;
|
|
85
|
+
draftLoading: boolean;
|
|
86
|
+
catalogLoading: boolean;
|
|
87
|
+
catalogFailed: boolean;
|
|
88
|
+
/** The composer is switching away from an unavailable model. */
|
|
89
|
+
replacingModel: boolean;
|
|
90
|
+
policyValid: boolean;
|
|
91
|
+
anyModelSelectable: boolean;
|
|
92
|
+
selectedModelNotConnected: boolean;
|
|
93
|
+
selectedModelSelectable: boolean;
|
|
94
|
+
/** Whether this workspace can create the chat's private visibility is still loading. */
|
|
95
|
+
privateSessionLoading?: boolean | undefined;
|
|
96
|
+
privateSessionUnavailable: boolean;
|
|
97
|
+
toolsLoading: boolean;
|
|
98
|
+
accountsLoading: boolean;
|
|
99
|
+
accountsFailed: boolean;
|
|
100
|
+
accountChoice: boolean;
|
|
101
|
+
resourcesLoading: boolean;
|
|
102
|
+
resourcesResolved: boolean;
|
|
103
|
+
uploadPending: boolean;
|
|
104
|
+
computeLoading: boolean;
|
|
105
|
+
computeReady: boolean;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The new-chat Send guard. Send's enabled state, the guard Send runs, the
|
|
110
|
+
* early-Send hold and the visible line all read this one answer, so a Send
|
|
111
|
+
* that looks available can never do nothing.
|
|
112
|
+
*/
|
|
113
|
+
export function getNewSessionSendBlocker(input: NewSessionSendState): ComposerSendBlocker | null {
|
|
114
|
+
if (input.draftLoading || input.catalogLoading || input.replacingModel) return "loading";
|
|
115
|
+
if (!input.policyValid) {
|
|
116
|
+
// A failed refresh keeps the last good list; only a choice it can't
|
|
117
|
+
// confirm is blocked by it.
|
|
118
|
+
if (input.catalogFailed) return "model_catalog";
|
|
119
|
+
if (!input.anyModelSelectable) return "no_model";
|
|
120
|
+
if (input.selectedModelNotConnected) return "model_not_connected";
|
|
121
|
+
return input.selectedModelSelectable ? "policy" : "model_unavailable";
|
|
122
|
+
}
|
|
123
|
+
// Unknown is not unavailable: an early Send waits for the answer.
|
|
124
|
+
if (input.privateSessionLoading) return "loading";
|
|
125
|
+
if (input.privateSessionUnavailable) return "private_session";
|
|
126
|
+
if (input.toolsLoading) return "loading";
|
|
127
|
+
// A session already created by a failed attempt keeps its accounts,
|
|
128
|
+
// environment, files and compute: only the checks above still apply.
|
|
129
|
+
if (input.created) return null;
|
|
130
|
+
if (!input.voice) {
|
|
131
|
+
if (input.accountsLoading) return "loading";
|
|
132
|
+
if (input.accountsFailed) return "accounts";
|
|
133
|
+
if (input.accountChoice) return "account_choice";
|
|
134
|
+
}
|
|
135
|
+
if (input.resourcesLoading) return "loading";
|
|
136
|
+
if (!input.resourcesResolved) return "resources";
|
|
137
|
+
if (input.uploadPending) return "upload";
|
|
138
|
+
if (input.computeLoading) return "loading";
|
|
139
|
+
if (!input.computeReady) return "compute";
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Blockers that clear on their own once loading finishes. */
|
|
144
|
+
export function composerSendBlockerIsLoading(blocker: ComposerSendBlocker | null): boolean {
|
|
145
|
+
return blocker === "loading" || blocker === "personal_loading";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** The one action a blocker's line may offer. */
|
|
149
|
+
export type ComposerSendBlockerAction = "fix_model_settings" | "retry";
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* One short line for a blocker, with at most one action. Blockers whose own
|
|
153
|
+
* surface always explains them (the upload chip, the personal access card,
|
|
154
|
+
* the machine access notice, the picker's Connect state) and loading return
|
|
155
|
+
* null; a host that explains another one itself passes it as explained.
|
|
156
|
+
*/
|
|
157
|
+
export function composerSendBlockerNotice(
|
|
158
|
+
blocker: ComposerSendBlocker | null,
|
|
159
|
+
): { message: string; action: { kind: ComposerSendBlockerAction; label: string } | null } | null {
|
|
160
|
+
switch (blocker) {
|
|
161
|
+
case "policy":
|
|
162
|
+
return {
|
|
163
|
+
message: "This model can't run with the selected reasoning level or speed.",
|
|
164
|
+
action: { kind: "fix_model_settings", label: "Use supported settings" },
|
|
165
|
+
};
|
|
166
|
+
case "model_not_connected":
|
|
167
|
+
return { message: "Connect this model or choose another one.", action: null };
|
|
168
|
+
case "model_unavailable":
|
|
169
|
+
return { message: "This model isn't available. Choose another one.", action: null };
|
|
170
|
+
case "model_catalog":
|
|
171
|
+
return { message: "Couldn't load models.", action: { kind: "retry", label: "Retry" } };
|
|
172
|
+
case "accounts":
|
|
173
|
+
return {
|
|
174
|
+
message: "Couldn't load your connected accounts.",
|
|
175
|
+
action: { kind: "retry", label: "Retry" },
|
|
176
|
+
};
|
|
177
|
+
case "accounts_denied":
|
|
178
|
+
return {
|
|
179
|
+
message: "You can't view this chat's accounts. Ask a workspace admin.",
|
|
180
|
+
action: null,
|
|
181
|
+
};
|
|
182
|
+
case "updating":
|
|
183
|
+
return { message: "Reconnecting. Send will work again in a moment.", action: null };
|
|
184
|
+
case "repository":
|
|
185
|
+
return { message: "Check the selected repositories to send.", action: null };
|
|
186
|
+
case "private_session":
|
|
187
|
+
return { message: "Private chats aren't available here.", action: null };
|
|
188
|
+
case "resources":
|
|
189
|
+
return { message: "The selected environment isn't available. Choose another.", action: null };
|
|
190
|
+
case "compute":
|
|
191
|
+
return { message: "Choose where this chat runs.", action: null };
|
|
192
|
+
default:
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The analytics reason for a blocked new-chat Send. Reasons recorded before
|
|
199
|
+
* this guard existed keep their names; blockers that were not recorded before
|
|
200
|
+
* (for example accounts, account_choice and resources) report their own name,
|
|
201
|
+
* and the order of checks changed (private chat comes before uploads).
|
|
202
|
+
*/
|
|
203
|
+
export function newSessionStartBlockerReason(blocker: ComposerSendBlocker | null): string | null {
|
|
204
|
+
switch (blocker) {
|
|
205
|
+
case null:
|
|
206
|
+
case "loading":
|
|
207
|
+
case "personal_loading":
|
|
208
|
+
return null;
|
|
209
|
+
case "model_catalog":
|
|
210
|
+
return "model_catalog_unavailable";
|
|
211
|
+
case "no_model":
|
|
212
|
+
return "no_model_connected";
|
|
213
|
+
case "model_not_connected":
|
|
214
|
+
return "selected_model_not_connected";
|
|
215
|
+
case "policy":
|
|
216
|
+
case "model_unavailable":
|
|
217
|
+
return "model_policy_unavailable";
|
|
218
|
+
case "private_session":
|
|
219
|
+
return "private_session_unavailable";
|
|
220
|
+
case "upload":
|
|
221
|
+
return "attachments_pending";
|
|
222
|
+
case "compute":
|
|
223
|
+
return "compute_unavailable";
|
|
224
|
+
default:
|
|
225
|
+
return blocker;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The visible line under a composer whose Send is blocked. */
|
|
230
|
+
export function ComposerSendBlockerNotice({
|
|
231
|
+
blocker,
|
|
232
|
+
explained,
|
|
233
|
+
onAction,
|
|
234
|
+
className,
|
|
235
|
+
}: {
|
|
236
|
+
blocker: ComposerSendBlocker | null;
|
|
237
|
+
/** Blockers another surface on this page already explains. */
|
|
238
|
+
explained?: readonly ComposerSendBlocker[] | undefined;
|
|
239
|
+
onAction?: ((action: ComposerSendBlockerAction) => void) | undefined;
|
|
240
|
+
className?: string | undefined;
|
|
241
|
+
}): ReactNode {
|
|
242
|
+
const notice =
|
|
243
|
+
blocker && explained?.includes(blocker) ? null : composerSendBlockerNotice(blocker);
|
|
244
|
+
if (!notice) return null;
|
|
245
|
+
const action = notice.action && onAction ? notice.action : null;
|
|
246
|
+
return (
|
|
247
|
+
<div role="status" className={className}>
|
|
248
|
+
<Notice
|
|
249
|
+
tone="waiting"
|
|
250
|
+
action={
|
|
251
|
+
action ? (
|
|
252
|
+
<Button variant="outline" size="sm" onClick={() => onAction?.(action.kind)}>
|
|
253
|
+
{action.label}
|
|
254
|
+
</Button>
|
|
255
|
+
) : undefined
|
|
256
|
+
}
|
|
257
|
+
>
|
|
258
|
+
{notice.message}
|
|
259
|
+
</Notice>
|
|
260
|
+
</div>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* A new chat the server refused to start. The chat does not exist yet, so the
|
|
266
|
+
* line under the composer is the only place that can say why; a toast alone
|
|
267
|
+
* disappears before it is read and leaves the person looking at nothing. The
|
|
268
|
+
* line stays until the person changes what they send (text, model, reasoning
|
|
269
|
+
* level or speed), sends successfully, or dismisses it.
|
|
270
|
+
*/
|
|
271
|
+
export type NewSessionCreateFailure = {
|
|
272
|
+
workspaceId: string;
|
|
273
|
+
/** What was sent when the start was refused (see newSessionSendSignature). */
|
|
274
|
+
signature: string;
|
|
275
|
+
message: string;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/** What a Send carries that a refusal is about: the text and the model choice. */
|
|
279
|
+
export function newSessionSendSignature(input: {
|
|
280
|
+
text: string;
|
|
281
|
+
model: string;
|
|
282
|
+
reasoningEffort: ReasoningEffort;
|
|
283
|
+
latencyMode: LatencyMode;
|
|
284
|
+
}): string {
|
|
285
|
+
return JSON.stringify([input.text, input.model, input.reasoningEffort, input.latencyMode]);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** The refusal message to show now, or null once the person changed what they send. */
|
|
289
|
+
export function visibleNewSessionCreateFailure(
|
|
290
|
+
failure: NewSessionCreateFailure | null,
|
|
291
|
+
current: { workspaceId: string; signature: string },
|
|
292
|
+
): string | null {
|
|
293
|
+
if (!failure) return null;
|
|
294
|
+
if (failure.workspaceId !== current.workspaceId) return null;
|
|
295
|
+
return failure.signature === current.signature ? failure.message : null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The refusal to keep under the composer, or null when the composer no longer
|
|
300
|
+
* holds what was sent (typing or a model change landed while the start was in
|
|
301
|
+
* flight). On null the caller keeps its toast, so a refused start is never
|
|
302
|
+
* silent.
|
|
303
|
+
*/
|
|
304
|
+
export function newSessionCreateFailureRecord(input: {
|
|
305
|
+
workspaceId: string;
|
|
306
|
+
/** newSessionSendSignature of the values the request actually carried. */
|
|
307
|
+
sent: string;
|
|
308
|
+
/** newSessionSendSignature of what the composer holds now. */
|
|
309
|
+
current: string;
|
|
310
|
+
message: string;
|
|
311
|
+
}): NewSessionCreateFailure | null {
|
|
312
|
+
if (input.sent !== input.current) return null;
|
|
313
|
+
return { workspaceId: input.workspaceId, signature: input.sent, message: input.message };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** The persistent line for a refused new chat. */
|
|
317
|
+
export function NewSessionCreateFailureNotice({
|
|
318
|
+
message,
|
|
319
|
+
onDismiss,
|
|
320
|
+
className,
|
|
321
|
+
}: {
|
|
322
|
+
message: string | null;
|
|
323
|
+
onDismiss?: (() => void) | undefined;
|
|
324
|
+
className?: string | undefined;
|
|
325
|
+
}): ReactNode {
|
|
326
|
+
if (!message) return null;
|
|
327
|
+
return (
|
|
328
|
+
<div role="alert" className={className}>
|
|
329
|
+
<Notice tone="failed" {...(onDismiss ? { onDismiss } : {})}>
|
|
330
|
+
{message}
|
|
331
|
+
</Notice>
|
|
332
|
+
</div>
|
|
333
|
+
);
|
|
334
|
+
}
|
package/src/app/lib/copy-link.ts
CHANGED
|
@@ -32,3 +32,13 @@ export async function copyLink(url: string): Promise<void> {
|
|
|
32
32
|
toast.error("Couldn't copy the link.", { description: userErrorText(error) });
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
/** Copies a chat's or Site's title and says so, as `copyLink` does for links. */
|
|
37
|
+
export async function copyTitle(title: string): Promise<void> {
|
|
38
|
+
try {
|
|
39
|
+
await writeClipboard(title);
|
|
40
|
+
toast.success("Title copied");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
toast.error("Couldn't copy the title.", { description: userErrorText(error) });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -10,8 +10,8 @@ export type SessionSendState = {
|
|
|
10
10
|
machineAccessDenied: boolean;
|
|
11
11
|
/** Something Send needs is still loading (the chat's tools, attachments, accounts). */
|
|
12
12
|
loading: boolean;
|
|
13
|
-
/** One of them failed to load
|
|
14
|
-
loadFailed:
|
|
13
|
+
/** One of them failed to load: a failure Retry may fix, a permission denial, or a brief outage. */
|
|
14
|
+
loadFailed: false | "failed" | "denied" | "updating";
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type SessionSendGate = {
|
|
@@ -38,7 +38,8 @@ export function useSessionSendGate(): SessionSendGate {
|
|
|
38
38
|
policyValid: committedPolicyValid,
|
|
39
39
|
personalDecision: state.personalDecision,
|
|
40
40
|
machineAccessDenied: state.machineAccessDenied,
|
|
41
|
-
personalLoading: state.loading
|
|
41
|
+
personalLoading: state.loading,
|
|
42
|
+
loadFailed: state.loadFailed,
|
|
42
43
|
}),
|
|
43
44
|
[committedPolicyValid],
|
|
44
45
|
);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { afterAll, beforeAll, expect, test } from "bun:test";
|
|
2
|
+
import { GlobalRegistrator } from "@happy-dom/global-registrator";
|
|
3
|
+
import { act } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
|
|
6
|
+
import { publishSiteSidebarBridge, useSiteSidebarActions } from "./site-sidebar-bridge";
|
|
7
|
+
|
|
8
|
+
let ownsDom = false;
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
ownsDom = !GlobalRegistrator.isRegistered;
|
|
11
|
+
if (ownsDom) GlobalRegistrator.register();
|
|
12
|
+
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });
|
|
13
|
+
});
|
|
14
|
+
afterAll(() => {
|
|
15
|
+
if (ownsDom) GlobalRegistrator.unregister();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const origin = { siteId: "site-1", title: "Opengeni usage" };
|
|
19
|
+
type Actions = ReturnType<typeof useSiteSidebarActions>;
|
|
20
|
+
|
|
21
|
+
function Probe({ workspaceId, seen }: { workspaceId: string; seen: Actions[] }) {
|
|
22
|
+
seen.push(useSiteSidebarActions(workspaceId, origin));
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
test("a Site's page gets the sidebar's Pin and Archive only while the sidebar publishes them", async () => {
|
|
27
|
+
const seen: Actions[] = [];
|
|
28
|
+
const container = document.createElement("div");
|
|
29
|
+
const root = createRoot(container);
|
|
30
|
+
await act(async () => root.render(<Probe workspaceId="ws-1" seen={seen} />));
|
|
31
|
+
expect(seen.at(-1)).toBeNull();
|
|
32
|
+
|
|
33
|
+
const calls: string[] = [];
|
|
34
|
+
const bridge = {
|
|
35
|
+
workspaceId: "ws-1",
|
|
36
|
+
pinnedSiteIds: new Set<string>(),
|
|
37
|
+
pin: (site: typeof origin, pinned: boolean) => void calls.push(`pin ${site.siteId} ${pinned}`),
|
|
38
|
+
archive: (site: typeof origin) => void calls.push(`archive ${site.siteId}`),
|
|
39
|
+
};
|
|
40
|
+
let withdraw = () => {};
|
|
41
|
+
await act(async () => void (withdraw = publishSiteSidebarBridge(bridge)));
|
|
42
|
+
expect(seen.at(-1)?.pinned).toBe(false);
|
|
43
|
+
seen.at(-1)!.togglePin();
|
|
44
|
+
seen.at(-1)!.archive();
|
|
45
|
+
expect(calls).toEqual(["pin site-1 true", "archive site-1"]);
|
|
46
|
+
|
|
47
|
+
// A newer sidebar takes over; when it goes, the older one acts again.
|
|
48
|
+
const pinned = { ...bridge, pinnedSiteIds: new Set(["site-1"]) };
|
|
49
|
+
let withdrawNewer = () => {};
|
|
50
|
+
await act(async () => void (withdrawNewer = publishSiteSidebarBridge(pinned)));
|
|
51
|
+
expect(seen.at(-1)?.pinned).toBe(true);
|
|
52
|
+
await act(async () => withdrawNewer());
|
|
53
|
+
expect(seen.at(-1)?.pinned).toBe(false);
|
|
54
|
+
// The older one's withdrawal leaves a newer one in place.
|
|
55
|
+
await act(async () => void (withdrawNewer = publishSiteSidebarBridge(pinned)));
|
|
56
|
+
await act(async () => withdraw());
|
|
57
|
+
expect(seen.at(-1)?.pinned).toBe(true);
|
|
58
|
+
|
|
59
|
+
// Another workspace's sidebar doesn't act on this page.
|
|
60
|
+
await act(async () => root.render(<Probe workspaceId="ws-2" seen={seen} />));
|
|
61
|
+
expect(seen.at(-1)).toBeNull();
|
|
62
|
+
|
|
63
|
+
await act(async () => root.render(<Probe workspaceId="ws-1" seen={seen} />));
|
|
64
|
+
await act(async () => withdrawNewer());
|
|
65
|
+
expect(seen.at(-1)).toBeNull();
|
|
66
|
+
act(() => root.unmount());
|
|
67
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
import type { SessionSiteOrigin } from "./session-site-origin";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The sidebar's Site actions for the Site's own page: Pin and Archive there
|
|
7
|
+
* act exactly as on the Site's row (same optimistic row, toasts and Undo),
|
|
8
|
+
* because the sidebar that owns those rows publishes them here while it is
|
|
9
|
+
* mounted. Absent while there is no sidebar list (a collapsed rail, a closed
|
|
10
|
+
* phone drawer, an embed without Site sidebar state); the page then offers
|
|
11
|
+
* neither.
|
|
12
|
+
*/
|
|
13
|
+
export type SiteSidebarBridge = {
|
|
14
|
+
workspaceId: string;
|
|
15
|
+
/** Sites pinned in this person's sidebar. */
|
|
16
|
+
pinnedSiteIds: ReadonlySet<string>;
|
|
17
|
+
pin: (origin: SessionSiteOrigin, pinned: boolean) => void;
|
|
18
|
+
archive: (origin: SessionSiteOrigin) => void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Newest last: when two sidebars are mounted (the shell's and an embedded
|
|
22
|
+
// chat's), the newest acts until it unmounts, then the one before it again.
|
|
23
|
+
let registrations: readonly SiteSidebarBridge[] = [];
|
|
24
|
+
const listeners = new Set<() => void>();
|
|
25
|
+
|
|
26
|
+
/** Publishes the sidebar's actions; returns the matching withdrawal. */
|
|
27
|
+
export function publishSiteSidebarBridge(bridge: SiteSidebarBridge): () => void {
|
|
28
|
+
registrations = [...registrations, bridge];
|
|
29
|
+
for (const listener of listeners) listener();
|
|
30
|
+
return () => {
|
|
31
|
+
if (!registrations.includes(bridge)) return;
|
|
32
|
+
registrations = registrations.filter((registered) => registered !== bridge);
|
|
33
|
+
for (const listener of listeners) listener();
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function subscribe(listener: () => void): () => void {
|
|
38
|
+
listeners.add(listener);
|
|
39
|
+
return () => listeners.delete(listener);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const snapshot = (): SiteSidebarBridge | null => registrations.at(-1) ?? null;
|
|
43
|
+
|
|
44
|
+
/** The sidebar's Pin and Archive for one Site, or null while there are none. */
|
|
45
|
+
export function useSiteSidebarActions(
|
|
46
|
+
workspaceId: string,
|
|
47
|
+
origin: SessionSiteOrigin | null,
|
|
48
|
+
): { pinned: boolean; togglePin: () => void; archive: () => void } | null {
|
|
49
|
+
const bridge = useSyncExternalStore(subscribe, snapshot, () => null);
|
|
50
|
+
if (!bridge || !origin || bridge.workspaceId !== workspaceId) return null;
|
|
51
|
+
const pinned = bridge.pinnedSiteIds.has(origin.siteId);
|
|
52
|
+
return {
|
|
53
|
+
pinned,
|
|
54
|
+
togglePin: () => bridge.pin(origin, !pinned),
|
|
55
|
+
archive: () => bridge.archive(origin),
|
|
56
|
+
};
|
|
57
|
+
}
|