@openhands/agent-canvas 1.2.0 → 1.3.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/README.md +1 -1
- package/README.windows.md +2 -2
- package/build/assets/{Trans-De9RwQhA.js → Trans-DY6toRDu.js} +1 -1
- package/build/assets/{acp-providers-D_D8VUpP.js → acp-providers-Djl6vNn-.js} +1 -1
- package/build/assets/active-backend-context-B3umL5R-.js +1 -0
- package/build/assets/{add-backend-modal-DzuB9zlG.js → add-backend-modal-DljoP9lc.js} +1 -1
- package/build/assets/{agent-profiles-settings-BfAwTshW.js → agent-profiles-settings-BJMmTZgv.js} +1 -1
- package/build/assets/{agent-server-conversation-service.api-DfH2k6Sx.js → agent-server-conversation-service.api-D_ZvtJjG.js} +3 -3
- package/build/assets/agent-settings-BVVFzBWS.js +1 -0
- package/build/assets/{agent-settings-DjVlKgaP.js → agent-settings-lUknCeaF.js} +1 -1
- package/build/assets/{alert-banner-BW0wRYw6.js → alert-banner-Bpf2NQJq.js} +1 -1
- package/build/assets/{api-key-entry-screen-O8gS-fnF.js → api-key-entry-screen-CWEHcPJA.js} +1 -1
- package/build/assets/{app-settings-SlZvaXlk.js → app-settings-Dj90qosy.js} +1 -1
- package/build/assets/automation-detail-CXJU0_gF.js +2 -0
- package/build/assets/automation-export-FWY9LPsG.js +2 -0
- package/build/assets/automations-list-DDGBkWLC.js +1 -0
- package/build/assets/{back-nav-button-BYmxFxGt.js → back-nav-button-CUS2mi-U.js} +1 -1
- package/build/assets/{backend-form-modal-D2EDGVAc.js → backend-form-modal-DSbrafX2.js} +1 -1
- package/build/assets/{backend-synced-settings-badge-6OCwIuLY.js → backend-synced-settings-badge-CanzmG12.js} +1 -1
- package/build/assets/{base-modal-CC5Pp8CF.js → base-modal-BuF2f0YL.js} +1 -1
- package/build/assets/{brand-button-DKPMEKcW.js → brand-button-vMVuyDXu.js} +1 -1
- package/build/assets/{browser-B39N74jU.js → browser-BifzWIBd.js} +1 -1
- package/build/assets/{browser-tab-aiDg7aEn.js → browser-tab-CkkqJnqw.js} +1 -1
- package/build/assets/{chat-send-button-DxuZIoW8.js → chat-send-button-B_jc5z5C.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-T3eAIuPQ.js → circle-plus-check-toggle-C5YxjxvI.js} +1 -1
- package/build/assets/{color-themes-Dd1sO5U6.js → color-themes-DPBzNtVg.js} +3 -3
- package/build/assets/{combobox-caret-CLGvOs32.js → combobox-caret-DoObzqf4.js} +1 -1
- package/build/assets/{command-menu-DKrLCRla.js → command-menu-D-JV3Wqm.js} +1 -1
- package/build/assets/{condenser-settings-BhxvlfoY.js → condenser-settings-30cX9SK6.js} +1 -1
- package/build/assets/{confirmation-modal-BK1F0A68.js → confirmation-modal-BGLu6XJN.js} +1 -1
- package/build/assets/{context-menu-list-item-DBFzplWW.js → context-menu-list-item-BD5_EaKN.js} +1 -1
- package/build/assets/conversation-BltULtFA.js +89 -0
- package/build/assets/conversation-e0a0_X4S.js +1 -0
- package/build/assets/conversation-panel-Cr9_ZGI-.js +1 -0
- package/build/assets/{conversation-service.api-Ch9kR9aE.js → conversation-service.api-DQaKzIRj.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-m8IUkfMj.js → conversation-tab-empty-state-B2dDYEwf.js} +1 -1
- package/build/assets/{copy-to-clipboard-button-Aj9wFmt2.js → copy-to-clipboard-button-CaR52OnA.js} +1 -1
- package/build/assets/declaration-gq8V5eTU.js +1 -0
- package/build/assets/{device-verify-B5YCrvSu.js → device-verify-BsznkV-a.js} +1 -1
- package/build/assets/{dropdown-classes-CgQ45JmQ.js → dropdown-classes-DJSXeLqc.js} +1 -1
- package/build/assets/{ellipsis-button-1BV9Sga8.js → ellipsis-button-C5Z-tPFp.js} +1 -1
- package/build/assets/{entry.client-BgWj9jL_.js → entry.client-JixNvFrr.js} +2 -2
- package/build/assets/{enum-filter-dropdown-DCITiYVi.js → enum-filter-dropdown-DXbVwiNZ.js} +1 -1
- package/build/assets/{environment-switch-overlay-DUnKILNH.js → environment-switch-overlay-DZQfRGTx.js} +1 -1
- package/build/assets/{extensions-hub-MtC8lK3A.js → extensions-hub-DfvgqzTc.js} +1 -1
- package/build/assets/{extensions-navigation-BtV14oQL.js → extensions-navigation-D9i0DL62.js} +1 -1
- package/build/assets/files-tab-DDtEJcGE.js +1 -0
- package/build/assets/{form-control-classes-9rkU4usZ.js → form-control-classes-ChpNBe9n.js} +1 -1
- package/build/assets/{git-provider-icon-CGU7_KiU.js → git-provider-icon-BjkecAuV.js} +1 -1
- package/build/assets/home-BCKWpKpf.js +1 -0
- package/build/assets/{install-server-modal-J_eQ6lhG.js → install-server-modal-BIugLhVB.js} +1 -1
- package/build/assets/{launch-DamfAY5L.js → launch-BgIlZLSX.js} +1 -1
- package/build/assets/lesson-plan-DgpP80mJ.js +4 -0
- package/build/assets/{llm-not-configured-banner-DTrLsVr_.js → llm-not-configured-banner-BlX8NifC.js} +4 -4
- package/build/assets/llm-settings-DJmbryaE.js +1 -0
- package/build/assets/{llm-settings-BgSFkbHC.js → llm-settings-kU5v0H1Z.js} +1 -1
- package/build/assets/{loading-spinner-DHAIPZkP.js → loading-spinner-BLdswi6q.js} +1 -1
- package/build/assets/{manage-backends-modal-BUzj5_Lq.js → manage-backends-modal-C8FJQIZR.js} +1 -1
- package/build/assets/manifest-56d40d7c.js +1 -0
- package/build/assets/{markdown-renderer-D8mayGjI.js → markdown-renderer-DMT7Zkpd.js} +1 -1
- package/build/assets/{mcp-DvqJYDbz.js → mcp-CHkklDMv.js} +1 -1
- package/build/assets/{messages-C4KEFkPk.js → messages-B3RugH7P.js} +11 -11
- package/build/assets/{modal-body-Dcu5McCa.js → modal-body-DouOE5KH.js} +1 -1
- package/build/assets/{modal-classes-DPqxSyuP.js → modal-classes-Cf-4tbHz.js} +1 -1
- package/build/assets/{modal-close-button-CTCX4nCH.js → modal-close-button-B6CfxxJj.js} +1 -1
- package/build/assets/{model-selector-VDHBytb6.js → model-selector-BOj1wBlq.js} +1 -1
- package/build/assets/onboarding-DYhDxmI9.js +1 -0
- package/build/assets/{onboarding-modal-CGHPoMp7.js → onboarding-modal-CP_WxDC9.js} +1 -1
- package/build/assets/{option-service.api-Dz7Eomnx.js → option-service.api-C0tYT4-r.js} +1 -1
- package/build/assets/{path-utils-CBaRYg35.js → path-utils-DWcgCGen.js} +1 -1
- package/build/assets/{plan-components-j9X4AxYM.js → plan-components-CcCBmCzW.js} +1 -1
- package/build/assets/{planner-tab-G4j36bJk.js → planner-tab-CCqdXxkL.js} +1 -1
- package/build/assets/providers-BxCuC9bZ.js +1 -0
- package/build/assets/recommended-automations-launcher-CVEF_1pc.js +58 -0
- package/build/assets/root-V8fkplMy.css +1 -0
- package/build/assets/root-layout-CttG_lQi.js +2 -0
- package/build/assets/{root-S6CfVoNm.js → root-uJ2t9rCQ.js} +2 -2
- package/build/assets/{runtime-waiting-state-DkzLgvMn.js → runtime-waiting-state-BsXLElvN.js} +1 -1
- package/build/assets/{schema-field-DwUzlw6b.js → schema-field-xUr6rDd6.js} +1 -1
- package/build/assets/{sdk-section-page-BUXONTx6.js → sdk-section-page-CbLrVUa3.js} +1 -1
- package/build/assets/{sdk-settings-schema-BjBkMHzZ.js → sdk-settings-schema-Cv7M9eSe.js} +1 -1
- package/build/assets/{secrets-settings-ZxyfRBgx.js → secrets-settings-DxTx9HgU.js} +1 -1
- package/build/assets/{segmented-toggle-Cen5AMUc.js → segmented-toggle-DyQqPhoD.js} +1 -1
- package/build/assets/{settings-Bx6vn-g8.js → settings-DnlfS09K.js} +1 -1
- package/build/assets/{settings-dropdown-input-xzoZwgUe.js → settings-dropdown-input-BjunGXJb.js} +1 -1
- package/build/assets/{settings-index-D4SM26d5.js → settings-index-BjeuYFFa.js} +1 -1
- package/build/assets/{settings-input-DYs7t3oK.js → settings-input-bD6npsDm.js} +1 -1
- package/build/assets/{settings-list-classes-DvQr5jVS.js → settings-list-classes-Dp_OgzN0.js} +1 -1
- package/build/assets/{settings-modal-BoC8oMlg.js → settings-modal-DfTcL-mV.js} +1 -1
- package/build/assets/settings-service.api-K4ncGlBv.js +1 -0
- package/build/assets/{settings-switch-C2N2xqEb.js → settings-switch-5cuxl8Dc.js} +1 -1
- package/build/assets/{shared-conversation-DMiaQFsj.js → shared-conversation-DWtBkJv7.js} +1 -1
- package/build/assets/{sidebar-layout-BtpUSN3j.js → sidebar-layout-DuzJMMw-.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-CaV3tQFF.js → sidebar-mobile-menu-toggle-CMmAYkh8.js} +1 -1
- package/build/assets/{sidebar-nav-link-CIB3NBRW.js → sidebar-nav-link-5AlTT5-j.js} +1 -1
- package/build/assets/{skill-card-pill-row-D2bUe2kB.js → skill-card-pill-row-eTIkE4nz.js} +1 -1
- package/build/assets/{skills-plugins-D2WkrXkr.js → skills-plugins-BJ040luO.js} +1 -1
- package/build/assets/{skills-settings-CZGVOp_t.js → skills-settings-BYn4-AQQ.js} +1 -1
- package/build/assets/{styled-tooltip-DsKsFjuq.js → styled-tooltip-CgX2oRaK.js} +1 -1
- package/build/assets/{task-list-tab-BAThr9Ex.js → task-list-tab-0k9PhuqO.js} +1 -1
- package/build/assets/{terminal-B0aL_iDZ.js → terminal-BsGcSpRS.js} +1 -1
- package/build/assets/{toggle-switch-DBlOOzBr.js → toggle-switch-2j5wwR85.js} +1 -1
- package/build/assets/{typography-YGPBGzOG.js → typography-D8mHDeNG.js} +1 -1
- package/build/assets/{use-acp-credential-form-rzaqkJ1n.js → use-acp-credential-form-EtnbtYt0.js} +1 -1
- package/build/assets/{use-activate-agent-profile-DY0txItX.js → use-activate-agent-profile-WaAZYz4E.js} +1 -1
- package/build/assets/{use-active-agent-profile-Cp5AFONR.js → use-active-agent-profile-CYY3vGar.js} +1 -1
- package/build/assets/{use-active-conversation-DvcFBqFe.js → use-active-conversation-D-r929nx.js} +1 -1
- package/build/assets/{use-agent-profiles-DnH16_Vm.js → use-agent-profiles-DEAMFp-W.js} +1 -1
- package/build/assets/{use-agent-state-BvRcEzY4.js → use-agent-state-DijdVAQ0.js} +1 -1
- package/build/assets/{use-backends-health-e-Ull4wz.js → use-backends-health-DkC7tKkC.js} +1 -1
- package/build/assets/{use-can-manage-org-profiles-OIhplvQ0.js → use-can-manage-org-profiles-BEo0peGn.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-ekU7UXDT.js → use-cloud-current-user-id-Dm99wXp2.js} +1 -1
- package/build/assets/{use-config-Dwf5gla-.js → use-config-CHzNIHpv.js} +1 -1
- package/build/assets/{use-create-conversation-CvAXfA3T.js → use-create-conversation-CTsvZ96U.js} +1 -1
- package/build/assets/{use-create-secret-BKeXCo__.js → use-create-secret-D5O5qdWC.js} +1 -1
- package/build/assets/{use-event-store-YSOxy9FC.js → use-event-store-DjgU4wfO.js} +1 -1
- package/build/assets/{use-handle-plan-click-cAXS-Hft.js → use-handle-plan-click-Mn_SNTCh.js} +1 -1
- package/build/assets/{use-llm-profiles-BcLibtGb.js → use-llm-profiles-BMhPDlwQ.js} +1 -1
- package/build/assets/use-runtime-is-ready-CC-KrLKe.js +1 -0
- package/build/assets/{use-save-agent-profile-DFjxHhNx.js → use-save-agent-profile-CLMmbx_X.js} +1 -1
- package/build/assets/{use-save-settings-5xPYpSQM.js → use-save-settings-D1HoCDbn.js} +1 -1
- package/build/assets/{use-settings-B07msZ2Z.js → use-settings-BReAMxCG.js} +1 -1
- package/build/assets/{use-settings-nav-items-CswsOEyw.js → use-settings-nav-items-xe1YgLnE.js} +1 -1
- package/build/assets/{use-skills-Aoaoq_ei.js → use-skills-Dqo-pDDx.js} +1 -1
- package/build/assets/{use-task-list-CmWGElgb.js → use-task-list-AVBLbbcR.js} +1 -1
- package/build/assets/{use-tracking-CqODdfO4.js → use-tracking-2ZwQwpg_.js} +1 -1
- package/build/assets/{use-user-conversation-BPHQ-dm-.js → use-user-conversation-OAfenBRG.js} +1 -1
- package/build/assets/{useTranslation-Cgy4JA_g.js → useTranslation-CDRCKC9-.js} +1 -1
- package/build/assets/{utils-CE0lDWtb.js → utils-D3U3rlqr.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~ki5qnp0d-DJHl5b-B.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~ki5qnp0d-rV6d1Iv_.js} +267 -27
- package/build/assets/vendor~root-layout~home~mcp~automations-list~onboarding-modal-CXyYYvYh.js +1 -0
- package/build/assets/{verification-settings-DZQ-JvKH.js → verification-settings-DnXS6VWv.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +24 -0
- package/build/locales/ca/openhands.json +24 -0
- package/build/locales/de/openhands.json +24 -0
- package/build/locales/en/openhands.json +24 -0
- package/build/locales/es/openhands.json +24 -0
- package/build/locales/fr/openhands.json +24 -0
- package/build/locales/it/openhands.json +24 -0
- package/build/locales/ja/openhands.json +24 -0
- package/build/locales/ko-KR/openhands.json +24 -0
- package/build/locales/no/openhands.json +24 -0
- package/build/locales/pt/openhands.json +24 -0
- package/build/locales/tr/openhands.json +24 -0
- package/build/locales/uk/openhands.json +24 -0
- package/build/locales/zh-CN/openhands.json +24 -0
- package/build/locales/zh-TW/openhands.json +24 -0
- package/config/defaults.json +4 -4
- package/dist/api/automation-service/automation-service.api.d.ts +2 -1
- package/dist/api/event-service/event-service.api.cjs +1 -1
- package/dist/api/event-service/event-service.api.cjs.map +1 -1
- package/dist/api/event-service/event-service.api.js +1 -1
- package/dist/api/event-service/event-service.api.js.map +1 -1
- package/dist/api/event-service/event-service.types.d.ts +6 -0
- package/dist/api/git-service/agent-server-git-service.api.cjs +1 -1
- package/dist/api/git-service/agent-server-git-service.api.cjs.map +1 -1
- package/dist/api/git-service/agent-server-git-service.api.js +2 -2
- package/dist/api/git-service/agent-server-git-service.api.js.map +1 -1
- package/dist/api/git-service/git-service.api.cjs +1 -1
- package/dist/api/git-service/git-service.api.cjs.map +1 -1
- package/dist/api/git-service/git-service.api.js +2 -2
- package/dist/api/git-service/git-service.api.js.map +1 -1
- package/dist/components/conversation-events/chat/event-thought-helpers.cjs +1 -1
- package/dist/components/conversation-events/chat/event-thought-helpers.js +1 -1
- package/dist/components/features/automations/automation-card.d.ts +2 -1
- package/dist/components/features/automations/automation-group.d.ts +2 -1
- package/dist/components/features/automations/automation-list-row.d.ts +2 -1
- package/dist/components/features/automations/build-automation-menu-items.d.ts +2 -1
- package/dist/components/features/automations/detail/detail-header.d.ts +3 -1
- package/dist/components/features/automations/import-automation-modal.d.ts +10 -0
- package/dist/components/features/conversation/conversation-name-context-menu.cjs +1 -1
- package/dist/components/features/conversation/conversation-name-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name-context-menu.d.ts +2 -1
- package/dist/components/features/conversation/conversation-name-context-menu.js +74 -63
- package/dist/components/features/conversation/conversation-name-context-menu.js.map +1 -1
- package/dist/components/features/conversation/conversation-name.cjs +1 -1
- package/dist/components/features/conversation/conversation-name.cjs.map +1 -1
- package/dist/components/features/conversation/conversation-name.js +73 -61
- package/dist/components/features/conversation/conversation-name.js.map +1 -1
- package/dist/components/features/conversation/transcript-export-modal.cjs +2 -0
- package/dist/components/features/conversation/transcript-export-modal.cjs.map +1 -0
- package/dist/components/features/conversation/transcript-export-modal.d.ts +10 -0
- package/dist/components/features/conversation/transcript-export-modal.js +140 -0
- package/dist/components/features/conversation/transcript-export-modal.js.map +1 -0
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card-context-menu.js.map +1 -1
- package/dist/components/features/home/shared/dropdown-item.cjs +1 -1
- package/dist/components/features/home/shared/dropdown-item.cjs.map +1 -1
- package/dist/components/features/home/shared/dropdown-item.d.ts +7 -1
- package/dist/components/features/home/shared/dropdown-item.js +2 -1
- package/dist/components/features/home/shared/dropdown-item.js.map +1 -1
- package/dist/components/features/home/shared/generic-dropdown-menu.cjs +1 -1
- package/dist/components/features/home/shared/generic-dropdown-menu.cjs.map +1 -1
- package/dist/components/features/home/shared/generic-dropdown-menu.d.ts +8 -1
- package/dist/components/features/home/shared/generic-dropdown-menu.js +18 -10
- package/dist/components/features/home/shared/generic-dropdown-menu.js.map +1 -1
- package/dist/components/features/home/workspace-dropdown/workspace-dropdown.d.ts +11 -2
- package/dist/config/defaults.cjs +1 -1
- package/dist/config/defaults.cjs.map +1 -1
- package/dist/config/defaults.js +4 -4
- package/dist/config/defaults.js.map +1 -1
- package/dist/hooks/query/use-automations.d.ts +2 -1
- package/dist/hooks/query/use-resolved-workspaces.cjs +1 -1
- package/dist/hooks/query/use-resolved-workspaces.cjs.map +1 -1
- package/dist/hooks/query/use-resolved-workspaces.d.ts +9 -1
- package/dist/hooks/query/use-resolved-workspaces.js +1 -0
- package/dist/hooks/query/use-resolved-workspaces.js.map +1 -1
- package/dist/hooks/query/use-workspace-file-content.cjs +1 -1
- package/dist/hooks/query/use-workspace-file-content.cjs.map +1 -1
- package/dist/hooks/query/use-workspace-file-content.js +61 -55
- package/dist/hooks/query/use-workspace-file-content.js.map +1 -1
- package/dist/hooks/query/use-workspace-files.cjs +1 -1
- package/dist/hooks/query/use-workspace-files.cjs.map +1 -1
- package/dist/hooks/query/use-workspace-files.d.ts +11 -4
- package/dist/hooks/query/use-workspace-files.js +39 -18
- package/dist/hooks/query/use-workspace-files.js.map +1 -1
- package/dist/hooks/use-auto-refresh-files-on-edit.cjs +1 -1
- package/dist/hooks/use-auto-refresh-files-on-edit.cjs.map +1 -1
- package/dist/hooks/use-auto-refresh-files-on-edit.d.ts +9 -0
- package/dist/hooks/use-auto-refresh-files-on-edit.js +15 -11
- package/dist/hooks/use-auto-refresh-files-on-edit.js.map +1 -1
- package/dist/hooks/use-tracking.cjs +1 -1
- package/dist/hooks/use-tracking.cjs.map +1 -1
- package/dist/hooks/use-tracking.d.ts +7 -0
- package/dist/hooks/use-tracking.js +9 -0
- package/dist/hooks/use-tracking.js.map +1 -1
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +24 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +1 -1
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +408 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +24 -0
- package/dist/locales/ca/openhands.json +24 -0
- package/dist/locales/de/openhands.json +24 -0
- package/dist/locales/en/openhands.json +24 -0
- package/dist/locales/es/openhands.json +24 -0
- package/dist/locales/fr/openhands.json +24 -0
- package/dist/locales/it/openhands.json +24 -0
- package/dist/locales/ja/openhands.json +24 -0
- package/dist/locales/ko-KR/openhands.json +24 -0
- package/dist/locales/no/openhands.json +24 -0
- package/dist/locales/pt/openhands.json +24 -0
- package/dist/locales/tr/openhands.json +24 -0
- package/dist/locales/uk/openhands.json +24 -0
- package/dist/locales/zh-CN/openhands.json +24 -0
- package/dist/locales/zh-TW/openhands.json +24 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js +70 -3
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js +27 -2
- package/dist/node_modules/@openhands/extensions/integrations/catalog/datadog.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/superhuman-mail.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/superhuman-mail.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/superhuman-mail.js +33 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/superhuman-mail.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js +48 -46
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +267 -27
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +36 -30
- package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/dist/routes/files-tab.cjs +1 -1
- package/dist/routes/files-tab.js +10 -10
- package/dist/themes/color-themes.cjs +3 -3
- package/dist/themes/color-themes.cjs.map +1 -1
- package/dist/themes/color-themes.d.ts +13 -2
- package/dist/themes/color-themes.js +2 -2
- package/dist/themes/color-themes.js.map +1 -1
- package/dist/types/automation.d.ts +8 -0
- package/dist/utils/custom-toast-handlers.cjs.map +1 -1
- package/dist/utils/custom-toast-handlers.d.ts +1 -0
- package/dist/utils/custom-toast-handlers.js.map +1 -1
- package/dist/utils/mcp-server-name.cjs +1 -1
- package/dist/utils/mcp-server-name.cjs.map +1 -1
- package/dist/utils/mcp-server-name.js +2 -2
- package/dist/utils/mcp-server-name.js.map +1 -1
- package/dist/utils/transcript-export/index.cjs +72 -0
- package/dist/utils/transcript-export/index.cjs.map +1 -0
- package/dist/utils/transcript-export/index.d.ts +10 -0
- package/dist/utils/transcript-export/index.js +302 -0
- package/dist/utils/transcript-export/index.js.map +1 -0
- package/dist/utils/transcript-export/load-complete-events.cjs +2 -0
- package/dist/utils/transcript-export/load-complete-events.cjs.map +1 -0
- package/dist/utils/transcript-export/load-complete-events.d.ts +22 -0
- package/dist/utils/transcript-export/load-complete-events.js +39 -0
- package/dist/utils/transcript-export/load-complete-events.js.map +1 -0
- package/package.json +2 -2
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/dev-safe.mjs +2 -2
- package/build/assets/active-backend-context-DRFevVIj.js +0 -1
- package/build/assets/agent-settings-CMMms-0q.js +0 -1
- package/build/assets/automation-detail-CwsNJ9AM.js +0 -2
- package/build/assets/automations-list-B9cPtugh.js +0 -1
- package/build/assets/conversation-B8prFAZF.js +0 -19
- package/build/assets/conversation-DGVDwGn8.js +0 -1
- package/build/assets/conversation-panel-C7DC4Cxx.js +0 -1
- package/build/assets/declaration-B9kpCaYl.js +0 -1
- package/build/assets/edit-automation-modal-BoibW8cd.js +0 -1
- package/build/assets/files-tab-DHqtsKLy.js +0 -1
- package/build/assets/home-BgjWP_UN.js +0 -1
- package/build/assets/lesson-plan-HD886V64.js +0 -4
- package/build/assets/llm-settings-Bkc8C5Bi.js +0 -1
- package/build/assets/manifest-4d6a1552.js +0 -1
- package/build/assets/onboarding-gGIqoxvA.js +0 -1
- package/build/assets/providers-CPoq0VXm.js +0 -1
- package/build/assets/recommended-automations-launcher-CXaEK1rW.js +0 -50
- package/build/assets/root-CxWZUXTQ.css +0 -1
- package/build/assets/root-layout-CvxdHJ6j.js +0 -2
- package/build/assets/settings-service.api-DldkFI1x.js +0 -1
- package/build/assets/use-runtime-is-ready-CBFe69Ew.js +0 -1
- package/build/assets/vendor~root-layout~home~mcp~automations-list~onboarding-modal-L2sdihTY.js +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../utils/utils.cjs`),n=require(`../../../../utils/dropdown-classes.cjs`);let r=require(`react`);r=e.__toESM(r,1);let i=require(`react/jsx-runtime`);function a({item:e,index:r,isSelected:a,getItemProps:o,getDisplayText:s,getItemKey:c,isProviderDropdown:l=!1,renderIcon:u,itemClassName:d}){return(0,i.jsx)(`li`,{...o({index:r,item:e,className:t.cn(l?`group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center`:`group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5`,`text-white focus:outline-none font-normal`,n.dropdownInstantColorClassName,{"bg-[var(--oh-interactive-selected)] text-white":a,"hover:bg-[var(--oh-interactive-hover)]":!a},d)}),children:(0,i.jsxs)(`div`,{className:t.cn(`flex items-center`,n.dropdownMenuRowGapClassName),children:[u?(0,i.jsx)(`span`,{className:n.dropdownMenuRowIconWrapperClassName,children:u(e)}):null,(0,i.jsx)(`span`,{className:`font-normal`,children:s(e)})]})},c(e))}exports.DropdownItem=a;
|
|
1
|
+
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../utils/utils.cjs`),n=require(`../../../../utils/dropdown-classes.cjs`);let r=require(`react`);r=e.__toESM(r,1);let i=require(`react/jsx-runtime`);function a({item:e,index:r,isSelected:a,getItemProps:o,getDisplayText:s,getItemKey:c,isProviderDropdown:l=!1,renderIcon:u,itemClassName:d,ariaLabel:f}){return(0,i.jsx)(`li`,{...o({index:r,item:e,...f?{"aria-label":f}:{},className:t.cn(l?`group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center`:`group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5`,`text-white focus:outline-none font-normal`,n.dropdownInstantColorClassName,{"bg-[var(--oh-interactive-selected)] text-white":a,"hover:bg-[var(--oh-interactive-hover)]":!a},d)}),children:(0,i.jsxs)(`div`,{className:t.cn(`flex items-center`,n.dropdownMenuRowGapClassName),children:[u?(0,i.jsx)(`span`,{className:n.dropdownMenuRowIconWrapperClassName,children:u(e)}):null,(0,i.jsx)(`span`,{className:`font-normal`,children:s(e)})]})},c(e))}exports.DropdownItem=a;
|
|
2
2
|
//# sourceMappingURL=dropdown-item.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-item.cjs","names":[],"sources":["../../../../../src/components/features/home/shared/dropdown-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport {\n dropdownInstantColorClassName,\n dropdownMenuRowGapClassName,\n dropdownMenuRowIconWrapperClassName,\n} from \"#/utils/dropdown-classes\";\n\ninterface DropdownItemProps<T> {\n item: T;\n index: number;\n isSelected: boolean;\n getItemProps: <Options>(options: any & Options) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getDisplayText: (item: T) => string;\n getItemKey: (item: T) => string;\n isProviderDropdown?: boolean;\n renderIcon?: (item: T) => React.ReactNode;\n itemClassName?: string;\n}\n\nexport function DropdownItem<T>({\n item,\n index,\n isSelected,\n getItemProps,\n getDisplayText,\n getItemKey,\n isProviderDropdown = false,\n renderIcon,\n itemClassName,\n}: DropdownItemProps<T>) {\n const itemProps = getItemProps({\n index,\n item,\n className: cn(\n isProviderDropdown\n ? \"group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center\"\n : \"group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5\",\n \"text-white focus:outline-none font-normal\",\n dropdownInstantColorClassName,\n {\n \"bg-[var(--oh-interactive-selected)] text-white\": isSelected,\n \"hover:bg-[var(--oh-interactive-hover)]\": !isSelected,\n },\n itemClassName,\n ),\n });\n\n return (\n <li key={getItemKey(item)} {...itemProps}>\n <div className={cn(\"flex items-center\", dropdownMenuRowGapClassName)}>\n {renderIcon ? (\n <span className={dropdownMenuRowIconWrapperClassName}>\n {renderIcon(item)}\n </span>\n ) : null}\n <span className=\"font-normal\">{getDisplayText(item)}</span>\n </div>\n </li>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"dropdown-item.cjs","names":[],"sources":["../../../../../src/components/features/home/shared/dropdown-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport {\n dropdownInstantColorClassName,\n dropdownMenuRowGapClassName,\n dropdownMenuRowIconWrapperClassName,\n} from \"#/utils/dropdown-classes\";\n\ninterface DropdownItemProps<T> {\n item: T;\n index: number;\n isSelected: boolean;\n getItemProps: <Options>(options: any & Options) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getDisplayText: (item: T) => string;\n getItemKey: (item: T) => string;\n isProviderDropdown?: boolean;\n renderIcon?: (item: T) => React.ReactNode;\n itemClassName?: string;\n /**\n * Overrides the option's accessible name. Used to fold a group label into the\n * announced name (e.g. \"Projects, alpha\") when the visual group header is\n * presentational and therefore invisible to assistive tech.\n */\n ariaLabel?: string;\n}\n\nexport function DropdownItem<T>({\n item,\n index,\n isSelected,\n getItemProps,\n getDisplayText,\n getItemKey,\n isProviderDropdown = false,\n renderIcon,\n itemClassName,\n ariaLabel,\n}: DropdownItemProps<T>) {\n const itemProps = getItemProps({\n index,\n item,\n ...(ariaLabel ? { \"aria-label\": ariaLabel } : {}),\n className: cn(\n isProviderDropdown\n ? \"group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center\"\n : \"group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5\",\n \"text-white focus:outline-none font-normal\",\n dropdownInstantColorClassName,\n {\n \"bg-[var(--oh-interactive-selected)] text-white\": isSelected,\n \"hover:bg-[var(--oh-interactive-hover)]\": !isSelected,\n },\n itemClassName,\n ),\n });\n\n return (\n <li key={getItemKey(item)} {...itemProps}>\n <div className={cn(\"flex items-center\", dropdownMenuRowGapClassName)}>\n {renderIcon ? (\n <span className={dropdownMenuRowIconWrapperClassName}>\n {renderIcon(item)}\n </span>\n ) : null}\n <span className=\"font-normal\">{getDisplayText(item)}</span>\n </div>\n </li>\n );\n}\n"],"mappings":"sOA0BA,SAAgB,EAAgB,CAC9B,OACA,QACA,aACA,eACA,iBACA,aACA,qBAAqB,GACrB,aACA,gBACA,aACuB,CAmBvB,OACE,EAAA,EAAA,KAAC,KAAD,CAA2B,GAnBX,EAAa,CAC7B,QACA,OACA,GAAI,EAAY,CAAE,aAAc,EAAW,CAAG,EAAE,CAChD,UAAW,EAAA,GACT,EACI,oFACA,gEACJ,4CACA,EAAA,8BACA,CACE,iDAAkD,EAClD,yCAA0C,CAAC,EAC5C,CACD,EACD,CACF,CAGgC,WAC7B,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAA,GAAG,oBAAqB,EAAA,4BAA4B,UAApE,CACG,GACC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAW,EAAA,6CACd,EAAW,EAAK,CACZ,CAAA,CACL,MACJ,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uBAAe,EAAe,EAAK,CAAQ,CAAA,CACvD,GACH,CATI,EAAW,EAAK,CASpB"}
|
|
@@ -9,6 +9,12 @@ interface DropdownItemProps<T> {
|
|
|
9
9
|
isProviderDropdown?: boolean;
|
|
10
10
|
renderIcon?: (item: T) => React.ReactNode;
|
|
11
11
|
itemClassName?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Overrides the option's accessible name. Used to fold a group label into the
|
|
14
|
+
* announced name (e.g. "Projects, alpha") when the visual group header is
|
|
15
|
+
* presentational and therefore invisible to assistive tech.
|
|
16
|
+
*/
|
|
17
|
+
ariaLabel?: string;
|
|
12
18
|
}
|
|
13
|
-
export declare function DropdownItem<T>({ item, index, isSelected, getItemProps, getDisplayText, getItemKey, isProviderDropdown, renderIcon, itemClassName, }: DropdownItemProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare function DropdownItem<T>({ item, index, isSelected, getItemProps, getDisplayText, getItemKey, isProviderDropdown, renderIcon, itemClassName, ariaLabel, }: DropdownItemProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
14
20
|
export {};
|
|
@@ -3,11 +3,12 @@ import { dropdownInstantColorClassName as t, dropdownMenuRowGapClassName as n, d
|
|
|
3
3
|
import "react";
|
|
4
4
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/features/home/shared/dropdown-item.tsx
|
|
6
|
-
function o({ item: o, index: s, isSelected: c, getItemProps: l, getDisplayText: u, getItemKey: d, isProviderDropdown: f = !1, renderIcon: p, itemClassName: m }) {
|
|
6
|
+
function o({ item: o, index: s, isSelected: c, getItemProps: l, getDisplayText: u, getItemKey: d, isProviderDropdown: f = !1, renderIcon: p, itemClassName: m, ariaLabel: h }) {
|
|
7
7
|
return /* @__PURE__ */ i("li", {
|
|
8
8
|
...l({
|
|
9
9
|
index: s,
|
|
10
10
|
item: o,
|
|
11
|
+
...h ? { "aria-label": h } : {},
|
|
11
12
|
className: e(f ? "group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center" : "group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5", "text-white focus:outline-none font-normal", t, {
|
|
12
13
|
"bg-[var(--oh-interactive-selected)] text-white": c,
|
|
13
14
|
"hover:bg-[var(--oh-interactive-hover)]": !c
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../../../src/components/features/home/shared/dropdown-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport {\n dropdownInstantColorClassName,\n dropdownMenuRowGapClassName,\n dropdownMenuRowIconWrapperClassName,\n} from \"#/utils/dropdown-classes\";\n\ninterface DropdownItemProps<T> {\n item: T;\n index: number;\n isSelected: boolean;\n getItemProps: <Options>(options: any & Options) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getDisplayText: (item: T) => string;\n getItemKey: (item: T) => string;\n isProviderDropdown?: boolean;\n renderIcon?: (item: T) => React.ReactNode;\n itemClassName?: string;\n}\n\nexport function DropdownItem<T>({\n item,\n index,\n isSelected,\n getItemProps,\n getDisplayText,\n getItemKey,\n isProviderDropdown = false,\n renderIcon,\n itemClassName,\n}: DropdownItemProps<T>) {\n const itemProps = getItemProps({\n index,\n item,\n className: cn(\n isProviderDropdown\n ? \"group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center\"\n : \"group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5\",\n \"text-white focus:outline-none font-normal\",\n dropdownInstantColorClassName,\n {\n \"bg-[var(--oh-interactive-selected)] text-white\": isSelected,\n \"hover:bg-[var(--oh-interactive-hover)]\": !isSelected,\n },\n itemClassName,\n ),\n });\n\n return (\n <li key={getItemKey(item)} {...itemProps}>\n <div className={cn(\"flex items-center\", dropdownMenuRowGapClassName)}>\n {renderIcon ? (\n <span className={dropdownMenuRowIconWrapperClassName}>\n {renderIcon(item)}\n </span>\n ) : null}\n <span className=\"font-normal\">{getDisplayText(item)}</span>\n </div>\n </li>\n );\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"dropdown-item.js","names":[],"sources":["../../../../../src/components/features/home/shared/dropdown-item.tsx"],"sourcesContent":["import React from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport {\n dropdownInstantColorClassName,\n dropdownMenuRowGapClassName,\n dropdownMenuRowIconWrapperClassName,\n} from \"#/utils/dropdown-classes\";\n\ninterface DropdownItemProps<T> {\n item: T;\n index: number;\n isSelected: boolean;\n getItemProps: <Options>(options: any & Options) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getDisplayText: (item: T) => string;\n getItemKey: (item: T) => string;\n isProviderDropdown?: boolean;\n renderIcon?: (item: T) => React.ReactNode;\n itemClassName?: string;\n /**\n * Overrides the option's accessible name. Used to fold a group label into the\n * announced name (e.g. \"Projects, alpha\") when the visual group header is\n * presentational and therefore invisible to assistive tech.\n */\n ariaLabel?: string;\n}\n\nexport function DropdownItem<T>({\n item,\n index,\n isSelected,\n getItemProps,\n getDisplayText,\n getItemKey,\n isProviderDropdown = false,\n renderIcon,\n itemClassName,\n ariaLabel,\n}: DropdownItemProps<T>) {\n const itemProps = getItemProps({\n index,\n item,\n ...(ariaLabel ? { \"aria-label\": ariaLabel } : {}),\n className: cn(\n isProviderDropdown\n ? \"group px-2 py-0 cursor-pointer text-xs rounded-md mx-0 my-0 h-6 flex items-center\"\n : \"group px-2 py-2 cursor-pointer text-sm rounded-md mx-0 my-0.5\",\n \"text-white focus:outline-none font-normal\",\n dropdownInstantColorClassName,\n {\n \"bg-[var(--oh-interactive-selected)] text-white\": isSelected,\n \"hover:bg-[var(--oh-interactive-hover)]\": !isSelected,\n },\n itemClassName,\n ),\n });\n\n return (\n <li key={getItemKey(item)} {...itemProps}>\n <div className={cn(\"flex items-center\", dropdownMenuRowGapClassName)}>\n {renderIcon ? (\n <span className={dropdownMenuRowIconWrapperClassName}>\n {renderIcon(item)}\n </span>\n ) : null}\n <span className=\"font-normal\">{getDisplayText(item)}</span>\n </div>\n </li>\n );\n}\n"],"mappings":";;;;;AA0BA,SAAgB,EAAgB,EAC9B,SACA,UACA,eACA,iBACA,mBACA,eACA,wBAAqB,IACrB,eACA,kBACA,gBACuB;AAmBvB,QACE,kBAAC,MAAD;EAA2B,GAnBX,EAAa;GAC7B;GACA;GACA,GAAI,IAAY,EAAE,cAAc,GAAW,GAAG,EAAE;GAChD,WAAW,EACT,IACI,sFACA,iEACJ,6CACA,GACA;IACE,kDAAkD;IAClD,0CAA0C,CAAC;IAC5C,EACD,EACD;GACF,CAGgC;YAC7B,kBAAC,OAAD;GAAK,WAAW,EAAG,qBAAqB,EAA4B;aAApE,CACG,IACC,kBAAC,QAAD;IAAM,WAAW;cACd,EAAW,EAAK;IACZ,CAAA,GACL,MACJ,kBAAC,QAAD;IAAM,WAAU;cAAe,EAAe,EAAK;IAAQ,CAAA,CACvD;;EACH,EATI,EAAW,EAAK,CASpB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../utils/utils.cjs`),n=require(`../../../../utils/dropdown-classes.cjs`);let r=require(`react`);r=e.__toESM(r,1);let i=require(`react/jsx-runtime`);function a({isOpen:e,filteredItems:a,inputValue:o,highlightedIndex:s,selectedItem:c,getMenuProps:l,getItemProps:u,onScroll:d,menuRef:f,renderItem:p,
|
|
1
|
+
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../utils/utils.cjs`),n=require(`../../../../utils/dropdown-classes.cjs`);let r=require(`react`);r=e.__toESM(r,1);let i=require(`react/jsx-runtime`);function a({isOpen:e,filteredItems:a,inputValue:o,highlightedIndex:s,selectedItem:c,getMenuProps:l,getItemProps:u,onScroll:d,menuRef:f,renderItem:p,renderItemPrefix:m,renderEmptyState:h,stickyTopItem:g,stickyFooterItem:_,testId:v,numberOfRecentItems:y=0,itemKey:b}){let x=!(a.length>0)&&!g&&!_;return e?(0,i.jsx)(`div`,{className:`relative`,children:(0,i.jsxs)(`div`,{className:t.cn(`absolute z-10 w-full bg-tertiary border border-[var(--oh-border-input)] rounded-lg shadow-none`,`focus:outline-none mt-1 z-[9999]`,`max-h-60`),children:[(0,i.jsx)(`ul`,{...l({ref:f,className:t.cn(`w-full overflow-auto p-1 custom-scrollbar-always`,n.dropdownMenuListClassName,g||_?`max-h-[calc(15rem-3rem)]`:`max-h-60`),onScroll:d,"data-testid":v}),children:x?h(o):(0,i.jsxs)(i.Fragment,{children:[g,a.map((e,t)=>{let n=b(e);return(0,i.jsxs)(r.default.Fragment,{children:[m?.(e,t),p(e,t,s,c,u),y>0&&t===y-1&&(0,i.jsx)(`li`,{role:`presentation`,"aria-hidden":`true`,className:`border-b border-[var(--oh-border-input)] bg-tertiary pb-1 mb-1 h-[1px]`})]},n)})]})}),_&&(0,i.jsx)(`div`,{className:`border-t border-[var(--oh-border-input)] bg-tertiary p-1 rounded-b-lg`,children:_})]})}):(0,i.jsx)(`div`,{className:`relative`,children:(0,i.jsx)(`ul`,{...l({ref:f,className:`hidden`,"data-testid":v})})})}exports.GenericDropdownMenu=a;
|
|
2
2
|
//# sourceMappingURL=generic-dropdown-menu.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-dropdown-menu.cjs","names":[],"sources":["../../../../../src/components/features/home/shared/generic-dropdown-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n UseComboboxGetMenuPropsOptions,\n UseComboboxGetItemPropsOptions,\n} from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { dropdownMenuListClassName } from \"#/utils/dropdown-classes\";\n\nexport interface GenericDropdownMenuProps<T> {\n isOpen: boolean;\n filteredItems: T[];\n inputValue: string;\n highlightedIndex: number;\n selectedItem: T | null;\n getMenuProps: <Options>(\n options?: UseComboboxGetMenuPropsOptions & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n onScroll?: (event: React.UIEvent<HTMLUListElement>) => void;\n menuRef?: React.RefObject<HTMLUListElement | null>;\n renderItem: (\n item: T,\n index: number,\n highlightedIndex: number,\n selectedItem: T | null,\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any, // eslint-disable-line @typescript-eslint/no-explicit-any\n ) => React.ReactNode;\n renderEmptyState: (inputValue: string) => React.ReactNode;\n stickyTopItem?: React.ReactNode;\n stickyFooterItem?: React.ReactNode;\n testId?: string;\n numberOfRecentItems?: number;\n itemKey: (item: T) => string | number;\n}\n\nexport function GenericDropdownMenu<T>({\n isOpen,\n filteredItems,\n inputValue,\n highlightedIndex,\n selectedItem,\n getMenuProps,\n getItemProps,\n onScroll,\n menuRef,\n renderItem,\n renderEmptyState,\n stickyTopItem,\n stickyFooterItem,\n testId,\n numberOfRecentItems = 0,\n itemKey,\n}: GenericDropdownMenuProps<T>) {\n const hasItems = filteredItems.length > 0;\n const showEmptyState = !hasItems && !stickyTopItem && !stickyFooterItem;\n\n // Always render the menu container (even when closed) so getMenuProps is always called\n // This prevents the downshift warning about forgetting to call getMenuProps\n if (!isOpen) {\n return (\n <div className=\"relative\">\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: \"hidden\",\n \"data-testid\": testId,\n })}\n />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n <div\n className={cn(\n \"absolute z-10 w-full bg-tertiary border border-[var(--oh-border-input)] rounded-lg shadow-none\",\n \"focus:outline-none mt-1 z-[9999]\",\n stickyTopItem || stickyFooterItem ? \"max-h-60\" : \"max-h-60\",\n )}\n >\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: cn(\n \"w-full overflow-auto p-1 custom-scrollbar-always\",\n dropdownMenuListClassName,\n stickyTopItem || stickyFooterItem\n ? \"max-h-[calc(15rem-3rem)]\"\n : \"max-h-60\", // Reserve space for sticky items\n ),\n onScroll,\n \"data-testid\": testId,\n })}\n >\n {showEmptyState ? (\n renderEmptyState(inputValue)\n ) : (\n <>\n {stickyTopItem}\n {filteredItems.map((item, index) => {\n const key = itemKey(item);\n return (\n <React.Fragment key={key}>\n {renderItem(\n item,\n index,\n highlightedIndex,\n selectedItem,\n getItemProps,\n )}\n {numberOfRecentItems > 0 &&\n index === numberOfRecentItems - 1 && (\n <
|
|
1
|
+
{"version":3,"file":"generic-dropdown-menu.cjs","names":[],"sources":["../../../../../src/components/features/home/shared/generic-dropdown-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n UseComboboxGetMenuPropsOptions,\n UseComboboxGetItemPropsOptions,\n} from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { dropdownMenuListClassName } from \"#/utils/dropdown-classes\";\n\nexport interface GenericDropdownMenuProps<T> {\n isOpen: boolean;\n filteredItems: T[];\n inputValue: string;\n highlightedIndex: number;\n selectedItem: T | null;\n getMenuProps: <Options>(\n options?: UseComboboxGetMenuPropsOptions & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n onScroll?: (event: React.UIEvent<HTMLUListElement>) => void;\n menuRef?: React.RefObject<HTMLUListElement | null>;\n renderItem: (\n item: T,\n index: number,\n highlightedIndex: number,\n selectedItem: T | null,\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any, // eslint-disable-line @typescript-eslint/no-explicit-any\n ) => React.ReactNode;\n /**\n * Optional presentational node rendered immediately BEFORE an item (e.g. a\n * group header). It is a sibling of the item, not part of downshift's `items`\n * array, so it consumes no item index — mirroring the `numberOfRecentItems`\n * divider. The consumer owns when a prefix appears (e.g. at group boundaries).\n */\n renderItemPrefix?: (item: T, index: number) => React.ReactNode;\n renderEmptyState: (inputValue: string) => React.ReactNode;\n stickyTopItem?: React.ReactNode;\n stickyFooterItem?: React.ReactNode;\n testId?: string;\n numberOfRecentItems?: number;\n itemKey: (item: T) => string | number;\n}\n\nexport function GenericDropdownMenu<T>({\n isOpen,\n filteredItems,\n inputValue,\n highlightedIndex,\n selectedItem,\n getMenuProps,\n getItemProps,\n onScroll,\n menuRef,\n renderItem,\n renderItemPrefix,\n renderEmptyState,\n stickyTopItem,\n stickyFooterItem,\n testId,\n numberOfRecentItems = 0,\n itemKey,\n}: GenericDropdownMenuProps<T>) {\n const hasItems = filteredItems.length > 0;\n const showEmptyState = !hasItems && !stickyTopItem && !stickyFooterItem;\n\n // Always render the menu container (even when closed) so getMenuProps is always called\n // This prevents the downshift warning about forgetting to call getMenuProps\n if (!isOpen) {\n return (\n <div className=\"relative\">\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: \"hidden\",\n \"data-testid\": testId,\n })}\n />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n <div\n className={cn(\n \"absolute z-10 w-full bg-tertiary border border-[var(--oh-border-input)] rounded-lg shadow-none\",\n \"focus:outline-none mt-1 z-[9999]\",\n stickyTopItem || stickyFooterItem ? \"max-h-60\" : \"max-h-60\",\n )}\n >\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: cn(\n \"w-full overflow-auto p-1 custom-scrollbar-always\",\n dropdownMenuListClassName,\n stickyTopItem || stickyFooterItem\n ? \"max-h-[calc(15rem-3rem)]\"\n : \"max-h-60\", // Reserve space for sticky items\n ),\n onScroll,\n \"data-testid\": testId,\n })}\n >\n {showEmptyState ? (\n renderEmptyState(inputValue)\n ) : (\n <>\n {stickyTopItem}\n {filteredItems.map((item, index) => {\n const key = itemKey(item);\n return (\n <React.Fragment key={key}>\n {renderItemPrefix?.(item, index)}\n {renderItem(\n item,\n index,\n highlightedIndex,\n selectedItem,\n getItemProps,\n )}\n {numberOfRecentItems > 0 &&\n index === numberOfRecentItems - 1 && (\n <li\n role=\"presentation\"\n aria-hidden=\"true\"\n className=\"border-b border-[var(--oh-border-input)] bg-tertiary pb-1 mb-1 h-[1px]\"\n />\n )}\n </React.Fragment>\n );\n })}\n </>\n )}\n </ul>\n {stickyFooterItem && (\n <div className=\"border-t border-[var(--oh-border-input)] bg-tertiary p-1 rounded-b-lg\">\n {stickyFooterItem}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"sOA8CA,SAAgB,EAAuB,CACrC,SACA,gBACA,aACA,mBACA,eACA,eACA,eACA,WACA,UACA,aACA,mBACA,mBACA,gBACA,mBACA,SACA,sBAAsB,EACtB,WAC8B,CAE9B,IAAM,EAAiB,EADN,EAAc,OAAS,IACJ,CAAC,GAAiB,CAAC,EAkBvD,OAdK,GAeH,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qBACb,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,EAAA,GACT,iGACA,mCACoC,WACrC,UALH,EAOE,EAAA,EAAA,KAAC,KAAD,CACE,GAAI,EAAa,CACf,IAAK,EACL,UAAW,EAAA,GACT,mDACA,EAAA,0BACA,GAAiB,EACb,2BACA,WACL,CACD,WACA,cAAe,EAChB,CAAC,UAED,EACC,EAAiB,EAAW,EAE5B,EAAA,EAAA,MAAA,EAAA,SAAA,CAAA,SAAA,CACG,EACA,EAAc,KAAK,EAAM,IAAU,CAClC,IAAM,EAAM,EAAQ,EAAK,CACzB,OACE,EAAA,EAAA,MAAC,EAAA,QAAM,SAAP,CAAA,SAAA,CACG,IAAmB,EAAM,EAAM,CAC/B,EACC,EACA,EACA,EACA,EACA,EACD,CACA,EAAsB,GACrB,IAAU,EAAsB,IAC9B,EAAA,EAAA,KAAC,KAAD,CACE,KAAK,eACL,cAAY,OACZ,UAAU,yEACV,CAAA,CAES,CAAA,CAjBI,EAiBJ,EAEnB,CACD,CAAA,CAAA,CAEF,CAAA,CACJ,IACC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iFACZ,EACG,CAAA,CAEJ,GACF,CAAA,EAxEJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qBACb,EAAA,EAAA,KAAC,KAAD,CACE,GAAI,EAAa,CACf,IAAK,EACL,UAAW,SACX,cAAe,EAChB,CAAC,CACF,CAAA,CACE,CAAA"}
|
|
@@ -11,6 +11,13 @@ export interface GenericDropdownMenuProps<T> {
|
|
|
11
11
|
onScroll?: (event: React.UIEvent<HTMLUListElement>) => void;
|
|
12
12
|
menuRef?: React.RefObject<HTMLUListElement | null>;
|
|
13
13
|
renderItem: (item: T, index: number, highlightedIndex: number, selectedItem: T | null, getItemProps: <Options>(options: UseComboboxGetItemPropsOptions<T> & Options) => any) => React.ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Optional presentational node rendered immediately BEFORE an item (e.g. a
|
|
16
|
+
* group header). It is a sibling of the item, not part of downshift's `items`
|
|
17
|
+
* array, so it consumes no item index — mirroring the `numberOfRecentItems`
|
|
18
|
+
* divider. The consumer owns when a prefix appears (e.g. at group boundaries).
|
|
19
|
+
*/
|
|
20
|
+
renderItemPrefix?: (item: T, index: number) => React.ReactNode;
|
|
14
21
|
renderEmptyState: (inputValue: string) => React.ReactNode;
|
|
15
22
|
stickyTopItem?: React.ReactNode;
|
|
16
23
|
stickyFooterItem?: React.ReactNode;
|
|
@@ -18,4 +25,4 @@ export interface GenericDropdownMenuProps<T> {
|
|
|
18
25
|
numberOfRecentItems?: number;
|
|
19
26
|
itemKey: (item: T) => string | number;
|
|
20
27
|
}
|
|
21
|
-
export declare function GenericDropdownMenu<T>({ isOpen, filteredItems, inputValue, highlightedIndex, selectedItem, getMenuProps, getItemProps, onScroll, menuRef, renderItem, renderEmptyState, stickyTopItem, stickyFooterItem, testId, numberOfRecentItems, itemKey, }: GenericDropdownMenuProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export declare function GenericDropdownMenu<T>({ isOpen, filteredItems, inputValue, highlightedIndex, selectedItem, getMenuProps, getItemProps, onScroll, menuRef, renderItem, renderItemPrefix, renderEmptyState, stickyTopItem, stickyFooterItem, testId, numberOfRecentItems, itemKey, }: GenericDropdownMenuProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,8 +3,8 @@ import { dropdownMenuListClassName as t } from "../../../../utils/dropdown-class
|
|
|
3
3
|
import n from "react";
|
|
4
4
|
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/features/home/shared/generic-dropdown-menu.tsx
|
|
6
|
-
function o({ isOpen: o, filteredItems: s, inputValue: c, highlightedIndex: l, selectedItem: u, getMenuProps: d, getItemProps: f, onScroll: p, menuRef: m, renderItem: h,
|
|
7
|
-
let
|
|
6
|
+
function o({ isOpen: o, filteredItems: s, inputValue: c, highlightedIndex: l, selectedItem: u, getMenuProps: d, getItemProps: f, onScroll: p, menuRef: m, renderItem: h, renderItemPrefix: g, renderEmptyState: _, stickyTopItem: v, stickyFooterItem: y, testId: b, numberOfRecentItems: x = 0, itemKey: S }) {
|
|
7
|
+
let C = !(s.length > 0) && !v && !y;
|
|
8
8
|
return o ? /* @__PURE__ */ i("div", {
|
|
9
9
|
className: "relative",
|
|
10
10
|
children: /* @__PURE__ */ a("div", {
|
|
@@ -12,17 +12,25 @@ function o({ isOpen: o, filteredItems: s, inputValue: c, highlightedIndex: l, se
|
|
|
12
12
|
children: [/* @__PURE__ */ i("ul", {
|
|
13
13
|
...d({
|
|
14
14
|
ref: m,
|
|
15
|
-
className: e("w-full overflow-auto p-1 custom-scrollbar-always", t,
|
|
15
|
+
className: e("w-full overflow-auto p-1 custom-scrollbar-always", t, v || y ? "max-h-[calc(15rem-3rem)]" : "max-h-60"),
|
|
16
16
|
onScroll: p,
|
|
17
|
-
"data-testid":
|
|
17
|
+
"data-testid": b
|
|
18
18
|
}),
|
|
19
|
-
children:
|
|
20
|
-
let r =
|
|
21
|
-
return /* @__PURE__ */ a(n.Fragment, { children: [
|
|
19
|
+
children: C ? _(c) : /* @__PURE__ */ a(r, { children: [v, s.map((e, t) => {
|
|
20
|
+
let r = S(e);
|
|
21
|
+
return /* @__PURE__ */ a(n.Fragment, { children: [
|
|
22
|
+
g?.(e, t),
|
|
23
|
+
h(e, t, l, u, f),
|
|
24
|
+
x > 0 && t === x - 1 && /* @__PURE__ */ i("li", {
|
|
25
|
+
role: "presentation",
|
|
26
|
+
"aria-hidden": "true",
|
|
27
|
+
className: "border-b border-[var(--oh-border-input)] bg-tertiary pb-1 mb-1 h-[1px]"
|
|
28
|
+
})
|
|
29
|
+
] }, r);
|
|
22
30
|
})] })
|
|
23
|
-
}),
|
|
31
|
+
}), y && /* @__PURE__ */ i("div", {
|
|
24
32
|
className: "border-t border-[var(--oh-border-input)] bg-tertiary p-1 rounded-b-lg",
|
|
25
|
-
children:
|
|
33
|
+
children: y
|
|
26
34
|
})]
|
|
27
35
|
})
|
|
28
36
|
}) : /* @__PURE__ */ i("div", {
|
|
@@ -30,7 +38,7 @@ function o({ isOpen: o, filteredItems: s, inputValue: c, highlightedIndex: l, se
|
|
|
30
38
|
children: /* @__PURE__ */ i("ul", { ...d({
|
|
31
39
|
ref: m,
|
|
32
40
|
className: "hidden",
|
|
33
|
-
"data-testid":
|
|
41
|
+
"data-testid": b
|
|
34
42
|
}) })
|
|
35
43
|
});
|
|
36
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-dropdown-menu.js","names":[],"sources":["../../../../../src/components/features/home/shared/generic-dropdown-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n UseComboboxGetMenuPropsOptions,\n UseComboboxGetItemPropsOptions,\n} from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { dropdownMenuListClassName } from \"#/utils/dropdown-classes\";\n\nexport interface GenericDropdownMenuProps<T> {\n isOpen: boolean;\n filteredItems: T[];\n inputValue: string;\n highlightedIndex: number;\n selectedItem: T | null;\n getMenuProps: <Options>(\n options?: UseComboboxGetMenuPropsOptions & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n onScroll?: (event: React.UIEvent<HTMLUListElement>) => void;\n menuRef?: React.RefObject<HTMLUListElement | null>;\n renderItem: (\n item: T,\n index: number,\n highlightedIndex: number,\n selectedItem: T | null,\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any, // eslint-disable-line @typescript-eslint/no-explicit-any\n ) => React.ReactNode;\n renderEmptyState: (inputValue: string) => React.ReactNode;\n stickyTopItem?: React.ReactNode;\n stickyFooterItem?: React.ReactNode;\n testId?: string;\n numberOfRecentItems?: number;\n itemKey: (item: T) => string | number;\n}\n\nexport function GenericDropdownMenu<T>({\n isOpen,\n filteredItems,\n inputValue,\n highlightedIndex,\n selectedItem,\n getMenuProps,\n getItemProps,\n onScroll,\n menuRef,\n renderItem,\n renderEmptyState,\n stickyTopItem,\n stickyFooterItem,\n testId,\n numberOfRecentItems = 0,\n itemKey,\n}: GenericDropdownMenuProps<T>) {\n const hasItems = filteredItems.length > 0;\n const showEmptyState = !hasItems && !stickyTopItem && !stickyFooterItem;\n\n // Always render the menu container (even when closed) so getMenuProps is always called\n // This prevents the downshift warning about forgetting to call getMenuProps\n if (!isOpen) {\n return (\n <div className=\"relative\">\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: \"hidden\",\n \"data-testid\": testId,\n })}\n />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n <div\n className={cn(\n \"absolute z-10 w-full bg-tertiary border border-[var(--oh-border-input)] rounded-lg shadow-none\",\n \"focus:outline-none mt-1 z-[9999]\",\n stickyTopItem || stickyFooterItem ? \"max-h-60\" : \"max-h-60\",\n )}\n >\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: cn(\n \"w-full overflow-auto p-1 custom-scrollbar-always\",\n dropdownMenuListClassName,\n stickyTopItem || stickyFooterItem\n ? \"max-h-[calc(15rem-3rem)]\"\n : \"max-h-60\", // Reserve space for sticky items\n ),\n onScroll,\n \"data-testid\": testId,\n })}\n >\n {showEmptyState ? (\n renderEmptyState(inputValue)\n ) : (\n <>\n {stickyTopItem}\n {filteredItems.map((item, index) => {\n const key = itemKey(item);\n return (\n <React.Fragment key={key}>\n {renderItem(\n item,\n index,\n highlightedIndex,\n selectedItem,\n getItemProps,\n )}\n {numberOfRecentItems > 0 &&\n index === numberOfRecentItems - 1 && (\n <
|
|
1
|
+
{"version":3,"file":"generic-dropdown-menu.js","names":[],"sources":["../../../../../src/components/features/home/shared/generic-dropdown-menu.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n UseComboboxGetMenuPropsOptions,\n UseComboboxGetItemPropsOptions,\n} from \"downshift\";\nimport { cn } from \"#/utils/utils\";\nimport { dropdownMenuListClassName } from \"#/utils/dropdown-classes\";\n\nexport interface GenericDropdownMenuProps<T> {\n isOpen: boolean;\n filteredItems: T[];\n inputValue: string;\n highlightedIndex: number;\n selectedItem: T | null;\n getMenuProps: <Options>(\n options?: UseComboboxGetMenuPropsOptions & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any; // eslint-disable-line @typescript-eslint/no-explicit-any\n onScroll?: (event: React.UIEvent<HTMLUListElement>) => void;\n menuRef?: React.RefObject<HTMLUListElement | null>;\n renderItem: (\n item: T,\n index: number,\n highlightedIndex: number,\n selectedItem: T | null,\n getItemProps: <Options>(\n options: UseComboboxGetItemPropsOptions<T> & Options,\n ) => any, // eslint-disable-line @typescript-eslint/no-explicit-any\n ) => React.ReactNode;\n /**\n * Optional presentational node rendered immediately BEFORE an item (e.g. a\n * group header). It is a sibling of the item, not part of downshift's `items`\n * array, so it consumes no item index — mirroring the `numberOfRecentItems`\n * divider. The consumer owns when a prefix appears (e.g. at group boundaries).\n */\n renderItemPrefix?: (item: T, index: number) => React.ReactNode;\n renderEmptyState: (inputValue: string) => React.ReactNode;\n stickyTopItem?: React.ReactNode;\n stickyFooterItem?: React.ReactNode;\n testId?: string;\n numberOfRecentItems?: number;\n itemKey: (item: T) => string | number;\n}\n\nexport function GenericDropdownMenu<T>({\n isOpen,\n filteredItems,\n inputValue,\n highlightedIndex,\n selectedItem,\n getMenuProps,\n getItemProps,\n onScroll,\n menuRef,\n renderItem,\n renderItemPrefix,\n renderEmptyState,\n stickyTopItem,\n stickyFooterItem,\n testId,\n numberOfRecentItems = 0,\n itemKey,\n}: GenericDropdownMenuProps<T>) {\n const hasItems = filteredItems.length > 0;\n const showEmptyState = !hasItems && !stickyTopItem && !stickyFooterItem;\n\n // Always render the menu container (even when closed) so getMenuProps is always called\n // This prevents the downshift warning about forgetting to call getMenuProps\n if (!isOpen) {\n return (\n <div className=\"relative\">\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: \"hidden\",\n \"data-testid\": testId,\n })}\n />\n </div>\n );\n }\n\n return (\n <div className=\"relative\">\n <div\n className={cn(\n \"absolute z-10 w-full bg-tertiary border border-[var(--oh-border-input)] rounded-lg shadow-none\",\n \"focus:outline-none mt-1 z-[9999]\",\n stickyTopItem || stickyFooterItem ? \"max-h-60\" : \"max-h-60\",\n )}\n >\n <ul\n {...getMenuProps({\n ref: menuRef,\n className: cn(\n \"w-full overflow-auto p-1 custom-scrollbar-always\",\n dropdownMenuListClassName,\n stickyTopItem || stickyFooterItem\n ? \"max-h-[calc(15rem-3rem)]\"\n : \"max-h-60\", // Reserve space for sticky items\n ),\n onScroll,\n \"data-testid\": testId,\n })}\n >\n {showEmptyState ? (\n renderEmptyState(inputValue)\n ) : (\n <>\n {stickyTopItem}\n {filteredItems.map((item, index) => {\n const key = itemKey(item);\n return (\n <React.Fragment key={key}>\n {renderItemPrefix?.(item, index)}\n {renderItem(\n item,\n index,\n highlightedIndex,\n selectedItem,\n getItemProps,\n )}\n {numberOfRecentItems > 0 &&\n index === numberOfRecentItems - 1 && (\n <li\n role=\"presentation\"\n aria-hidden=\"true\"\n className=\"border-b border-[var(--oh-border-input)] bg-tertiary pb-1 mb-1 h-[1px]\"\n />\n )}\n </React.Fragment>\n );\n })}\n </>\n )}\n </ul>\n {stickyFooterItem && (\n <div className=\"border-t border-[var(--oh-border-input)] bg-tertiary p-1 rounded-b-lg\">\n {stickyFooterItem}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AA8CA,SAAgB,EAAuB,EACrC,WACA,kBACA,eACA,qBACA,iBACA,iBACA,iBACA,aACA,YACA,eACA,qBACA,qBACA,kBACA,qBACA,WACA,yBAAsB,GACtB,cAC8B;CAE9B,IAAM,IAAiB,EADN,EAAc,SAAS,MACJ,CAAC,KAAiB,CAAC;AAkBvD,QAdK,IAeH,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GACE,WAAW,EACT,kGACA,oCACoC,WACrC;aALH,CAOE,kBAAC,MAAD;IACE,GAAI,EAAa;KACf,KAAK;KACL,WAAW,EACT,oDACA,GACA,KAAiB,IACb,6BACA,WACL;KACD;KACA,eAAe;KAChB,CAAC;cAED,IACC,EAAiB,EAAW,GAE5B,kBAAA,GAAA,EAAA,UAAA,CACG,GACA,EAAc,KAAK,GAAM,MAAU;KAClC,IAAM,IAAM,EAAQ,EAAK;AACzB,YACE,kBAAC,EAAM,UAAP,EAAA,UAAA;MACG,IAAmB,GAAM,EAAM;MAC/B,EACC,GACA,GACA,GACA,GACA,EACD;MACA,IAAsB,KACrB,MAAU,IAAsB,KAC9B,kBAAC,MAAD;OACE,MAAK;OACL,eAAY;OACZ,WAAU;OACV,CAAA;MAES,EAAA,EAjBI,EAiBJ;MAEnB,CACD,EAAA,CAAA;IAEF,CAAA,EACJ,KACC,kBAAC,OAAD;IAAK,WAAU;cACZ;IACG,CAAA,CAEJ;;EACF,CAAA,GAxEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,MAAD,EACE,GAAI,EAAa;GACf,KAAK;GACL,WAAW;GACX,eAAe;GAChB,CAAC,EACF,CAAA;EACE,CAAA"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import { LocalWorkspace } from "#/types/workspace";
|
|
1
|
+
import type { LocalWorkspace, LocalWorkspaceParent } from "#/types/workspace";
|
|
2
2
|
export interface WorkspaceDropdownProps {
|
|
3
3
|
workspaces: LocalWorkspace[];
|
|
4
|
+
/**
|
|
5
|
+
* The workspace parents that produced the dynamic children in `workspaces`
|
|
6
|
+
* (from `useResolvedWorkspaces`, including the implicit `/projects`). Used to
|
|
7
|
+
* label each folder's group by its parent's `name`. When two or more distinct
|
|
8
|
+
* groups are present the list renders grouped under headers; with one group
|
|
9
|
+
* (or omitted) it stays flat. A child whose `parentPath` has no matching
|
|
10
|
+
* parent here falls back to the path basename.
|
|
11
|
+
*/
|
|
12
|
+
parents?: LocalWorkspaceParent[];
|
|
4
13
|
value: LocalWorkspace | null;
|
|
5
14
|
placeholder?: string;
|
|
6
15
|
className?: string;
|
|
@@ -17,4 +26,4 @@ export interface WorkspaceDropdownProps {
|
|
|
17
26
|
onAddClick: () => void;
|
|
18
27
|
onManageClick: () => void;
|
|
19
28
|
}
|
|
20
|
-
export declare function WorkspaceDropdown({ workspaces, value, placeholder, className, disabled, disabledTooltip, showManage, onChange, onAddClick, onManageClick, }: WorkspaceDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export declare function WorkspaceDropdown({ workspaces, parents, value, placeholder, className, disabled, disabledTooltip, showManage, onChange, onAddClick, onManageClick, }: WorkspaceDropdownProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/config/defaults.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../_virtual/_rolldown/runtime.cjs`);var e={_comment:`Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.`,versions:{agentServer:`1.
|
|
1
|
+
require(`../_virtual/_rolldown/runtime.cjs`);var e={_comment:`Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.`,versions:{agentServer:`1.35.0`,agentCanvas:`1.3.0`,automation:`1.1.6`},compatibility:{minimumAgentServer:`1.28.0`},constraints:{_comment:`Temporary upper bound on the agent-client-protocol (acp) transitive dependency. openhands-sdk 1.35.0 requires agent-client-protocol>=0.10.1 with no upper bound, but acp 0.11.0 reordered the ACP prompt() arguments and breaks the SDK's ACP client (a PromptRequest validation error surfaces as 'ACP error: 2 validation errors for PromptRequest'). Pin acp <0.11 until a fixed openhands-sdk ships. Consumed by scripts/dev-safe.mjs (agent-server uvx install) and .github/workflows/mock-llm-e2e.yml (mock ACP server venv).`,agentClientProtocol:`agent-client-protocol<0.11`},images:{agentServer:`ghcr.io/openhands/agent-server`,agentCanvas:`ghcr.io/openhands/agent-canvas`},ports:{agentServer:18e3,automation:18001,proxy:8e3},paths:{stateSubdir:`agent-canvas`,conversations:`agent-canvas/conversations`,bashEvents:`agent-canvas/bash_events`,automationDb:`automation/automations.db`},packages:{agentServer:`openhands-agent-server`,automation:`openhands-automation`,tools:`openhands-tools`,workspace:`openhands-workspace`}};exports.default=e;
|
|
2
2
|
//# sourceMappingURL=defaults.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.cjs","names":[],"sources":["../../config/defaults.json"],"sourcesContent":["{\n \"_comment\": \"Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.\",\n \"versions\": {\n \"agentServer\": \"1.
|
|
1
|
+
{"version":3,"file":"defaults.cjs","names":[],"sources":["../../config/defaults.json"],"sourcesContent":["{\n \"_comment\": \"Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.\",\n \"versions\": {\n \"agentServer\": \"1.35.0\",\n \"agentCanvas\": \"1.3.0\",\n \"automation\": \"1.1.6\"\n },\n \"compatibility\": {\n \"minimumAgentServer\": \"1.28.0\"\n },\n \"constraints\": {\n \"_comment\": \"Temporary upper bound on the agent-client-protocol (acp) transitive dependency. openhands-sdk 1.35.0 requires agent-client-protocol>=0.10.1 with no upper bound, but acp 0.11.0 reordered the ACP prompt() arguments and breaks the SDK's ACP client (a PromptRequest validation error surfaces as 'ACP error: 2 validation errors for PromptRequest'). Pin acp <0.11 until a fixed openhands-sdk ships. Consumed by scripts/dev-safe.mjs (agent-server uvx install) and .github/workflows/mock-llm-e2e.yml (mock ACP server venv).\",\n \"agentClientProtocol\": \"agent-client-protocol<0.11\"\n },\n \"images\": {\n \"agentServer\": \"ghcr.io/openhands/agent-server\",\n \"agentCanvas\": \"ghcr.io/openhands/agent-canvas\"\n },\n \"ports\": {\n \"agentServer\": 18000,\n \"automation\": 18001,\n \"proxy\": 8000\n },\n \"paths\": {\n \"stateSubdir\": \"agent-canvas\",\n \"conversations\": \"agent-canvas/conversations\",\n \"bashEvents\": \"agent-canvas/bash_events\",\n \"automationDb\": \"automation/automations.db\"\n },\n \"packages\": {\n \"agentServer\": \"openhands-agent-server\",\n \"automation\": \"openhands-automation\",\n \"tools\": \"openhands-tools\",\n \"workspace\": \"openhands-workspace\"\n }\n}\n"],"mappings":""}
|
package/dist/config/defaults.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
var e = {
|
|
2
2
|
_comment: "Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.",
|
|
3
3
|
versions: {
|
|
4
|
-
agentServer: "1.
|
|
5
|
-
agentCanvas: "1.
|
|
6
|
-
automation: "1.1.
|
|
4
|
+
agentServer: "1.35.0",
|
|
5
|
+
agentCanvas: "1.3.0",
|
|
6
|
+
automation: "1.1.6"
|
|
7
7
|
},
|
|
8
8
|
compatibility: { minimumAgentServer: "1.28.0" },
|
|
9
9
|
constraints: {
|
|
10
|
-
_comment: "Temporary upper bound on the agent-client-protocol (acp) transitive dependency. openhands-sdk 1.
|
|
10
|
+
_comment: "Temporary upper bound on the agent-client-protocol (acp) transitive dependency. openhands-sdk 1.35.0 requires agent-client-protocol>=0.10.1 with no upper bound, but acp 0.11.0 reordered the ACP prompt() arguments and breaks the SDK's ACP client (a PromptRequest validation error surfaces as 'ACP error: 2 validation errors for PromptRequest'). Pin acp <0.11 until a fixed openhands-sdk ships. Consumed by scripts/dev-safe.mjs (agent-server uvx install) and .github/workflows/mock-llm-e2e.yml (mock ACP server venv).",
|
|
11
11
|
agentClientProtocol: "agent-client-protocol<0.11"
|
|
12
12
|
},
|
|
13
13
|
images: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","names":[],"sources":["../../config/defaults.json"],"sourcesContent":["{\n \"_comment\": \"Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.\",\n \"versions\": {\n \"agentServer\": \"1.
|
|
1
|
+
{"version":3,"file":"defaults.js","names":[],"sources":["../../config/defaults.json"],"sourcesContent":["{\n \"_comment\": \"Single source of truth for version pins, ports, paths, and defaults shared across the npm and Docker install paths. Read by scripts/dev-safe.mjs, scripts/dev-with-automation.mjs, docker/entrypoint.sh (via generated defaults.env), and .github/workflows/docker.yml.\",\n \"versions\": {\n \"agentServer\": \"1.35.0\",\n \"agentCanvas\": \"1.3.0\",\n \"automation\": \"1.1.6\"\n },\n \"compatibility\": {\n \"minimumAgentServer\": \"1.28.0\"\n },\n \"constraints\": {\n \"_comment\": \"Temporary upper bound on the agent-client-protocol (acp) transitive dependency. openhands-sdk 1.35.0 requires agent-client-protocol>=0.10.1 with no upper bound, but acp 0.11.0 reordered the ACP prompt() arguments and breaks the SDK's ACP client (a PromptRequest validation error surfaces as 'ACP error: 2 validation errors for PromptRequest'). Pin acp <0.11 until a fixed openhands-sdk ships. Consumed by scripts/dev-safe.mjs (agent-server uvx install) and .github/workflows/mock-llm-e2e.yml (mock ACP server venv).\",\n \"agentClientProtocol\": \"agent-client-protocol<0.11\"\n },\n \"images\": {\n \"agentServer\": \"ghcr.io/openhands/agent-server\",\n \"agentCanvas\": \"ghcr.io/openhands/agent-canvas\"\n },\n \"ports\": {\n \"agentServer\": 18000,\n \"automation\": 18001,\n \"proxy\": 8000\n },\n \"paths\": {\n \"stateSubdir\": \"agent-canvas\",\n \"conversations\": \"agent-canvas/conversations\",\n \"bashEvents\": \"agent-canvas/bash_events\",\n \"automationDb\": \"automation/automations.db\"\n },\n \"packages\": {\n \"agentServer\": \"openhands-agent-server\",\n \"automation\": \"openhands-automation\",\n \"tools\": \"openhands-tools\",\n \"workspace\": \"openhands-workspace\"\n }\n}\n"],"mappings":""}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Automation } from "#/types/automation";
|
|
1
|
+
import type { Automation, AutomationSpec } from "#/types/automation";
|
|
2
2
|
export declare const AUTOMATIONS_QUERY_KEY: readonly ["automations"];
|
|
3
3
|
interface UseAutomationsOptions {
|
|
4
4
|
limit?: number;
|
|
@@ -10,6 +10,7 @@ export declare function useToggleAutomation(): import("@tanstack/react-query").U
|
|
|
10
10
|
id: string;
|
|
11
11
|
enabled: boolean;
|
|
12
12
|
}, unknown>;
|
|
13
|
+
export declare function useImportAutomation(): import("@tanstack/react-query").UseMutationResult<Automation, import("axios").AxiosError<unknown, any>, AutomationSpec, unknown>;
|
|
13
14
|
export declare function useUpdateAutomation(): import("@tanstack/react-query").UseMutationResult<Automation, import("axios").AxiosError<unknown, any>, {
|
|
14
15
|
id: string;
|
|
15
16
|
body: Partial<Automation>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@openhands/typescript-client/dist/client/file-client.cjs`),t=require(`../../node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.cjs`);require(`../../node_modules/@openhands/typescript-client/dist/clients.cjs`);const n=require(`../../api/agent-server-client-options.cjs`),r=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),i=require(`./use-local-workspaces.cjs`);let a=require(`react`);function o(){let{data:o,isLoading:s,isError:c,error:l}=i.useLocalWorkspaces(),u=t.isAgentServerVersionError(l),d=o?.workspaces??[],f=o?.workspaceParents??[],p=(0,a.useMemo)(()=>{let e=new Set(f.map(e=>e.path)),t=[].filter(t=>!e.has(t.path));return t.length===0?f:[...f,...t]},[f,u]),m=r.useQueries({queries:u?[]:p.map(t=>({queryKey:[`file`,`search_subdirs`,t.path],queryFn:()=>new e.FileClient(n.getAgentServerClientOptions()).searchSubdirectories(t.path),retry:!1,meta:{disableToast:!0}}))}),h=s||m.some(e=>e.isLoading),g=c||m.some(e=>e.isError);return{workspaces:(0,a.useMemo)(()=>{let e=new Map,t=new Map(p.map((e,t)=>[e.path,m[t]]));return p.forEach(n=>{(t.get(n.path)?.data?.items??[]).forEach(t=>{e.has(t.path)||e.set(t.path,{id:t.path,name:t.name,path:t.path,parentPath:n.path})})}),d.forEach(t=>{e.set(t.path,t)}),Array.from(e.values())},[d,p,m.map(e=>`${e.dataUpdatedAt??0}:${e.status}`).join(`|`)]),isLoading:h,isError:g,error:l}}exports.useResolvedWorkspaces=o;
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@openhands/typescript-client/dist/client/file-client.cjs`),t=require(`../../node_modules/@openhands/typescript-client/dist/client/agent-server-compatibility.cjs`);require(`../../node_modules/@openhands/typescript-client/dist/clients.cjs`);const n=require(`../../api/agent-server-client-options.cjs`),r=require(`../../node_modules/@tanstack/react-query/build/modern/useQueries.cjs`),i=require(`./use-local-workspaces.cjs`);let a=require(`react`);function o(){let{data:o,isLoading:s,isError:c,error:l}=i.useLocalWorkspaces(),u=t.isAgentServerVersionError(l),d=o?.workspaces??[],f=o?.workspaceParents??[],p=(0,a.useMemo)(()=>{let e=new Set(f.map(e=>e.path)),t=[].filter(t=>!e.has(t.path));return t.length===0?f:[...f,...t]},[f,u]),m=r.useQueries({queries:u?[]:p.map(t=>({queryKey:[`file`,`search_subdirs`,t.path],queryFn:()=>new e.FileClient(n.getAgentServerClientOptions()).searchSubdirectories(t.path),retry:!1,meta:{disableToast:!0}}))}),h=s||m.some(e=>e.isLoading),g=c||m.some(e=>e.isError);return{workspaces:(0,a.useMemo)(()=>{let e=new Map,t=new Map(p.map((e,t)=>[e.path,m[t]]));return p.forEach(n=>{(t.get(n.path)?.data?.items??[]).forEach(t=>{e.has(t.path)||e.set(t.path,{id:t.path,name:t.name,path:t.path,parentPath:n.path})})}),d.forEach(t=>{e.set(t.path,t)}),Array.from(e.values())},[d,p,m.map(e=>`${e.dataUpdatedAt??0}:${e.status}`).join(`|`)]),parents:p,isLoading:h,isError:g,error:l}}exports.useResolvedWorkspaces=o;
|
|
2
2
|
//# sourceMappingURL=use-resolved-workspaces.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-resolved-workspaces.cjs","names":[],"sources":["../../../src/hooks/query/use-resolved-workspaces.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n FileClient,\n isAgentServerVersionError,\n} from \"@openhands/typescript-client/clients\";\n\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { useLocalWorkspaces } from \"#/hooks/query/use-local-workspaces\";\nimport { LocalWorkspace, LocalWorkspaceParent } from \"#/types/workspace\";\n\ninterface UseResolvedWorkspacesResult {\n workspaces: LocalWorkspace[];\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Implicit workspace parents that are always considered when resolving\n * workspaces. `/projects` is a well-known directory that some agent-server\n * setups use as the projects root. We surface its immediate subdirectories\n * as workspaces automatically in dev mode.\n *\n * This is a development convenience only. Production previews may point at\n * arbitrary remote agent servers that do not expose the file-browser endpoint;\n * probing `/projects` there creates noisy 404s before the user has added any\n * workspace parent explicitly.\n */\nconst INCLUDE_IMPLICIT_WORKSPACE_PARENTS = import.meta.env.DEV;\n\nconst IMPLICIT_WORKSPACE_PARENTS: LocalWorkspaceParent[] = [\n { id: \"implicit:/projects\", name: \"/projects\", path: \"/projects\" },\n];\n\n/**\n * Returns the merged list of workspaces to display:\n * - workspaces explicitly added by the user (from the persisted store),\n * - the immediate subdirectories of every saved \"workspace parent\",\n * fetched dynamically, and\n * - the immediate subdirectories of any implicit, built-in parents\n * (currently just `/projects`).\n *\n * Static workspaces always take precedence over a dynamic child with the\n * same path so that user-selected names/ids are preserved.\n */\nexport function useResolvedWorkspaces(): UseResolvedWorkspacesResult {\n const {\n data,\n isLoading: isLoadingList,\n isError: isErrorList,\n error: listError,\n } = useLocalWorkspaces();\n const workspacesUnsupported = isAgentServerVersionError(listError);\n const workspaces = data?.workspaces ?? [];\n const storedParents = data?.workspaceParents ?? [];\n\n // Merge stored parents with the implicit ones, deduping on path so a\n // user-added `/projects` doesn't trigger a second query.\n const workspaceParents = useMemo(() => {\n const seen = new Set(storedParents.map((p) => p.path));\n // Filter out implicit parents that conflict with user-added ones (by path)\n // so custom names/ids are preserved.\n const implicitParents =\n INCLUDE_IMPLICIT_WORKSPACE_PARENTS && !workspacesUnsupported\n ? IMPLICIT_WORKSPACE_PARENTS\n : [];\n const extras = implicitParents.filter((p) => !seen.has(p.path));\n return extras.length === 0 ? storedParents : [...storedParents, ...extras];\n }, [storedParents, workspacesUnsupported]);\n\n const parentQueries = useQueries({\n queries: workspacesUnsupported\n ? []\n : workspaceParents.map((parent) => ({\n queryKey: [\"file\", \"search_subdirs\", parent.path],\n queryFn: () =>\n new FileClient(getAgentServerClientOptions()).searchSubdirectories(\n parent.path,\n ),\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n const isLoading = isLoadingList || parentQueries.some((q) => q.isLoading);\n const isError = isErrorList || parentQueries.some((q) => q.isError);\n\n // Stable string fingerprint that changes whenever any parent's subdir\n // results change. Avoids spreading timestamps into the `useMemo` deps,\n // which would change the array length as parents are added/removed.\n const queriesFingerprint = parentQueries\n .map((q) => `${q.dataUpdatedAt ?? 0}:${q.status}`)\n .join(\"|\");\n\n const merged = useMemo(() => {\n const byPath = new Map<string, LocalWorkspace>();\n const resultsByParent = new Map(\n workspaceParents.map((parent, index) => [\n parent.path,\n parentQueries[index],\n ]),\n );\n\n workspaceParents.forEach((parent) => {\n const result = resultsByParent.get(parent.path);\n const items = result?.data?.items ?? [];\n items.forEach((entry) => {\n if (byPath.has(entry.path)) return;\n byPath.set(entry.path, {\n id: entry.path,\n name: entry.name,\n path: entry.path,\n parentPath: parent.path,\n });\n });\n });\n\n // Static workspaces win on duplicate paths.\n workspaces.forEach((w) => {\n byPath.set(w.path, w);\n });\n\n return Array.from(byPath.values());\n }, [workspaces, workspaceParents, queriesFingerprint]);\n\n return {
|
|
1
|
+
{"version":3,"file":"use-resolved-workspaces.cjs","names":[],"sources":["../../../src/hooks/query/use-resolved-workspaces.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n FileClient,\n isAgentServerVersionError,\n} from \"@openhands/typescript-client/clients\";\n\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { useLocalWorkspaces } from \"#/hooks/query/use-local-workspaces\";\nimport { LocalWorkspace, LocalWorkspaceParent } from \"#/types/workspace\";\n\ninterface UseResolvedWorkspacesResult {\n workspaces: LocalWorkspace[];\n /**\n * The merged workspace parents that produced the dynamic children above:\n * the user's stored parents plus any implicit built-in parents (currently\n * `/projects` in dev). Consumers use this to label a child's group by its\n * parent's `name` — `parentPath` alone only yields a path. Includes the\n * implicit parents that `useLocalWorkspaces` does not expose on its own.\n */\n parents: LocalWorkspaceParent[];\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Implicit workspace parents that are always considered when resolving\n * workspaces. `/projects` is a well-known directory that some agent-server\n * setups use as the projects root. We surface its immediate subdirectories\n * as workspaces automatically in dev mode.\n *\n * This is a development convenience only. Production previews may point at\n * arbitrary remote agent servers that do not expose the file-browser endpoint;\n * probing `/projects` there creates noisy 404s before the user has added any\n * workspace parent explicitly.\n */\nconst INCLUDE_IMPLICIT_WORKSPACE_PARENTS = import.meta.env.DEV;\n\nconst IMPLICIT_WORKSPACE_PARENTS: LocalWorkspaceParent[] = [\n { id: \"implicit:/projects\", name: \"/projects\", path: \"/projects\" },\n];\n\n/**\n * Returns the merged list of workspaces to display:\n * - workspaces explicitly added by the user (from the persisted store),\n * - the immediate subdirectories of every saved \"workspace parent\",\n * fetched dynamically, and\n * - the immediate subdirectories of any implicit, built-in parents\n * (currently just `/projects`).\n *\n * Static workspaces always take precedence over a dynamic child with the\n * same path so that user-selected names/ids are preserved.\n */\nexport function useResolvedWorkspaces(): UseResolvedWorkspacesResult {\n const {\n data,\n isLoading: isLoadingList,\n isError: isErrorList,\n error: listError,\n } = useLocalWorkspaces();\n const workspacesUnsupported = isAgentServerVersionError(listError);\n const workspaces = data?.workspaces ?? [];\n const storedParents = data?.workspaceParents ?? [];\n\n // Merge stored parents with the implicit ones, deduping on path so a\n // user-added `/projects` doesn't trigger a second query.\n const workspaceParents = useMemo(() => {\n const seen = new Set(storedParents.map((p) => p.path));\n // Filter out implicit parents that conflict with user-added ones (by path)\n // so custom names/ids are preserved.\n const implicitParents =\n INCLUDE_IMPLICIT_WORKSPACE_PARENTS && !workspacesUnsupported\n ? IMPLICIT_WORKSPACE_PARENTS\n : [];\n const extras = implicitParents.filter((p) => !seen.has(p.path));\n return extras.length === 0 ? storedParents : [...storedParents, ...extras];\n }, [storedParents, workspacesUnsupported]);\n\n const parentQueries = useQueries({\n queries: workspacesUnsupported\n ? []\n : workspaceParents.map((parent) => ({\n queryKey: [\"file\", \"search_subdirs\", parent.path],\n queryFn: () =>\n new FileClient(getAgentServerClientOptions()).searchSubdirectories(\n parent.path,\n ),\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n const isLoading = isLoadingList || parentQueries.some((q) => q.isLoading);\n const isError = isErrorList || parentQueries.some((q) => q.isError);\n\n // Stable string fingerprint that changes whenever any parent's subdir\n // results change. Avoids spreading timestamps into the `useMemo` deps,\n // which would change the array length as parents are added/removed.\n const queriesFingerprint = parentQueries\n .map((q) => `${q.dataUpdatedAt ?? 0}:${q.status}`)\n .join(\"|\");\n\n const merged = useMemo(() => {\n const byPath = new Map<string, LocalWorkspace>();\n const resultsByParent = new Map(\n workspaceParents.map((parent, index) => [\n parent.path,\n parentQueries[index],\n ]),\n );\n\n workspaceParents.forEach((parent) => {\n const result = resultsByParent.get(parent.path);\n const items = result?.data?.items ?? [];\n items.forEach((entry) => {\n if (byPath.has(entry.path)) return;\n byPath.set(entry.path, {\n id: entry.path,\n name: entry.name,\n path: entry.path,\n parentPath: parent.path,\n });\n });\n });\n\n // Static workspaces win on duplicate paths.\n workspaces.forEach((w) => {\n byPath.set(w.path, w);\n });\n\n return Array.from(byPath.values());\n }, [workspaces, workspaceParents, queriesFingerprint]);\n\n return {\n workspaces: merged,\n parents: workspaceParents,\n isLoading,\n isError,\n error: listError,\n };\n}\n"],"mappings":"ihBAsDA,SAAgB,GAAqD,CACnE,GAAM,CACJ,OACA,UAAW,EACX,QAAS,EACT,MAAO,GACL,EAAA,oBAAoB,CAClB,EAAwB,EAAA,0BAA0B,EAAU,CAC5D,EAAa,GAAM,YAAc,EAAE,CACnC,EAAgB,GAAM,kBAAoB,EAAE,CAI5C,GAAA,EAAA,EAAA,aAAiC,CACrC,IAAM,EAAO,IAAI,IAAI,EAAc,IAAK,GAAM,EAAE,KAAK,CAAC,CAOhD,EAAS,EAAA,CAAgB,OAAQ,GAAM,CAAC,EAAK,IAAI,EAAE,KAAK,CAAC,CAC/D,OAAO,EAAO,SAAW,EAAI,EAAgB,CAAC,GAAG,EAAe,GAAG,EAAO,EACzE,CAAC,EAAe,EAAsB,CAAC,CAEpC,EAAgB,EAAA,WAAW,CAC/B,QAAS,EACL,EAAE,CACF,EAAiB,IAAK,IAAY,CAChC,SAAU,CAAC,OAAQ,iBAAkB,EAAO,KAAK,CACjD,YACE,IAAI,EAAA,WAAW,EAAA,6BAA6B,CAAC,CAAC,qBAC5C,EAAO,KACR,CACH,MAAO,GACP,KAAM,CAAE,aAAc,GAAM,CAC7B,EAAE,CACR,CAAC,CAEI,EAAY,GAAiB,EAAc,KAAM,GAAM,EAAE,UAAU,CACnE,EAAU,GAAe,EAAc,KAAM,GAAM,EAAE,QAAQ,CAwCnE,MAAO,CACL,YAAA,EAAA,EAAA,aAhC2B,CAC3B,IAAM,EAAS,IAAI,IACb,EAAkB,IAAI,IAC1B,EAAiB,KAAK,EAAQ,IAAU,CACtC,EAAO,KACP,EAAc,GACf,CAAC,CACH,CAqBD,OAnBA,EAAiB,QAAS,GAAW,EACpB,EAAgB,IAAI,EAAO,KAC5B,EAAQ,MAAM,OAAS,EAAE,EACjC,QAAS,GAAU,CACnB,EAAO,IAAI,EAAM,KAAK,EAC1B,EAAO,IAAI,EAAM,KAAM,CACrB,GAAI,EAAM,KACV,KAAM,EAAM,KACZ,KAAM,EAAM,KACZ,WAAY,EAAO,KACpB,CAAC,EACF,EACF,CAGF,EAAW,QAAS,GAAM,CACxB,EAAO,IAAI,EAAE,KAAM,EAAE,EACrB,CAEK,MAAM,KAAK,EAAO,QAAQ,CAAC,EACjC,CAAC,EAAY,EAjCW,EACxB,IAAK,GAAM,GAAG,EAAE,eAAiB,EAAE,GAAG,EAAE,SAAS,CACjD,KAAK,IA+B0B,CAAmB,CAGvC,CACZ,QAAS,EACT,YACA,UACA,MAAO,EACR"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { LocalWorkspace } from "#/types/workspace";
|
|
1
|
+
import { LocalWorkspace, LocalWorkspaceParent } from "#/types/workspace";
|
|
2
2
|
interface UseResolvedWorkspacesResult {
|
|
3
3
|
workspaces: LocalWorkspace[];
|
|
4
|
+
/**
|
|
5
|
+
* The merged workspace parents that produced the dynamic children above:
|
|
6
|
+
* the user's stored parents plus any implicit built-in parents (currently
|
|
7
|
+
* `/projects` in dev). Consumers use this to label a child's group by its
|
|
8
|
+
* parent's `name` — `parentPath` alone only yields a path. Includes the
|
|
9
|
+
* implicit parents that `useLocalWorkspaces` does not expose on its own.
|
|
10
|
+
*/
|
|
11
|
+
parents: LocalWorkspaceParent[];
|
|
4
12
|
isLoading: boolean;
|
|
5
13
|
isError: boolean;
|
|
6
14
|
error: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-resolved-workspaces.js","names":[],"sources":["../../../src/hooks/query/use-resolved-workspaces.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n FileClient,\n isAgentServerVersionError,\n} from \"@openhands/typescript-client/clients\";\n\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { useLocalWorkspaces } from \"#/hooks/query/use-local-workspaces\";\nimport { LocalWorkspace, LocalWorkspaceParent } from \"#/types/workspace\";\n\ninterface UseResolvedWorkspacesResult {\n workspaces: LocalWorkspace[];\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Implicit workspace parents that are always considered when resolving\n * workspaces. `/projects` is a well-known directory that some agent-server\n * setups use as the projects root. We surface its immediate subdirectories\n * as workspaces automatically in dev mode.\n *\n * This is a development convenience only. Production previews may point at\n * arbitrary remote agent servers that do not expose the file-browser endpoint;\n * probing `/projects` there creates noisy 404s before the user has added any\n * workspace parent explicitly.\n */\nconst INCLUDE_IMPLICIT_WORKSPACE_PARENTS = import.meta.env.DEV;\n\nconst IMPLICIT_WORKSPACE_PARENTS: LocalWorkspaceParent[] = [\n { id: \"implicit:/projects\", name: \"/projects\", path: \"/projects\" },\n];\n\n/**\n * Returns the merged list of workspaces to display:\n * - workspaces explicitly added by the user (from the persisted store),\n * - the immediate subdirectories of every saved \"workspace parent\",\n * fetched dynamically, and\n * - the immediate subdirectories of any implicit, built-in parents\n * (currently just `/projects`).\n *\n * Static workspaces always take precedence over a dynamic child with the\n * same path so that user-selected names/ids are preserved.\n */\nexport function useResolvedWorkspaces(): UseResolvedWorkspacesResult {\n const {\n data,\n isLoading: isLoadingList,\n isError: isErrorList,\n error: listError,\n } = useLocalWorkspaces();\n const workspacesUnsupported = isAgentServerVersionError(listError);\n const workspaces = data?.workspaces ?? [];\n const storedParents = data?.workspaceParents ?? [];\n\n // Merge stored parents with the implicit ones, deduping on path so a\n // user-added `/projects` doesn't trigger a second query.\n const workspaceParents = useMemo(() => {\n const seen = new Set(storedParents.map((p) => p.path));\n // Filter out implicit parents that conflict with user-added ones (by path)\n // so custom names/ids are preserved.\n const implicitParents =\n INCLUDE_IMPLICIT_WORKSPACE_PARENTS && !workspacesUnsupported\n ? IMPLICIT_WORKSPACE_PARENTS\n : [];\n const extras = implicitParents.filter((p) => !seen.has(p.path));\n return extras.length === 0 ? storedParents : [...storedParents, ...extras];\n }, [storedParents, workspacesUnsupported]);\n\n const parentQueries = useQueries({\n queries: workspacesUnsupported\n ? []\n : workspaceParents.map((parent) => ({\n queryKey: [\"file\", \"search_subdirs\", parent.path],\n queryFn: () =>\n new FileClient(getAgentServerClientOptions()).searchSubdirectories(\n parent.path,\n ),\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n const isLoading = isLoadingList || parentQueries.some((q) => q.isLoading);\n const isError = isErrorList || parentQueries.some((q) => q.isError);\n\n // Stable string fingerprint that changes whenever any parent's subdir\n // results change. Avoids spreading timestamps into the `useMemo` deps,\n // which would change the array length as parents are added/removed.\n const queriesFingerprint = parentQueries\n .map((q) => `${q.dataUpdatedAt ?? 0}:${q.status}`)\n .join(\"|\");\n\n const merged = useMemo(() => {\n const byPath = new Map<string, LocalWorkspace>();\n const resultsByParent = new Map(\n workspaceParents.map((parent, index) => [\n parent.path,\n parentQueries[index],\n ]),\n );\n\n workspaceParents.forEach((parent) => {\n const result = resultsByParent.get(parent.path);\n const items = result?.data?.items ?? [];\n items.forEach((entry) => {\n if (byPath.has(entry.path)) return;\n byPath.set(entry.path, {\n id: entry.path,\n name: entry.name,\n path: entry.path,\n parentPath: parent.path,\n });\n });\n });\n\n // Static workspaces win on duplicate paths.\n workspaces.forEach((w) => {\n byPath.set(w.path, w);\n });\n\n return Array.from(byPath.values());\n }, [workspaces, workspaceParents, queriesFingerprint]);\n\n return {
|
|
1
|
+
{"version":3,"file":"use-resolved-workspaces.js","names":[],"sources":["../../../src/hooks/query/use-resolved-workspaces.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useQueries } from \"@tanstack/react-query\";\nimport {\n FileClient,\n isAgentServerVersionError,\n} from \"@openhands/typescript-client/clients\";\n\nimport { getAgentServerClientOptions } from \"#/api/agent-server-client-options\";\nimport { useLocalWorkspaces } from \"#/hooks/query/use-local-workspaces\";\nimport { LocalWorkspace, LocalWorkspaceParent } from \"#/types/workspace\";\n\ninterface UseResolvedWorkspacesResult {\n workspaces: LocalWorkspace[];\n /**\n * The merged workspace parents that produced the dynamic children above:\n * the user's stored parents plus any implicit built-in parents (currently\n * `/projects` in dev). Consumers use this to label a child's group by its\n * parent's `name` — `parentPath` alone only yields a path. Includes the\n * implicit parents that `useLocalWorkspaces` does not expose on its own.\n */\n parents: LocalWorkspaceParent[];\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n}\n\n/**\n * Implicit workspace parents that are always considered when resolving\n * workspaces. `/projects` is a well-known directory that some agent-server\n * setups use as the projects root. We surface its immediate subdirectories\n * as workspaces automatically in dev mode.\n *\n * This is a development convenience only. Production previews may point at\n * arbitrary remote agent servers that do not expose the file-browser endpoint;\n * probing `/projects` there creates noisy 404s before the user has added any\n * workspace parent explicitly.\n */\nconst INCLUDE_IMPLICIT_WORKSPACE_PARENTS = import.meta.env.DEV;\n\nconst IMPLICIT_WORKSPACE_PARENTS: LocalWorkspaceParent[] = [\n { id: \"implicit:/projects\", name: \"/projects\", path: \"/projects\" },\n];\n\n/**\n * Returns the merged list of workspaces to display:\n * - workspaces explicitly added by the user (from the persisted store),\n * - the immediate subdirectories of every saved \"workspace parent\",\n * fetched dynamically, and\n * - the immediate subdirectories of any implicit, built-in parents\n * (currently just `/projects`).\n *\n * Static workspaces always take precedence over a dynamic child with the\n * same path so that user-selected names/ids are preserved.\n */\nexport function useResolvedWorkspaces(): UseResolvedWorkspacesResult {\n const {\n data,\n isLoading: isLoadingList,\n isError: isErrorList,\n error: listError,\n } = useLocalWorkspaces();\n const workspacesUnsupported = isAgentServerVersionError(listError);\n const workspaces = data?.workspaces ?? [];\n const storedParents = data?.workspaceParents ?? [];\n\n // Merge stored parents with the implicit ones, deduping on path so a\n // user-added `/projects` doesn't trigger a second query.\n const workspaceParents = useMemo(() => {\n const seen = new Set(storedParents.map((p) => p.path));\n // Filter out implicit parents that conflict with user-added ones (by path)\n // so custom names/ids are preserved.\n const implicitParents =\n INCLUDE_IMPLICIT_WORKSPACE_PARENTS && !workspacesUnsupported\n ? IMPLICIT_WORKSPACE_PARENTS\n : [];\n const extras = implicitParents.filter((p) => !seen.has(p.path));\n return extras.length === 0 ? storedParents : [...storedParents, ...extras];\n }, [storedParents, workspacesUnsupported]);\n\n const parentQueries = useQueries({\n queries: workspacesUnsupported\n ? []\n : workspaceParents.map((parent) => ({\n queryKey: [\"file\", \"search_subdirs\", parent.path],\n queryFn: () =>\n new FileClient(getAgentServerClientOptions()).searchSubdirectories(\n parent.path,\n ),\n retry: false,\n meta: { disableToast: true },\n })),\n });\n\n const isLoading = isLoadingList || parentQueries.some((q) => q.isLoading);\n const isError = isErrorList || parentQueries.some((q) => q.isError);\n\n // Stable string fingerprint that changes whenever any parent's subdir\n // results change. Avoids spreading timestamps into the `useMemo` deps,\n // which would change the array length as parents are added/removed.\n const queriesFingerprint = parentQueries\n .map((q) => `${q.dataUpdatedAt ?? 0}:${q.status}`)\n .join(\"|\");\n\n const merged = useMemo(() => {\n const byPath = new Map<string, LocalWorkspace>();\n const resultsByParent = new Map(\n workspaceParents.map((parent, index) => [\n parent.path,\n parentQueries[index],\n ]),\n );\n\n workspaceParents.forEach((parent) => {\n const result = resultsByParent.get(parent.path);\n const items = result?.data?.items ?? [];\n items.forEach((entry) => {\n if (byPath.has(entry.path)) return;\n byPath.set(entry.path, {\n id: entry.path,\n name: entry.name,\n path: entry.path,\n parentPath: parent.path,\n });\n });\n });\n\n // Static workspaces win on duplicate paths.\n workspaces.forEach((w) => {\n byPath.set(w.path, w);\n });\n\n return Array.from(byPath.values());\n }, [workspaces, workspaceParents, queriesFingerprint]);\n\n return {\n workspaces: merged,\n parents: workspaceParents,\n isLoading,\n isError,\n error: listError,\n };\n}\n"],"mappings":";;;;;;;;AAsDA,SAAgB,IAAqD;CACnE,IAAM,EACJ,SACA,WAAW,GACX,SAAS,GACT,OAAO,MACL,GAAoB,EAClB,IAAwB,EAA0B,EAAU,EAC5D,IAAa,GAAM,cAAc,EAAE,EACnC,IAAgB,GAAM,oBAAoB,EAAE,EAI5C,IAAmB,QAAc;EACrC,IAAM,IAAO,IAAI,IAAI,EAAc,KAAK,MAAM,EAAE,KAAK,CAAC,EAOhD,IAAS,EAAA,CAAgB,QAAQ,MAAM,CAAC,EAAK,IAAI,EAAE,KAAK,CAAC;AAC/D,SAAO,EAAO,WAAW,IAAI,IAAgB,CAAC,GAAG,GAAe,GAAG,EAAO;IACzE,CAAC,GAAe,EAAsB,CAAC,EAEpC,IAAgB,EAAW,EAC/B,SAAS,IACL,EAAE,GACF,EAAiB,KAAK,OAAY;EAChC,UAAU;GAAC;GAAQ;GAAkB,EAAO;GAAK;EACjD,eACE,IAAI,EAAW,GAA6B,CAAC,CAAC,qBAC5C,EAAO,KACR;EACH,OAAO;EACP,MAAM,EAAE,cAAc,IAAM;EAC7B,EAAE,EACR,CAAC,EAEI,IAAY,KAAiB,EAAc,MAAM,MAAM,EAAE,UAAU,EACnE,IAAU,KAAe,EAAc,MAAM,MAAM,EAAE,QAAQ;AAwCnE,QAAO;EACL,YAhCa,QAAc;GAC3B,IAAM,oBAAS,IAAI,KAA6B,EAC1C,IAAkB,IAAI,IAC1B,EAAiB,KAAK,GAAQ,MAAU,CACtC,EAAO,MACP,EAAc,GACf,CAAC,CACH;AAqBD,UAnBA,EAAiB,SAAS,MAAW;AAGnC,KAFe,EAAgB,IAAI,EAAO,KAC5B,EAAQ,MAAM,SAAS,EAAE,EACjC,SAAS,MAAU;AACnB,OAAO,IAAI,EAAM,KAAK,IAC1B,EAAO,IAAI,EAAM,MAAM;MACrB,IAAI,EAAM;MACV,MAAM,EAAM;MACZ,MAAM,EAAM;MACZ,YAAY,EAAO;MACpB,CAAC;MACF;KACF,EAGF,EAAW,SAAS,MAAM;AACxB,MAAO,IAAI,EAAE,MAAM,EAAE;KACrB,EAEK,MAAM,KAAK,EAAO,QAAQ,CAAC;KACjC;GAAC;GAAY;GAjCW,EACxB,KAAK,MAAM,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,SAAS,CACjD,KAAK,IA+B0B;GAAmB,CAGvC;EACZ,SAAS;EACT;EACA;EACA,OAAO;EACR"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../api/backend-registry/active-store.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useQuery.cjs`),n=require(`./use-active-conversation.cjs`),
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../api/backend-registry/active-store.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useQuery.cjs`),n=require(`../../api/cloud/conversation-service.api.cjs`),r=require(`./use-active-conversation.cjs`),i=require(`../use-runtime-is-ready.cjs`),a=require(`../../utils/get-git-path.cjs`),o=require(`./use-workspace-session.cjs`),s=require(`../../stores/use-workspace-mutation-counter.cjs`);var c=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`ico`,`svg`,`avif`]),l=new Set([`pdf`]);function u(e){let t=e.lastIndexOf(`.`);return t===-1?``:e.slice(t+1).toLowerCase()}function d(e){switch(u(e)){case`html`:case`htm`:return`text/html`;case`css`:return`text/css`;case`js`:case`mjs`:case`cjs`:return`text/javascript`;case`json`:return`application/json`;case`md`:case`markdown`:return`text/markdown`;case`svg`:return`image/svg+xml`;case`png`:return`image/png`;case`jpg`:case`jpeg`:return`image/jpeg`;case`gif`:return`image/gif`;case`webp`:return`image/webp`;case`bmp`:return`image/bmp`;case`ico`:return`image/x-icon`;case`avif`:return`image/avif`;case`pdf`:return`application/pdf`;default:return`text/plain`}}function f(e){let t=u(e);return c.has(t)?`image`:l.has(t)?`pdf`:`text`}function p(e){let t=new Uint8Array(e,0,Math.min(e.byteLength,8e3));for(let e=0;e<t.length;e+=1)if(t[e]===0)return!0;return!1}function m(e){let t=new Uint8Array(e),n=32768,r=``;for(let e=0;e<t.length;e+=n)r+=String.fromCharCode.apply(null,t.subarray(e,e+n));return btoa(r)}function h(c){let{data:l}=r.useActiveConversation(),u=i.useRuntimeIsReady(),{data:h}=o.useWorkspaceSession(),g=s.useWorkspaceMutationCounter(e=>e.count),_=l?.id,v=l?.conversation_url,y=l?.session_api_key,b=l?.selected_repository,x=l?.workspace?.working_dir?.trim(),S=h?.baseUrl,C=e.getActiveBackend().backend.kind===`cloud`,w=a.getGitPath(b,x),T=w.startsWith(`/`)?w:`/${w}`,E=c?`${T}/${c}`:null;return t.useQuery({queryKey:[`workspace-file-content`,_,v,y,C?`cloud`:S,c,E,g],queryFn:async()=>{if(!c)throw Error(`No path`);let e=f(c),t=d(c);if(C){let r=await n.readCloudConversationFile(_,E);if(e===`text`){let e=new TextEncoder().encode(r);return p(e.buffer)?{path:c,kind:`binary`,text:null,staticUrl:`data:application/octet-stream;base64,${m(e.buffer)}`,mimeType:`application/octet-stream`}:{path:c,kind:`text`,text:r,staticUrl:`data:${t};charset=utf-8;base64,${m(e.buffer)}`,mimeType:t}}return{path:c,kind:e,text:null,staticUrl:`data:${t};base64,${m(new TextEncoder().encode(r).buffer)}`,mimeType:t}}if(!S)throw Error(`No workspace session`);let r=o.joinWorkspaceUrl(S,c);if(e!==`text`)return{path:c,kind:e,text:null,staticUrl:r,mimeType:t};let i=await fetch(r,{credentials:`include`});if(!i.ok)throw Error(`Failed to read ${c}: ${i.status}`);let a=await i.arrayBuffer();return p(a)?{path:c,kind:`binary`,text:null,staticUrl:r,mimeType:`application/octet-stream`}:{path:c,kind:`text`,text:new TextDecoder(`utf-8`,{fatal:!1}).decode(a),staticUrl:r,mimeType:t}},enabled:u&&!!_&&!!c&&(C||!!S),retry:!1,staleTime:1e3*5,gcTime:1e3*60,meta:{disableToast:!0}})}exports.useWorkspaceFileContent=h;
|
|
2
2
|
//# sourceMappingURL=use-workspace-file-content.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-workspace-file-content.cjs","names":[],"sources":["../../../src/hooks/query/use-workspace-file-content.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\n\nimport { getActiveBackend } from \"#/api/backend-registry/active-store\";\nimport AgentServerRuntimeService from \"#/api/runtime-service/agent-server-runtime-service\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useRuntimeIsReady } from \"#/hooks/use-runtime-is-ready\";\nimport {\n joinWorkspaceUrl,\n useWorkspaceSession,\n} from \"#/hooks/query/use-workspace-session\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// Magic-number sniff for common binary formats we can render via iframe.\nconst IMAGE_EXTENSIONS = new Set([\n \"png\",\n \"jpg\",\n \"jpeg\",\n \"gif\",\n \"webp\",\n \"bmp\",\n \"ico\",\n \"svg\",\n \"avif\",\n]);\n\nconst PDF_EXTENSIONS = new Set([\"pdf\"]);\n\nexport type WorkspaceFileKind = \"text\" | \"image\" | \"pdf\" | \"binary\";\n\nexport interface WorkspaceFileContent {\n path: string;\n kind: WorkspaceFileKind;\n /** Decoded text contents — only populated when kind === \"text\". */\n text: string | null;\n /**\n * URL pointing at the file on the agent server's static workspace\n * fileserver (the `/api/conversations/{id}/workspace/...` route minted\n * by `RemoteWorkspace.startWorkspaceSession`). Suitable to use as an\n * `<iframe src>` or `<img src>` — the workspace-session cookie\n * authenticates the browser request, and relative asset references\n * inside an HTML preview resolve naturally against this URL.\n */\n staticUrl: string;\n /** MIME type guessed from the file extension. */\n mimeType: string;\n}\n\nfunction getExtension(path: string): string {\n const idx = path.lastIndexOf(\".\");\n if (idx === -1) return \"\";\n return path.slice(idx + 1).toLowerCase();\n}\n\nfunction guessMimeType(path: string): string {\n const ext = getExtension(path);\n switch (ext) {\n case \"html\":\n case \"htm\":\n return \"text/html\";\n case \"css\":\n return \"text/css\";\n case \"js\":\n case \"mjs\":\n case \"cjs\":\n return \"text/javascript\";\n case \"json\":\n return \"application/json\";\n case \"md\":\n case \"markdown\":\n return \"text/markdown\";\n case \"svg\":\n return \"image/svg+xml\";\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n case \"jpeg\":\n return \"image/jpeg\";\n case \"gif\":\n return \"image/gif\";\n case \"webp\":\n return \"image/webp\";\n case \"bmp\":\n return \"image/bmp\";\n case \"ico\":\n return \"image/x-icon\";\n case \"avif\":\n return \"image/avif\";\n case \"pdf\":\n return \"application/pdf\";\n default:\n return \"text/plain\";\n }\n}\n\nfunction classifyKind(path: string): WorkspaceFileKind {\n const ext = getExtension(path);\n if (IMAGE_EXTENSIONS.has(ext)) return \"image\";\n if (PDF_EXTENSIONS.has(ext)) return \"pdf\";\n // Everything else is treated as text and decoded; if decoding produces\n // null bytes we fall back to \"binary\" downstream.\n return \"text\";\n}\n\nfunction isLikelyBinary(buffer: ArrayBuffer): boolean {\n // Same heuristic git uses: presence of a NUL byte in the first ~8KB.\n const view = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 8000));\n for (let i = 0; i < view.length; i += 1) {\n if (view[i] === 0) return true;\n }\n return false;\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n // Chunk to stay under the call-stack limit of `String.fromCharCode(...arr)`\n // for larger files (>~100KB) while avoiding per-byte allocation.\n const CHUNK = 0x8000;\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode.apply(\n null,\n bytes.subarray(i, i + CHUNK) as unknown as number[],\n );\n }\n return btoa(binary);\n}\n\n/**\n * Reads a single file out of the active conversation's workspace via the\n * agent server's static workspace fileserver and classifies it as\n * text/image/pdf/binary so the UI can pick a renderer.\n *\n * Image and PDF kinds are rendered directly from `staticUrl` (no fetch\n * here). Text/binary classification still requires reading the body so\n * we can run a NUL-byte sniff and decode UTF-8 for the plain/markdown\n * renderers.\n *\n * Pass a falsy `relativePath` to disable the query (e.g. when no file is\n * selected yet).\n */\nexport function useWorkspaceFileContent(relativePath: string | null) {\n const { data: conversation } = useActiveConversation();\n const runtimeIsReady = useRuntimeIsReady();\n const { data: workspaceSession } = useWorkspaceSession();\n // Bump on every agent-side file mutation so the query refetches the\n // currently-selected file's body even when the *path* hasn't changed.\n // The iframe / <img> cache-busting for the rich preview is handled at\n // the consumer (FileContentViewer / files-tab) by appending the same\n // counter to the staticUrl, so a single tick refreshes both the\n // decoded text and the iframe-rendered HTML's sibling assets.\n const workspaceMutationCount = useWorkspaceMutationCounter(\n (state) => state.count,\n );\n\n const conversationId = conversation?.id;\n const conversationUrl = conversation?.conversation_url;\n const sessionApiKey = conversation?.session_api_key;\n const baseUrl = workspaceSession?.baseUrl;\n const isCloud = getActiveBackend().backend.kind === \"cloud\";\n\n return useQuery<WorkspaceFileContent>({\n queryKey: [\n \"workspace-file-content\",\n conversationId,\n conversationUrl,\n sessionApiKey,\n isCloud ? \"cloud\" : baseUrl,\n relativePath,\n workspaceMutationCount,\n ],\n queryFn: async () => {\n if (!relativePath) throw new Error(\"No path\");\n\n const kind = classifyKind(relativePath);\n const mimeType = guessMimeType(relativePath);\n\n if (isCloud) {\n // Cloud: no static fileserver cookie path is reachable from the\n // browser. Fetch bytes server-side through callCloudProxy and\n // hand the consumer a self-contained `data:` URI for iframe /\n // <img> rendering.\n const buffer = await AgentServerRuntimeService.downloadFile(\n conversationUrl,\n sessionApiKey,\n relativePath,\n );\n if (kind === \"text\") {\n if (isLikelyBinary(buffer)) {\n return {\n path: relativePath,\n kind: \"binary\",\n text: null,\n staticUrl: `data:application/octet-stream;base64,${arrayBufferToBase64(buffer)}`,\n mimeType: \"application/octet-stream\",\n };\n }\n const text = new TextDecoder(\"utf-8\", { fatal: false }).decode(\n buffer,\n );\n return {\n path: relativePath,\n kind: \"text\",\n text,\n staticUrl: `data:${mimeType};charset=utf-8;base64,${arrayBufferToBase64(buffer)}`,\n mimeType,\n };\n }\n return {\n path: relativePath,\n kind,\n text: null,\n staticUrl: `data:${mimeType};base64,${arrayBufferToBase64(buffer)}`,\n mimeType,\n };\n }\n\n // Local: rely on the workspace-session cookie minted by\n // useWorkspaceSession to authenticate the same-origin static\n // fileserver fetch.\n if (!baseUrl) throw new Error(\"No workspace session\");\n\n const staticUrl = joinWorkspaceUrl(baseUrl, relativePath);\n\n // Image / PDF: don't fetch the bytes — the consumer renders them\n // directly via `staticUrl` in an iframe or <img>. The browser\n // will attach the `oh_workspace_session_key` cookie minted by\n // `useWorkspaceSession` so the request authenticates without us\n // having to set any headers (which a top-level <iframe src> can't\n // do anyway).\n if (kind !== \"text\") {\n return {\n path: relativePath,\n kind,\n text: null,\n staticUrl,\n mimeType,\n };\n }\n\n // For our own fetch we also rely on the workspace-session cookie\n // (it travels because we opt in to credentialed requests). This\n // matches the auth path the iframe / <img> uses, and avoids a CORS\n // preflight for a custom header.\n const response = await fetch(staticUrl, {\n credentials: \"include\",\n });\n if (!response.ok) {\n throw new Error(`Failed to read ${relativePath}: ${response.status}`);\n }\n\n const buffer = await response.arrayBuffer();\n if (isLikelyBinary(buffer)) {\n return {\n path: relativePath,\n kind: \"binary\",\n text: null,\n staticUrl,\n mimeType: \"application/octet-stream\",\n };\n }\n\n const text = new TextDecoder(\"utf-8\", { fatal: false }).decode(buffer);\n return {\n path: relativePath,\n kind: \"text\",\n text,\n staticUrl,\n mimeType,\n };\n },\n enabled:\n runtimeIsReady &&\n !!conversationId &&\n !!relativePath &&\n (isCloud || !!baseUrl),\n retry: false,\n staleTime: 1000 * 5,\n gcTime: 1000 * 60,\n meta: { disableToast: true },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-workspace-file-content.cjs","names":[],"sources":["../../../src/hooks/query/use-workspace-file-content.ts"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\n\nimport { readCloudConversationFile } from \"#/api/cloud/conversation-service.api\";\nimport { getActiveBackend } from \"#/api/backend-registry/active-store\";\nimport { getGitPath } from \"#/utils/get-git-path\";\nimport { useActiveConversation } from \"#/hooks/query/use-active-conversation\";\nimport { useRuntimeIsReady } from \"#/hooks/use-runtime-is-ready\";\nimport {\n joinWorkspaceUrl,\n useWorkspaceSession,\n} from \"#/hooks/query/use-workspace-session\";\nimport { useWorkspaceMutationCounter } from \"#/stores/use-workspace-mutation-counter\";\n\n// Magic-number sniff for common binary formats we can render via iframe.\nconst IMAGE_EXTENSIONS = new Set([\n \"png\",\n \"jpg\",\n \"jpeg\",\n \"gif\",\n \"webp\",\n \"bmp\",\n \"ico\",\n \"svg\",\n \"avif\",\n]);\n\nconst PDF_EXTENSIONS = new Set([\"pdf\"]);\n\nexport type WorkspaceFileKind = \"text\" | \"image\" | \"pdf\" | \"binary\";\n\nexport interface WorkspaceFileContent {\n path: string;\n kind: WorkspaceFileKind;\n /** Decoded text contents — only populated when kind === \"text\". */\n text: string | null;\n /**\n * URL pointing at the file on the agent server's static workspace\n * fileserver (the `/api/conversations/{id}/workspace/...` route minted\n * by `RemoteWorkspace.startWorkspaceSession`). Suitable to use as an\n * `<iframe src>` or `<img src>` — the workspace-session cookie\n * authenticates the browser request, and relative asset references\n * inside an HTML preview resolve naturally against this URL.\n */\n staticUrl: string;\n /** MIME type guessed from the file extension. */\n mimeType: string;\n}\n\nfunction getExtension(path: string): string {\n const idx = path.lastIndexOf(\".\");\n if (idx === -1) return \"\";\n return path.slice(idx + 1).toLowerCase();\n}\n\nfunction guessMimeType(path: string): string {\n const ext = getExtension(path);\n switch (ext) {\n case \"html\":\n case \"htm\":\n return \"text/html\";\n case \"css\":\n return \"text/css\";\n case \"js\":\n case \"mjs\":\n case \"cjs\":\n return \"text/javascript\";\n case \"json\":\n return \"application/json\";\n case \"md\":\n case \"markdown\":\n return \"text/markdown\";\n case \"svg\":\n return \"image/svg+xml\";\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n case \"jpeg\":\n return \"image/jpeg\";\n case \"gif\":\n return \"image/gif\";\n case \"webp\":\n return \"image/webp\";\n case \"bmp\":\n return \"image/bmp\";\n case \"ico\":\n return \"image/x-icon\";\n case \"avif\":\n return \"image/avif\";\n case \"pdf\":\n return \"application/pdf\";\n default:\n return \"text/plain\";\n }\n}\n\nfunction classifyKind(path: string): WorkspaceFileKind {\n const ext = getExtension(path);\n if (IMAGE_EXTENSIONS.has(ext)) return \"image\";\n if (PDF_EXTENSIONS.has(ext)) return \"pdf\";\n // Everything else is treated as text and decoded; if decoding produces\n // null bytes we fall back to \"binary\" downstream.\n return \"text\";\n}\n\nfunction isLikelyBinary(buffer: ArrayBuffer): boolean {\n // Same heuristic git uses: presence of a NUL byte in the first ~8KB.\n const view = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 8000));\n for (let i = 0; i < view.length; i += 1) {\n if (view[i] === 0) return true;\n }\n return false;\n}\n\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n // Chunk to stay under the call-stack limit of `String.fromCharCode(...arr)`\n // for larger files (>~100KB) while avoiding per-byte allocation.\n const CHUNK = 0x8000;\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode.apply(\n null,\n bytes.subarray(i, i + CHUNK) as unknown as number[],\n );\n }\n return btoa(binary);\n}\n\n/**\n * Reads a single file out of the active conversation's workspace via the\n * agent server's static workspace fileserver and classifies it as\n * text/image/pdf/binary so the UI can pick a renderer.\n *\n * Image and PDF kinds are rendered directly from `staticUrl` (no fetch\n * here). Text/binary classification still requires reading the body so\n * we can run a NUL-byte sniff and decode UTF-8 for the plain/markdown\n * renderers.\n *\n * Pass a falsy `relativePath` to disable the query (e.g. when no file is\n * selected yet).\n */\nexport function useWorkspaceFileContent(relativePath: string | null) {\n const { data: conversation } = useActiveConversation();\n const runtimeIsReady = useRuntimeIsReady();\n const { data: workspaceSession } = useWorkspaceSession();\n // Bump on every agent-side file mutation so the query refetches the\n // currently-selected file's body even when the *path* hasn't changed.\n // The iframe / <img> cache-busting for the rich preview is handled at\n // the consumer (FileContentViewer / files-tab) by appending the same\n // counter to the staticUrl, so a single tick refreshes both the\n // decoded text and the iframe-rendered HTML's sibling assets.\n const workspaceMutationCount = useWorkspaceMutationCounter(\n (state) => state.count,\n );\n\n const conversationId = conversation?.id;\n const conversationUrl = conversation?.conversation_url;\n const sessionApiKey = conversation?.session_api_key;\n const selectedRepository = conversation?.selected_repository;\n const workingDir = conversation?.workspace?.working_dir?.trim();\n const baseUrl = workspaceSession?.baseUrl;\n const isCloud = getActiveBackend().backend.kind === \"cloud\";\n\n // The cloud `/file` endpoint downloads via the runtime's\n // `/api/file/download`, which rejects relative paths (400 → the cloud API\n // swallows it and returns \"\"). Anchor the file against the working dir the\n // same way the diff view builds its git-diff path (see use-unified-git-diff),\n // then force a leading slash since `getGitPath`'s default is relative.\n const gitPath = getGitPath(selectedRepository, workingDir);\n const workspaceRoot = gitPath.startsWith(\"/\") ? gitPath : `/${gitPath}`;\n const absoluteFilePath = relativePath\n ? `${workspaceRoot}/${relativePath}`\n : null;\n\n return useQuery<WorkspaceFileContent>({\n queryKey: [\n \"workspace-file-content\",\n conversationId,\n conversationUrl,\n sessionApiKey,\n isCloud ? \"cloud\" : baseUrl,\n relativePath,\n absoluteFilePath,\n workspaceMutationCount,\n ],\n queryFn: async () => {\n if (!relativePath) throw new Error(\"No path\");\n\n const kind = classifyKind(relativePath);\n const mimeType = guessMimeType(relativePath);\n\n if (isCloud) {\n // Cloud: fetch through the cloud API's first-class runtime proxy\n // (GET /api/v1/app-conversations/{id}/file), which avoids the\n // removed /api/cloud-proxy hop. The endpoint returns file content as\n // a string; binary files are detected via NUL-byte sniff on the\n // decoded result and served as base64 data URIs.\n const content = await readCloudConversationFile(\n conversationId!,\n absoluteFilePath!,\n );\n\n if (kind === \"text\") {\n // NUL-byte sniff on the decoded text to catch binary files that\n // the cloud endpoint decoded as UTF-8 (fallible but sufficient).\n const buf = new TextEncoder().encode(content);\n if (isLikelyBinary(buf.buffer)) {\n return {\n path: relativePath,\n kind: \"binary\",\n text: null,\n staticUrl: `data:application/octet-stream;base64,${arrayBufferToBase64(buf.buffer)}`,\n mimeType: \"application/octet-stream\",\n };\n }\n return {\n path: relativePath,\n kind: \"text\",\n text: content,\n staticUrl: `data:${mimeType};charset=utf-8;base64,${arrayBufferToBase64(buf.buffer)}`,\n mimeType,\n };\n }\n // Image / PDF via cloud API: the endpoint returns text, so binary\n // bytes are decoded as UTF-8 server-side and can't round-trip\n // faithfully. Best-effort base64 of the returned string — a proper\n // binary path needs a cloud download endpoint (the old byte-accurate\n // downloadFile route went through the removed /api/cloud-proxy).\n const buf = new TextEncoder().encode(content);\n return {\n path: relativePath,\n kind,\n text: null,\n staticUrl: `data:${mimeType};base64,${arrayBufferToBase64(buf.buffer)}`,\n mimeType,\n };\n }\n\n // Local: rely on the workspace-session cookie minted by\n // useWorkspaceSession to authenticate the same-origin static\n // fileserver fetch.\n if (!baseUrl) throw new Error(\"No workspace session\");\n\n const staticUrl = joinWorkspaceUrl(baseUrl, relativePath);\n\n // Image / PDF: don't fetch the bytes — the consumer renders them\n // directly via `staticUrl` in an iframe or <img>. The browser\n // will attach the `oh_workspace_session_key` cookie minted by\n // `useWorkspaceSession` so the request authenticates without us\n // having to set any headers (which a top-level <iframe src> can't\n // do anyway).\n if (kind !== \"text\") {\n return {\n path: relativePath,\n kind,\n text: null,\n staticUrl,\n mimeType,\n };\n }\n\n // For our own fetch we also rely on the workspace-session cookie\n // (it travels because we opt in to credentialed requests). This\n // matches the auth path the iframe / <img> uses, and avoids a CORS\n // preflight for a custom header.\n const response = await fetch(staticUrl, {\n credentials: \"include\",\n });\n if (!response.ok) {\n throw new Error(`Failed to read ${relativePath}: ${response.status}`);\n }\n\n const buffer = await response.arrayBuffer();\n if (isLikelyBinary(buffer)) {\n return {\n path: relativePath,\n kind: \"binary\",\n text: null,\n staticUrl,\n mimeType: \"application/octet-stream\",\n };\n }\n\n const text = new TextDecoder(\"utf-8\", { fatal: false }).decode(buffer);\n return {\n path: relativePath,\n kind: \"text\",\n text,\n staticUrl,\n mimeType,\n };\n },\n enabled:\n runtimeIsReady &&\n !!conversationId &&\n !!relativePath &&\n (isCloud || !!baseUrl),\n retry: false,\n staleTime: 1000 * 5,\n gcTime: 1000 * 60,\n meta: { disableToast: true },\n });\n}\n"],"mappings":"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"}
|