@openhands/agent-canvas 1.0.0-rc.6 → 1.0.0-rc.8
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 -3
- package/README.windows.md +2 -2
- package/build/assets/{QueryClientProvider-2bFjjuvv.js → QueryClientProvider-XcSjsfpb.js} +1 -1
- package/build/assets/{Trans-D1xHkKyr.js → Trans-sy4l4TyQ.js} +1 -1
- package/build/assets/{acp-providers-Djbp2WMV.js → acp-providers-BqUvf67Q.js} +1 -1
- package/build/assets/{active-backend-context-BiVlte2V.js → active-backend-context-CNF2lPkA.js} +1 -1
- package/build/assets/add-backend-modal-BywVr6uq.js +1 -0
- package/build/assets/{agent-server-adapter-BD6kvwWb.js → agent-server-adapter-k8veH-1O.js} +1 -1
- package/build/assets/{agent-server-conversation-service.api-8AC86rC5.js → agent-server-conversation-service.api-CGbkhsLj.js} +1 -1
- package/build/assets/{agent-settings-DycVwGfd.js → agent-settings-DoHXHcoA.js} +1 -1
- package/build/assets/{alert-banner-BUqPui_3.js → alert-banner-Bsvys-hT.js} +1 -1
- package/build/assets/{analytics-consent-form-modal-CdP5JRph.js → analytics-consent-form-modal-CVhsAREx.js} +1 -1
- package/build/assets/{api-key-entry-screen-BnvQM0v5.js → api-key-entry-screen-Dnr5TcV0.js} +1 -1
- package/build/assets/{app-settings-FRYUtG-Z.js → app-settings-Bgm2-yOM.js} +1 -1
- package/build/assets/{automation-detail-DiIq3Vsh.js → automation-detail-86M_yMqz.js} +1 -1
- package/build/assets/{automations-list-DQn7k1Ix.js → automations-list-BWUILrqY.js} +1 -1
- package/build/assets/{back-nav-button-B8eULM4t.js → back-nav-button-D20Avel_.js} +1 -1
- package/build/assets/{backend-form-modal-DY3My0us.js → backend-form-modal-Dl29wkF5.js} +1 -1
- package/build/assets/{backend-synced-settings-badge-BW2WPX-c.js → backend-synced-settings-badge-Dcd4712m.js} +1 -1
- package/build/assets/{base-modal-B_MCb3rx.js → base-modal-DvuGYyu1.js} +1 -1
- package/build/assets/{brand-button-B6g_UvEG.js → brand-button-9SOzmqPP.js} +1 -1
- package/build/assets/{browser-tab-DVHx54yn.js → browser-tab-bveyJhG9.js} +1 -1
- package/build/assets/{chat-send-button-Ce9rK8Vd.js → chat-send-button-BhoO7T0s.js} +1 -1
- package/build/assets/{checkmark-BQIxLn5W.js → checkmark--JWAesua.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-DRwQ4Z7K.js → circle-plus-check-toggle-AO9DWyDX.js} +1 -1
- package/build/assets/{close-HybccyBS.js → close--W-tHn1h.js} +1 -1
- package/build/assets/{code-tag-DZCEX2zo.js → code-tag-chmctf4w.js} +1 -1
- package/build/assets/{combobox-caret-kEa3kTvf.js → combobox-caret-C9BNHfSu.js} +1 -1
- package/build/assets/{condenser-settings-BlbT8YRd.js → condenser-settings-DgQ0rsAf.js} +1 -1
- package/build/assets/{confirmation-modal-CG_Fgrny.js → confirmation-modal-Cq3eqvqH.js} +1 -1
- package/build/assets/{context-menu-list-item-CvJv3-kq.js → context-menu-list-item-BQU0jZPq.js} +1 -1
- package/build/assets/conversation-CayU5Lrr.js +19 -0
- package/build/assets/conversation-erinyBqT.js +1 -0
- package/build/assets/conversation-panel-DiI4q-8-.js +1 -0
- package/build/assets/{conversation-service.api-CngSQhPh.js → conversation-service.api-shHWtFwu.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-B5eOSEGv.js → conversation-tab-empty-state-C8tztloo.js} +1 -1
- package/build/assets/{copy-D6CyDz2n.js → copy-CdKN5rtJ.js} +1 -1
- package/build/assets/{declaration-BDfM67Kl.js → declaration-D9ucT0fq.js} +1 -1
- package/build/assets/{device-verify-CAevP6_3.js → device-verify-YuGXnpRk.js} +1 -1
- package/build/assets/{dropdown-classes-CL8egwz_.js → dropdown-classes-CVp0kVdt.js} +1 -1
- package/build/assets/{edit-automation-modal-CwLfhSMN.js → edit-automation-modal-8y9Uctxo.js} +1 -1
- package/build/assets/{ellipsis-button-Db-AwbLv.js → ellipsis-button-k7HLwYth.js} +1 -1
- package/build/assets/{entry.client-BKDpKmdB.js → entry.client-D_wtryHT.js} +2 -2
- package/build/assets/{enum-filter-dropdown-DnYXhc1E.js → enum-filter-dropdown-COqUq3mB.js} +1 -1
- package/build/assets/{environment-switch-overlay-BgYKFdf6.js → environment-switch-overlay-wB5LxfYZ.js} +1 -1
- package/build/assets/{extensions-hub-CgisT2wb.js → extensions-hub-CoWO3SzQ.js} +1 -1
- package/build/assets/{extensions-navigation-nurGkQe5.js → extensions-navigation-D5w2sFQe.js} +1 -1
- package/build/assets/{files-tab-DIyAYvp0.js → files-tab-CxdtgkIe.js} +1 -1
- package/build/assets/{files-tab-store-RScGdwu8.js → files-tab-store-DSKUhziI.js} +1 -1
- package/build/assets/{folder-IChmji2Y.js → folder-DPTBlxWb.js} +1 -1
- package/build/assets/home-3joHMYSR.js +1 -0
- package/build/assets/{install-server-modal-C8fylTet.js → install-server-modal-_7l1gcjd.js} +1 -1
- package/build/assets/{launch-BNiqgTvz.js → launch-fU77utLO.js} +1 -1
- package/build/assets/{lesson-plan-BdmMvboE.js → lesson-plan-CHGc-B8Y.js} +1 -1
- package/build/assets/{lightbulb-DzViGAuw.js → lightbulb-S616sGEL.js} +1 -1
- package/build/assets/{link-external-Dwv3oQAx.js → link-external-ooNztGLp.js} +1 -1
- package/build/assets/llm-not-configured-banner-BMGzpBPV.js +27 -0
- package/build/assets/llm-settings-BRotm_g6.js +1 -0
- package/build/assets/{llm-settings-B92l1Z2N.js → llm-settings-yDgbXP6Q.js} +1 -1
- package/build/assets/{loading-spinner-Dtm7y-w5.js → loading-spinner-D7bOU6I7.js} +1 -1
- package/build/assets/{manage-backends-modal-qpq2M_oN.js → manage-backends-modal-tfdzTXWU.js} +1 -1
- package/build/assets/{manifest-05156141.js → manifest-bbc1374e.js} +1 -1
- package/build/assets/{markdown-renderer-Dt0RXhUJ.js → markdown-renderer-z446oW0Z.js} +1 -1
- package/build/assets/{mcp-BKdD21xY.js → mcp-Dopstf0t.js} +1 -1
- package/build/assets/{messages-Ch8Rd1cx.js → messages-CsFUrAen.js} +1 -1
- package/build/assets/{modal-backdrop-DmDLoot0.js → modal-backdrop-_VbcKk5K.js} +1 -1
- package/build/assets/{modal-body-BWjhfiSa.js → modal-body-Cd-PtMHr.js} +1 -1
- package/build/assets/{modal-classes-DbJbhQCW.js → modal-classes-CNm4ovfm.js} +1 -1
- package/build/assets/{modal-close-button-DXN6uYvt.js → modal-close-button-Dbo0NAMt.js} +1 -1
- package/build/assets/{model-selector-BMn4D5v6.js → model-selector-sioC8xP4.js} +1 -1
- package/build/assets/{navigation-context-BrRCrWhm.js → navigation-context-BpAOh_t5.js} +1 -1
- package/build/assets/{navigation-link-qUrH_I5_.js → navigation-link-Dci7Nuyf.js} +1 -1
- package/build/assets/{onboarding-B50IeNyy.js → onboarding-CQh50i2z.js} +1 -1
- package/build/assets/{openhands-logo-DnfHAq7Y.js → openhands-logo-Dzm-d_V_.js} +1 -1
- package/build/assets/{option-service.api-lzN_3s9w.js → option-service.api-DjPvPAtd.js} +1 -1
- package/build/assets/{organization-service.api-CNmSPGj4.js → organization-service.api-BNc9Kn6n.js} +1 -1
- package/build/assets/{path-utils-CKgIQZAY.js → path-utils-YlkpoImJ.js} +1 -1
- package/build/assets/{plan-components-D9fU4FFh.js → plan-components-CutRBi0G.js} +1 -1
- package/build/assets/{planner-tab-B7kpsTT8.js → planner-tab-DjIFIQDk.js} +1 -1
- package/build/assets/{providers-189W9TJO.js → providers-BiWSYwRT.js} +1 -1
- package/build/assets/{query-client-config-B9ZI-1_w.js → query-client-config-Ca3tW1AH.js} +1 -1
- package/build/assets/{recommended-automations-launcher-C_RcP2yb.js → recommended-automations-launcher-DCi0RXIj.js} +1 -1
- package/build/assets/{root-CFnl2e43.js → root-DrHpnAqU.js} +2 -2
- package/build/assets/{root-layout-BQGwrist.js → root-layout-Cf7FC9DC.js} +2 -2
- package/build/assets/{runtime-waiting-state-DPjfE32a.js → runtime-waiting-state-8i0Z3A_i.js} +1 -1
- package/build/assets/{sdk-section-page-ozvrzW4r.js → sdk-section-page-COlGKv4E.js} +1 -1
- package/build/assets/{sdk-settings-schema-Ck6f2ON9.js → sdk-settings-schema-Big50zDH.js} +1 -1
- package/build/assets/{search-aDWSdSb7.js → search-C_l_XW4e.js} +1 -1
- package/build/assets/{secrets-settings-Bga0bwB1.js → secrets-settings-DYfTc5c8.js} +1 -1
- package/build/assets/{settings-DHAhcPm2.js → settings-DRmVFdOc.js} +1 -1
- package/build/assets/{settings-dropdown-input-N0FtDFkk.js → settings-dropdown-input-BP-arqjU.js} +1 -1
- package/build/assets/{settings-gear-D8ao16bi.js → settings-gear-f-zWpxfI.js} +1 -1
- package/build/assets/{settings-index-CJvQH5ls.js → settings-index-B035V2pu.js} +1 -1
- package/build/assets/{settings-input-CyWJBrqC.js → settings-input-BM8ANxDb.js} +1 -1
- package/build/assets/{settings-list-classes-CYRnRf8r.js → settings-list-classes-B9uo5WES.js} +1 -1
- package/build/assets/{settings-modal-BeAlR7Be.js → settings-modal-CeRvS5Bc.js} +1 -1
- package/build/assets/{settings-section-header-context-1fN7Xkb3.js → settings-section-header-context-Cid25HM2.js} +1 -1
- package/build/assets/{settings-switch-D3aEIphL.js → settings-switch-xa6q4M6j.js} +1 -1
- package/build/assets/{shared-conversation-CtRf6CQN.js → shared-conversation-CBbpyPaD.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-DkYaKR6Q.js → sidebar-mobile-menu-toggle-SKcwsEtD.js} +1 -1
- package/build/assets/{sidebar-nav-link-CzeuB4So.js → sidebar-nav-link-CPWuQ_c6.js} +1 -1
- package/build/assets/{skill-card-pill-row-CvLCLqqD.js → skill-card-pill-row-DeodrwPG.js} +1 -1
- package/build/assets/{skills-jKeJCunm.js → skills-BE5HJuGM.js} +1 -1
- package/build/assets/{skills-plugins-juwPhlEE.js → skills-plugins-Dc4ec3CW.js} +1 -1
- package/build/assets/{skills-settings-BW09n_Px.js → skills-settings-B6HwvA0S.js} +1 -1
- package/build/assets/{styled-tooltip-B3wz8m5E.js → styled-tooltip-X61SEwqk.js} +1 -1
- package/build/assets/{suspense-BpkWt-39.js → suspense-Bqb0V0q1.js} +1 -1
- package/build/assets/{switch-skeleton-Cl_Nh2kt.js → switch-skeleton-BbIWemkK.js} +1 -1
- package/build/assets/{task-list-tab-DKnHShLG.js → task-list-tab-BFnyHGsn.js} +1 -1
- package/build/assets/{telemetry-Ca_YAGcO.js → telemetry-DCFAqpIA.js} +1 -1
- package/build/assets/{terminal-BFi5FOMc.js → terminal-B92mACR5.js} +1 -1
- package/build/assets/{terminal-CZH2h1J3.js → terminal-CltMeLv4.js} +1 -1
- package/build/assets/{toggle-switch-BzaEofjj.js → toggle-switch-CL_wRiGs.js} +1 -1
- package/build/assets/{typography-BFj4IzMj.js → typography-BLSEGjph.js} +1 -1
- package/build/assets/{u-check-circle-Cs2GOrZ7.js → u-check-circle-dG_VJqx5.js} +1 -1
- package/build/assets/{u-check-circle-half-DGgLKVV1.js → u-check-circle-half-D-5ZPRnd.js} +1 -1
- package/build/assets/{u-circuit-DniZPNAV.js → u-circuit-BXoisXOA.js} +1 -1
- package/build/assets/{u-edit-BvTiDr33.js → u-edit-DIgADxLH.js} +1 -1
- package/build/assets/{use-acp-credential-form-8yHKY_py.js → use-acp-credential-form-LjCIhMSK.js} +1 -1
- package/build/assets/{use-active-conversation-CLzls6XV.js → use-active-conversation-B0_rXnqa.js} +1 -1
- package/build/assets/{use-agent-settings-schema-BCXxH2N-.js → use-agent-settings-schema-D8x5LJVS.js} +1 -1
- package/build/assets/{use-agent-state-BocVPR5S.js → use-agent-state-BuOzLeFN.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-BjDwnldw.js → use-cloud-current-user-id-DVZXa_WH.js} +1 -1
- package/build/assets/use-config-5zEjywCL.js +1 -0
- package/build/assets/{use-create-conversation-CIkPp9u9.js → use-create-conversation-pV2eA-e9.js} +1 -1
- package/build/assets/{use-create-secret-Bwy6457V.js → use-create-secret-ClPpLBgD.js} +1 -1
- package/build/assets/{use-handle-plan-click-CjNwpDeO.js → use-handle-plan-click-CwN_nNib.js} +1 -1
- package/build/assets/use-is-authed-B8eLO-Xq.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-QmcJQxUY.js → use-launch-skill-in-chat-BTgXIu3N.js} +1 -1
- package/build/assets/{use-llm-profiles-CZD1ALup.js → use-llm-profiles-CWLfWjav.js} +1 -1
- package/build/assets/use-runtime-is-ready-Bbory9-s.js +1 -0
- package/build/assets/{use-save-settings-BjYPOrtF.js → use-save-settings-Xp8DD-jf.js} +1 -1
- package/build/assets/{use-settings-YTDcMvj1.js → use-settings-0SeqaDeW.js} +1 -1
- package/build/assets/{use-settings-nav-items-DMit9adK.js → use-settings-nav-items-DVrMNk0I.js} +1 -1
- package/build/assets/{use-skills-fh_U4ZGe.js → use-skills-Bv8LXrys.js} +1 -1
- package/build/assets/{use-tracking-DJ3Z7ha1.js → use-tracking-BhyV5A9i.js} +1 -1
- package/build/assets/{use-user-conversation-Ct93yaXj.js → use-user-conversation-6yFVEXiG.js} +1 -1
- package/build/assets/{useMutation-B1gQr_yr.js → useMutation-Dm84WAKR.js} +1 -1
- package/build/assets/{useQuery-CbqdITLM.js → useQuery-DGRSm7IT.js} +1 -1
- package/build/assets/{useTranslation-C-T8J2U-.js → useTranslation-CL6FTf1b.js} +1 -1
- package/build/assets/{utils-CXRkUr73.js → utils-eXk6yerZ.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-CkFCLbQW.js → vendor~conversation-panel~conversation-D98u43rl.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-C1BmvJX4.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dqpi2xyZ.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-RuHTcYaf.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-7eqKdLSQ.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-B04AZhMW.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BP3MGAAY.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-D7ZsdcLa.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Dkd2wxJA.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DH07jaIY.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DavKsAvB.js} +186 -40
- package/build/assets/{vendor~root-layout~home~mcp~automations-list-COlx7Is6.js → vendor~root-layout~home~mcp~automations-list-D40jgugf.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-DuiHR4ce.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BIm99UaF.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-4yr76Evz.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-xCM3k6Rd.js} +1 -1
- package/build/assets/{verification-settings-CeIuPtF2.js → verification-settings-Be6NxjuT.js} +1 -1
- package/build/assets/{x-mark-BMhi11Sg.js → x-mark-C42svtnu.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +45 -40
- package/build/locales/ca/openhands.json +41 -36
- package/build/locales/de/openhands.json +42 -37
- package/build/locales/en/openhands.json +6 -1
- package/build/locales/es/openhands.json +44 -39
- package/build/locales/fr/openhands.json +44 -39
- package/build/locales/it/openhands.json +44 -39
- package/build/locales/ja/openhands.json +44 -39
- package/build/locales/ko-KR/openhands.json +44 -39
- package/build/locales/no/openhands.json +44 -39
- package/build/locales/pt/openhands.json +44 -39
- package/build/locales/tr/openhands.json +43 -38
- package/build/locales/uk/openhands.json +44 -39
- package/build/locales/zh-CN/openhands.json +44 -39
- package/build/locales/zh-TW/openhands.json +44 -39
- package/config/defaults.json +9 -4
- package/dist/components/features/backends/backend-form-modal.cjs +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
- package/dist/components/features/backends/backend-form-modal.js +1 -1
- package/dist/components/features/backends/backend-form-modal.js.map +1 -1
- package/dist/components/features/chat/chat-interface.cjs +1 -1
- package/dist/components/features/chat/chat-interface.cjs.map +1 -1
- package/dist/components/features/chat/chat-interface.js +1 -1
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/git-control-bar.cjs +1 -1
- package/dist/components/features/chat/git-control-bar.cjs.map +1 -1
- package/dist/components/features/chat/git-control-bar.js +1 -1
- package/dist/components/features/chat/git-control-bar.js.map +1 -1
- package/dist/components/features/chat/open-repository-modal.cjs +1 -1
- package/dist/components/features/chat/open-repository-modal.cjs.map +1 -1
- package/dist/components/features/chat/open-repository-modal.js +0 -3
- package/dist/components/features/chat/open-repository-modal.js.map +1 -1
- package/dist/components/features/chat/pending-user-messages.cjs +1 -1
- package/dist/components/features/chat/pending-user-messages.cjs.map +1 -1
- package/dist/components/features/chat/pending-user-messages.js +31 -28
- package/dist/components/features/chat/pending-user-messages.js.map +1 -1
- package/dist/components/features/home/git-branch-dropdown/git-branch-dropdown.cjs +1 -1
- package/dist/components/features/home/git-branch-dropdown/git-branch-dropdown.cjs.map +1 -1
- package/dist/components/features/home/git-branch-dropdown/git-branch-dropdown.js +79 -77
- package/dist/components/features/home/git-branch-dropdown/git-branch-dropdown.js.map +1 -1
- package/dist/components/features/home/git-provider-dropdown/git-provider-dropdown.cjs +1 -1
- package/dist/components/features/home/git-provider-dropdown/git-provider-dropdown.cjs.map +1 -1
- package/dist/components/features/home/git-provider-dropdown/git-provider-dropdown.js +67 -65
- package/dist/components/features/home/git-provider-dropdown/git-provider-dropdown.js.map +1 -1
- package/dist/components/features/home/git-repo-dropdown/git-repo-dropdown.cjs +1 -1
- package/dist/components/features/home/git-repo-dropdown/git-repo-dropdown.cjs.map +1 -1
- package/dist/components/features/home/git-repo-dropdown/git-repo-dropdown.js +2 -2
- package/dist/components/features/home/git-repo-dropdown/git-repo-dropdown.js.map +1 -1
- package/dist/components/features/settings/settings-navigation.cjs +1 -1
- package/dist/components/features/settings/settings-navigation.cjs.map +1 -1
- package/dist/components/features/settings/settings-navigation.js +1 -1
- package/dist/components/features/settings/settings-navigation.js.map +1 -1
- package/dist/components/features/sidebar/sidebar.cjs +1 -1
- package/dist/components/features/sidebar/sidebar.cjs.map +1 -1
- package/dist/components/features/sidebar/sidebar.js +3 -2
- package/dist/components/features/sidebar/sidebar.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 +6 -1
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +3 -3
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +612 -527
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +45 -40
- package/dist/locales/ca/openhands.json +41 -36
- package/dist/locales/de/openhands.json +42 -37
- package/dist/locales/en/openhands.json +6 -1
- package/dist/locales/es/openhands.json +44 -39
- package/dist/locales/fr/openhands.json +44 -39
- package/dist/locales/it/openhands.json +44 -39
- package/dist/locales/ja/openhands.json +44 -39
- package/dist/locales/ko-KR/openhands.json +44 -39
- package/dist/locales/no/openhands.json +44 -39
- package/dist/locales/pt/openhands.json +44 -39
- package/dist/locales/tr/openhands.json +43 -38
- package/dist/locales/uk/openhands.json +44 -39
- package/dist/locales/zh-CN/openhands.json +44 -39
- package/dist/locales/zh-TW/openhands.json +44 -39
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +186 -40
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +2 -2
- 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/package.json +2 -2
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/check-translation-completeness.cjs +149 -59
- package/scripts/dev-safe.mjs +1 -1
- package/build/assets/add-backend-modal-CSfOPrnr.js +0 -1
- package/build/assets/conversation-B7ztPdyS.js +0 -1
- package/build/assets/conversation-DZYd8QiZ.js +0 -19
- package/build/assets/conversation-panel-CklMXcs6.js +0 -1
- package/build/assets/home-iVOrSOWL.js +0 -1
- package/build/assets/llm-not-configured-banner-BQgVTo0O.js +0 -27
- package/build/assets/llm-settings-ICWFhhjM.js +0 -1
- package/build/assets/use-config-C4DX1-nF.js +0 -1
- package/build/assets/use-is-authed-7P3xSsit.js +0 -1
- package/build/assets/use-runtime-is-ready-B7sbw-q5.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-navigation.cjs","names":[],"sources":["../../../../src/components/features/settings/settings-navigation.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { cn } from \"#/utils/utils\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport SettingsIcon from \"#/icons/settings-gear.svg?react\";\nimport CloseIcon from \"#/icons/close.svg?react\";\nimport { SettingsNavRenderedItem } from \"#/hooks/use-settings-nav-items\";\nimport { SettingsNavHeader } from \"./settings-nav-header\";\nimport { SettingsNavDivider } from \"./settings-nav-divider\";\nimport { SettingsNavLink } from \"./settings-nav-link\";\nimport { SidebarNavLink } from \"#/components/features/sidebar/sidebar-nav-link\";\nimport { navInteractiveTransitionClassName } from \"#/components/features/sidebar/sidebar-layout\";\nimport { BackendSyncedSettingsBadge } from \"#/components/features/settings/backend-synced-settings-badge\";\n\ninterface SettingsNavigationProps {\n isMobileMenuOpen: boolean;\n onCloseMobileMenu: () => void;\n navigationItems: SettingsNavRenderedItem[];\n}\n\n/**\n * Desktop sidebar — sibling of the scrolling main column (same pattern as\n * {@link ExtensionsNavigation}). Mobile drawer stays `position: fixed` outside\n * this row in the layout.\n */\nexport function SettingsDesktopSidebar({\n navigationItems,\n}: Pick<SettingsNavigationProps, \"navigationItems\">) {\n const { t } = useTranslation(\"openhands\");\n const desktopNavItems = navigationItems.filter(\n (item): item is Extract<SettingsNavRenderedItem, { type: \"item\" }> =>\n item.type === \"item\",\n );\n\n return (\n <aside\n data-testid=\"settings-navbar-desktop\"\n className={cn(\n \"hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2\",\n \"md:sticky md:top-8 md:self-start md:pl-8\",\n )}\n >\n <Typography.Text className=\"px-2 text-sm font-normal text-white\">\n {t(I18nKey.SETTINGS$TITLE)}\n </Typography.Text>\n <div className=\"flex flex-col gap-0.5 pt-0.5\">\n {desktopNavItems.map((renderedItem) => (\n <SidebarNavLink\n key={renderedItem.item.to}\n to={renderedItem.item.to}\n label={t(renderedItem.item.text as I18nKey)}\n end\n testId={`sidebar-settings-${renderedItem.item.to}`}\n icon={renderedItem.item.icon}\n // Items marked ``disabledByAcp`` (LLM, Condenser, …) are greyed\n // out and un-clickable while an ACP agent is active — those\n // pages have nothing to configure while a separate sub-agent\n // owns the LLM/condenser/MCP layers. The mobile drawer below\n // already does this via ``SettingsNavLink``; do the same on\n // desktop. The clientLoader-side redirect in ``routes/\n // settings.tsx`` handles direct URL navigation.\n disabled={renderedItem.disabled}\n disabledReason={\n renderedItem.disabled && renderedItem.disabledAgentName\n ? t(I18nKey.SETTINGS$AGENT_DISABLED_TOOLTIP, {\n agentName: renderedItem.disabledAgentName,\n })\n : undefined\n }\n />\n ))}\n </div>\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </aside>\n );\n}\n\n/**\n * Mobile overlay + drawer. Rendered outside the scrolling flex row so `position:\n * fixed` does not interact with flex item sizing on desktop.\n */\nexport function SettingsMobileDrawer({\n isMobileMenuOpen,\n onCloseMobileMenu,\n navigationItems,\n}: SettingsNavigationProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <>\n {isMobileMenuOpen && (\n <div\n className=\"fixed inset-0 z-40 bg-black bg-opacity-50 md:hidden\"\n onClick={onCloseMobileMenu}\n />\n )}\n <nav\n data-testid=\"settings-navbar\"\n className={cn(\n \"flex flex-col gap-6 transition-transform duration-300 ease-in-out\",\n \"fixed inset-0 z-50 w-full bg-[var(--oh-surface-deep)] p-4 transform md:hidden\",\n isMobileMenuOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"ml-1 flex items-center gap-2 sm:ml-4.5\">\n <SettingsIcon width={16} height={16} />\n <Typography.H2>{t(I18nKey.SETTINGS$TITLE)}</Typography.H2>\n </div>\n <button\n type=\"button\"\n onClick={onCloseMobileMenu}\n className={cn(\n \"cursor-pointer rounded-md p-0.5 hover:bg-tertiary md:hidden\",\n navInteractiveTransitionClassName,\n )}\n aria-label
|
|
1
|
+
{"version":3,"file":"settings-navigation.cjs","names":[],"sources":["../../../../src/components/features/settings/settings-navigation.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { cn } from \"#/utils/utils\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport SettingsIcon from \"#/icons/settings-gear.svg?react\";\nimport CloseIcon from \"#/icons/close.svg?react\";\nimport { SettingsNavRenderedItem } from \"#/hooks/use-settings-nav-items\";\nimport { SettingsNavHeader } from \"./settings-nav-header\";\nimport { SettingsNavDivider } from \"./settings-nav-divider\";\nimport { SettingsNavLink } from \"./settings-nav-link\";\nimport { SidebarNavLink } from \"#/components/features/sidebar/sidebar-nav-link\";\nimport { navInteractiveTransitionClassName } from \"#/components/features/sidebar/sidebar-layout\";\nimport { BackendSyncedSettingsBadge } from \"#/components/features/settings/backend-synced-settings-badge\";\n\ninterface SettingsNavigationProps {\n isMobileMenuOpen: boolean;\n onCloseMobileMenu: () => void;\n navigationItems: SettingsNavRenderedItem[];\n}\n\n/**\n * Desktop sidebar — sibling of the scrolling main column (same pattern as\n * {@link ExtensionsNavigation}). Mobile drawer stays `position: fixed` outside\n * this row in the layout.\n */\nexport function SettingsDesktopSidebar({\n navigationItems,\n}: Pick<SettingsNavigationProps, \"navigationItems\">) {\n const { t } = useTranslation(\"openhands\");\n const desktopNavItems = navigationItems.filter(\n (item): item is Extract<SettingsNavRenderedItem, { type: \"item\" }> =>\n item.type === \"item\",\n );\n\n return (\n <aside\n data-testid=\"settings-navbar-desktop\"\n className={cn(\n \"hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2\",\n \"md:sticky md:top-8 md:self-start md:pl-8\",\n )}\n >\n <Typography.Text className=\"px-2 text-sm font-normal text-white\">\n {t(I18nKey.SETTINGS$TITLE)}\n </Typography.Text>\n <div className=\"flex flex-col gap-0.5 pt-0.5\">\n {desktopNavItems.map((renderedItem) => (\n <SidebarNavLink\n key={renderedItem.item.to}\n to={renderedItem.item.to}\n label={t(renderedItem.item.text as I18nKey)}\n end\n testId={`sidebar-settings-${renderedItem.item.to}`}\n icon={renderedItem.item.icon}\n // Items marked ``disabledByAcp`` (LLM, Condenser, …) are greyed\n // out and un-clickable while an ACP agent is active — those\n // pages have nothing to configure while a separate sub-agent\n // owns the LLM/condenser/MCP layers. The mobile drawer below\n // already does this via ``SettingsNavLink``; do the same on\n // desktop. The clientLoader-side redirect in ``routes/\n // settings.tsx`` handles direct URL navigation.\n disabled={renderedItem.disabled}\n disabledReason={\n renderedItem.disabled && renderedItem.disabledAgentName\n ? t(I18nKey.SETTINGS$AGENT_DISABLED_TOOLTIP, {\n agentName: renderedItem.disabledAgentName,\n })\n : undefined\n }\n />\n ))}\n </div>\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </aside>\n );\n}\n\n/**\n * Mobile overlay + drawer. Rendered outside the scrolling flex row so `position:\n * fixed` does not interact with flex item sizing on desktop.\n */\nexport function SettingsMobileDrawer({\n isMobileMenuOpen,\n onCloseMobileMenu,\n navigationItems,\n}: SettingsNavigationProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <>\n {isMobileMenuOpen && (\n <div\n className=\"fixed inset-0 z-40 bg-black bg-opacity-50 md:hidden\"\n onClick={onCloseMobileMenu}\n />\n )}\n <nav\n data-testid=\"settings-navbar\"\n className={cn(\n \"flex flex-col gap-6 transition-transform duration-300 ease-in-out\",\n \"fixed inset-0 z-50 w-full bg-[var(--oh-surface-deep)] p-4 transform md:hidden\",\n isMobileMenuOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"ml-1 flex items-center gap-2 sm:ml-4.5\">\n <SettingsIcon width={16} height={16} />\n <Typography.H2>{t(I18nKey.SETTINGS$TITLE)}</Typography.H2>\n </div>\n <button\n type=\"button\"\n onClick={onCloseMobileMenu}\n className={cn(\n \"cursor-pointer rounded-md p-0.5 hover:bg-tertiary md:hidden\",\n navInteractiveTransitionClassName,\n )}\n aria-label={t(I18nKey.SIDEBAR$CLOSE_MENU)}\n >\n <CloseIcon width={32} height={32} />\n </button>\n </div>\n\n <div className=\"flex flex-col gap-2\">\n {navigationItems.map((renderedItem, index) => {\n if (renderedItem.type === \"header\") {\n return (\n <SettingsNavHeader\n key={`header-${renderedItem.text}`}\n text={renderedItem.text}\n />\n );\n }\n\n if (renderedItem.type === \"divider\") {\n return <SettingsNavDivider key={`divider-${index}`} />;\n }\n\n return (\n <SettingsNavLink\n key={renderedItem.item.to}\n item={renderedItem.item}\n onClick={onCloseMobileMenu}\n disabled={renderedItem.disabled}\n disabledAgentName={renderedItem.disabledAgentName}\n />\n );\n })}\n </div>\n\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </nav>\n </>\n );\n}\n\nexport function SettingsNavigation(props: SettingsNavigationProps) {\n return (\n <>\n <SettingsDesktopSidebar navigationItems={props.navigationItems} />\n <SettingsMobileDrawer {...props} />\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -62,7 +62,7 @@ function g({ isMobileMenuOpen: u, onCloseMobileMenu: h, navigationItems: g }) {
|
|
|
62
62
|
type: "button",
|
|
63
63
|
onClick: h,
|
|
64
64
|
className: n("cursor-pointer rounded-md p-0.5 hover:bg-tertiary md:hidden", c),
|
|
65
|
-
"aria-label":
|
|
65
|
+
"aria-label": _(t.SIDEBAR$CLOSE_MENU),
|
|
66
66
|
children: /* @__PURE__ */ p(a, {
|
|
67
67
|
width: 32,
|
|
68
68
|
height: 32
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-navigation.js","names":[],"sources":["../../../../src/components/features/settings/settings-navigation.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { cn } from \"#/utils/utils\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport SettingsIcon from \"#/icons/settings-gear.svg?react\";\nimport CloseIcon from \"#/icons/close.svg?react\";\nimport { SettingsNavRenderedItem } from \"#/hooks/use-settings-nav-items\";\nimport { SettingsNavHeader } from \"./settings-nav-header\";\nimport { SettingsNavDivider } from \"./settings-nav-divider\";\nimport { SettingsNavLink } from \"./settings-nav-link\";\nimport { SidebarNavLink } from \"#/components/features/sidebar/sidebar-nav-link\";\nimport { navInteractiveTransitionClassName } from \"#/components/features/sidebar/sidebar-layout\";\nimport { BackendSyncedSettingsBadge } from \"#/components/features/settings/backend-synced-settings-badge\";\n\ninterface SettingsNavigationProps {\n isMobileMenuOpen: boolean;\n onCloseMobileMenu: () => void;\n navigationItems: SettingsNavRenderedItem[];\n}\n\n/**\n * Desktop sidebar — sibling of the scrolling main column (same pattern as\n * {@link ExtensionsNavigation}). Mobile drawer stays `position: fixed` outside\n * this row in the layout.\n */\nexport function SettingsDesktopSidebar({\n navigationItems,\n}: Pick<SettingsNavigationProps, \"navigationItems\">) {\n const { t } = useTranslation(\"openhands\");\n const desktopNavItems = navigationItems.filter(\n (item): item is Extract<SettingsNavRenderedItem, { type: \"item\" }> =>\n item.type === \"item\",\n );\n\n return (\n <aside\n data-testid=\"settings-navbar-desktop\"\n className={cn(\n \"hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2\",\n \"md:sticky md:top-8 md:self-start md:pl-8\",\n )}\n >\n <Typography.Text className=\"px-2 text-sm font-normal text-white\">\n {t(I18nKey.SETTINGS$TITLE)}\n </Typography.Text>\n <div className=\"flex flex-col gap-0.5 pt-0.5\">\n {desktopNavItems.map((renderedItem) => (\n <SidebarNavLink\n key={renderedItem.item.to}\n to={renderedItem.item.to}\n label={t(renderedItem.item.text as I18nKey)}\n end\n testId={`sidebar-settings-${renderedItem.item.to}`}\n icon={renderedItem.item.icon}\n // Items marked ``disabledByAcp`` (LLM, Condenser, …) are greyed\n // out and un-clickable while an ACP agent is active — those\n // pages have nothing to configure while a separate sub-agent\n // owns the LLM/condenser/MCP layers. The mobile drawer below\n // already does this via ``SettingsNavLink``; do the same on\n // desktop. The clientLoader-side redirect in ``routes/\n // settings.tsx`` handles direct URL navigation.\n disabled={renderedItem.disabled}\n disabledReason={\n renderedItem.disabled && renderedItem.disabledAgentName\n ? t(I18nKey.SETTINGS$AGENT_DISABLED_TOOLTIP, {\n agentName: renderedItem.disabledAgentName,\n })\n : undefined\n }\n />\n ))}\n </div>\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </aside>\n );\n}\n\n/**\n * Mobile overlay + drawer. Rendered outside the scrolling flex row so `position:\n * fixed` does not interact with flex item sizing on desktop.\n */\nexport function SettingsMobileDrawer({\n isMobileMenuOpen,\n onCloseMobileMenu,\n navigationItems,\n}: SettingsNavigationProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <>\n {isMobileMenuOpen && (\n <div\n className=\"fixed inset-0 z-40 bg-black bg-opacity-50 md:hidden\"\n onClick={onCloseMobileMenu}\n />\n )}\n <nav\n data-testid=\"settings-navbar\"\n className={cn(\n \"flex flex-col gap-6 transition-transform duration-300 ease-in-out\",\n \"fixed inset-0 z-50 w-full bg-[var(--oh-surface-deep)] p-4 transform md:hidden\",\n isMobileMenuOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"ml-1 flex items-center gap-2 sm:ml-4.5\">\n <SettingsIcon width={16} height={16} />\n <Typography.H2>{t(I18nKey.SETTINGS$TITLE)}</Typography.H2>\n </div>\n <button\n type=\"button\"\n onClick={onCloseMobileMenu}\n className={cn(\n \"cursor-pointer rounded-md p-0.5 hover:bg-tertiary md:hidden\",\n navInteractiveTransitionClassName,\n )}\n aria-label
|
|
1
|
+
{"version":3,"file":"settings-navigation.js","names":[],"sources":["../../../../src/components/features/settings/settings-navigation.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport { cn } from \"#/utils/utils\";\nimport { Typography } from \"#/ui/typography\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport SettingsIcon from \"#/icons/settings-gear.svg?react\";\nimport CloseIcon from \"#/icons/close.svg?react\";\nimport { SettingsNavRenderedItem } from \"#/hooks/use-settings-nav-items\";\nimport { SettingsNavHeader } from \"./settings-nav-header\";\nimport { SettingsNavDivider } from \"./settings-nav-divider\";\nimport { SettingsNavLink } from \"./settings-nav-link\";\nimport { SidebarNavLink } from \"#/components/features/sidebar/sidebar-nav-link\";\nimport { navInteractiveTransitionClassName } from \"#/components/features/sidebar/sidebar-layout\";\nimport { BackendSyncedSettingsBadge } from \"#/components/features/settings/backend-synced-settings-badge\";\n\ninterface SettingsNavigationProps {\n isMobileMenuOpen: boolean;\n onCloseMobileMenu: () => void;\n navigationItems: SettingsNavRenderedItem[];\n}\n\n/**\n * Desktop sidebar — sibling of the scrolling main column (same pattern as\n * {@link ExtensionsNavigation}). Mobile drawer stays `position: fixed` outside\n * this row in the layout.\n */\nexport function SettingsDesktopSidebar({\n navigationItems,\n}: Pick<SettingsNavigationProps, \"navigationItems\">) {\n const { t } = useTranslation(\"openhands\");\n const desktopNavItems = navigationItems.filter(\n (item): item is Extract<SettingsNavRenderedItem, { type: \"item\" }> =>\n item.type === \"item\",\n );\n\n return (\n <aside\n data-testid=\"settings-navbar-desktop\"\n className={cn(\n \"hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2\",\n \"md:sticky md:top-8 md:self-start md:pl-8\",\n )}\n >\n <Typography.Text className=\"px-2 text-sm font-normal text-white\">\n {t(I18nKey.SETTINGS$TITLE)}\n </Typography.Text>\n <div className=\"flex flex-col gap-0.5 pt-0.5\">\n {desktopNavItems.map((renderedItem) => (\n <SidebarNavLink\n key={renderedItem.item.to}\n to={renderedItem.item.to}\n label={t(renderedItem.item.text as I18nKey)}\n end\n testId={`sidebar-settings-${renderedItem.item.to}`}\n icon={renderedItem.item.icon}\n // Items marked ``disabledByAcp`` (LLM, Condenser, …) are greyed\n // out and un-clickable while an ACP agent is active — those\n // pages have nothing to configure while a separate sub-agent\n // owns the LLM/condenser/MCP layers. The mobile drawer below\n // already does this via ``SettingsNavLink``; do the same on\n // desktop. The clientLoader-side redirect in ``routes/\n // settings.tsx`` handles direct URL navigation.\n disabled={renderedItem.disabled}\n disabledReason={\n renderedItem.disabled && renderedItem.disabledAgentName\n ? t(I18nKey.SETTINGS$AGENT_DISABLED_TOOLTIP, {\n agentName: renderedItem.disabledAgentName,\n })\n : undefined\n }\n />\n ))}\n </div>\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </aside>\n );\n}\n\n/**\n * Mobile overlay + drawer. Rendered outside the scrolling flex row so `position:\n * fixed` does not interact with flex item sizing on desktop.\n */\nexport function SettingsMobileDrawer({\n isMobileMenuOpen,\n onCloseMobileMenu,\n navigationItems,\n}: SettingsNavigationProps) {\n const { t } = useTranslation(\"openhands\");\n\n return (\n <>\n {isMobileMenuOpen && (\n <div\n className=\"fixed inset-0 z-40 bg-black bg-opacity-50 md:hidden\"\n onClick={onCloseMobileMenu}\n />\n )}\n <nav\n data-testid=\"settings-navbar\"\n className={cn(\n \"flex flex-col gap-6 transition-transform duration-300 ease-in-out\",\n \"fixed inset-0 z-50 w-full bg-[var(--oh-surface-deep)] p-4 transform md:hidden\",\n isMobileMenuOpen ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"ml-1 flex items-center gap-2 sm:ml-4.5\">\n <SettingsIcon width={16} height={16} />\n <Typography.H2>{t(I18nKey.SETTINGS$TITLE)}</Typography.H2>\n </div>\n <button\n type=\"button\"\n onClick={onCloseMobileMenu}\n className={cn(\n \"cursor-pointer rounded-md p-0.5 hover:bg-tertiary md:hidden\",\n navInteractiveTransitionClassName,\n )}\n aria-label={t(I18nKey.SIDEBAR$CLOSE_MENU)}\n >\n <CloseIcon width={32} height={32} />\n </button>\n </div>\n\n <div className=\"flex flex-col gap-2\">\n {navigationItems.map((renderedItem, index) => {\n if (renderedItem.type === \"header\") {\n return (\n <SettingsNavHeader\n key={`header-${renderedItem.text}`}\n text={renderedItem.text}\n />\n );\n }\n\n if (renderedItem.type === \"divider\") {\n return <SettingsNavDivider key={`divider-${index}`} />;\n }\n\n return (\n <SettingsNavLink\n key={renderedItem.item.to}\n item={renderedItem.item}\n onClick={onCloseMobileMenu}\n disabled={renderedItem.disabled}\n disabledAgentName={renderedItem.disabledAgentName}\n />\n );\n })}\n </div>\n\n <div className=\"px-2 pt-3\">\n <BackendSyncedSettingsBadge />\n </div>\n </nav>\n </>\n );\n}\n\nexport function SettingsNavigation(props: SettingsNavigationProps) {\n return (\n <>\n <SettingsDesktopSidebar navigationItems={props.navigationItems} />\n <SettingsMobileDrawer {...props} />\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAyBA,SAAgB,EAAuB,EACrC,sBACmD;CACnD,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,IAAkB,EAAgB,QACrC,MACC,EAAK,SAAS,OACjB;AAED,QACE,kBAAC,SAAD;EACE,eAAY;EACZ,WAAW,EACT,gEACA,2CACD;YALH;GAOE,kBAAC,EAAW,MAAZ;IAAiB,WAAU;cACxB,EAAE,EAAQ,eAAe;IACV,CAAA;GAClB,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAgB,KAAK,MACpB,kBAAC,GAAD;KAEE,IAAI,EAAa,KAAK;KACtB,OAAO,EAAE,EAAa,KAAK,KAAgB;KAC3C,KAAA;KACA,QAAQ,oBAAoB,EAAa,KAAK;KAC9C,MAAM,EAAa,KAAK;KAQxB,UAAU,EAAa;KACvB,gBACE,EAAa,YAAY,EAAa,oBAClC,EAAE,EAAQ,iCAAiC,EACzC,WAAW,EAAa,mBACzB,CAAC,GACF,KAAA;KAEN,EArBK,EAAa,KAAK,GAqBvB,CACF;IACE,CAAA;GACN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAA8B,CAAA;IAC1B,CAAA;GACA;;;AAQZ,SAAgB,EAAqB,EACnC,qBACA,sBACA,sBAC0B;CAC1B,IAAM,EAAE,SAAM,EAAe,YAAY;AAEzC,QACE,kBAAA,GAAA,EAAA,UAAA,CACG,KACC,kBAAC,OAAD;EACE,WAAU;EACV,SAAS;EACT,CAAA,EAEJ,kBAAC,OAAD;EACE,eAAY;EACZ,WAAW,EACT,qEACA,iFACA,IAAmB,kBAAkB,oBACtC;YANH;GAQE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAc,OAAO;MAAI,QAAQ;MAAM,CAAA,EACvC,kBAAC,EAAW,IAAZ,EAAA,UAAgB,EAAE,EAAQ,eAAe,EAAiB,CAAA,CACtD;QACN,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAW,EACT,+DACA,EACD;KACD,cAAY,EAAE,EAAQ,mBAAmB;eAEzC,kBAAC,GAAD;MAAW,OAAO;MAAI,QAAQ;MAAM,CAAA;KAC7B,CAAA,CACL;;GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAgB,KAAK,GAAc,MAC9B,EAAa,SAAS,WAEtB,kBAAC,GAAD,EAEE,MAAM,EAAa,MACnB,EAFK,UAAU,EAAa,OAE5B,GAIF,EAAa,SAAS,YACjB,kBAAC,GAAD,EAA+C,EAAtB,WAAW,IAAW,GAItD,kBAAC,GAAD;KAEE,MAAM,EAAa;KACnB,SAAS;KACT,UAAU,EAAa;KACvB,mBAAmB,EAAa;KAChC,EALK,EAAa,KAAK,GAKvB,CAEJ;IACE,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAA8B,CAAA;IAC1B,CAAA;GACF;IACL,EAAA,CAAA;;AAIP,SAAgB,EAAmB,GAAgC;AACjE,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAwB,iBAAiB,EAAM,iBAAmB,CAAA,EAClE,kBAAC,GAAD,EAAsB,GAAI,GAAS,CAAA,CAClC,EAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/utils.cjs`),i=require(`../../../context/navigation-context.cjs`),a=require(`../../../utils/custom-toast-handlers.cjs`),o=require(`../../../contexts/active-backend-context.cjs`),s=require(`../../../hooks/query/use-settings.cjs`),c=require(`../../../hooks/use-click-outside-element.cjs`),l=require(`../../../hooks/query/use-config.cjs`),ee=require(`./sidebar-mobile-nav-context.cjs`),u=require(`../../../hooks/query/use-backends-health.cjs`),d=require(`./sidebar-rail-body.cjs`),f=require(`../../../stores/sidebar-store.cjs`);let p=require(`react`);p=e.__toESM(p,1);let m=require(`react/jsx-runtime`);var h=p.default.lazy(()=>Promise.resolve().then(()=>require(`../../shared/modals/settings/settings-modal.cjs`)).then(e=>({default:e.SettingsModal}))),g=p.default.lazy(()=>Promise.resolve().then(()=>require(`../backends/add-backend-modal.cjs`)).then(e=>({default:e.AddBackendModal}))),_=p.default.lazy(()=>Promise.resolve().then(()=>require(`../backends/manage-backends-modal.cjs`)).then(e=>({default:e.ManageBackendsModal}))),v=250;function y(){let{t:e}=t.useTranslation(`openhands`),{currentPath:y}=i.useNavigation(),{data:b}=l.useConfig(),{data:x,error:S,isError:C,isFetching:w}=s.useSettings(),{backends:T,active:E}=o.useActiveBackendContext(),D=u.useBackendsHealth(T)[E.backend.id],O=f.useSidebarStore(e=>e.collapsed),k=f.useSidebarStore(e=>e.setCollapsed),[A,j]=p.default.useState(!1),[M,N]=p.default.useState(!1),P=p.default.useRef(null),[F,I]=p.default.useState(!1),[L,R]=p.default.useState(!1),[z,B]=p.default.useState(!1),V=p.default.useRef(!1),[,H]=p.default.useReducer(e=>e+1,0),{isOpen:U,close:W}=ee.useSidebarMobileNav(),[G,K]=p.default.useState(!1),[q,J]=p.default.useState(!1),Y=c.useClickOutsideElement(()=>N(!1)),X=s.getErrorStatus(S);p.default.useEffect(()=>{W()},[y,W]),p.default.useEffect(()=>{if(U){K(!0);let e=requestAnimationFrame(()=>{J(!0)});return()=>cancelAnimationFrame(e)}J(!1);let e=window.setTimeout(()=>{K(!1)},v);return()=>window.clearTimeout(e)},[U]),p.default.useEffect(()=>{if(!U)return;let e=e=>{e.key===`Escape`&&W()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[U,W]),p.default.useEffect(()=>{y===`/settings`?j(!1):!w&&C&&X!==404?a.displayErrorToast(
|
|
1
|
+
const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../i18n/declaration.cjs`),r=require(`../../../utils/utils.cjs`),i=require(`../../../context/navigation-context.cjs`),a=require(`../../../utils/custom-toast-handlers.cjs`),o=require(`../../../contexts/active-backend-context.cjs`),s=require(`../../../hooks/query/use-settings.cjs`),c=require(`../../../hooks/use-click-outside-element.cjs`),l=require(`../../../hooks/query/use-config.cjs`),ee=require(`./sidebar-mobile-nav-context.cjs`),u=require(`../../../hooks/query/use-backends-health.cjs`),d=require(`./sidebar-rail-body.cjs`),f=require(`../../../stores/sidebar-store.cjs`);let p=require(`react`);p=e.__toESM(p,1);let m=require(`react/jsx-runtime`);var h=p.default.lazy(()=>Promise.resolve().then(()=>require(`../../shared/modals/settings/settings-modal.cjs`)).then(e=>({default:e.SettingsModal}))),g=p.default.lazy(()=>Promise.resolve().then(()=>require(`../backends/add-backend-modal.cjs`)).then(e=>({default:e.AddBackendModal}))),_=p.default.lazy(()=>Promise.resolve().then(()=>require(`../backends/manage-backends-modal.cjs`)).then(e=>({default:e.ManageBackendsModal}))),v=250;function y(){let{t:e}=t.useTranslation(`openhands`),{currentPath:y}=i.useNavigation(),{data:b}=l.useConfig(),{data:x,error:S,isError:C,isFetching:w}=s.useSettings(),{backends:T,active:E}=o.useActiveBackendContext(),D=u.useBackendsHealth(T)[E.backend.id],O=f.useSidebarStore(e=>e.collapsed),k=f.useSidebarStore(e=>e.setCollapsed),[A,j]=p.default.useState(!1),[M,N]=p.default.useState(!1),P=p.default.useRef(null),[F,I]=p.default.useState(!1),[L,R]=p.default.useState(!1),[z,B]=p.default.useState(!1),V=p.default.useRef(!1),[,H]=p.default.useReducer(e=>e+1,0),{isOpen:U,close:W}=ee.useSidebarMobileNav(),[G,K]=p.default.useState(!1),[q,J]=p.default.useState(!1),Y=c.useClickOutsideElement(()=>N(!1)),X=s.getErrorStatus(S);p.default.useEffect(()=>{W()},[y,W]),p.default.useEffect(()=>{if(U){K(!0);let e=requestAnimationFrame(()=>{J(!0)});return()=>cancelAnimationFrame(e)}J(!1);let e=window.setTimeout(()=>{K(!1)},v);return()=>window.clearTimeout(e)},[U]),p.default.useEffect(()=>{if(!U)return;let e=e=>{e.key===`Escape`&&W()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[U,W]),p.default.useEffect(()=>{y===`/settings`?j(!1):!w&&C&&X!==404?a.displayErrorToast(e(n.I18nKey.SETTINGS$FETCH_ERROR)):X===404&&!b?.feature_flags?.hide_llm_settings&&j(!0)},[y,w,C,X,b?.feature_flags?.hide_llm_settings,e]);let Z=x?.email_verified===!1,Q=e(O?n.I18nKey.SIDEBAR$EXPAND:n.I18nKey.SIDEBAR$COLLAPSE),te=p.default.useCallback(e=>{if(!O)return;let t=e.target;t instanceof HTMLElement&&(t.closest(`a,button,input,textarea,select,[role='button'],[role='link']`)||k(!1))},[O,k]),$={linkDisabled:Z,collapseToggleLabel:Q,onCollapse:p.default.useCallback(()=>{B(!1),V.current=!0,H(),k(!0),window.setTimeout(()=>{V.current=!1,H()},250)},[k]),onExpand:()=>k(!1),showCollapsedExpandButton:O&&z&&!V.current,isExtensionsActive:y===`/customize`||y.startsWith(`/skills`)||y===`/plugins`||y===`/mcp`,currentPath:y,activeBackendHealth:D,collapsedBackendPopoverOpen:M,setCollapsedBackendPopoverOpen:N,collapsedBackendPopoverRef:Y,collapsedBackendCloseTimer:P,onOpenAddBackend:()=>I(!0),onOpenManageBackends:()=>R(!0)};return(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`aside`,{"aria-label":e(n.I18nKey.SIDEBAR$NAVIGATION_LABEL),"data-collapsed":O?`true`:`false`,onClick:te,onMouseEnter:()=>{O&&B(!0)},onMouseLeave:()=>{B(!1)},className:r.cn(`max-md:hidden flex bg-base flex-col min-h-0 transition-[width,min-width] duration-200`,`md:border-r md:border-[var(--oh-border)] md:h-full`,O?`md:w-[60px] md:min-w-[60px] md:px-2.5`:`md:w-[300px] md:min-w-[300px] pb-2 md:pl-2.5 md:pr-0`,y===`/`&&`md:pb-3`),children:(0,m.jsx)(d.SidebarRailBody,{collapsed:O,showCollapseToggle:!0,...$})}),G?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`div`,{className:r.cn(`fixed inset-0 z-40 bg-black/50 md:hidden`,`transition-opacity ease-in-out motion-reduce:transition-none`,q?`opacity-100`:`pointer-events-none opacity-0`),style:{transitionDuration:`${v}ms`},onClick:W,"aria-hidden":!q}),(0,m.jsx)(`aside`,{"aria-label":e(n.I18nKey.SIDEBAR$NAVIGATION_LABEL),"data-testid":`sidebar-mobile-drawer`,"aria-hidden":!q,className:r.cn(`fixed inset-y-0 left-0 z-50 flex min-h-0 w-[min(300px,85vw)] flex-col bg-base`,`border-r border-[var(--oh-border)] pb-2 pl-2.5 pr-0 md:hidden`,`transition-transform ease-in-out motion-reduce:transition-none`,q?`translate-x-0`:`-translate-x-full`),style:{transitionDuration:`${v}ms`},children:(0,m.jsx)(d.SidebarRailBody,{collapsed:!1,showCollapseToggle:!1,showMobileCloseButton:!0,onCloseMobile:W,...$})})]}):null,A&&(0,m.jsx)(p.default.Suspense,{fallback:null,children:(0,m.jsx)(h,{settings:x,onClose:()=>j(!1)})}),F&&(0,m.jsx)(p.default.Suspense,{fallback:null,children:(0,m.jsx)(g,{onClose:()=>I(!1)})}),L&&(0,m.jsx)(p.default.Suspense,{fallback:null,children:(0,m.jsx)(_,{onClose:()=>R(!1)})})]})}exports.Sidebar=y;
|
|
2
2
|
//# sourceMappingURL=sidebar.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.cjs","names":[],"sources":["../../../../src/components/features/sidebar/sidebar.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SidebarRailBody } from \"./sidebar-rail-body\";\nimport { getErrorStatus, useSettings } from \"#/hooks/query/use-settings\";\nimport { useConfig } from \"#/hooks/query/use-config\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { cn } from \"#/utils/utils\";\nimport { useSidebarMobileNav } from \"./sidebar-mobile-nav-context\";\nimport { useSidebarStore } from \"#/stores/sidebar-store\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\n// The LLM settings modal is only mounted when the settings query 404s and\n// LLM settings aren't hidden — keep it out of the sidebar's eager graph.\nconst SettingsModal = React.lazy(() =>\n import(\"#/components/shared/modals/settings/settings-modal\").then((m) => ({\n default: m.SettingsModal,\n })),\n);\n\n// Add/Manage backend modals are lifted into the sidebar (instead of living\n// inside BackendSelector) so they survive the collapsed popover unmounting\n// when the user moves the cursor out of the popover toward the modal.\nconst AddBackendModal = React.lazy(() =>\n import(\"#/components/features/backends/add-backend-modal\").then((m) => ({\n default: m.AddBackendModal,\n })),\n);\nconst ManageBackendsModal = React.lazy(() =>\n import(\"#/components/features/backends/manage-backends-modal\").then((m) => ({\n default: m.ManageBackendsModal,\n })),\n);\n\nconst MOBILE_DRAWER_TRANSITION_MS = 250;\n\nexport function Sidebar() {\n const { t } = useTranslation(\"openhands\");\n const { currentPath } = useNavigation();\n const { data: config } = useConfig();\n const {\n data: settings,\n error: settingsError,\n isError: settingsIsError,\n isFetching: isFetchingSettings,\n } = useSettings();\n const { backends, active } = useActiveBackendContext();\n const healthByBackendId = useBackendsHealth(backends);\n const activeBackendHealth = healthByBackendId[active.backend.id];\n const collapsed = useSidebarStore((state) => state.collapsed);\n const setCollapsed = useSidebarStore((state) => state.setCollapsed);\n const [settingsModalIsOpen, setSettingsModalIsOpen] = React.useState(false);\n const [collapsedBackendPopoverOpen, setCollapsedBackendPopoverOpen] =\n React.useState(false);\n const collapsedBackendCloseTimer = React.useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n // Lifted out of BackendSelector so opening these modals from the\n // collapsed-sidebar popover doesn't lose state when the popover unmounts\n // (cursor moving toward the modal triggers onMouseLeave -> close).\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n const [collapsedRailHovered, setCollapsedRailHovered] = React.useState(false);\n const suppressCollapsedExpandRef = React.useRef(false);\n const [, refreshCollapsedExpandGate] = React.useReducer((n) => n + 1, 0);\n const { isOpen: isMobileNavOpen, close: closeMobileNav } =\n useSidebarMobileNav();\n const [mobileDrawerMounted, setMobileDrawerMounted] = React.useState(false);\n const [mobileDrawerVisible, setMobileDrawerVisible] = React.useState(false);\n const collapsedBackendPopoverRef = useClickOutsideElement<HTMLDivElement>(\n () => setCollapsedBackendPopoverOpen(false),\n );\n const settingsErrorStatus = getErrorStatus(settingsError);\n\n React.useEffect(() => {\n closeMobileNav();\n }, [currentPath, closeMobileNav]);\n\n React.useEffect(() => {\n if (isMobileNavOpen) {\n setMobileDrawerMounted(true);\n const frame = requestAnimationFrame(() => {\n setMobileDrawerVisible(true);\n });\n return () => cancelAnimationFrame(frame);\n }\n\n setMobileDrawerVisible(false);\n const timer = window.setTimeout(() => {\n setMobileDrawerMounted(false);\n }, MOBILE_DRAWER_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [isMobileNavOpen]);\n\n React.useEffect(() => {\n if (!isMobileNavOpen) {\n return undefined;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMobileNav();\n }\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [isMobileNavOpen, closeMobileNav]);\n\n React.useEffect(() => {\n if (currentPath === \"/settings\") {\n setSettingsModalIsOpen(false);\n } else if (\n !isFetchingSettings &&\n settingsIsError &&\n settingsErrorStatus !== 404\n ) {\n // We don't show toast errors for settings in the global error handler\n // because we have a special case for 404 errors\n displayErrorToast(\n \"Something went wrong while fetching settings. Please reload the page.\",\n );\n } else if (\n settingsErrorStatus === 404 &&\n !config?.feature_flags?.hide_llm_settings\n ) {\n setSettingsModalIsOpen(true);\n }\n }, [\n currentPath,\n isFetchingSettings,\n settingsIsError,\n settingsErrorStatus,\n config?.feature_flags?.hide_llm_settings,\n ]);\n\n const linkDisabled = settings?.email_verified === false;\n\n const collapseToggleLabel = t(\n collapsed ? I18nKey.SIDEBAR$EXPAND : I18nKey.SIDEBAR$COLLAPSE,\n );\n const handleCollapsedRailClick = React.useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n if (!collapsed) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n // Keep existing behavior for explicit controls/links and only use\n // this as a convenience hit-area for empty collapsed-rail space.\n if (\n target.closest(\n \"a,button,input,textarea,select,[role='button'],[role='link']\",\n )\n ) {\n return;\n }\n\n setCollapsed(false);\n },\n [collapsed, setCollapsed],\n );\n const handleCollapse = React.useCallback(() => {\n setCollapsedRailHovered(false);\n suppressCollapsedExpandRef.current = true;\n refreshCollapsedExpandGate();\n setCollapsed(true);\n window.setTimeout(() => {\n suppressCollapsedExpandRef.current = false;\n refreshCollapsedExpandGate();\n }, 250);\n }, [setCollapsed]);\n const showCollapsedExpandButton =\n collapsed && collapsedRailHovered && !suppressCollapsedExpandRef.current;\n\n const isExtensionsActive =\n currentPath === \"/customize\" ||\n currentPath.startsWith(\"/skills\") ||\n currentPath === \"/plugins\" ||\n currentPath === \"/mcp\";\n\n const railBodyProps = {\n linkDisabled,\n collapseToggleLabel,\n onCollapse: handleCollapse,\n onExpand: () => setCollapsed(false),\n showCollapsedExpandButton,\n isExtensionsActive,\n currentPath,\n activeBackendHealth,\n collapsedBackendPopoverOpen,\n setCollapsedBackendPopoverOpen,\n collapsedBackendPopoverRef,\n collapsedBackendCloseTimer,\n onOpenAddBackend: () => setAddBackendModalOpen(true),\n onOpenManageBackends: () => setManageBackendsModalOpen(true),\n };\n\n return (\n <>\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the aside acts as a hit-area for the collapsed rail; nested controls handle their own keyboard interactions. */}\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-collapsed={collapsed ? \"true\" : \"false\"}\n onClick={handleCollapsedRailClick}\n onMouseEnter={() => {\n if (collapsed) {\n setCollapsedRailHovered(true);\n }\n }}\n onMouseLeave={() => {\n setCollapsedRailHovered(false);\n }}\n className={cn(\n \"max-md:hidden flex bg-base flex-col min-h-0 transition-[width,min-width] duration-200\",\n \"md:border-r md:border-[var(--oh-border)] md:h-full\",\n collapsed\n ? \"md:w-[60px] md:min-w-[60px] md:px-2.5\"\n : \"md:w-[300px] md:min-w-[300px] pb-2 md:pl-2.5 md:pr-0\",\n currentPath === \"/\" && \"md:pb-3\",\n )}\n >\n <SidebarRailBody\n collapsed={collapsed}\n showCollapseToggle\n {...railBodyProps}\n />\n </aside>\n\n {mobileDrawerMounted ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 z-40 bg-black/50 md:hidden\",\n \"transition-opacity ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible\n ? \"opacity-100\"\n : \"pointer-events-none opacity-0\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n onClick={closeMobileNav}\n aria-hidden={!mobileDrawerVisible}\n />\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-testid=\"sidebar-mobile-drawer\"\n aria-hidden={!mobileDrawerVisible}\n className={cn(\n \"fixed inset-y-0 left-0 z-50 flex min-h-0 w-[min(300px,85vw)] flex-col bg-base\",\n \"border-r border-[var(--oh-border)] pb-2 pl-2.5 pr-0 md:hidden\",\n \"transition-transform ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n >\n <SidebarRailBody\n collapsed={false}\n showCollapseToggle={false}\n showMobileCloseButton\n onCloseMobile={closeMobileNav}\n {...railBodyProps}\n />\n </aside>\n </>\n ) : null}\n\n {settingsModalIsOpen && (\n <React.Suspense fallback={null}>\n <SettingsModal\n settings={settings}\n onClose={() => setSettingsModalIsOpen(false)}\n />\n </React.Suspense>\n )}\n {addBackendModalOpen && (\n <React.Suspense fallback={null}>\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n </React.Suspense>\n )}\n {manageBackendsModalOpen && (\n <React.Suspense fallback={null}>\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n </React.Suspense>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sidebar.cjs","names":[],"sources":["../../../../src/components/features/sidebar/sidebar.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SidebarRailBody } from \"./sidebar-rail-body\";\nimport { getErrorStatus, useSettings } from \"#/hooks/query/use-settings\";\nimport { useConfig } from \"#/hooks/query/use-config\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { cn } from \"#/utils/utils\";\nimport { useSidebarMobileNav } from \"./sidebar-mobile-nav-context\";\nimport { useSidebarStore } from \"#/stores/sidebar-store\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\n// The LLM settings modal is only mounted when the settings query 404s and\n// LLM settings aren't hidden — keep it out of the sidebar's eager graph.\nconst SettingsModal = React.lazy(() =>\n import(\"#/components/shared/modals/settings/settings-modal\").then((m) => ({\n default: m.SettingsModal,\n })),\n);\n\n// Add/Manage backend modals are lifted into the sidebar (instead of living\n// inside BackendSelector) so they survive the collapsed popover unmounting\n// when the user moves the cursor out of the popover toward the modal.\nconst AddBackendModal = React.lazy(() =>\n import(\"#/components/features/backends/add-backend-modal\").then((m) => ({\n default: m.AddBackendModal,\n })),\n);\nconst ManageBackendsModal = React.lazy(() =>\n import(\"#/components/features/backends/manage-backends-modal\").then((m) => ({\n default: m.ManageBackendsModal,\n })),\n);\n\nconst MOBILE_DRAWER_TRANSITION_MS = 250;\n\nexport function Sidebar() {\n const { t } = useTranslation(\"openhands\");\n const { currentPath } = useNavigation();\n const { data: config } = useConfig();\n const {\n data: settings,\n error: settingsError,\n isError: settingsIsError,\n isFetching: isFetchingSettings,\n } = useSettings();\n const { backends, active } = useActiveBackendContext();\n const healthByBackendId = useBackendsHealth(backends);\n const activeBackendHealth = healthByBackendId[active.backend.id];\n const collapsed = useSidebarStore((state) => state.collapsed);\n const setCollapsed = useSidebarStore((state) => state.setCollapsed);\n const [settingsModalIsOpen, setSettingsModalIsOpen] = React.useState(false);\n const [collapsedBackendPopoverOpen, setCollapsedBackendPopoverOpen] =\n React.useState(false);\n const collapsedBackendCloseTimer = React.useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n // Lifted out of BackendSelector so opening these modals from the\n // collapsed-sidebar popover doesn't lose state when the popover unmounts\n // (cursor moving toward the modal triggers onMouseLeave -> close).\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n const [collapsedRailHovered, setCollapsedRailHovered] = React.useState(false);\n const suppressCollapsedExpandRef = React.useRef(false);\n const [, refreshCollapsedExpandGate] = React.useReducer((n) => n + 1, 0);\n const { isOpen: isMobileNavOpen, close: closeMobileNav } =\n useSidebarMobileNav();\n const [mobileDrawerMounted, setMobileDrawerMounted] = React.useState(false);\n const [mobileDrawerVisible, setMobileDrawerVisible] = React.useState(false);\n const collapsedBackendPopoverRef = useClickOutsideElement<HTMLDivElement>(\n () => setCollapsedBackendPopoverOpen(false),\n );\n const settingsErrorStatus = getErrorStatus(settingsError);\n\n React.useEffect(() => {\n closeMobileNav();\n }, [currentPath, closeMobileNav]);\n\n React.useEffect(() => {\n if (isMobileNavOpen) {\n setMobileDrawerMounted(true);\n const frame = requestAnimationFrame(() => {\n setMobileDrawerVisible(true);\n });\n return () => cancelAnimationFrame(frame);\n }\n\n setMobileDrawerVisible(false);\n const timer = window.setTimeout(() => {\n setMobileDrawerMounted(false);\n }, MOBILE_DRAWER_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [isMobileNavOpen]);\n\n React.useEffect(() => {\n if (!isMobileNavOpen) {\n return undefined;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMobileNav();\n }\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [isMobileNavOpen, closeMobileNav]);\n\n React.useEffect(() => {\n if (currentPath === \"/settings\") {\n setSettingsModalIsOpen(false);\n } else if (\n !isFetchingSettings &&\n settingsIsError &&\n settingsErrorStatus !== 404\n ) {\n // We don't show toast errors for settings in the global error handler\n // because we have a special case for 404 errors\n displayErrorToast(t(I18nKey.SETTINGS$FETCH_ERROR));\n } else if (\n settingsErrorStatus === 404 &&\n !config?.feature_flags?.hide_llm_settings\n ) {\n setSettingsModalIsOpen(true);\n }\n }, [\n currentPath,\n isFetchingSettings,\n settingsIsError,\n settingsErrorStatus,\n config?.feature_flags?.hide_llm_settings,\n t,\n ]);\n\n const linkDisabled = settings?.email_verified === false;\n\n const collapseToggleLabel = t(\n collapsed ? I18nKey.SIDEBAR$EXPAND : I18nKey.SIDEBAR$COLLAPSE,\n );\n const handleCollapsedRailClick = React.useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n if (!collapsed) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n // Keep existing behavior for explicit controls/links and only use\n // this as a convenience hit-area for empty collapsed-rail space.\n if (\n target.closest(\n \"a,button,input,textarea,select,[role='button'],[role='link']\",\n )\n ) {\n return;\n }\n\n setCollapsed(false);\n },\n [collapsed, setCollapsed],\n );\n const handleCollapse = React.useCallback(() => {\n setCollapsedRailHovered(false);\n suppressCollapsedExpandRef.current = true;\n refreshCollapsedExpandGate();\n setCollapsed(true);\n window.setTimeout(() => {\n suppressCollapsedExpandRef.current = false;\n refreshCollapsedExpandGate();\n }, 250);\n }, [setCollapsed]);\n const showCollapsedExpandButton =\n collapsed && collapsedRailHovered && !suppressCollapsedExpandRef.current;\n\n const isExtensionsActive =\n currentPath === \"/customize\" ||\n currentPath.startsWith(\"/skills\") ||\n currentPath === \"/plugins\" ||\n currentPath === \"/mcp\";\n\n const railBodyProps = {\n linkDisabled,\n collapseToggleLabel,\n onCollapse: handleCollapse,\n onExpand: () => setCollapsed(false),\n showCollapsedExpandButton,\n isExtensionsActive,\n currentPath,\n activeBackendHealth,\n collapsedBackendPopoverOpen,\n setCollapsedBackendPopoverOpen,\n collapsedBackendPopoverRef,\n collapsedBackendCloseTimer,\n onOpenAddBackend: () => setAddBackendModalOpen(true),\n onOpenManageBackends: () => setManageBackendsModalOpen(true),\n };\n\n return (\n <>\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the aside acts as a hit-area for the collapsed rail; nested controls handle their own keyboard interactions. */}\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-collapsed={collapsed ? \"true\" : \"false\"}\n onClick={handleCollapsedRailClick}\n onMouseEnter={() => {\n if (collapsed) {\n setCollapsedRailHovered(true);\n }\n }}\n onMouseLeave={() => {\n setCollapsedRailHovered(false);\n }}\n className={cn(\n \"max-md:hidden flex bg-base flex-col min-h-0 transition-[width,min-width] duration-200\",\n \"md:border-r md:border-[var(--oh-border)] md:h-full\",\n collapsed\n ? \"md:w-[60px] md:min-w-[60px] md:px-2.5\"\n : \"md:w-[300px] md:min-w-[300px] pb-2 md:pl-2.5 md:pr-0\",\n currentPath === \"/\" && \"md:pb-3\",\n )}\n >\n <SidebarRailBody\n collapsed={collapsed}\n showCollapseToggle\n {...railBodyProps}\n />\n </aside>\n\n {mobileDrawerMounted ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 z-40 bg-black/50 md:hidden\",\n \"transition-opacity ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible\n ? \"opacity-100\"\n : \"pointer-events-none opacity-0\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n onClick={closeMobileNav}\n aria-hidden={!mobileDrawerVisible}\n />\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-testid=\"sidebar-mobile-drawer\"\n aria-hidden={!mobileDrawerVisible}\n className={cn(\n \"fixed inset-y-0 left-0 z-50 flex min-h-0 w-[min(300px,85vw)] flex-col bg-base\",\n \"border-r border-[var(--oh-border)] pb-2 pl-2.5 pr-0 md:hidden\",\n \"transition-transform ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n >\n <SidebarRailBody\n collapsed={false}\n showCollapseToggle={false}\n showMobileCloseButton\n onCloseMobile={closeMobileNav}\n {...railBodyProps}\n />\n </aside>\n </>\n ) : null}\n\n {settingsModalIsOpen && (\n <React.Suspense fallback={null}>\n <SettingsModal\n settings={settings}\n onClose={() => setSettingsModalIsOpen(false)}\n />\n </React.Suspense>\n )}\n {addBackendModalOpen && (\n <React.Suspense fallback={null}>\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n </React.Suspense>\n )}\n {manageBackendsModalOpen && (\n <React.Suspense fallback={null}>\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n </React.Suspense>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -39,13 +39,14 @@ function b() {
|
|
|
39
39
|
};
|
|
40
40
|
return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
|
|
41
41
|
}, [G, K]), f.useEffect(() => {
|
|
42
|
-
x === "/settings" ? N(!1) : !E && T && Q !== 404 ? i(
|
|
42
|
+
x === "/settings" ? N(!1) : !E && T && Q !== 404 ? i(b(t.SETTINGS$FETCH_ERROR)) : Q === 404 && !S?.feature_flags?.hide_llm_settings && N(!0);
|
|
43
43
|
}, [
|
|
44
44
|
x,
|
|
45
45
|
E,
|
|
46
46
|
T,
|
|
47
47
|
Q,
|
|
48
|
-
S?.feature_flags?.hide_llm_settings
|
|
48
|
+
S?.feature_flags?.hide_llm_settings,
|
|
49
|
+
b
|
|
49
50
|
]);
|
|
50
51
|
let ne = C?.email_verified === !1, re = b(A ? t.SIDEBAR$EXPAND : t.SIDEBAR$COLLAPSE), ie = f.useCallback((e) => {
|
|
51
52
|
if (!A) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.js","names":[],"sources":["../../../../src/components/features/sidebar/sidebar.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SidebarRailBody } from \"./sidebar-rail-body\";\nimport { getErrorStatus, useSettings } from \"#/hooks/query/use-settings\";\nimport { useConfig } from \"#/hooks/query/use-config\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { cn } from \"#/utils/utils\";\nimport { useSidebarMobileNav } from \"./sidebar-mobile-nav-context\";\nimport { useSidebarStore } from \"#/stores/sidebar-store\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\n// The LLM settings modal is only mounted when the settings query 404s and\n// LLM settings aren't hidden — keep it out of the sidebar's eager graph.\nconst SettingsModal = React.lazy(() =>\n import(\"#/components/shared/modals/settings/settings-modal\").then((m) => ({\n default: m.SettingsModal,\n })),\n);\n\n// Add/Manage backend modals are lifted into the sidebar (instead of living\n// inside BackendSelector) so they survive the collapsed popover unmounting\n// when the user moves the cursor out of the popover toward the modal.\nconst AddBackendModal = React.lazy(() =>\n import(\"#/components/features/backends/add-backend-modal\").then((m) => ({\n default: m.AddBackendModal,\n })),\n);\nconst ManageBackendsModal = React.lazy(() =>\n import(\"#/components/features/backends/manage-backends-modal\").then((m) => ({\n default: m.ManageBackendsModal,\n })),\n);\n\nconst MOBILE_DRAWER_TRANSITION_MS = 250;\n\nexport function Sidebar() {\n const { t } = useTranslation(\"openhands\");\n const { currentPath } = useNavigation();\n const { data: config } = useConfig();\n const {\n data: settings,\n error: settingsError,\n isError: settingsIsError,\n isFetching: isFetchingSettings,\n } = useSettings();\n const { backends, active } = useActiveBackendContext();\n const healthByBackendId = useBackendsHealth(backends);\n const activeBackendHealth = healthByBackendId[active.backend.id];\n const collapsed = useSidebarStore((state) => state.collapsed);\n const setCollapsed = useSidebarStore((state) => state.setCollapsed);\n const [settingsModalIsOpen, setSettingsModalIsOpen] = React.useState(false);\n const [collapsedBackendPopoverOpen, setCollapsedBackendPopoverOpen] =\n React.useState(false);\n const collapsedBackendCloseTimer = React.useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n // Lifted out of BackendSelector so opening these modals from the\n // collapsed-sidebar popover doesn't lose state when the popover unmounts\n // (cursor moving toward the modal triggers onMouseLeave -> close).\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n const [collapsedRailHovered, setCollapsedRailHovered] = React.useState(false);\n const suppressCollapsedExpandRef = React.useRef(false);\n const [, refreshCollapsedExpandGate] = React.useReducer((n) => n + 1, 0);\n const { isOpen: isMobileNavOpen, close: closeMobileNav } =\n useSidebarMobileNav();\n const [mobileDrawerMounted, setMobileDrawerMounted] = React.useState(false);\n const [mobileDrawerVisible, setMobileDrawerVisible] = React.useState(false);\n const collapsedBackendPopoverRef = useClickOutsideElement<HTMLDivElement>(\n () => setCollapsedBackendPopoverOpen(false),\n );\n const settingsErrorStatus = getErrorStatus(settingsError);\n\n React.useEffect(() => {\n closeMobileNav();\n }, [currentPath, closeMobileNav]);\n\n React.useEffect(() => {\n if (isMobileNavOpen) {\n setMobileDrawerMounted(true);\n const frame = requestAnimationFrame(() => {\n setMobileDrawerVisible(true);\n });\n return () => cancelAnimationFrame(frame);\n }\n\n setMobileDrawerVisible(false);\n const timer = window.setTimeout(() => {\n setMobileDrawerMounted(false);\n }, MOBILE_DRAWER_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [isMobileNavOpen]);\n\n React.useEffect(() => {\n if (!isMobileNavOpen) {\n return undefined;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMobileNav();\n }\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [isMobileNavOpen, closeMobileNav]);\n\n React.useEffect(() => {\n if (currentPath === \"/settings\") {\n setSettingsModalIsOpen(false);\n } else if (\n !isFetchingSettings &&\n settingsIsError &&\n settingsErrorStatus !== 404\n ) {\n // We don't show toast errors for settings in the global error handler\n // because we have a special case for 404 errors\n displayErrorToast(\n \"Something went wrong while fetching settings. Please reload the page.\",\n );\n } else if (\n settingsErrorStatus === 404 &&\n !config?.feature_flags?.hide_llm_settings\n ) {\n setSettingsModalIsOpen(true);\n }\n }, [\n currentPath,\n isFetchingSettings,\n settingsIsError,\n settingsErrorStatus,\n config?.feature_flags?.hide_llm_settings,\n ]);\n\n const linkDisabled = settings?.email_verified === false;\n\n const collapseToggleLabel = t(\n collapsed ? I18nKey.SIDEBAR$EXPAND : I18nKey.SIDEBAR$COLLAPSE,\n );\n const handleCollapsedRailClick = React.useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n if (!collapsed) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n // Keep existing behavior for explicit controls/links and only use\n // this as a convenience hit-area for empty collapsed-rail space.\n if (\n target.closest(\n \"a,button,input,textarea,select,[role='button'],[role='link']\",\n )\n ) {\n return;\n }\n\n setCollapsed(false);\n },\n [collapsed, setCollapsed],\n );\n const handleCollapse = React.useCallback(() => {\n setCollapsedRailHovered(false);\n suppressCollapsedExpandRef.current = true;\n refreshCollapsedExpandGate();\n setCollapsed(true);\n window.setTimeout(() => {\n suppressCollapsedExpandRef.current = false;\n refreshCollapsedExpandGate();\n }, 250);\n }, [setCollapsed]);\n const showCollapsedExpandButton =\n collapsed && collapsedRailHovered && !suppressCollapsedExpandRef.current;\n\n const isExtensionsActive =\n currentPath === \"/customize\" ||\n currentPath.startsWith(\"/skills\") ||\n currentPath === \"/plugins\" ||\n currentPath === \"/mcp\";\n\n const railBodyProps = {\n linkDisabled,\n collapseToggleLabel,\n onCollapse: handleCollapse,\n onExpand: () => setCollapsed(false),\n showCollapsedExpandButton,\n isExtensionsActive,\n currentPath,\n activeBackendHealth,\n collapsedBackendPopoverOpen,\n setCollapsedBackendPopoverOpen,\n collapsedBackendPopoverRef,\n collapsedBackendCloseTimer,\n onOpenAddBackend: () => setAddBackendModalOpen(true),\n onOpenManageBackends: () => setManageBackendsModalOpen(true),\n };\n\n return (\n <>\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the aside acts as a hit-area for the collapsed rail; nested controls handle their own keyboard interactions. */}\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-collapsed={collapsed ? \"true\" : \"false\"}\n onClick={handleCollapsedRailClick}\n onMouseEnter={() => {\n if (collapsed) {\n setCollapsedRailHovered(true);\n }\n }}\n onMouseLeave={() => {\n setCollapsedRailHovered(false);\n }}\n className={cn(\n \"max-md:hidden flex bg-base flex-col min-h-0 transition-[width,min-width] duration-200\",\n \"md:border-r md:border-[var(--oh-border)] md:h-full\",\n collapsed\n ? \"md:w-[60px] md:min-w-[60px] md:px-2.5\"\n : \"md:w-[300px] md:min-w-[300px] pb-2 md:pl-2.5 md:pr-0\",\n currentPath === \"/\" && \"md:pb-3\",\n )}\n >\n <SidebarRailBody\n collapsed={collapsed}\n showCollapseToggle\n {...railBodyProps}\n />\n </aside>\n\n {mobileDrawerMounted ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 z-40 bg-black/50 md:hidden\",\n \"transition-opacity ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible\n ? \"opacity-100\"\n : \"pointer-events-none opacity-0\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n onClick={closeMobileNav}\n aria-hidden={!mobileDrawerVisible}\n />\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-testid=\"sidebar-mobile-drawer\"\n aria-hidden={!mobileDrawerVisible}\n className={cn(\n \"fixed inset-y-0 left-0 z-50 flex min-h-0 w-[min(300px,85vw)] flex-col bg-base\",\n \"border-r border-[var(--oh-border)] pb-2 pl-2.5 pr-0 md:hidden\",\n \"transition-transform ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n >\n <SidebarRailBody\n collapsed={false}\n showCollapseToggle={false}\n showMobileCloseButton\n onCloseMobile={closeMobileNav}\n {...railBodyProps}\n />\n </aside>\n </>\n ) : null}\n\n {settingsModalIsOpen && (\n <React.Suspense fallback={null}>\n <SettingsModal\n settings={settings}\n onClose={() => setSettingsModalIsOpen(false)}\n />\n </React.Suspense>\n )}\n {addBackendModalOpen && (\n <React.Suspense fallback={null}>\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n </React.Suspense>\n )}\n {manageBackendsModalOpen && (\n <React.Suspense fallback={null}>\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n </React.Suspense>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sidebar.js","names":[],"sources":["../../../../src/components/features/sidebar/sidebar.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SidebarRailBody } from \"./sidebar-rail-body\";\nimport { getErrorStatus, useSettings } from \"#/hooks/query/use-settings\";\nimport { useConfig } from \"#/hooks/query/use-config\";\nimport { displayErrorToast } from \"#/utils/custom-toast-handlers\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { useActiveBackendContext } from \"#/contexts/active-backend-context\";\nimport { cn } from \"#/utils/utils\";\nimport { useSidebarMobileNav } from \"./sidebar-mobile-nav-context\";\nimport { useSidebarStore } from \"#/stores/sidebar-store\";\nimport { useClickOutsideElement } from \"#/hooks/use-click-outside-element\";\nimport { useBackendsHealth } from \"#/hooks/query/use-backends-health\";\n// The LLM settings modal is only mounted when the settings query 404s and\n// LLM settings aren't hidden — keep it out of the sidebar's eager graph.\nconst SettingsModal = React.lazy(() =>\n import(\"#/components/shared/modals/settings/settings-modal\").then((m) => ({\n default: m.SettingsModal,\n })),\n);\n\n// Add/Manage backend modals are lifted into the sidebar (instead of living\n// inside BackendSelector) so they survive the collapsed popover unmounting\n// when the user moves the cursor out of the popover toward the modal.\nconst AddBackendModal = React.lazy(() =>\n import(\"#/components/features/backends/add-backend-modal\").then((m) => ({\n default: m.AddBackendModal,\n })),\n);\nconst ManageBackendsModal = React.lazy(() =>\n import(\"#/components/features/backends/manage-backends-modal\").then((m) => ({\n default: m.ManageBackendsModal,\n })),\n);\n\nconst MOBILE_DRAWER_TRANSITION_MS = 250;\n\nexport function Sidebar() {\n const { t } = useTranslation(\"openhands\");\n const { currentPath } = useNavigation();\n const { data: config } = useConfig();\n const {\n data: settings,\n error: settingsError,\n isError: settingsIsError,\n isFetching: isFetchingSettings,\n } = useSettings();\n const { backends, active } = useActiveBackendContext();\n const healthByBackendId = useBackendsHealth(backends);\n const activeBackendHealth = healthByBackendId[active.backend.id];\n const collapsed = useSidebarStore((state) => state.collapsed);\n const setCollapsed = useSidebarStore((state) => state.setCollapsed);\n const [settingsModalIsOpen, setSettingsModalIsOpen] = React.useState(false);\n const [collapsedBackendPopoverOpen, setCollapsedBackendPopoverOpen] =\n React.useState(false);\n const collapsedBackendCloseTimer = React.useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n // Lifted out of BackendSelector so opening these modals from the\n // collapsed-sidebar popover doesn't lose state when the popover unmounts\n // (cursor moving toward the modal triggers onMouseLeave -> close).\n const [addBackendModalOpen, setAddBackendModalOpen] = React.useState(false);\n const [manageBackendsModalOpen, setManageBackendsModalOpen] =\n React.useState(false);\n const [collapsedRailHovered, setCollapsedRailHovered] = React.useState(false);\n const suppressCollapsedExpandRef = React.useRef(false);\n const [, refreshCollapsedExpandGate] = React.useReducer((n) => n + 1, 0);\n const { isOpen: isMobileNavOpen, close: closeMobileNav } =\n useSidebarMobileNav();\n const [mobileDrawerMounted, setMobileDrawerMounted] = React.useState(false);\n const [mobileDrawerVisible, setMobileDrawerVisible] = React.useState(false);\n const collapsedBackendPopoverRef = useClickOutsideElement<HTMLDivElement>(\n () => setCollapsedBackendPopoverOpen(false),\n );\n const settingsErrorStatus = getErrorStatus(settingsError);\n\n React.useEffect(() => {\n closeMobileNav();\n }, [currentPath, closeMobileNav]);\n\n React.useEffect(() => {\n if (isMobileNavOpen) {\n setMobileDrawerMounted(true);\n const frame = requestAnimationFrame(() => {\n setMobileDrawerVisible(true);\n });\n return () => cancelAnimationFrame(frame);\n }\n\n setMobileDrawerVisible(false);\n const timer = window.setTimeout(() => {\n setMobileDrawerMounted(false);\n }, MOBILE_DRAWER_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [isMobileNavOpen]);\n\n React.useEffect(() => {\n if (!isMobileNavOpen) {\n return undefined;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeMobileNav();\n }\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [isMobileNavOpen, closeMobileNav]);\n\n React.useEffect(() => {\n if (currentPath === \"/settings\") {\n setSettingsModalIsOpen(false);\n } else if (\n !isFetchingSettings &&\n settingsIsError &&\n settingsErrorStatus !== 404\n ) {\n // We don't show toast errors for settings in the global error handler\n // because we have a special case for 404 errors\n displayErrorToast(t(I18nKey.SETTINGS$FETCH_ERROR));\n } else if (\n settingsErrorStatus === 404 &&\n !config?.feature_flags?.hide_llm_settings\n ) {\n setSettingsModalIsOpen(true);\n }\n }, [\n currentPath,\n isFetchingSettings,\n settingsIsError,\n settingsErrorStatus,\n config?.feature_flags?.hide_llm_settings,\n t,\n ]);\n\n const linkDisabled = settings?.email_verified === false;\n\n const collapseToggleLabel = t(\n collapsed ? I18nKey.SIDEBAR$EXPAND : I18nKey.SIDEBAR$COLLAPSE,\n );\n const handleCollapsedRailClick = React.useCallback(\n (event: React.MouseEvent<HTMLElement>) => {\n if (!collapsed) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof HTMLElement)) {\n return;\n }\n\n // Keep existing behavior for explicit controls/links and only use\n // this as a convenience hit-area for empty collapsed-rail space.\n if (\n target.closest(\n \"a,button,input,textarea,select,[role='button'],[role='link']\",\n )\n ) {\n return;\n }\n\n setCollapsed(false);\n },\n [collapsed, setCollapsed],\n );\n const handleCollapse = React.useCallback(() => {\n setCollapsedRailHovered(false);\n suppressCollapsedExpandRef.current = true;\n refreshCollapsedExpandGate();\n setCollapsed(true);\n window.setTimeout(() => {\n suppressCollapsedExpandRef.current = false;\n refreshCollapsedExpandGate();\n }, 250);\n }, [setCollapsed]);\n const showCollapsedExpandButton =\n collapsed && collapsedRailHovered && !suppressCollapsedExpandRef.current;\n\n const isExtensionsActive =\n currentPath === \"/customize\" ||\n currentPath.startsWith(\"/skills\") ||\n currentPath === \"/plugins\" ||\n currentPath === \"/mcp\";\n\n const railBodyProps = {\n linkDisabled,\n collapseToggleLabel,\n onCollapse: handleCollapse,\n onExpand: () => setCollapsed(false),\n showCollapsedExpandButton,\n isExtensionsActive,\n currentPath,\n activeBackendHealth,\n collapsedBackendPopoverOpen,\n setCollapsedBackendPopoverOpen,\n collapsedBackendPopoverRef,\n collapsedBackendCloseTimer,\n onOpenAddBackend: () => setAddBackendModalOpen(true),\n onOpenManageBackends: () => setManageBackendsModalOpen(true),\n };\n\n return (\n <>\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- the aside acts as a hit-area for the collapsed rail; nested controls handle their own keyboard interactions. */}\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-collapsed={collapsed ? \"true\" : \"false\"}\n onClick={handleCollapsedRailClick}\n onMouseEnter={() => {\n if (collapsed) {\n setCollapsedRailHovered(true);\n }\n }}\n onMouseLeave={() => {\n setCollapsedRailHovered(false);\n }}\n className={cn(\n \"max-md:hidden flex bg-base flex-col min-h-0 transition-[width,min-width] duration-200\",\n \"md:border-r md:border-[var(--oh-border)] md:h-full\",\n collapsed\n ? \"md:w-[60px] md:min-w-[60px] md:px-2.5\"\n : \"md:w-[300px] md:min-w-[300px] pb-2 md:pl-2.5 md:pr-0\",\n currentPath === \"/\" && \"md:pb-3\",\n )}\n >\n <SidebarRailBody\n collapsed={collapsed}\n showCollapseToggle\n {...railBodyProps}\n />\n </aside>\n\n {mobileDrawerMounted ? (\n <>\n <div\n className={cn(\n \"fixed inset-0 z-40 bg-black/50 md:hidden\",\n \"transition-opacity ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible\n ? \"opacity-100\"\n : \"pointer-events-none opacity-0\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n onClick={closeMobileNav}\n aria-hidden={!mobileDrawerVisible}\n />\n <aside\n aria-label={t(I18nKey.SIDEBAR$NAVIGATION_LABEL)}\n data-testid=\"sidebar-mobile-drawer\"\n aria-hidden={!mobileDrawerVisible}\n className={cn(\n \"fixed inset-y-0 left-0 z-50 flex min-h-0 w-[min(300px,85vw)] flex-col bg-base\",\n \"border-r border-[var(--oh-border)] pb-2 pl-2.5 pr-0 md:hidden\",\n \"transition-transform ease-in-out motion-reduce:transition-none\",\n mobileDrawerVisible ? \"translate-x-0\" : \"-translate-x-full\",\n )}\n style={{ transitionDuration: `${MOBILE_DRAWER_TRANSITION_MS}ms` }}\n >\n <SidebarRailBody\n collapsed={false}\n showCollapseToggle={false}\n showMobileCloseButton\n onCloseMobile={closeMobileNav}\n {...railBodyProps}\n />\n </aside>\n </>\n ) : null}\n\n {settingsModalIsOpen && (\n <React.Suspense fallback={null}>\n <SettingsModal\n settings={settings}\n onClose={() => setSettingsModalIsOpen(false)}\n />\n </React.Suspense>\n )}\n {addBackendModalOpen && (\n <React.Suspense fallback={null}>\n <AddBackendModal onClose={() => setAddBackendModalOpen(false)} />\n </React.Suspense>\n )}\n {manageBackendsModalOpen && (\n <React.Suspense fallback={null}>\n <ManageBackendsModal\n onClose={() => setManageBackendsModalOpen(false)}\n />\n </React.Suspense>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|