@openhands/agent-canvas 1.0.0-beta.8 → 1.0.0-beta.9
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 +2 -2
- package/README.windows.md +2 -2
- package/build/assets/{QueryClientProvider-Cnr-Yl3j.js → QueryClientProvider-w1cZWY41.js} +1 -1
- package/build/assets/{Trans-4jmk54WC.js → Trans-BJeYqz2A.js} +1 -1
- package/build/assets/{acp-providers-BAX8OU5C.js → acp-providers-DJr8DlNG.js} +1 -1
- package/build/assets/{acp-route-guard-HPk6TV-L.js → acp-route-guard-A__sWgbc.js} +1 -1
- package/build/assets/{active-backend-context-BSPE-W72.js → active-backend-context-I2w666XY.js} +1 -1
- package/build/assets/add-backend-modal-BDBDBXsJ.js +1 -0
- package/build/assets/agent-server-conversation-service.api-Cagoqq1V.js +5 -0
- package/build/assets/agent-settings-BXBaybB_.js +2 -0
- package/build/assets/{alert-banner-DFnn_lC6.js → alert-banner-NeUl1-PQ.js} +1 -1
- package/build/assets/analytics-consent-form-modal-CmWcFlc6.js +1 -0
- package/build/assets/{api-key-entry-screen-myuWMqzW.js → api-key-entry-screen-ByXA4hXH.js} +1 -1
- package/build/assets/{app-settings-CCcX8ZEH.js → app-settings-C-U6jONZ.js} +1 -1
- package/build/assets/automation-detail-Dbmgt974.js +1 -0
- package/build/assets/automations-list-BLJzAd-p.js +1 -0
- package/build/assets/{back-nav-button-7dQJ2k3O.js → back-nav-button-DgkK0Ka6.js} +1 -1
- package/build/assets/{backend-form-modal-D3bDMO3C.js → backend-form-modal-CeB983Sj.js} +1 -1
- package/build/assets/{backend-synced-settings-badge-BkW5evM0.js → backend-synced-settings-badge-BktJcGgH.js} +1 -1
- package/build/assets/{base-modal-C2oy2EBG.js → base-modal-DZCNv0A4.js} +1 -1
- package/build/assets/{brand-button-DJ_S16rO.js → brand-button-LBFNic99.js} +1 -1
- package/build/assets/browser-D08Sp3ZY.js +5 -0
- package/build/assets/{browser-tab-dvSPdvkm.js → browser-tab-be3QvXg9.js} +1 -1
- package/build/assets/chat-send-button-5qz0zj6R.js +1 -0
- package/build/assets/{checkmark-Dus0b6jt.js → checkmark-Rmpruj7q.js} +1 -1
- package/build/assets/{chevron-left-small-_uvG7RVM.js → chevron-left-small-6nyFCWVQ.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-DKS8MAVV.js → circle-plus-check-toggle-DquBwJ_6.js} +1 -1
- package/build/assets/{close-BU5iTc66.js → close-D_o3d8QM.js} +1 -1
- package/build/assets/{code-tag-BzyqOtPD.js → code-tag-DhsjDB-v.js} +1 -1
- package/build/assets/{combobox-caret-BJC7XJsz.js → combobox-caret-CO7eozIY.js} +1 -1
- package/build/assets/{condenser-settings-DCTulgLO.js → condenser-settings-BulzYEuW.js} +1 -1
- package/build/assets/{confirmation-modal-B5Ca6qFE.js → confirmation-modal-CMAtd9R0.js} +1 -1
- package/build/assets/{context-menu-list-item-7tAcm2c3.js → context-menu-list-item-D0swnhFt.js} +1 -1
- package/build/assets/conversation-BrjF2-Ky.js +1 -0
- package/build/assets/conversation-HgR_TTPE.js +19 -0
- package/build/assets/conversation-panel-BlRcO5AC.js +1 -0
- package/build/assets/conversation-service.api-B_Pdmwsa.js +1 -0
- package/build/assets/{conversation-tab-empty-state-CStQLPVW.js → conversation-tab-empty-state-DYjKsg_c.js} +1 -1
- package/build/assets/conversation-websocket-context-G95yfL81.js +3 -0
- package/build/assets/{copy-Chg-sFu3.js → copy-BM0RpLez.js} +1 -1
- package/build/assets/{custom-toast-handlers-ufGJ6_Rc.js → custom-toast-handlers-BohXx7uh.js} +1 -1
- package/build/assets/{declaration-CR6HMp29.js → declaration-DaUdB2Wg.js} +1 -1
- package/build/assets/{device-verify-C6mj28zv.js → device-verify-DiEJqpJb.js} +1 -1
- package/build/assets/dist-Bl-1K5Tv.js +1 -0
- package/build/assets/{dist-C3NfioQC.js → dist-xtCm0O6P.js} +1 -1
- package/build/assets/{dropdown-classes-BsVmxlNG.js → dropdown-classes-Vqz86I0R.js} +1 -1
- package/build/assets/{edit-automation-modal-DamwL0s0.js → edit-automation-modal-CNZgSSiH.js} +1 -1
- package/build/assets/{entry.client-Cn71WM8q.js → entry.client-BvKgdCQ9.js} +2 -2
- package/build/assets/{enum-filter-dropdown-5JeF2RLb.js → enum-filter-dropdown-DdFgk0EM.js} +1 -1
- package/build/assets/{environment-switch-overlay-Tf_BIfeR.js → environment-switch-overlay-CuBuZOaa.js} +1 -1
- package/build/assets/{extensions-hub-CUEmfvGy.js → extensions-hub-Dayqvv0n.js} +1 -1
- package/build/assets/{extensions-navigation-VQ-3umJ7.js → extensions-navigation-yFLAU06N.js} +1 -1
- package/build/assets/{file-BTY6Gyy9.js → file-DwHCkWZT.js} +1 -1
- package/build/assets/files-tab-CMredyYX.js +1 -0
- package/build/assets/{folder-D1T2W1cj.js → folder-2h1hR1Qb.js} +1 -1
- package/build/assets/git-control-bar-branch-button-D8blTNXh.js +27 -0
- package/build/assets/{globe-Bzj_0oXT.js → globe-qFjFNG6J.js} +1 -1
- package/build/assets/home-TrU0fLgG.js +1 -0
- package/build/assets/{i18n-DET2iOyh.js → i18n-zDndR1Ne.js} +1 -1
- package/build/assets/install-server-modal-D8Q0xZcN.js +1 -0
- package/build/assets/{launch-DGghLfGx.js → launch-I00QV8YT.js} +1 -1
- package/build/assets/{lesson-plan-duSsqWVs.js → lesson-plan-C18uB_56.js} +1 -1
- package/build/assets/{link-external-DGxVm4Ps.js → link-external-DtcdPFbw.js} +1 -1
- package/build/assets/llm-settings-C4R4HMUO.js +1 -0
- package/build/assets/llm-settings-Dq3w2cob.js +1 -0
- package/build/assets/{loading-spinner-5GT9q1xy.js → loading-spinner-DNwR4--Z.js} +1 -1
- package/build/assets/{manage-backends-modal-CRMwyU0t.js → manage-backends-modal-Ceo_SOcf.js} +1 -1
- package/build/assets/manifest-8c2efa8a.js +1 -0
- package/build/assets/{markdown-renderer-B3IAVfv4.js → markdown-renderer-D6B-u2nM.js} +1 -1
- package/build/assets/{mcp-CfDRAmPn.js → mcp-EvrLVTla.js} +1 -1
- package/build/assets/messages-Bz9TWjlh.js +36 -0
- package/build/assets/modal-backdrop-BDqI1zBV.js +1 -0
- package/build/assets/{modal-body-aoa2fx5W.js → modal-body-CCLCqX1J.js} +1 -1
- package/build/assets/{modal-classes-6YqcqA6y.js → modal-classes-DwTdT3IK.js} +1 -1
- package/build/assets/{modal-close-button-CtWOUMmw.js → modal-close-button-gQgKqUf-.js} +1 -1
- package/build/assets/{model-selector-DcztJSxT.js → model-selector-DoL0CL0_.js} +1 -1
- package/build/assets/{mutation-D0OogFCz.js → mutation-CaJwPR9O.js} +1 -1
- package/build/assets/{navigation-context-BdKYH32C.js → navigation-context-aNGUUtdq.js} +1 -1
- package/build/assets/{navigation-link-U4vY9i_C.js → navigation-link-CYkF2y3K.js} +1 -1
- package/build/assets/onboarding-DLr9jbKH.js +1 -0
- package/build/assets/{openhands-logo-CCo0wJZX.js → openhands-logo-CHmtDV-t.js} +1 -1
- package/build/assets/{organization-service.api-BeuMC9QL.js → organization-service.api-Dn74hBTH.js} +1 -1
- package/build/assets/path-utils-BjxzIGLp.js +1 -0
- package/build/assets/{plan-components-CRDMQzsS.js → plan-components--aLlpASH.js} +1 -1
- package/build/assets/{planner-tab-Dte6Vzza.js → planner-tab-B-5EeCEm.js} +1 -1
- package/build/assets/{providers-eUyo6pgr.js → providers-DknP6O2g.js} +1 -1
- package/build/assets/{proxy-BqDMnUY-.js → proxy-sRh0WKI7.js} +1 -1
- package/build/assets/{query-client-config-CRnGSujB.js → query-client-config-CWWGQWvw.js} +1 -1
- package/build/assets/{recommended-automations-launcher-D5ADbXao.js → recommended-automations-launcher-BIul0osB.js} +3 -3
- package/build/assets/root-BietmyRa.js +2 -0
- package/build/assets/{root-Z2VHU4R3.css → root-CN7qsvxg.css} +1 -1
- package/build/assets/root-layout-BgPi-t57.js +2 -0
- package/build/assets/{sdk-section-page-CRCRY3PG.js → sdk-section-page-VmtJWH3A.js} +1 -1
- package/build/assets/{sdk-settings-schema-CLmJ9sho.js → sdk-settings-schema-DFievvEK.js} +1 -1
- package/build/assets/{search-SuJctqNJ.js → search-BeVRXvX7.js} +1 -1
- package/build/assets/{secrets-service-B9AFn9OE.js → secrets-service-DVtlLWY8.js} +1 -1
- package/build/assets/{secrets-settings-0UrKMS60.js → secrets-settings-BLMvCkKm.js} +1 -1
- package/build/assets/{settings-6t6LGW04.js → settings-CXvJUx_j.js} +1 -1
- package/build/assets/{settings-dropdown-input-BtoovFre.js → settings-dropdown-input-DA_pzHWE.js} +1 -1
- package/build/assets/{settings-gear-Dd8K2_8B.js → settings-gear-aNebYlCy.js} +1 -1
- package/build/assets/{settings-index-CR6Ou73o.js → settings-index-CycvkOoq.js} +1 -1
- package/build/assets/{settings-input-CehsXnb3.js → settings-input-8y5p4kze.js} +1 -1
- package/build/assets/{settings-list-classes-E3v_f6QG.js → settings-list-classes-Qk7zl0Wu.js} +1 -1
- package/build/assets/settings-modal-nJYxCsyp.js +1 -0
- package/build/assets/{settings-section-header-context-DewwJ0-F.js → settings-section-header-context-B77tsYlx.js} +1 -1
- package/build/assets/{settings-service.api-DwtyDeGh.js → settings-service.api-DxIEtvx6.js} +1 -1
- package/build/assets/{settings-switch-BiBuS3xa.js → settings-switch-ba4DuiNO.js} +1 -1
- package/build/assets/{settings-utils-DY04tWG1.js → settings-utils-BxzHqLmZ.js} +1 -1
- package/build/assets/{shared-conversation-BzccsVej.js → shared-conversation-x41nZQi7.js} +1 -1
- package/build/assets/{sidebar-mobile-menu-toggle-DGlRg6jG.js → sidebar-mobile-menu-toggle-C0mmabKj.js} +1 -1
- package/build/assets/{sidebar-nav-link-dgVb8Fpy.js → sidebar-nav-link-BsYdDFfb.js} +1 -1
- package/build/assets/{skill-card-pill-row-BW9qvhoK.js → skill-card-pill-row-BhUlGcYB.js} +1 -1
- package/build/assets/{skills-0GRKX5Xj.js → skills-TYjOUQ2d.js} +1 -1
- package/build/assets/{skills-plugins-DctDrZ8Y.js → skills-plugins-D0pdqgKa.js} +1 -1
- package/build/assets/{skills-settings-rvxImDj_.js → skills-settings-VqKTkmVl.js} +2 -2
- package/build/assets/{styled-tooltip-hdfMXPQC.js → styled-tooltip-TCp7svY3.js} +1 -1
- package/build/assets/{switch-skeleton-DSKqSx2A.js → switch-skeleton-cKrdaYGj.js} +1 -1
- package/build/assets/{task-list-tab-DT6_zfUs.js → task-list-tab-BiizRsY3.js} +1 -1
- package/build/assets/telemetry-3piyXm5H.js +2 -0
- package/build/assets/{terminal-CPYWdo4j.js → terminal-BSYITdM0.js} +1 -1
- package/build/assets/{terminal-KldRPIRT.js → terminal-CpgZx6go.js} +1 -1
- package/build/assets/{toggle-switch-T2v6sJ6l.js → toggle-switch-CUgOZqZu.js} +1 -1
- package/build/assets/{typography-BDgnT7Yp.js → typography-Bvw0IxaN.js} +1 -1
- package/build/assets/{u-check-circle-half-steSK_JB.js → u-check-circle-half-DjpjzWu3.js} +1 -1
- package/build/assets/{u-check-circle-DOauqQKb.js → u-check-circle-u9QiS4Fr.js} +1 -1
- package/build/assets/{u-circuit-x3ExjBbU.js → u-circuit-DlBlOwx9.js} +1 -1
- package/build/assets/{u-edit-BbrptMCa.js → u-edit-BIYzjs3v.js} +1 -1
- package/build/assets/{use-active-conversation-sPgfSkql.js → use-active-conversation-q1wT8LI5.js} +1 -1
- package/build/assets/{use-agent-settings-schema-B66kGIi_.js → use-agent-settings-schema-Yxf7KGyG.js} +1 -1
- package/build/assets/{use-agent-state-Dp3pD1h3.js → use-agent-state-CCHlVqvY.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-ClKFPjFz.js → use-cloud-current-user-id-BAKf91Zx.js} +1 -1
- package/build/assets/{use-config-C9pvb0Sm.js → use-config-DwfigQ_Y.js} +1 -1
- package/build/assets/use-create-conversation-BEzddjXn.js +1 -0
- package/build/assets/{use-get-secrets-oyC7PFRz.js → use-get-secrets-BlO1BfUo.js} +1 -1
- package/build/assets/{use-handle-plan-click-DP6Rs-YP.js → use-handle-plan-click-Bfl0zIBr.js} +1 -1
- package/build/assets/use-is-authed-hHndEep7.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-sQNEOLGD.js → use-launch-skill-in-chat-3ydwpi_M.js} +1 -1
- package/build/assets/use-llm-profiles-E-jjZMZw.js +1 -0
- package/build/assets/use-runtime-is-ready-DBWzvAmc.js +1 -0
- package/build/assets/use-save-settings-rE9aA29R.js +1 -0
- package/build/assets/{use-settings-DeO7nvpM.js → use-settings-BPTbE7lg.js} +1 -1
- package/build/assets/{use-settings-nav-items-BGMFn25b.js → use-settings-nav-items-C7MOWj09.js} +1 -1
- package/build/assets/{use-skills-DWIK3l3a.js → use-skills-QhoaIYGF.js} +1 -1
- package/build/assets/{use-task-list-CsT10CBb.js → use-task-list-YMkSzdDv.js} +1 -1
- package/build/assets/use-tracking-DQYdZpxi.js +1 -0
- package/build/assets/{use-unified-vscode-url-DXPtB317.js → use-unified-vscode-url-DFtNIC1Q.js} +1 -1
- package/build/assets/{use-user-conversation-DJen4YIP.js → use-user-conversation-BRAseenw.js} +1 -1
- package/build/assets/{useMutation-GSSKKebK.js → useMutation-DDo48A8t.js} +1 -1
- package/build/assets/{useTranslation-B6voJV4y.js → useTranslation-CEcjrme-.js} +1 -1
- package/build/assets/{utils-DCVfKFRt.js → utils-CdgBzLA7.js} +1 -1
- package/build/assets/{vendor~browser-BrOJLj3y.js → vendor~browser-DWk6fNtJ.js} +1 -1
- package/build/assets/{vendor~browser-tab-BxhTtM9_.js → vendor~browser-tab-NZdVoI2Z.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-C9o-K1hW.js → vendor~conversation-panel~conversation-gp03cWZW.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation~index-RXYdJYxU.js → vendor~conversation-panel~conversation~index-BZ5C6Xpz.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~jfc6hidu-DJS-rJdI.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BodGsxSf.js} +1 -1
- package/build/assets/{vendor~files-tab-BtkpAiMX.js → vendor~files-tab-Buz36Y-q.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation-PK1-gtXU.js → vendor~home~conversation-panel~conversation-DG0H5SkJ.js} +2 -2
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-6ByzelMS.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-1pTajrpX.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BED5W_c4.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-9Il_wz8U.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CCbqAFiI.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-B7I1ZxCx.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-E4d6IEfI.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Ceeqkj0k.js} +1 -1
- package/build/assets/{vendor~launch-BXgl67Re.js → vendor~launch-DXL78kBf.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-DW31UyBp.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-CfAc3nMS.js} +1 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation-DkwcKRtv.js +1 -0
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-tTR8C6m0.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-BC9XTECT.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-6Rm8U_Sr.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~iguv7bgw-DSqEbr0N.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-BJbu9kpL.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~k776hupu-D0XUSHNN.js} +2 -2
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-d2oallMa.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CcFtthyg.js} +1 -1
- package/build/assets/vendor~root-layout~home~mcp~automations-list-BnIlGhjl.js +1 -0
- package/build/assets/{vendor~home~mcp~automations-list-BgV86Sti.js → vendor~root-layout~home~mcp~automations-list-cNHi83v_.js} +1 -1
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-CjJdFLoM.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BGWUbqUq.js} +1 -1
- package/build/assets/{vendor~home~mcp~llm-settings~agent-settings~condenser-settings~verification-settings~app-se~ocm3mykx-m8dOii0J.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BuCSnjsW.js} +2 -2
- package/build/assets/{vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~f2l2lr17-DYXOLEck.js → vendor~root~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-s~jaomi49z-Cw89stA6.js} +1 -1
- package/build/assets/{verification-settings-C_zHuDx9.js → verification-settings-CIqtxWat.js} +1 -1
- package/build/assets/{vscode-tab-DH9x7xXS.js → vscode-tab-DEt72yJX.js} +1 -1
- package/build/assets/{waiting-for-runtime-message-CdK3btDZ.js → waiting-for-runtime-message-DSjJfeoj.js} +1 -1
- package/build/assets/{x-mark-BrkSPIiT.js → x-mark-DsJ9tDD0.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +4 -2
- package/build/locales/ca/openhands.json +4 -2
- package/build/locales/de/openhands.json +4 -2
- package/build/locales/en/openhands.json +4 -2
- package/build/locales/es/openhands.json +4 -2
- package/build/locales/fr/openhands.json +4 -2
- package/build/locales/it/openhands.json +4 -2
- package/build/locales/ja/openhands.json +4 -2
- package/build/locales/ko-KR/openhands.json +4 -2
- package/build/locales/no/openhands.json +4 -2
- package/build/locales/pt/openhands.json +4 -2
- package/build/locales/tr/openhands.json +4 -2
- package/build/locales/uk/openhands.json +4 -2
- package/build/locales/zh-CN/openhands.json +4 -2
- package/build/locales/zh-TW/openhands.json +4 -2
- package/config/defaults.json +1 -1
- package/dist/api/agent-server-home.cjs +2 -0
- package/dist/api/agent-server-home.cjs.map +1 -0
- package/dist/api/agent-server-home.d.ts +34 -0
- package/dist/api/agent-server-home.js +33 -0
- package/dist/api/agent-server-home.js.map +1 -0
- package/dist/api/conversation-file-upload.api.cjs +1 -1
- package/dist/api/conversation-file-upload.api.cjs.map +1 -1
- package/dist/api/conversation-file-upload.api.js +4 -1
- package/dist/api/conversation-file-upload.api.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +101 -100
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/option-service/option-service.api.cjs.map +1 -1
- package/dist/api/option-service/option-service.api.js.map +1 -1
- package/dist/api/workspace-upload-path.cjs +1 -1
- package/dist/api/workspace-upload-path.cjs.map +1 -1
- package/dist/api/workspace-upload-path.d.ts +44 -2
- package/dist/api/workspace-upload-path.js +16 -14
- package/dist/api/workspace-upload-path.js.map +1 -1
- package/dist/components/features/automations/recommended-automations-launcher.d.ts +3 -1
- package/dist/components/features/automations/recommended-automations-section.d.ts +3 -1
- 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.d.ts +7 -1
- package/dist/components/features/backends/backend-form-modal.js +94 -91
- package/dist/components/features/backends/backend-form-modal.js.map +1 -1
- package/dist/components/features/chat/chat-interface.cjs +2 -2
- package/dist/components/features/chat/chat-interface.cjs.map +1 -1
- package/dist/components/features/chat/chat-interface.js +66 -66
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
- package/dist/components/features/chat/switch-profile-button.cjs +1 -1
- package/dist/components/features/chat/switch-profile-button.js +3 -3
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.cjs.map +1 -1
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.js +5 -5
- package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map +1 -1
- package/dist/components/features/onboarding/index.d.ts +1 -0
- package/dist/components/features/onboarding/onboarding-host.d.ts +3 -1
- package/dist/components/features/onboarding/onboarding-modal.d.ts +7 -3
- package/dist/components/features/onboarding/onboarding-preview.d.ts +4 -0
- package/dist/components/features/onboarding/steps/say-hello-step.d.ts +3 -1
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs +1 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.cjs.map +1 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.d.ts +3 -1
- package/dist/components/features/settings/sdk-settings/sdk-section-page.js +56 -56
- package/dist/components/features/settings/sdk-settings/sdk-section-page.js.map +1 -1
- package/dist/components/features/skills/extensions-navigation.cjs +1 -1
- package/dist/components/features/skills/extensions-navigation.js +7 -7
- package/dist/components/shared/modals/modal-backdrop.cjs +1 -1
- package/dist/components/shared/modals/modal-backdrop.cjs.map +1 -1
- package/dist/components/shared/modals/modal-backdrop.d.ts +3 -1
- package/dist/components/shared/modals/modal-backdrop.js +3 -3
- package/dist/components/shared/modals/modal-backdrop.js.map +1 -1
- package/dist/components/shared/modals/settings/settings-form.cjs +1 -1
- package/dist/components/shared/modals/settings/settings-form.cjs.map +1 -1
- package/dist/components/shared/modals/settings/settings-form.js +7 -7
- package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
- package/dist/hooks/chat/use-model-interceptor.cjs +1 -1
- package/dist/hooks/chat/use-model-interceptor.js +4 -4
- package/dist/hooks/mutation/use-save-settings.cjs +1 -1
- package/dist/hooks/mutation/use-save-settings.cjs.map +1 -1
- package/dist/hooks/mutation/use-save-settings.js +13 -14
- package/dist/hooks/mutation/use-save-settings.js.map +1 -1
- package/dist/hooks/query/use-llm-profiles.cjs +1 -1
- package/dist/hooks/query/use-llm-profiles.js +5 -5
- package/dist/hooks/use-download-conversation.cjs +1 -1
- package/dist/hooks/use-download-conversation.cjs.map +1 -1
- package/dist/hooks/use-download-conversation.js +4 -4
- package/dist/hooks/use-download-conversation.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 +31 -0
- package/dist/hooks/use-tracking.js +51 -14
- 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 +2 -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 +64 -30
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +4 -2
- package/dist/locales/ca/openhands.json +4 -2
- package/dist/locales/de/openhands.json +4 -2
- package/dist/locales/en/openhands.json +4 -2
- package/dist/locales/es/openhands.json +4 -2
- package/dist/locales/fr/openhands.json +4 -2
- package/dist/locales/it/openhands.json +4 -2
- package/dist/locales/ja/openhands.json +4 -2
- package/dist/locales/ko-KR/openhands.json +4 -2
- package/dist/locales/no/openhands.json +4 -2
- package/dist/locales/pt/openhands.json +4 -2
- package/dist/locales/tr/openhands.json +4 -2
- package/dist/locales/uk/openhands.json +4 -2
- package/dist/locales/zh-CN/openhands.json +4 -2
- package/dist/locales/zh-TW/openhands.json +4 -2
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/dist/routes/llm-settings.cjs +1 -1
- package/dist/routes/llm-settings.cjs.map +1 -1
- package/dist/routes/llm-settings.d.ts +3 -1
- package/dist/routes/llm-settings.js +17 -16
- package/dist/routes/llm-settings.js.map +1 -1
- package/package.json +1 -1
- package/scripts/dev-static.mjs +0 -2
- package/scripts/dev-with-automation.mjs +0 -2
- package/scripts/static-server.mjs +13 -3
- package/build/assets/add-backend-modal-mXKmfMI2.js +0 -1
- package/build/assets/agent-server-conversation-service.api-B9TUYJon.js +0 -5
- package/build/assets/agent-settings-g3F623RJ.js +0 -2
- package/build/assets/analytics-consent-form-modal-BQCNeNVt.js +0 -1
- package/build/assets/automation-detail-BDHLHSJd.js +0 -1
- package/build/assets/automations-list-CiNtQhq_.js +0 -1
- package/build/assets/browser-CGM-k-sH.js +0 -5
- package/build/assets/conversation-BKhikfYl.js +0 -1
- package/build/assets/conversation-DTn8jN8L.js +0 -19
- package/build/assets/conversation-panel-DfHR42mG.js +0 -1
- package/build/assets/conversation-service.api-B6CkzaKD.js +0 -1
- package/build/assets/conversation-websocket-context-DShEuLjh.js +0 -3
- package/build/assets/dist-DNeWJ2bh.js +0 -1
- package/build/assets/ellipsis-button-Vh5MvRZa.js +0 -1
- package/build/assets/files-tab-C47fQEeL.js +0 -1
- package/build/assets/git-branch-DQS2nMK4.js +0 -1
- package/build/assets/git-control-bar-branch-button-BT0aWH-o.js +0 -27
- package/build/assets/git-provider-icon-Pi-Cxpgv.js +0 -1
- package/build/assets/home-C3k6sFvB.js +0 -1
- package/build/assets/install-server-modal-6fuq-TU6.js +0 -1
- package/build/assets/llm-settings-BKraGtOu.js +0 -1
- package/build/assets/llm-settings-DRQTgOF1.js +0 -1
- package/build/assets/manage-workspaces-modal-BYmGD1W7.js +0 -1
- package/build/assets/manifest-99b06a11.js +0 -1
- package/build/assets/messages-Ba1vaw6t.js +0 -36
- package/build/assets/modal-backdrop-RfNCrSpK.js +0 -1
- package/build/assets/path-utils-z12iCrQO.js +0 -1
- package/build/assets/root-BmhaEJJ8.js +0 -2
- package/build/assets/root-layout-CNggm0d8.js +0 -2
- package/build/assets/settings-modal-T_Yk1Zfo.js +0 -1
- package/build/assets/use-create-conversation-B-lwTnfE.js +0 -1
- package/build/assets/use-is-authed-dw2026rR.js +0 -1
- package/build/assets/use-is-creating-conversation-DX2qSlfL.js +0 -1
- package/build/assets/use-llm-profiles-Bh5JqZUZ.js +0 -1
- package/build/assets/use-runtime-is-ready-BakOUVU-.js +0 -1
- package/build/assets/use-save-settings-uXXkqvD7.js +0 -1
- package/build/assets/vendor~home~mcp~automations-list-CZSK-lT2.js +0 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation-B5WNMnt4.js +0 -1
- /package/build/assets/{automation-XDPAjiZi.js → automation-DJ_3GeXD.js} +0 -0
- /package/build/assets/{browser-store-DAsixKdU.js → browser-store-JRrcGdlk.js} +0 -0
- /package/build/assets/{check-CYxAHs85.js → check-CZhEL6rP.js} +0 -0
- /package/build/assets/{chevron-down-Bnmd5iG-.js → chevron-down-KhWYEjeW.js} +0 -0
- /package/build/assets/{color-themes-B9pm9c-R.js → color-themes-0biOprdo.js} +0 -0
- /package/build/assets/{command-store-CE1weJy8.js → command-store-UzKGSUC2.js} +0 -0
- /package/build/assets/{files-tab-store-m0ARqX_E.js → files-tab-store-DLU28g8C.js} +0 -0
- /package/build/assets/{iconBase-DE30Zj_-.js → iconBase-BVhFI-0E.js} +0 -0
- /package/build/assets/{map-provider-BJ_8KZKU.js → map-provider-C3Z5Dx2J.js} +0 -0
- /package/build/assets/{sdk-settings-field-metadata-DQiaIBie.js → sdk-settings-field-metadata-C6KMD-jZ.js} +0 -0
- /package/build/assets/{settings-like-page-layout-classes-D7YjdTd0.js → settings-like-page-layout-classes-DNg2vKSM.js} +0 -0
- /package/build/assets/{use-breakpoint-DF_RiQ6s.js → use-breakpoint-DpxHDmuH.js} +0 -0
- /package/build/assets/{use-event-store-BomO7ywK.js → use-event-store-Cxqc45Sw.js} +0 -0
- /package/build/assets/{vendor~browser-DisFGEp9.js → vendor~browser-BDNLFng6.js} +0 -0
- /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-w-I2sY6c.js → vendor~conversation-panel~conversation~alert-banner-D_hRW_zc.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~g56ukk6u-DsSvIDZQ.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~h07fzaqi-D15MEcqi.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~hkqzh1hb-BZ0HXuHD.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~j8sdb9mk-OFpe9fX_.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~zm51vy4j-BClAMeFe.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BPuuVEqr.js} +0 -0
- /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CG96FCly.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CXivI4Ym.js} +0 -0
- /package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CyZ-3lDQ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dr3Ow7Ms.js} +0 -0
- /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~i4kjfqhl-CbAhtEMv.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~skil~i4kjfqhl-B1TKKuuH.js} +0 -0
- /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~ninslayh-CLlsvdNP.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~e9ykmtgh-Fa-nXZ4M.js} +0 -0
- /package/build/assets/{vendor~terminal-DZaJIY8A.js → vendor~terminal-0ObOedYm.js} +0 -0
- /package/build/assets/{vscode-url-helper-Cwy1A62q.js → vscode-url-helper-BMq8JBhB.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-section-page.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showAdvanced,\n showAll,\n }: {\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n return \"basic\";\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema–driven settings page that renders fields\n * from one or more schema sections.\n *\n * @param sectionKeys - which schema section(s) this page owns (e.g. [\"condenser\"])\n * @param excludeKeys - field keys to skip (rendered elsewhere by the caller)\n * @param header - optional render prop receiving shared state to render above fields\n * @param testId - data-testid for the page wrapper\n */\nexport function SdkSectionPage({\n sectionKeys,\n excludeKeys = EMPTY_EXCLUDE_KEYS,\n scope = \"personal\",\n settingsSource = \"agent_settings\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n sectionKeys: string[];\n excludeKeys?: Set<string>;\n scope?: SettingsScope;\n settingsSource?: SettingsValueSource;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n buildPayload?: (\n payload: ReturnType<typeof buildSdkSettingsPayloadForView>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n /**\n * When true, the Save button container is rendered inline (no\n * sticky positioning, no contrasting `bg-base` band) so the page\n * can be dropped into a modal/card without a hard footer break.\n */\n embedded?: boolean;\n /**\n * Suppress the built-in Save Changes button entirely. Pair with\n * {@link onSaveControlChange} to drive saving from a parent-rendered\n * action (e.g. an onboarding \"Next\" button).\n */\n hideSaveButton?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const activeSchemaQuery =\n settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery\n : agentSchemaQuery;\n const schema = activeSchemaQuery.data;\n const isSchemaLoading = activeSchemaQuery.isLoading;\n const isReadOnly = false;\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [values, setValues] = React.useState<SettingsFormValues>({});\n const [dirty, setDirty] = React.useState<SettingsDirtyState>({});\n const hasHydratedViewRef = React.useRef(false);\n\n const sectionKeysSignature = React.useMemo(\n () => JSON.stringify(sectionKeys),\n [sectionKeys],\n );\n const stableSectionKeys = React.useMemo(\n () => JSON.parse(sectionKeysSignature) as string[],\n [sectionKeysSignature],\n );\n\n // Build a filtered schema containing only the requested sections.\n // `isValidSettingsSchema` guards against truthy-but-malformed schema\n // responses (e.g. when the deployment is pointed at a host that does\n // not serve `/api/settings/agent-schema` and returns an SPA shell\n // that parses into an object without a `sections` array). Without\n // the guard, `schema.sections.filter(...)` would throw and React\n // Router would escalate the crash to a full-screen error.\n const filteredSchema = React.useMemo(() => {\n if (!isValidSettingsSchema(schema)) return null;\n const sectionSet = new Set(stableSectionKeys);\n return {\n ...schema,\n sections: schema.sections.filter((s) => sectionSet.has(s.key)),\n };\n }, [schema, stableSectionKeys]);\n\n const showAdvanced =\n forceShowAdvancedView || hasAdvancedSettings(filteredSchema);\n const showAll = allowAllView && hasMinorSettings(filteredSchema);\n const schemaUnavailableMessage = React.useMemo(\n () =>\n getSchemaUnavailableMessage(\n activeSchemaQuery.error,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n ),\n [activeSchemaQuery.error, t],\n );\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const initialValues = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n const base = buildInitialSettingsFormValues(\n settings,\n filteredSchema,\n settingsSource,\n );\n if (!initialValueOverrides) return base;\n return { ...base, ...initialValueOverrides };\n // overridesSignature keeps the memo reactive without depending on\n // a (potentially recreated) object reference each render.\n }, [settings, filteredSchema, settingsSource, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n\n const resolvedInitialView = getInitialView\n ? getInitialView(settings, filteredSchema)\n : inferInitialView(settings, filteredSchema, settingsSource);\n\n return normalizeView(resolvedInitialView, { showAdvanced, showAll });\n }, [\n settings,\n filteredSchema,\n getInitialView,\n settingsSource,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValues({});\n setDirty({});\n }, [scope, settingsSource, sectionKeysSignature]);\n\n React.useEffect(() => {\n if (!initialValues || !initialView) return;\n\n setValues(initialValues);\n // Override-supplied keys are pre-populated for the user, so mark\n // them dirty up-front; otherwise the Save button stays disabled\n // until the user touches a field, defeating the point of the\n // override.\n const overrideDirty: SettingsDirtyState = initialValueOverrides\n ? Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n )\n : {};\n setDirty(overrideDirty);\n setView((currentView) => {\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n return initialView;\n }\n\n return getLessDetailedView(currentView, initialView);\n });\n // initialValueOverrides is intentionally tracked via\n // overridesSignature on initialValues; including the object ref\n // here would re-fire the effect every render.\n }, [initialValues, initialView]);\n\n const visibleSections = React.useMemo(() => {\n if (!filteredSchema) return [];\n return getVisibleSettingsSections(\n filteredSchema,\n values,\n view,\n excludeKeys,\n );\n }, [filteredSchema, values, view, excludeKeys]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n setValues((prev) => ({ ...prev, [fieldKey]: nextValue }));\n setDirty((prev) => ({ ...prev, [fieldKey]: true }));\n },\n [],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n // Stable save callback so `onSaveControlChange` can hand a single\n // function reference to the parent across renders. The latest\n // closure is kept up to date via `handleSaveRef`.\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (!filteredSchema || isReadOnly) return;\n\n let payload: Record<string, unknown>;\n try {\n const basePayload = buildSdkSettingsPayloadForView(\n filteredSchema,\n values,\n dirty,\n view,\n );\n let defaultPayload: Record<string, unknown>;\n if (settingsSource === \"conversation_settings\") {\n defaultPayload = { conversation_settings_diff: basePayload };\n } else {\n defaultPayload = { agent_settings_diff: basePayload };\n }\n payload = buildPayload\n ? buildPayload(basePayload, { values, dirty, view })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n setDirty({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above.\n buildDirtyPayloadRef.current = () =>\n filteredSchema\n ? buildSdkSettingsPayload(filteredSchema, values, dirty)\n : {};\n\n // Surface save state to the parent. Hooks must run before any\n // conditional early-returns below, so this lives here rather than\n // alongside the JSX. The dependency list deliberately excludes\n // `stableSave` (it never changes) and `onSaveControlChange` (we\n // tolerate ref-instability of the callback to avoid spamming the\n // parent on every render).\n const saveControlIsDirty = Object.keys(dirty).length > 0 || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, values, view]);\n\n if (isLoading || isFetching || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n if (!filteredSchema || filteredSchema.sections.length === 0) {\n return (\n <Typography.Paragraph className=\"text-tertiary-alt\">\n {schemaUnavailableMessage}\n </Typography.Paragraph>\n );\n }\n\n if (Object.keys(values).length === 0) return <LlmSettingsInputsSkeleton />;\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {visibleSections.map((section, sectionIndex) => (\n <section\n key={`${section.key}-${sectionIndex}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"flex flex-col gap-4\">\n {section.fields.map((field) => (\n <SchemaField\n key={field.key}\n field={field}\n value={values[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n ))}\n </div>\n </section>\n ))}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={\n isPending || (Object.keys(dirty).length === 0 && !extraDirty)\n }\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sdk-section-page.js","names":[],"sources":["../../../../../src/components/features/settings/sdk-settings/sdk-section-page.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { LlmSettingsInputsSkeleton } from \"#/components/features/settings/llm-settings/llm-settings-inputs-skeleton\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport {\n useAgentSettingsSchema,\n useConversationSettingsSchema,\n} from \"#/hooks/query/use-agent-settings-schema\";\nimport { useSettings } from \"#/hooks/query/use-settings\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport { Settings, SettingsSchema, SettingsScope } from \"#/types/settings\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport {\n buildInitialSettingsFormValues,\n buildSdkSettingsPayload,\n buildSdkSettingsPayloadForView,\n getVisibleSettingsSections,\n hasAdvancedSettings,\n hasMinorSettings,\n inferInitialView,\n isValidSettingsSchema,\n SettingsDirtyState,\n SettingsFormValues,\n type SettingsValueSource,\n type SettingsView,\n} from \"#/utils/sdk-settings-schema\";\nimport { SchemaField } from \"./schema-field\";\nimport { ViewToggle } from \"./view-toggle\";\n\nconst EMPTY_EXCLUDE_KEYS = new Set<string>();\n\nconst VIEW_ORDER: Record<SettingsView, number> = {\n basic: 0,\n advanced: 1,\n all: 2,\n};\n\nconst getLessDetailedView = (\n currentView: SettingsView,\n nextView: SettingsView,\n): SettingsView =>\n VIEW_ORDER[nextView] < VIEW_ORDER[currentView] ? nextView : currentView;\n\nconst normalizeView = (\n view: SettingsView,\n {\n showAdvanced,\n showAll,\n }: {\n showAdvanced: boolean;\n showAll: boolean;\n },\n): SettingsView => {\n if (view === \"all\") {\n if (showAll) {\n return \"all\";\n }\n\n return showAdvanced ? \"advanced\" : \"basic\";\n }\n\n if (view === \"advanced\") {\n if (showAdvanced) {\n return \"advanced\";\n }\n\n return showAll ? \"all\" : \"basic\";\n }\n\n return \"basic\";\n};\n\nconst getSchemaUnavailableMessage = (\n error: unknown,\n fallbackMessage: string,\n): string => {\n if (!(error instanceof AxiosError)) {\n return fallbackMessage;\n }\n\n if (error.response?.status === 401) {\n return `${fallbackMessage} This agent server requires X-Session-API-Key. Set VITE_SESSION_API_KEY in the frontend to the same value used by the backend SESSION_API_KEY or OH_SESSION_API_KEYS_0.`;\n }\n\n if (error.response?.status === 404) {\n return `${fallbackMessage} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`;\n }\n\n return fallbackMessage;\n};\n\nexport interface SdkSectionHeaderProps {\n values: SettingsFormValues;\n isDisabled: boolean;\n view: SettingsView;\n onChange: (key: string, value: string | boolean) => void;\n}\n\n/**\n * Snapshot of the page's save state, surfaced to the parent so it can\n * render its own Save/Next button (e.g. in onboarding) when\n * {@link SdkSectionPage}'s built-in button is hidden via\n * `hideSaveButton`.\n */\nexport interface SdkSectionSaveControl {\n /** Trigger a save of the currently-dirty fields. No-op while `isSaving` or `!isDirty`. */\n save: () => void;\n /** A save mutation is in flight. */\n isSaving: boolean;\n /** At least one field is dirty (or `extraDirty` was passed in). */\n isDirty: boolean;\n /** Current form values (for custom save flows). */\n values: SettingsFormValues;\n /** The active view tier (basic/advanced/all) the form is rendering. */\n view: SettingsView;\n /**\n * Returns the coerced, dirty-only payload as a nested object\n * (e.g. `{ llm: { temperature: 0.7 } }`). Lets a custom save flow persist\n * exactly the fields the user changed, with proper types, without\n * re-implementing schema-driven coercion. Throws if a field fails coercion.\n */\n getDirtyPayload: () => Record<string, unknown>;\n}\n\n/**\n * A generic SDK-schema–driven settings page that renders fields\n * from one or more schema sections.\n *\n * @param sectionKeys - which schema section(s) this page owns (e.g. [\"condenser\"])\n * @param excludeKeys - field keys to skip (rendered elsewhere by the caller)\n * @param header - optional render prop receiving shared state to render above fields\n * @param testId - data-testid for the page wrapper\n */\nexport function SdkSectionPage({\n sectionKeys,\n excludeKeys = EMPTY_EXCLUDE_KEYS,\n scope = \"personal\",\n settingsSource = \"agent_settings\",\n header,\n extraDirty = false,\n buildPayload,\n onSaveSuccess,\n getInitialView,\n forceShowAdvancedView = false,\n allowAllView = true,\n initialValueOverrides,\n embedded = false,\n hideSaveButton = false,\n suppressSuccessToast = false,\n onSaveControlChange,\n testId = \"sdk-section-settings-screen\",\n}: {\n sectionKeys: string[];\n excludeKeys?: Set<string>;\n scope?: SettingsScope;\n settingsSource?: SettingsValueSource;\n\n header?: (props: SdkSectionHeaderProps) => React.ReactNode;\n extraDirty?: boolean;\n buildPayload?: (\n payload: ReturnType<typeof buildSdkSettingsPayloadForView>,\n context: {\n values: SettingsFormValues;\n dirty: SettingsDirtyState;\n view: SettingsView;\n },\n ) => Record<string, unknown>;\n onSaveSuccess?: () => void;\n getInitialView?: (\n settings: Settings,\n filteredSchema: SettingsSchema,\n ) => SettingsView;\n forceShowAdvancedView?: boolean;\n allowAllView?: boolean;\n /**\n * Per-field initial value overrides that win over the values\n * derived from `useSettings`. The keys of each override are also\n * marked dirty on hydration so the user can save the form without\n * having to touch the prefilled fields. Useful when the page is\n * embedded in a flow that wants to nudge brand-new users toward a\n * particular default (e.g. onboarding pre-filling OpenHands/Opus).\n */\n initialValueOverrides?: SettingsFormValues;\n /**\n * When true, the Save button container is rendered inline (no\n * sticky positioning, no contrasting `bg-base` band) so the page\n * can be dropped into a modal/card without a hard footer break.\n */\n embedded?: boolean;\n /**\n * Suppress the built-in Save Changes button entirely. Pair with\n * {@link onSaveControlChange} to drive saving from a parent-rendered\n * action (e.g. an onboarding \"Next\" button).\n */\n hideSaveButton?: boolean;\n /** Suppress the default success toast after save completes. */\n suppressSuccessToast?: boolean;\n /**\n * Fires whenever the save state changes (a mutation starts/finishes,\n * dirty status flips). Provides a stable `save()` callback the\n * parent can wire to its own button. Useful when the form is\n * embedded in a custom flow and the built-in Save button is hidden.\n */\n onSaveControlChange?: (control: SdkSectionSaveControl) => void;\n testId?: string;\n}) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: saveSettings, isPending } = useSaveSettings(scope);\n const { data: settings, isLoading, isFetching } = useSettings(scope);\n const agentSchemaQuery = useAgentSettingsSchema(\n settings?.agent_settings_schema,\n );\n const conversationSchemaQuery = useConversationSettingsSchema(\n settings?.conversation_settings_schema,\n );\n const activeSchemaQuery =\n settingsSource === \"conversation_settings\"\n ? conversationSchemaQuery\n : agentSchemaQuery;\n const schema = activeSchemaQuery.data;\n const isSchemaLoading = activeSchemaQuery.isLoading;\n const isReadOnly = false;\n\n const [view, setView] = React.useState<SettingsView>(\"basic\");\n const [values, setValues] = React.useState<SettingsFormValues>({});\n const [dirty, setDirty] = React.useState<SettingsDirtyState>({});\n const hasHydratedViewRef = React.useRef(false);\n\n const sectionKeysSignature = React.useMemo(\n () => JSON.stringify(sectionKeys),\n [sectionKeys],\n );\n const stableSectionKeys = React.useMemo(\n () => JSON.parse(sectionKeysSignature) as string[],\n [sectionKeysSignature],\n );\n\n // Build a filtered schema containing only the requested sections.\n // `isValidSettingsSchema` guards against truthy-but-malformed schema\n // responses (e.g. when the deployment is pointed at a host that does\n // not serve `/api/settings/agent-schema` and returns an SPA shell\n // that parses into an object without a `sections` array). Without\n // the guard, `schema.sections.filter(...)` would throw and React\n // Router would escalate the crash to a full-screen error.\n const filteredSchema = React.useMemo(() => {\n if (!isValidSettingsSchema(schema)) return null;\n const sectionSet = new Set(stableSectionKeys);\n return {\n ...schema,\n sections: schema.sections.filter((s) => sectionSet.has(s.key)),\n };\n }, [schema, stableSectionKeys]);\n\n const showAdvanced =\n forceShowAdvancedView || hasAdvancedSettings(filteredSchema);\n const showAll = allowAllView && hasMinorSettings(filteredSchema);\n const schemaUnavailableMessage = React.useMemo(\n () =>\n getSchemaUnavailableMessage(\n activeSchemaQuery.error,\n t(I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE),\n ),\n [activeSchemaQuery.error, t],\n );\n\n const overridesSignature = React.useMemo(\n () => (initialValueOverrides ? JSON.stringify(initialValueOverrides) : \"\"),\n [initialValueOverrides],\n );\n\n const initialValues = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n const base = buildInitialSettingsFormValues(\n settings,\n filteredSchema,\n settingsSource,\n );\n if (!initialValueOverrides) return base;\n return { ...base, ...initialValueOverrides };\n // overridesSignature keeps the memo reactive without depending on\n // a (potentially recreated) object reference each render.\n }, [settings, filteredSchema, settingsSource, overridesSignature]);\n\n const initialView = React.useMemo(() => {\n if (!settings || !filteredSchema) return null;\n\n const resolvedInitialView = getInitialView\n ? getInitialView(settings, filteredSchema)\n : inferInitialView(settings, filteredSchema, settingsSource);\n\n return normalizeView(resolvedInitialView, { showAdvanced, showAll });\n }, [\n settings,\n filteredSchema,\n getInitialView,\n settingsSource,\n showAdvanced,\n showAll,\n ]);\n\n React.useEffect(() => {\n hasHydratedViewRef.current = false;\n setView(\"basic\");\n setValues({});\n setDirty({});\n }, [scope, settingsSource, sectionKeysSignature]);\n\n React.useEffect(() => {\n if (!initialValues || !initialView) return;\n\n setValues(initialValues);\n // Override-supplied keys are pre-populated for the user, so mark\n // them dirty up-front; otherwise the Save button stays disabled\n // until the user touches a field, defeating the point of the\n // override.\n const overrideDirty: SettingsDirtyState = initialValueOverrides\n ? Object.fromEntries(\n Object.keys(initialValueOverrides).map((key) => [key, true]),\n )\n : {};\n setDirty(overrideDirty);\n setView((currentView) => {\n if (!hasHydratedViewRef.current) {\n hasHydratedViewRef.current = true;\n return initialView;\n }\n\n return getLessDetailedView(currentView, initialView);\n });\n // initialValueOverrides is intentionally tracked via\n // overridesSignature on initialValues; including the object ref\n // here would re-fire the effect every render.\n }, [initialValues, initialView]);\n\n const visibleSections = React.useMemo(() => {\n if (!filteredSchema) return [];\n return getVisibleSettingsSections(\n filteredSchema,\n values,\n view,\n excludeKeys,\n );\n }, [filteredSchema, values, view, excludeKeys]);\n\n const handleFieldChange = React.useCallback(\n (fieldKey: string, nextValue: string | boolean) => {\n setValues((prev) => ({ ...prev, [fieldKey]: nextValue }));\n setDirty((prev) => ({ ...prev, [fieldKey]: true }));\n },\n [],\n );\n\n const handleError = React.useCallback(\n (error: AxiosError) => {\n const msg = retrieveAxiosErrorMessage(error);\n displayErrorToast(msg || t(I18nKey.ERROR$GENERIC));\n },\n [t],\n );\n\n // Stable save callback so `onSaveControlChange` can hand a single\n // function reference to the parent across renders. The latest\n // closure is kept up to date via `handleSaveRef`.\n const handleSaveRef = React.useRef<() => void>(() => {});\n const stableSave = React.useCallback(() => {\n handleSaveRef.current();\n }, []);\n\n // Stable accessor for the coerced, dirty-only payload. Mirrors the\n // `handleSaveRef` pattern so the exposed function reference stays stable\n // across renders while always reading the latest closure at call time.\n const buildDirtyPayloadRef = React.useRef<() => Record<string, unknown>>(\n () => ({}),\n );\n const stableGetDirtyPayload = React.useCallback(\n () => buildDirtyPayloadRef.current(),\n [],\n );\n\n const handleSave = () => {\n if (!filteredSchema || isReadOnly) return;\n\n let payload: Record<string, unknown>;\n try {\n const basePayload = buildSdkSettingsPayloadForView(\n filteredSchema,\n values,\n dirty,\n view,\n );\n let defaultPayload: Record<string, unknown>;\n if (settingsSource === \"conversation_settings\") {\n defaultPayload = { conversation_settings_diff: basePayload };\n } else {\n defaultPayload = { agent_settings_diff: basePayload };\n }\n payload = buildPayload\n ? buildPayload(basePayload, { values, dirty, view })\n : defaultPayload;\n } catch (error) {\n displayErrorToast(\n error instanceof Error ? error.message : t(I18nKey.ERROR$GENERIC),\n );\n return;\n }\n\n if (Object.keys(payload).length === 0) return;\n\n saveSettings(payload, {\n onError: handleError,\n onSuccess: () => {\n if (!suppressSuccessToast) {\n displaySuccessToast(t(I18nKey.SETTINGS$SAVED_WARNING));\n }\n setDirty({});\n onSaveSuccess?.();\n },\n });\n };\n\n handleSaveRef.current = handleSave;\n // Dirty-only (NOT view-filtered): we must never inject defaults for\n // non-visible fields here, or a custom save flow would reset fields the\n // user never touched. `buildSdkSettingsPayloadForView` is reserved for the\n // built-in full-replace save above.\n buildDirtyPayloadRef.current = () =>\n filteredSchema\n ? buildSdkSettingsPayload(filteredSchema, values, dirty)\n : {};\n\n // Surface save state to the parent. Hooks must run before any\n // conditional early-returns below, so this lives here rather than\n // alongside the JSX. The dependency list deliberately excludes\n // `stableSave` (it never changes) and `onSaveControlChange` (we\n // tolerate ref-instability of the callback to avoid spamming the\n // parent on every render).\n const saveControlIsDirty = Object.keys(dirty).length > 0 || extraDirty;\n React.useEffect(() => {\n if (!onSaveControlChange) return;\n onSaveControlChange({\n save: stableSave,\n isSaving: isPending,\n isDirty: saveControlIsDirty,\n values,\n view,\n getDirtyPayload: stableGetDirtyPayload,\n });\n }, [isPending, saveControlIsDirty, values, view]);\n\n // Keep existing form content visible during background refetches to avoid\n // flashing the full skeleton (notably during onboarding Next transitions).\n const isInitialSettingsLoad = (isLoading || isFetching) && !settings;\n if (isInitialSettingsLoad || isSchemaLoading) {\n return <LlmSettingsInputsSkeleton />;\n }\n\n if (!filteredSchema || filteredSchema.sections.length === 0) {\n return (\n <Typography.Paragraph className=\"text-tertiary-alt\">\n {schemaUnavailableMessage}\n </Typography.Paragraph>\n );\n }\n\n if (Object.keys(values).length === 0) return <LlmSettingsInputsSkeleton />;\n\n // Scrolling is owned by the settings shell (or onboarding wrapper), not a\n // nested scroll region. Save actions are inline after the last field.\n const bodyClassName = \"flex flex-col gap-8\";\n\n return (\n <div\n data-testid={testId}\n className={\n embedded\n ? \"relative flex min-h-0 w-full flex-1 flex-col\"\n : \"relative w-full min-h-0\"\n }\n >\n <ViewToggle\n view={view}\n setView={setView}\n showAdvanced={showAdvanced}\n showAll={showAll}\n isDisabled={isReadOnly}\n />\n\n <div className={bodyClassName}>\n {header?.({\n values,\n isDisabled: isReadOnly,\n view,\n onChange: handleFieldChange,\n })}\n\n {visibleSections.map((section, sectionIndex) => (\n <section\n key={`${section.key}-${sectionIndex}`}\n className=\"flex flex-col gap-4\"\n >\n <div className=\"flex flex-col gap-4\">\n {section.fields.map((field) => (\n <SchemaField\n key={field.key}\n field={field}\n value={values[field.key]}\n isDisabled={isReadOnly}\n onChange={(nextValue) =>\n handleFieldChange(field.key, nextValue)\n }\n />\n ))}\n </div>\n </section>\n ))}\n\n {!isReadOnly && !hideSaveButton ? (\n <div className=\"flex justify-start pt-2\">\n <BrandButton\n testId=\"save-button\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={\n isPending || (Object.keys(dirty).length === 0 && !extraDirty)\n }\n onClick={handleSave}\n >\n {isPending\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.SETTINGS$SAVE_CHANGES)}\n </BrandButton>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoCA,IAAM,qBAAqB,IAAI,KAAa,EAEtC,IAA2C;CAC/C,OAAO;CACP,UAAU;CACV,KAAK;CACN,EAEK,MACJ,GACA,MAEA,EAAW,KAAY,EAAW,KAAe,IAAW,GAExD,MACJ,GACA,EACE,iBACA,iBAME,MAAS,QACP,IACK,QAGF,IAAe,aAAa,UAGjC,MAAS,aACP,IACK,aAGF,IAAU,QAAQ,UAGpB,SAGH,KACJ,GACA,MAEM,aAAiB,IAInB,EAAM,UAAU,WAAW,MACtB,GAAG,EAAgB,2KAGxB,EAAM,UAAU,WAAW,MACtB,GAAG,EAAgB,uHAGrB,IAXE;AAwDX,SAAgB,EAAe,EAC7B,gBACA,iBAAc,IACd,WAAQ,YACR,oBAAiB,kBACjB,YACA,gBAAa,IACb,iBACA,mBACA,mBACA,4BAAwB,IACxB,mBAAe,IACf,0BACA,eAAW,IACX,oBAAiB,IACjB,0BAAuB,IACvB,wBACA,YAAS,iCAuDR;CACD,IAAM,EAAE,SAAM,EAAe,YAAY,EACnC,EAAE,QAAQ,GAAc,iBAAc,EAAgB,EAAM,EAC5D,EAAE,MAAM,GAAU,cAAW,kBAAe,GAAY,EAAM,EAC9D,IAAmB,GACvB,GAAU,sBACX,EACK,IAA0B,EAC9B,GAAU,6BACX,EACK,IACJ,MAAmB,0BACf,IACA,GACA,IAAS,EAAkB,MAC3B,KAAkB,EAAkB,WAGpC,CAAC,GAAM,KAAW,EAAM,SAAuB,QAAQ,EACvD,CAAC,GAAQ,KAAa,EAAM,SAA6B,EAAE,CAAC,EAC5D,CAAC,GAAO,KAAY,EAAM,SAA6B,EAAE,CAAC,EAC1D,IAAqB,EAAM,OAAO,GAAM,EAExC,IAAuB,EAAM,cAC3B,KAAK,UAAU,EAAY,EACjC,CAAC,EAAY,CACd,EACK,IAAoB,EAAM,cACxB,KAAK,MAAM,EAAqB,EACtC,CAAC,EAAqB,CACvB,EASK,IAAiB,EAAM,cAAc;AACzC,MAAI,CAAC,GAAsB,EAAO,CAAE,QAAO;EAC3C,IAAM,IAAa,IAAI,IAAI,EAAkB;AAC7C,SAAO;GACL,GAAG;GACH,UAAU,EAAO,SAAS,QAAQ,MAAM,EAAW,IAAI,EAAE,IAAI,CAAC;GAC/D;IACA,CAAC,GAAQ,EAAkB,CAAC,EAEzB,IACJ,MAAyB,GAAoB,EAAe,EACxD,IAAU,MAAgB,GAAiB,EAAe,EAC1D,KAA2B,EAAM,cAEnC,EACE,EAAkB,OAClB,EAAE,EAAQ,gCAAgC,CAC3C,EACH,CAAC,EAAkB,OAAO,EAAE,CAC7B,EAEK,KAAqB,EAAM,cACxB,IAAwB,KAAK,UAAU,EAAsB,GAAG,IACvE,CAAC,EAAsB,CACxB,EAEK,IAAgB,EAAM,cAAc;AACxC,MAAI,CAAC,KAAY,CAAC,EAAgB,QAAO;EACzC,IAAM,IAAO,EACX,GACA,GACA,EACD;AAED,SADK,IACE;GAAE,GAAG;GAAM,GAAG;GAAuB,GADT;IAIlC;EAAC;EAAU;EAAgB;EAAgB;EAAmB,CAAC,EAE5D,IAAc,EAAM,cACpB,CAAC,KAAY,CAAC,IAAuB,OAMlC,GAJqB,IACxB,EAAe,GAAU,EAAe,GACxC,GAAiB,GAAU,GAAgB,EAAe,EAEpB;EAAE;EAAc;EAAS,CAAC,EACnE;EACD;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AASF,CAPA,EAAM,gBAAgB;AAIpB,EAHA,EAAmB,UAAU,IAC7B,EAAQ,QAAQ,EAChB,EAAU,EAAE,CAAC,EACb,EAAS,EAAE,CAAC;IACX;EAAC;EAAO;EAAgB;EAAqB,CAAC,EAEjD,EAAM,gBAAgB;AAChB,GAAC,KAAiB,CAAC,MAEvB,EAAU,EAAc,EAUxB,EAL0C,IACtC,OAAO,YACL,OAAO,KAAK,EAAsB,CAAC,KAAK,MAAQ,CAAC,GAAK,GAAK,CAAC,CAC7D,GACD,EAAE,CACiB,EACvB,GAAS,MACF,EAAmB,UAKjB,GAAoB,GAAa,EAAY,IAJlD,EAAmB,UAAU,IACtB,GAIT;IAID,CAAC,GAAe,EAAY,CAAC;CAEhC,IAAM,KAAkB,EAAM,cACvB,IACE,GACL,GACA,GACA,GACA,EACD,GAN2B,EAAE,EAO7B;EAAC;EAAgB;EAAQ;EAAM;EAAY,CAAC,EAEzC,IAAoB,EAAM,aAC7B,GAAkB,MAAgC;AAEjD,EADA,GAAW,OAAU;GAAE,GAAG;IAAO,IAAW;GAAW,EAAE,EACzD,GAAU,OAAU;GAAE,GAAG;IAAO,IAAW;GAAM,EAAE;IAErD,EAAE,CACH,EAEK,KAAc,EAAM,aACvB,MAAsB;AAErB,IADY,GAA0B,EACpB,IAAO,EAAE,EAAQ,cAAc,CAAC;IAEpD,CAAC,EAAE,CACJ,EAKK,IAAgB,EAAM,aAAyB,GAAG,EAClD,KAAa,EAAM,kBAAkB;AACzC,IAAc,SAAS;IACtB,EAAE,CAAC,EAKA,IAAuB,EAAM,cAC1B,EAAE,EACV,EACK,KAAwB,EAAM,kBAC5B,EAAqB,SAAS,EACpC,EAAE,CACH,EAEK,UAAmB;AACvB,MAAI,CAAC,EAA8B;EAEnC,IAAI;AACJ,MAAI;GACF,IAAM,IAAc,EAClB,GACA,GACA,GACA,EACD,EACG;AAMJ,GALA,AAGE,IAHE,MAAmB,0BACJ,EAAE,4BAA4B,GAAa,GAE3C,EAAE,qBAAqB,GAAa,EAEvD,IAAU,IACN,EAAa,GAAa;IAAE;IAAQ;IAAO;IAAM,CAAC,GAClD;WACG,GAAO;AACd,KACE,aAAiB,QAAQ,EAAM,UAAU,EAAE,EAAQ,cAAc,CAClE;AACD;;AAGE,SAAO,KAAK,EAAQ,CAAC,WAAW,KAEpC,EAAa,GAAS;GACpB,SAAS;GACT,iBAAiB;AAKf,IAJK,KACH,GAAoB,EAAE,EAAQ,uBAAuB,CAAC,EAExD,EAAS,EAAE,CAAC,EACZ,MAAiB;;GAEpB,CAAC;;AAQJ,CALA,EAAc,UAAU,GAKxB,EAAqB,gBACnB,IACI,EAAwB,GAAgB,GAAQ,EAAM,GACtD,EAAE;CAQR,IAAM,IAAqB,OAAO,KAAK,EAAM,CAAC,SAAS,KAAK;AAkC5D,QAjCA,EAAM,gBAAgB;AACf,OACL,EAAoB;GAClB,MAAM;GACN,UAAU;GACV,SAAS;GACT;GACA;GACA,iBAAiB;GAClB,CAAC;IACD;EAAC;EAAW;EAAoB;EAAQ;EAAK,CAAC,GAIlB,KAAa,MAAe,CAAC,KAC/B,KACpB,kBAAC,GAAD,EAA6B,CAAA,GAGlC,CAAC,KAAkB,EAAe,SAAS,WAAW,IAEtD,kBAAC,GAAW,WAAZ;EAAsB,WAAU;YAC7B;EACoB,CAAA,GAIvB,OAAO,KAAK,EAAO,CAAC,WAAW,IAAU,kBAAC,GAAD,EAA6B,CAAA,GAOxE,kBAAC,OAAD;EACE,eAAa;EACb,WACE,KACI,iDACA;YALR,CAQE,kBAAC,IAAD;GACQ;GACG;GACK;GACL;GACT,YAAY;GACZ,CAAA,EAEF,kBAAC,OAAD;GAAK,WAAW;aAAhB;IACG,KAAS;KACR;KACA,YAAY;KACZ;KACA,UAAU;KACX,CAAC;IAED,GAAgB,KAAK,GAAS,MAC7B,kBAAC,WAAD;KAEE,WAAU;eAEV,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,OAAO,KAAK,MACnB,kBAAC,IAAD;OAES;OACP,OAAO,EAAO,EAAM;OACpB,YAAY;OACZ,WAAW,MACT,EAAkB,EAAM,KAAK,EAAU;OAEzC,EAPK,EAAM,IAOX,CACF;MACE,CAAA;KACE,EAhBH,GAAG,EAAQ,IAAI,GAAG,IAgBf,CACV;IAEe,IAgBb,OAfF,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,IAAD;MACE,QAAO;MACP,MAAK;MACL,SAAQ;MACR,YACE,KAAc,OAAO,KAAK,EAAM,CAAC,WAAW,KAAK,CAAC;MAEpD,SAAS;gBAGL,EADH,IACK,EAAQ,kBACR,EAAQ,sBAAsB;MACxB,CAAA;KACV,CAAA;IAEJ;KACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../../i18n/declaration.cjs`),n=require(`../../../utils/utils.cjs`),r=require(`../../../constants/acp-providers.cjs`),i=require(
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../../i18n/declaration.cjs`),n=require(`../../../utils/utils.cjs`),r=require(`../../../constants/acp-providers.cjs`),i=require(`../../../hooks/query/use-settings.cjs`),a=require(`../../shared/buttons/styled-tooltip.cjs`),o=require(`../../shared/navigation-link.cjs`),s=require(`../../../icons/skills.cjs`),c=require(`../../../hooks/use-breakpoint.cjs`),l=require(`../sidebar/sidebar-layout.cjs`),u=require(`../settings/backend-synced-settings-badge.cjs`),d=require(`../../../icons/server-process.cjs`),f=require(`../../../stores/sidebar-store.cjs`);let p=require(`react/jsx-runtime`);var m=[{to:`/skills`,label:`Skills`,icon:(0,p.jsx)(s.default,{width:16,height:16,"aria-hidden":`true`}),end:!0},{to:`/mcp`,label:`MCP Servers`,icon:(0,p.jsx)(d.default,{width:16,height:16}),end:!0,disabledByAcp:!0},{to:`/plugins`,label:`Plugins`,icon:(0,p.jsxs)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,width:16,height:16,"aria-hidden":`true`,children:[(0,p.jsx)(`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`}),(0,p.jsx)(`path`,{d:`m3.3 7 8.7 5 8.7-5`}),(0,p.jsx)(`path`,{d:`M12 22V12`})]}),end:!0,comingSoon:!0}];function h(){let{t:s}=e.useTranslation(`openhands`),{data:d}=i.useSettings(),h=f.useSidebarStore(e=>e.collapsed),g=c.useBreakpoint(1023),_=c.useBreakpoint(767),v=!h&&g&&!_,y=d?.agent_settings?.agent_kind===`acp`,b=typeof d?.agent_settings?.acp_server==`string`?d.agent_settings.acp_server:void 0,x=y?r.ACP_PROVIDERS.find(({key:e})=>e===b)?.display_name??`ACP Agent`:void 0;return v?null:(0,p.jsxs)(`aside`,{"data-testid":`extensions-navbar-desktop`,className:`hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2 md:sticky md:top-8 md:self-start`,children:[(0,p.jsx)(`span`,{className:`px-2 text-sm font-normal text-white`,children:s(t.I18nKey.NAV$CUSTOMIZE)}),(0,p.jsx)(`div`,{className:`flex flex-col gap-0.5 pt-0.5`,children:m.map(e=>{let r=!!(y&&e.disabledByAcp),i=(0,p.jsx)(`span`,{className:`shrink-0 flex items-center justify-center`,children:e.icon}),c=(0,p.jsx)(`span`,{className:`truncate`,children:e.label}),u=e.comingSoon&&(0,p.jsx)(`span`,{className:`ml-auto shrink-0 rounded-full border border-white/20 bg-white/5 px-1.5 py-0.5 text-[10px] font-medium text-[var(--oh-text-dim)]`,children:s(t.I18nKey.NAV$COMING_SOON)});return r?(0,p.jsx)(a.StyledTooltip,{content:s(t.I18nKey.SETTINGS$AGENT_DISABLED_TOOLTIP,{agentName:x}),placement:`right`,children:(0,p.jsxs)(`span`,{"aria-disabled":`true`,"data-testid":`sidebar-extensions-${e.to}`,className:n.cn(l.sidebarNavRowClassName(),`truncate text-[var(--oh-muted)] opacity-50 cursor-not-allowed`),children:[i,c,u]})},e.to):(0,p.jsxs)(o.NavigationLink,{to:e.to,end:e.end,"data-testid":`sidebar-extensions-${e.to}`,className:({isActive:e})=>n.cn(l.sidebarNavRowClassName(),`truncate`,e?l.SIDEBAR_ROW_INTERACTIVE_CLASS.active:l.SIDEBAR_ROW_INTERACTIVE_CLASS.idle),children:[i,c,u]},e.to)})}),(0,p.jsx)(`div`,{className:`px-2 pt-3`,children:(0,p.jsx)(u.BackendSyncedSettingsBadge,{})})]})}exports.ExtensionsNavigation=h;
|
|
2
2
|
//# sourceMappingURL=extensions-navigation.cjs.map
|
|
@@ -2,8 +2,8 @@ import { useTranslation as e } from "../../../node_modules/react-i18next/dist/es
|
|
|
2
2
|
import { I18nKey as t } from "../../../i18n/declaration.js";
|
|
3
3
|
import { cn as n } from "../../../utils/utils.js";
|
|
4
4
|
import { ACP_PROVIDERS as r } from "../../../constants/acp-providers.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useSettings as i } from "../../../hooks/query/use-settings.js";
|
|
6
|
+
import { StyledTooltip as a } from "../../shared/buttons/styled-tooltip.js";
|
|
7
7
|
import { NavigationLink as o } from "../../shared/navigation-link.js";
|
|
8
8
|
import s from "../../../icons/skills.js";
|
|
9
9
|
import { useBreakpoint as c } from "../../../hooks/use-breakpoint.js";
|
|
@@ -59,7 +59,7 @@ var g = [
|
|
|
59
59
|
}
|
|
60
60
|
];
|
|
61
61
|
function _() {
|
|
62
|
-
let { t: s } = e("openhands"), { data: f } =
|
|
62
|
+
let { t: s } = e("openhands"), { data: f } = i(), _ = p((e) => e.collapsed), v = c(1023), y = c(767), b = !_ && v && !y, x = f?.agent_settings?.agent_kind === "acp", S = typeof f?.agent_settings?.acp_server == "string" ? f.agent_settings.acp_server : void 0, C = x ? r.find(({ key: e }) => e === S)?.display_name ?? "ACP Agent" : void 0;
|
|
63
63
|
return b ? null : /* @__PURE__ */ h("aside", {
|
|
64
64
|
"data-testid": "extensions-navbar-desktop",
|
|
65
65
|
className: "hidden md:flex md:w-[260px] md:shrink-0 md:flex-col md:gap-2 md:sticky md:top-8 md:self-start",
|
|
@@ -71,7 +71,7 @@ function _() {
|
|
|
71
71
|
/* @__PURE__ */ m("div", {
|
|
72
72
|
className: "flex flex-col gap-0.5 pt-0.5",
|
|
73
73
|
children: g.map((e) => {
|
|
74
|
-
let r = !!(x && e.disabledByAcp),
|
|
74
|
+
let r = !!(x && e.disabledByAcp), i = /* @__PURE__ */ m("span", {
|
|
75
75
|
className: "shrink-0 flex items-center justify-center",
|
|
76
76
|
children: e.icon
|
|
77
77
|
}), c = /* @__PURE__ */ m("span", {
|
|
@@ -81,7 +81,7 @@ function _() {
|
|
|
81
81
|
className: "ml-auto shrink-0 rounded-full border border-white/20 bg-white/5 px-1.5 py-0.5 text-[10px] font-medium text-[var(--oh-text-dim)]",
|
|
82
82
|
children: s(t.NAV$COMING_SOON)
|
|
83
83
|
});
|
|
84
|
-
return r ? /* @__PURE__ */ m(
|
|
84
|
+
return r ? /* @__PURE__ */ m(a, {
|
|
85
85
|
content: s(t.SETTINGS$AGENT_DISABLED_TOOLTIP, { agentName: C }),
|
|
86
86
|
placement: "right",
|
|
87
87
|
children: /* @__PURE__ */ h("span", {
|
|
@@ -89,7 +89,7 @@ function _() {
|
|
|
89
89
|
"data-testid": `sidebar-extensions-${e.to}`,
|
|
90
90
|
className: n(u(), "truncate text-[var(--oh-muted)] opacity-50 cursor-not-allowed"),
|
|
91
91
|
children: [
|
|
92
|
-
|
|
92
|
+
i,
|
|
93
93
|
c,
|
|
94
94
|
d
|
|
95
95
|
]
|
|
@@ -100,7 +100,7 @@ function _() {
|
|
|
100
100
|
"data-testid": `sidebar-extensions-${e.to}`,
|
|
101
101
|
className: ({ isActive: e }) => n(u(), "truncate", e ? l.active : l.idle),
|
|
102
102
|
children: [
|
|
103
|
-
|
|
103
|
+
i,
|
|
104
104
|
c,
|
|
105
105
|
d
|
|
106
106
|
]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../_virtual/_rolldown/runtime.cjs`);let t=require(`react`);t=e.__toESM(t,1);let n=require(`react/jsx-runtime`),r=require(`react-dom`);function i({children:e,onClose:i,closeOnEscape:a=!0,"aria-label":
|
|
1
|
+
const e=require(`../../../_virtual/_rolldown/runtime.cjs`);let t=require(`react`);t=e.__toESM(t,1);let n=require(`react/jsx-runtime`),r=require(`react-dom`);function i({children:e,onClose:i,closeOnEscape:a=!0,closeOnBackdropClick:o=!0,"aria-label":s}){return t.default.useEffect(()=>{if(!a)return;let e=e=>{e.key===`Escape`&&i?.()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[a,i]),typeof document>`u`?null:(0,r.createPortal)((0,n.jsxs)(`div`,{role:`dialog`,"aria-modal":`true`,"aria-label":s,className:`fixed inset-0 flex items-center justify-center z-60`,children:[(0,n.jsx)(`div`,{onClick:e=>{o&&e.target===e.currentTarget&&i?.()},className:`fixed inset-0 bg-black opacity-60`}),(0,n.jsx)(`div`,{className:`relative`,children:e})]}),document.body)}exports.ModalBackdrop=i;
|
|
2
2
|
//# sourceMappingURL=modal-backdrop.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal-backdrop.cjs","names":[],"sources":["../../../../src/components/shared/modals/modal-backdrop.tsx"],"sourcesContent":["import React from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ModalBackdropProps {\n children: React.ReactNode;\n onClose?: () => void;\n /** When false, pressing Escape does not close the modal. Defaults to true. */\n closeOnEscape?: boolean;\n \"aria-label\"?: string;\n}\n\nexport function ModalBackdrop({\n children,\n onClose,\n closeOnEscape = true,\n \"aria-label\": ariaLabel,\n}: ModalBackdropProps) {\n React.useEffect(() => {\n if (!closeOnEscape) return undefined;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose?.();\n };\n\n window.addEventListener(\"keydown\", handleEscape);\n return () => window.removeEventListener(\"keydown\", handleEscape);\n }, [closeOnEscape, onClose]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose?.(); // only close if the click was on the backdrop\n };\n\n if (typeof document === \"undefined\") return null;\n\n // Portal to document.body so the modal's `position: fixed` resolves\n // against the viewport. Otherwise a transformed ancestor (e.g. the\n // onboarding slide rail) would become the containing block and the\n // modal would render trapped inside it instead of overlapping its\n // parent modal.\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n className=\"fixed inset-0 flex items-center justify-center z-60\"\n >\n <div\n onClick={handleClick}\n className=\"fixed inset-0 bg-black opacity-60\"\n />\n <div className=\"relative\">{children}</div>\n </div>,\n document.body,\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"modal-backdrop.cjs","names":[],"sources":["../../../../src/components/shared/modals/modal-backdrop.tsx"],"sourcesContent":["import React from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ModalBackdropProps {\n children: React.ReactNode;\n onClose?: () => void;\n /** When false, pressing Escape does not close the modal. Defaults to true. */\n closeOnEscape?: boolean;\n /** When false, clicking the backdrop does not close the modal. Defaults to true. */\n closeOnBackdropClick?: boolean;\n \"aria-label\"?: string;\n}\n\nexport function ModalBackdrop({\n children,\n onClose,\n closeOnEscape = true,\n closeOnBackdropClick = true,\n \"aria-label\": ariaLabel,\n}: ModalBackdropProps) {\n React.useEffect(() => {\n if (!closeOnEscape) return undefined;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose?.();\n };\n\n window.addEventListener(\"keydown\", handleEscape);\n return () => window.removeEventListener(\"keydown\", handleEscape);\n }, [closeOnEscape, onClose]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (!closeOnBackdropClick) return;\n if (e.target === e.currentTarget) onClose?.(); // only close if the click was on the backdrop\n };\n\n if (typeof document === \"undefined\") return null;\n\n // Portal to document.body so the modal's `position: fixed` resolves\n // against the viewport. Otherwise a transformed ancestor (e.g. the\n // onboarding slide rail) would become the containing block and the\n // modal would render trapped inside it instead of overlapping its\n // parent modal.\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n className=\"fixed inset-0 flex items-center justify-center z-60\"\n >\n <div\n onClick={handleClick}\n className=\"fixed inset-0 bg-black opacity-60\"\n />\n <div className=\"relative\">{children}</div>\n </div>,\n document.body,\n );\n}\n"],"mappings":"6JAaA,SAAgB,EAAc,CAC5B,WACA,UACA,gBAAgB,GAChB,uBAAuB,GACvB,aAAc,GACO,CAuBrB,OAtBA,EAAA,QAAM,cAAgB,CACpB,GAAI,CAAC,EAAe,OACpB,IAAM,EAAgB,GAAqB,CACrC,EAAE,MAAQ,UAAU,KAAW,EAIrC,OADA,OAAO,iBAAiB,UAAW,EAAa,KACnC,OAAO,oBAAoB,UAAW,EAAa,EAC/D,CAAC,EAAe,EAAQ,CAAC,CAOxB,OAAO,SAAa,IAAoB,MAO5C,EAAA,EAAA,eACE,EAAA,EAAA,MAAC,MAAD,CACE,KAAK,SACL,aAAW,OACX,aAAY,EACZ,UAAU,+DAJZ,EAME,EAAA,EAAA,KAAC,MAAD,CACE,QApBe,GAAwC,CACtD,GACD,EAAE,SAAW,EAAE,eAAe,KAAW,EAmBzC,UAAU,oCACV,CAAA,EACF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,WAAY,WAAe,CAAA,CACtC,GACN,SAAS,KACV"}
|
|
@@ -4,7 +4,9 @@ interface ModalBackdropProps {
|
|
|
4
4
|
onClose?: () => void;
|
|
5
5
|
/** When false, pressing Escape does not close the modal. Defaults to true. */
|
|
6
6
|
closeOnEscape?: boolean;
|
|
7
|
+
/** When false, clicking the backdrop does not close the modal. Defaults to true. */
|
|
8
|
+
closeOnBackdropClick?: boolean;
|
|
7
9
|
"aria-label"?: string;
|
|
8
10
|
}
|
|
9
|
-
export declare function ModalBackdrop({ children, onClose, closeOnEscape, "aria-label": ariaLabel, }: ModalBackdropProps): React.ReactPortal | null;
|
|
11
|
+
export declare function ModalBackdrop({ children, onClose, closeOnEscape, closeOnBackdropClick, "aria-label": ariaLabel, }: ModalBackdropProps): React.ReactPortal | null;
|
|
10
12
|
export {};
|
|
@@ -2,7 +2,7 @@ import e from "react";
|
|
|
2
2
|
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
3
|
import { createPortal as r } from "react-dom";
|
|
4
4
|
//#region src/components/shared/modals/modal-backdrop.tsx
|
|
5
|
-
function i({ children: i, onClose: a, closeOnEscape: o = !0, "aria-label":
|
|
5
|
+
function i({ children: i, onClose: a, closeOnEscape: o = !0, closeOnBackdropClick: s = !0, "aria-label": c }) {
|
|
6
6
|
return e.useEffect(() => {
|
|
7
7
|
if (!o) return;
|
|
8
8
|
let e = (e) => {
|
|
@@ -12,11 +12,11 @@ function i({ children: i, onClose: a, closeOnEscape: o = !0, "aria-label": s })
|
|
|
12
12
|
}, [o, a]), typeof document > "u" ? null : r(/* @__PURE__ */ n("div", {
|
|
13
13
|
role: "dialog",
|
|
14
14
|
"aria-modal": "true",
|
|
15
|
-
"aria-label":
|
|
15
|
+
"aria-label": c,
|
|
16
16
|
className: "fixed inset-0 flex items-center justify-center z-60",
|
|
17
17
|
children: [/* @__PURE__ */ t("div", {
|
|
18
18
|
onClick: (e) => {
|
|
19
|
-
e.target === e.currentTarget && a?.();
|
|
19
|
+
s && e.target === e.currentTarget && a?.();
|
|
20
20
|
},
|
|
21
21
|
className: "fixed inset-0 bg-black opacity-60"
|
|
22
22
|
}), /* @__PURE__ */ t("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal-backdrop.js","names":[],"sources":["../../../../src/components/shared/modals/modal-backdrop.tsx"],"sourcesContent":["import React from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ModalBackdropProps {\n children: React.ReactNode;\n onClose?: () => void;\n /** When false, pressing Escape does not close the modal. Defaults to true. */\n closeOnEscape?: boolean;\n \"aria-label\"?: string;\n}\n\nexport function ModalBackdrop({\n children,\n onClose,\n closeOnEscape = true,\n \"aria-label\": ariaLabel,\n}: ModalBackdropProps) {\n React.useEffect(() => {\n if (!closeOnEscape) return undefined;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose?.();\n };\n\n window.addEventListener(\"keydown\", handleEscape);\n return () => window.removeEventListener(\"keydown\", handleEscape);\n }, [closeOnEscape, onClose]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (e.target === e.currentTarget) onClose?.(); // only close if the click was on the backdrop\n };\n\n if (typeof document === \"undefined\") return null;\n\n // Portal to document.body so the modal's `position: fixed` resolves\n // against the viewport. Otherwise a transformed ancestor (e.g. the\n // onboarding slide rail) would become the containing block and the\n // modal would render trapped inside it instead of overlapping its\n // parent modal.\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n className=\"fixed inset-0 flex items-center justify-center z-60\"\n >\n <div\n onClick={handleClick}\n className=\"fixed inset-0 bg-black opacity-60\"\n />\n <div className=\"relative\">{children}</div>\n </div>,\n document.body,\n );\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"modal-backdrop.js","names":[],"sources":["../../../../src/components/shared/modals/modal-backdrop.tsx"],"sourcesContent":["import React from \"react\";\nimport { createPortal } from \"react-dom\";\n\ninterface ModalBackdropProps {\n children: React.ReactNode;\n onClose?: () => void;\n /** When false, pressing Escape does not close the modal. Defaults to true. */\n closeOnEscape?: boolean;\n /** When false, clicking the backdrop does not close the modal. Defaults to true. */\n closeOnBackdropClick?: boolean;\n \"aria-label\"?: string;\n}\n\nexport function ModalBackdrop({\n children,\n onClose,\n closeOnEscape = true,\n closeOnBackdropClick = true,\n \"aria-label\": ariaLabel,\n}: ModalBackdropProps) {\n React.useEffect(() => {\n if (!closeOnEscape) return undefined;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose?.();\n };\n\n window.addEventListener(\"keydown\", handleEscape);\n return () => window.removeEventListener(\"keydown\", handleEscape);\n }, [closeOnEscape, onClose]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n if (!closeOnBackdropClick) return;\n if (e.target === e.currentTarget) onClose?.(); // only close if the click was on the backdrop\n };\n\n if (typeof document === \"undefined\") return null;\n\n // Portal to document.body so the modal's `position: fixed` resolves\n // against the viewport. Otherwise a transformed ancestor (e.g. the\n // onboarding slide rail) would become the containing block and the\n // modal would render trapped inside it instead of overlapping its\n // parent modal.\n return createPortal(\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n className=\"fixed inset-0 flex items-center justify-center z-60\"\n >\n <div\n onClick={handleClick}\n className=\"fixed inset-0 bg-black opacity-60\"\n />\n <div className=\"relative\">{children}</div>\n </div>,\n document.body,\n );\n}\n"],"mappings":";;;;AAaA,SAAgB,EAAc,EAC5B,aACA,YACA,mBAAgB,IAChB,0BAAuB,IACvB,cAAc,KACO;AAuBrB,QAtBA,EAAM,gBAAgB;AACpB,MAAI,CAAC,EAAe;EACpB,IAAM,KAAgB,MAAqB;AACzC,GAAI,EAAE,QAAQ,YAAU,KAAW;;AAIrC,SADA,OAAO,iBAAiB,WAAW,EAAa,QACnC,OAAO,oBAAoB,WAAW,EAAa;IAC/D,CAAC,GAAe,EAAQ,CAAC,EAOxB,OAAO,WAAa,MAAoB,OAOrC,EACL,kBAAC,OAAD;EACE,MAAK;EACL,cAAW;EACX,cAAY;EACZ,WAAU;YAJZ,CAME,kBAAC,OAAD;GACE,UApBe,MAAwC;AACtD,SACD,EAAE,WAAW,EAAE,iBAAe,KAAW;;GAmBzC,WAAU;GACV,CAAA,EACF,kBAAC,OAAD;GAAK,WAAU;GAAY;GAAe,CAAA,CACtC;KACN,SAAS,KACV"}
|
|
@@ -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/constants.cjs`),i=require(`../../../../context/navigation-context.cjs`),a=require(`../../../../
|
|
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/constants.cjs`),i=require(`../../../../context/navigation-context.cjs`),a=require(`../../../../hooks/use-tracking.cjs`),o=require(`../modal-backdrop.cjs`),s=require(`../../../features/settings/brand-button.cjs`),c=require(`../../../../hooks/mutation/use-save-settings.cjs`),l=require(`../../../features/settings/settings-input.cjs`),u=require(`../../../../ui/help-link.cjs`),d=require(`./model-selector.cjs`),f=require(`../../../../utils/sdk-settings-schema.cjs`),p=require(`../confirmation-modals/danger-modal.cjs`),m=require(`../../../../utils/settings-utils.cjs`);let h=require(`react`);h=e.__toESM(h,1);let g=require(`react/jsx-runtime`);function _({settings:e,onClose:_}){let{trackSettingsSaved:v}=a.useTracking(),{mutate:y}=c.useSaveSettings(),{currentPath:b}=i.useNavigation(),{t:x}=t.useTranslation(`openhands`),S=h.default.useRef(null),[C,w]=h.default.useState(!1),T=async e=>{let t=m.extractSettings(e);await y(t,{onSuccess:()=>{_();let e=t.agent_settings_diff?.llm??{};v({llmModel:e.model,llmApiKeySet:e.api_key?`SET`:`UNSET`,searchApiKeySet:t.search_api_key?`SET`:`UNSET`,remoteRuntimeResourceFactor:t.remote_runtime_resource_factor})}})},E=()=>{T(new FormData(S.current??void 0))},D=e=>{e.preventDefault();let t=new FormData(e.currentTarget);b.startsWith(`/conversations/`)?w(!0):T(t)},O=e.llm_api_key_set,k=f.getAgentSettingValue(e,`llm.model`),A=f.getAgentSettingValue(e,`llm.base_url`);return(0,g.jsxs)(`div`,{children:[(0,g.jsxs)(`form`,{ref:S,"data-testid":`settings-form`,className:`flex flex-col gap-6`,onSubmit:D,children:[(0,g.jsxs)(`div`,{className:`flex flex-col gap-[17px]`,children:[(0,g.jsx)(d.ModelSelector,{currentModel:typeof k==`string`?k:void 0,currentBaseUrl:typeof A==`string`?A:void 0,wrapperClassName:`!flex-col !gap-[17px]`,labelClassName:r.SETTINGS_FORM.LABEL_CLASSNAME}),(0,g.jsx)(l.SettingsInput,{testId:`llm-api-key-input`,name:`llm-api-key-input`,label:x(n.I18nKey.SETTINGS_FORM$API_KEY),type:`password`,className:`w-full`,placeholder:O?`<hidden>`:``,labelClassName:r.SETTINGS_FORM.LABEL_CLASSNAME}),(0,g.jsx)(u.HelpLink,{testId:`llm-api-key-help-anchor`,text:x(n.I18nKey.SETTINGS$DONT_KNOW_API_KEY),linkText:x(n.I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS),href:`https://docs.openhands.dev/usage/local-setup#getting-an-api-key`,size:`settings`,linkColor:`white`})]}),(0,g.jsx)(`div`,{className:`flex flex-col gap-2`,children:(0,g.jsx)(s.BrandButton,{testId:`save-settings-button`,type:`submit`,variant:`primary`,className:`w-full`,children:x(n.I18nKey.BUTTON$SAVE)})})]}),C&&(0,g.jsx)(o.ModalBackdrop,{children:(0,g.jsx)(p.DangerModal,{title:x(n.I18nKey.MODAL$END_SESSION_TITLE),description:x(n.I18nKey.MODAL$END_SESSION_MESSAGE),buttons:{danger:{text:x(n.I18nKey.BUTTON$END_SESSION),onClick:E},cancel:{text:x(n.I18nKey.BUTTON$CANCEL),onClick:()=>w(!1)}}})})]})}exports.SettingsForm=_;
|
|
2
2
|
//# sourceMappingURL=settings-form.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-form.cjs","names":[],"sources":["../../../../../src/components/shared/modals/settings/settings-form.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"settings-form.cjs","names":[],"sources":["../../../../../src/components/shared/modals/settings/settings-form.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport React from \"react\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { DangerModal } from \"../confirmation-modals/danger-modal\";\nimport { extractSettings } from \"#/utils/settings-utils\";\nimport { ModalBackdrop } from \"../modal-backdrop\";\nimport { ModelSelector } from \"./model-selector\";\nimport { Settings } from \"#/types/settings\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport { getAgentSettingValue } from \"#/utils/sdk-settings-schema\";\nimport { SETTINGS_FORM } from \"#/utils/constants\";\n\ninterface SettingsFormProps {\n settings: Settings;\n onClose: () => void;\n}\n\nexport function SettingsForm({ settings, onClose }: SettingsFormProps) {\n const { trackSettingsSaved } = useTracking();\n const { mutate: saveUserSettings } = useSaveSettings();\n const { currentPath } = useNavigation();\n const { t } = useTranslation(\"openhands\");\n\n const formRef = React.useRef<HTMLFormElement>(null);\n\n const [confirmEndSessionModalOpen, setConfirmEndSessionModalOpen] =\n React.useState(false);\n\n const handleFormSubmission = async (formData: FormData) => {\n const newSettings = extractSettings(formData);\n\n await saveUserSettings(newSettings, {\n onSuccess: () => {\n onClose();\n\n const agentLlm =\n ((newSettings.agent_settings_diff as Record<string, unknown>)\n ?.llm as Record<string, unknown>) ?? {};\n trackSettingsSaved({\n llmModel: agentLlm.model,\n llmApiKeySet: agentLlm.api_key ? \"SET\" : \"UNSET\",\n searchApiKeySet: newSettings.search_api_key ? \"SET\" : \"UNSET\",\n remoteRuntimeResourceFactor:\n newSettings.remote_runtime_resource_factor,\n });\n },\n });\n };\n\n const handleConfirmEndSession = () => {\n const formData = new FormData(formRef.current ?? undefined);\n handleFormSubmission(formData);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const formData = new FormData(event.currentTarget);\n\n if (currentPath.startsWith(\"/conversations/\")) {\n setConfirmEndSessionModalOpen(true);\n } else {\n handleFormSubmission(formData);\n }\n };\n\n const isLLMKeySet = settings.llm_api_key_set;\n const currentModel = getAgentSettingValue(settings, \"llm.model\");\n const currentBaseUrl = getAgentSettingValue(settings, \"llm.base_url\");\n\n return (\n <div>\n <form\n ref={formRef}\n data-testid=\"settings-form\"\n className=\"flex flex-col gap-6\"\n onSubmit={handleSubmit}\n >\n <div className=\"flex flex-col gap-[17px]\">\n <ModelSelector\n currentModel={\n typeof currentModel === \"string\" ? currentModel : undefined\n }\n currentBaseUrl={\n typeof currentBaseUrl === \"string\" ? currentBaseUrl : undefined\n }\n wrapperClassName=\"!flex-col !gap-[17px]\"\n labelClassName={SETTINGS_FORM.LABEL_CLASSNAME}\n />\n\n <SettingsInput\n testId=\"llm-api-key-input\"\n name=\"llm-api-key-input\"\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n placeholder={isLLMKeySet ? \"<hidden>\" : \"\"}\n labelClassName={SETTINGS_FORM.LABEL_CLASSNAME}\n />\n\n <HelpLink\n testId=\"llm-api-key-help-anchor\"\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n size=\"settings\"\n linkColor=\"white\"\n />\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <BrandButton\n testId=\"save-settings-button\"\n type=\"submit\"\n variant=\"primary\"\n className=\"w-full\"\n >\n {t(I18nKey.BUTTON$SAVE)}\n </BrandButton>\n </div>\n </form>\n\n {confirmEndSessionModalOpen && (\n <ModalBackdrop>\n <DangerModal\n title={t(I18nKey.MODAL$END_SESSION_TITLE)}\n description={t(I18nKey.MODAL$END_SESSION_MESSAGE)}\n buttons={{\n danger: {\n text: t(I18nKey.BUTTON$END_SESSION),\n onClick: handleConfirmEndSession,\n },\n cancel: {\n text: t(I18nKey.BUTTON$CANCEL),\n onClick: () => setConfirmEndSessionModalOpen(false),\n },\n }}\n />\n </ModalBackdrop>\n )}\n </div>\n );\n}\n"],"mappings":"01BAsBA,SAAgB,EAAa,CAAE,WAAU,WAA8B,CACrE,GAAM,CAAE,sBAAuB,EAAA,aAAa,CACtC,CAAE,OAAQ,GAAqB,EAAA,iBAAiB,CAChD,CAAE,eAAgB,EAAA,eAAe,CACjC,CAAE,KAAM,EAAA,eAAe,YAAY,CAEnC,EAAU,EAAA,QAAM,OAAwB,KAAK,CAE7C,CAAC,EAA4B,GACjC,EAAA,QAAM,SAAS,GAAM,CAEjB,EAAuB,KAAO,IAAuB,CACzD,IAAM,EAAc,EAAA,gBAAgB,EAAS,CAE7C,MAAM,EAAiB,EAAa,CAClC,cAAiB,CACf,GAAS,CAET,IAAM,EACF,EAAY,qBACV,KAAmC,EAAE,CAC3C,EAAmB,CACjB,SAAU,EAAS,MACnB,aAAc,EAAS,QAAU,MAAQ,QACzC,gBAAiB,EAAY,eAAiB,MAAQ,QACtD,4BACE,EAAY,+BACf,CAAC,EAEL,CAAC,EAGE,MAAgC,CAEpC,EAAqB,IADA,SAAS,EAAQ,SAAW,IAAA,GAC5B,CAAS,EAG1B,EAAgB,GAA4C,CAChE,EAAM,gBAAgB,CACtB,IAAM,EAAW,IAAI,SAAS,EAAM,cAAc,CAE9C,EAAY,WAAW,kBAAkB,CAC3C,EAA8B,GAAK,CAEnC,EAAqB,EAAS,EAI5B,EAAc,EAAS,gBACvB,EAAe,EAAA,qBAAqB,EAAU,YAAY,CAC1D,EAAiB,EAAA,qBAAqB,EAAU,eAAe,CAErE,OACE,EAAA,EAAA,MAAC,MAAD,CAAA,SAAA,EACE,EAAA,EAAA,MAAC,OAAD,CACE,IAAK,EACL,cAAY,gBACZ,UAAU,sBACV,SAAU,WAJZ,EAME,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oCAAf,EACE,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,aACE,OAAO,GAAiB,SAAW,EAAe,IAAA,GAEpD,eACE,OAAO,GAAmB,SAAW,EAAiB,IAAA,GAExD,iBAAiB,wBACjB,eAAgB,EAAA,cAAc,gBAC9B,CAAA,EAEF,EAAA,EAAA,KAAC,EAAA,cAAD,CACE,OAAO,oBACP,KAAK,oBACL,MAAO,EAAE,EAAA,QAAQ,sBAAsB,CACvC,KAAK,WACL,UAAU,SACV,YAAa,EAAc,WAAa,GACxC,eAAgB,EAAA,cAAc,gBAC9B,CAAA,EAEF,EAAA,EAAA,KAAC,EAAA,SAAD,CACE,OAAO,0BACP,KAAM,EAAE,EAAA,QAAQ,2BAA2B,CAC3C,SAAU,EAAE,EAAA,QAAQ,gCAAgC,CACpD,KAAK,kEACL,KAAK,WACL,UAAU,QACV,CAAA,CACE,IAEN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gCACb,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,OAAO,uBACP,KAAK,SACL,QAAQ,UACR,UAAU,kBAET,EAAE,EAAA,QAAQ,YAAY,CACX,CAAA,CACV,CAAA,CACD,GAEN,IACC,EAAA,EAAA,KAAC,EAAA,cAAD,CAAA,UACE,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,MAAO,EAAE,EAAA,QAAQ,wBAAwB,CACzC,YAAa,EAAE,EAAA,QAAQ,0BAA0B,CACjD,QAAS,CACP,OAAQ,CACN,KAAM,EAAE,EAAA,QAAQ,mBAAmB,CACnC,QAAS,EACV,CACD,OAAQ,CACN,KAAM,EAAE,EAAA,QAAQ,cAAc,CAC9B,YAAe,EAA8B,GAAM,CACpD,CACF,CACD,CAAA,CACY,CAAA,CAEd,CAAA,CAAA"}
|
|
@@ -2,7 +2,7 @@ import { useTranslation as e } from "../../../../node_modules/react-i18next/dist
|
|
|
2
2
|
import { I18nKey as t } from "../../../../i18n/declaration.js";
|
|
3
3
|
import { SETTINGS_FORM as n } from "../../../../utils/constants.js";
|
|
4
4
|
import { useNavigation as r } from "../../../../context/navigation-context.js";
|
|
5
|
-
import {
|
|
5
|
+
import { useTracking as i } from "../../../../hooks/use-tracking.js";
|
|
6
6
|
import { ModalBackdrop as a } from "../modal-backdrop.js";
|
|
7
7
|
import { BrandButton as o } from "../../../features/settings/brand-button.js";
|
|
8
8
|
import { useSaveSettings as s } from "../../../../hooks/mutation/use-save-settings.js";
|
|
@@ -16,16 +16,16 @@ import m from "react";
|
|
|
16
16
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
17
17
|
//#region src/components/shared/modals/settings/settings-form.tsx
|
|
18
18
|
function _({ settings: _, onClose: v }) {
|
|
19
|
-
let y = i(), { mutate: b } = s(), { currentPath: x } = r(), { t: S } = e("openhands"), C = m.useRef(null), [w, T] = m.useState(!1), E = async (e) => {
|
|
19
|
+
let { trackSettingsSaved: y } = i(), { mutate: b } = s(), { currentPath: x } = r(), { t: S } = e("openhands"), C = m.useRef(null), [w, T] = m.useState(!1), E = async (e) => {
|
|
20
20
|
let t = p(e);
|
|
21
21
|
await b(t, { onSuccess: () => {
|
|
22
22
|
v();
|
|
23
23
|
let e = t.agent_settings_diff?.llm ?? {};
|
|
24
|
-
y
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
y({
|
|
25
|
+
llmModel: e.model,
|
|
26
|
+
llmApiKeySet: e.api_key ? "SET" : "UNSET",
|
|
27
|
+
searchApiKeySet: t.search_api_key ? "SET" : "UNSET",
|
|
28
|
+
remoteRuntimeResourceFactor: t.remote_runtime_resource_factor
|
|
29
29
|
});
|
|
30
30
|
} });
|
|
31
31
|
}, D = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-form.js","names":[],"sources":["../../../../../src/components/shared/modals/settings/settings-form.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"settings-form.js","names":[],"sources":["../../../../../src/components/shared/modals/settings/settings-form.tsx"],"sourcesContent":["import { useTranslation } from \"react-i18next\";\nimport React from \"react\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { useNavigation } from \"#/context/navigation-context\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { DangerModal } from \"../confirmation-modals/danger-modal\";\nimport { extractSettings } from \"#/utils/settings-utils\";\nimport { ModalBackdrop } from \"../modal-backdrop\";\nimport { ModelSelector } from \"./model-selector\";\nimport { Settings } from \"#/types/settings\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { useSaveSettings } from \"#/hooks/mutation/use-save-settings\";\nimport { getAgentSettingValue } from \"#/utils/sdk-settings-schema\";\nimport { SETTINGS_FORM } from \"#/utils/constants\";\n\ninterface SettingsFormProps {\n settings: Settings;\n onClose: () => void;\n}\n\nexport function SettingsForm({ settings, onClose }: SettingsFormProps) {\n const { trackSettingsSaved } = useTracking();\n const { mutate: saveUserSettings } = useSaveSettings();\n const { currentPath } = useNavigation();\n const { t } = useTranslation(\"openhands\");\n\n const formRef = React.useRef<HTMLFormElement>(null);\n\n const [confirmEndSessionModalOpen, setConfirmEndSessionModalOpen] =\n React.useState(false);\n\n const handleFormSubmission = async (formData: FormData) => {\n const newSettings = extractSettings(formData);\n\n await saveUserSettings(newSettings, {\n onSuccess: () => {\n onClose();\n\n const agentLlm =\n ((newSettings.agent_settings_diff as Record<string, unknown>)\n ?.llm as Record<string, unknown>) ?? {};\n trackSettingsSaved({\n llmModel: agentLlm.model,\n llmApiKeySet: agentLlm.api_key ? \"SET\" : \"UNSET\",\n searchApiKeySet: newSettings.search_api_key ? \"SET\" : \"UNSET\",\n remoteRuntimeResourceFactor:\n newSettings.remote_runtime_resource_factor,\n });\n },\n });\n };\n\n const handleConfirmEndSession = () => {\n const formData = new FormData(formRef.current ?? undefined);\n handleFormSubmission(formData);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const formData = new FormData(event.currentTarget);\n\n if (currentPath.startsWith(\"/conversations/\")) {\n setConfirmEndSessionModalOpen(true);\n } else {\n handleFormSubmission(formData);\n }\n };\n\n const isLLMKeySet = settings.llm_api_key_set;\n const currentModel = getAgentSettingValue(settings, \"llm.model\");\n const currentBaseUrl = getAgentSettingValue(settings, \"llm.base_url\");\n\n return (\n <div>\n <form\n ref={formRef}\n data-testid=\"settings-form\"\n className=\"flex flex-col gap-6\"\n onSubmit={handleSubmit}\n >\n <div className=\"flex flex-col gap-[17px]\">\n <ModelSelector\n currentModel={\n typeof currentModel === \"string\" ? currentModel : undefined\n }\n currentBaseUrl={\n typeof currentBaseUrl === \"string\" ? currentBaseUrl : undefined\n }\n wrapperClassName=\"!flex-col !gap-[17px]\"\n labelClassName={SETTINGS_FORM.LABEL_CLASSNAME}\n />\n\n <SettingsInput\n testId=\"llm-api-key-input\"\n name=\"llm-api-key-input\"\n label={t(I18nKey.SETTINGS_FORM$API_KEY)}\n type=\"password\"\n className=\"w-full\"\n placeholder={isLLMKeySet ? \"<hidden>\" : \"\"}\n labelClassName={SETTINGS_FORM.LABEL_CLASSNAME}\n />\n\n <HelpLink\n testId=\"llm-api-key-help-anchor\"\n text={t(I18nKey.SETTINGS$DONT_KNOW_API_KEY)}\n linkText={t(I18nKey.SETTINGS$CLICK_FOR_INSTRUCTIONS)}\n href=\"https://docs.openhands.dev/usage/local-setup#getting-an-api-key\"\n size=\"settings\"\n linkColor=\"white\"\n />\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <BrandButton\n testId=\"save-settings-button\"\n type=\"submit\"\n variant=\"primary\"\n className=\"w-full\"\n >\n {t(I18nKey.BUTTON$SAVE)}\n </BrandButton>\n </div>\n </form>\n\n {confirmEndSessionModalOpen && (\n <ModalBackdrop>\n <DangerModal\n title={t(I18nKey.MODAL$END_SESSION_TITLE)}\n description={t(I18nKey.MODAL$END_SESSION_MESSAGE)}\n buttons={{\n danger: {\n text: t(I18nKey.BUTTON$END_SESSION),\n onClick: handleConfirmEndSession,\n },\n cancel: {\n text: t(I18nKey.BUTTON$CANCEL),\n onClick: () => setConfirmEndSessionModalOpen(false),\n },\n }}\n />\n </ModalBackdrop>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,SAAgB,EAAa,EAAE,aAAU,cAA8B;CACrE,IAAM,EAAE,0BAAuB,GAAa,EACtC,EAAE,QAAQ,MAAqB,GAAiB,EAChD,EAAE,mBAAgB,GAAe,EACjC,EAAE,SAAM,EAAe,YAAY,EAEnC,IAAU,EAAM,OAAwB,KAAK,EAE7C,CAAC,GAA4B,KACjC,EAAM,SAAS,GAAM,EAEjB,IAAuB,OAAO,MAAuB;EACzD,IAAM,IAAc,EAAgB,EAAS;AAE7C,QAAM,EAAiB,GAAa,EAClC,iBAAiB;AACf,MAAS;GAET,IAAM,IACF,EAAY,qBACV,OAAmC,EAAE;AAC3C,KAAmB;IACjB,UAAU,EAAS;IACnB,cAAc,EAAS,UAAU,QAAQ;IACzC,iBAAiB,EAAY,iBAAiB,QAAQ;IACtD,6BACE,EAAY;IACf,CAAC;KAEL,CAAC;IAGE,UAAgC;AAEpC,IAAqB,IADA,SAAS,EAAQ,WAAW,KAAA,EAC5B,CAAS;IAG1B,KAAgB,MAA4C;AAChE,IAAM,gBAAgB;EACtB,IAAM,IAAW,IAAI,SAAS,EAAM,cAAc;AAElD,EAAI,EAAY,WAAW,kBAAkB,GAC3C,EAA8B,GAAK,GAEnC,EAAqB,EAAS;IAI5B,IAAc,EAAS,iBACvB,IAAe,EAAqB,GAAU,YAAY,EAC1D,IAAiB,EAAqB,GAAU,eAAe;AAErE,QACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;EACE,KAAK;EACL,eAAY;EACZ,WAAU;EACV,UAAU;YAJZ,CAME,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,cACE,OAAO,KAAiB,WAAW,IAAe,KAAA;KAEpD,gBACE,OAAO,KAAmB,WAAW,IAAiB,KAAA;KAExD,kBAAiB;KACjB,gBAAgB,EAAc;KAC9B,CAAA;IAEF,kBAAC,GAAD;KACE,QAAO;KACP,MAAK;KACL,OAAO,EAAE,EAAQ,sBAAsB;KACvC,MAAK;KACL,WAAU;KACV,aAAa,IAAc,aAAa;KACxC,gBAAgB,EAAc;KAC9B,CAAA;IAEF,kBAAC,GAAD;KACE,QAAO;KACP,MAAM,EAAE,EAAQ,2BAA2B;KAC3C,UAAU,EAAE,EAAQ,gCAAgC;KACpD,MAAK;KACL,MAAK;KACL,WAAU;KACV,CAAA;IACE;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACE,QAAO;IACP,MAAK;IACL,SAAQ;IACR,WAAU;cAET,EAAE,EAAQ,YAAY;IACX,CAAA;GACV,CAAA,CACD;KAEN,KACC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,OAAO,EAAE,EAAQ,wBAAwB;EACzC,aAAa,EAAE,EAAQ,0BAA0B;EACjD,SAAS;GACP,QAAQ;IACN,MAAM,EAAE,EAAQ,mBAAmB;IACnC,SAAS;IACV;GACD,QAAQ;IACN,MAAM,EAAE,EAAQ,cAAc;IAC9B,eAAe,EAA8B,GAAM;IACpD;GACF;EACD,CAAA,EACY,CAAA,CAEd,EAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../i18n/declaration.cjs`),n=require(`../../utils/constants.cjs`),r=require(`../../contexts/active-backend-context.cjs`),i=require(`../../utils/custom-toast-handlers.cjs`),a=require(`../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),o=require(`../../stores/model-store.cjs`),s=require(`./model-command-event-anchor.cjs`),c=require(
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/react-i18next/dist/es/useTranslation.cjs`),t=require(`../../i18n/declaration.cjs`),n=require(`../../utils/constants.cjs`),r=require(`../../contexts/active-backend-context.cjs`),i=require(`../../utils/custom-toast-handlers.cjs`),a=require(`../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),o=require(`../../stores/model-store.cjs`),s=require(`./model-command-event-anchor.cjs`),c=require(`../query/query-keys.cjs`),l=require(`../../api/profiles-service/profiles-service.api.cjs`),u=require(`../mutation/use-switch-llm-profile-and-log.cjs`);let d=require(`react`);var f=`${n.MODEL_COMMAND} `,p=(p,m)=>{let h=o.useModelStore(e=>e.show),g=a.useQueryClient(),{switchAndLog:_}=u.useSwitchLlmProfileAndLog(),{backend:v,orgId:y}=r.useActiveBackend(),b=v.kind===`local`,{t:x}=e.useTranslation();return(0,d.useCallback)(e=>{let r=e.trim();if(!(r===`/model`||r.startsWith(f))||!b){m(e);return}let a=r.slice(n.MODEL_COMMAND.length).trim();if(a){_(p??null,a);return}if(!p)return;let o=s.getLastRenderableEventId();g.fetchQuery({queryKey:[...c.LLM_PROFILES_QUERY_KEYS.all,v.id,y],queryFn:l.default.listProfiles,staleTime:0}).then(({profiles:e})=>h(p,o,e)).catch(e=>{let n=x(t.I18nKey.MODEL$LIST_FAILED);i.displayErrorToast(e instanceof Error&&e.message?e.message:n)})},[p,b,m,h,g,_,v.id,y,x])};exports.useModelInterceptor=p;
|
|
2
2
|
//# sourceMappingURL=use-model-interceptor.cjs.map
|
|
@@ -6,8 +6,8 @@ import { displayErrorToast as i } from "../../utils/custom-toast-handlers.js";
|
|
|
6
6
|
import { useQueryClient as a } from "../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.js";
|
|
7
7
|
import { useModelStore as o } from "../../stores/model-store.js";
|
|
8
8
|
import { getLastRenderableEventId as s } from "./model-command-event-anchor.js";
|
|
9
|
-
import c from "
|
|
10
|
-
import
|
|
9
|
+
import { LLM_PROFILES_QUERY_KEYS as c } from "../query/query-keys.js";
|
|
10
|
+
import l from "../../api/profiles-service/profiles-service.api.js";
|
|
11
11
|
import { useSwitchLlmProfileAndLog as u } from "../mutation/use-switch-llm-profile-and-log.js";
|
|
12
12
|
import { useCallback as d } from "react";
|
|
13
13
|
//#region src/hooks/chat/use-model-interceptor.ts
|
|
@@ -28,11 +28,11 @@ var f = `${n} `, p = (p, m) => {
|
|
|
28
28
|
let o = s();
|
|
29
29
|
g.fetchQuery({
|
|
30
30
|
queryKey: [
|
|
31
|
-
...
|
|
31
|
+
...c.all,
|
|
32
32
|
v.id,
|
|
33
33
|
y
|
|
34
34
|
],
|
|
35
|
-
queryFn:
|
|
35
|
+
queryFn: l.listProfiles,
|
|
36
36
|
staleTime: 0
|
|
37
37
|
}).then(({ profiles: e }) => h(p, o, e)).catch((e) => {
|
|
38
38
|
let n = x(t.MODEL$LIST_FAILED);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useMutation.cjs`),n=require(`../../
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useMutation.cjs`),n=require(`../../api/settings-service/settings-service.api.cjs`),r=require(`../query/query-keys.cjs`),i=require(`../query/use-settings.cjs`),a=require(`../use-tracking.cjs`);var o=async e=>{let t={...e};delete t.agent_settings_schema,delete t.conversation_settings_schema;let r={...t.conversation_settings_diff??{}};Object.keys(r).length>0?t.conversation_settings_diff=r:delete t.conversation_settings_diff,delete t.conversation_settings;let i=t.agent_settings_diff,a=i?.llm;if(a&&typeof a.api_key==`string`){let e=a.api_key.trim();a.api_key=e===``?``:e}i&&Object.keys(i).length>0?t.agent_settings_diff=i:delete t.agent_settings_diff,delete t.agent_settings,typeof t.search_api_key==`string`&&(t.search_api_key=t.search_api_key.trim()),typeof t.git_user_name==`string`&&(t.git_user_name=t.git_user_name.trim()),typeof t.git_user_email==`string`&&(t.git_user_email=t.git_user_email.trim()),await n.default.saveSettings(t)},s=(n=`personal`)=>{let{trackMcpConfigUpdated:s}=a.useTracking(),c=e.useQueryClient(),{data:l}=i.useSettings(n);return t.useMutation({mutationFn:async e=>{let t=e.mcp_config,n=l?.mcp_config;t&&n!==t&&s({sseServersCount:t.sse_servers?.length??0,stdioServersCount:t.stdio_servers?.length??0}),await o(e)},onSuccess:async()=>{await c.invalidateQueries({queryKey:r.SETTINGS_QUERY_KEYS.byScope(n)})},meta:{disableToast:!0}})};exports.useSaveSettings=s;
|
|
2
2
|
//# sourceMappingURL=use-save-settings.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-save-settings.cjs","names":[],"sources":["../../../src/hooks/mutation/use-save-settings.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport {
|
|
1
|
+
{"version":3,"file":"use-save-settings.cjs","names":[],"sources":["../../../src/hooks/mutation/use-save-settings.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport SettingsService from \"#/api/settings-service/settings-service.api\";\nimport {\n MCPConfig,\n Settings,\n SettingsScope,\n SettingsValue,\n} from \"#/types/settings\";\nimport { useSettings } from \"../query/use-settings\";\nimport { SETTINGS_QUERY_KEYS } from \"../query/query-keys\";\n\ntype SettingsUpdate = Partial<Settings> & Record<string, unknown>;\n\nconst saveSettingsMutationFn = async (settings: SettingsUpdate) => {\n const settingsToSave: SettingsUpdate = { ...settings };\n delete settingsToSave.agent_settings_schema;\n delete settingsToSave.conversation_settings_schema;\n\n const conversationSettings = {\n ...((settingsToSave.conversation_settings_diff as Record<\n string,\n SettingsValue\n >) ?? {}),\n };\n\n if (Object.keys(conversationSettings).length > 0) {\n settingsToSave.conversation_settings_diff = conversationSettings;\n } else {\n delete settingsToSave.conversation_settings_diff;\n }\n delete settingsToSave.conversation_settings;\n\n const agentSettings = settingsToSave.agent_settings_diff as\n | Record<string, unknown>\n | undefined;\n const llmSettings = agentSettings?.llm as Record<string, unknown> | undefined;\n if (llmSettings && typeof llmSettings.api_key === \"string\") {\n const apiKey = llmSettings.api_key.trim();\n llmSettings.api_key = apiKey === \"\" ? \"\" : apiKey;\n }\n if (agentSettings && Object.keys(agentSettings).length > 0) {\n settingsToSave.agent_settings_diff = agentSettings;\n } else {\n delete settingsToSave.agent_settings_diff;\n }\n delete settingsToSave.agent_settings;\n\n if (typeof settingsToSave.search_api_key === \"string\") {\n settingsToSave.search_api_key = settingsToSave.search_api_key.trim();\n }\n if (typeof settingsToSave.git_user_name === \"string\") {\n settingsToSave.git_user_name = settingsToSave.git_user_name.trim();\n }\n if (typeof settingsToSave.git_user_email === \"string\") {\n settingsToSave.git_user_email = settingsToSave.git_user_email.trim();\n }\n\n await SettingsService.saveSettings(settingsToSave);\n};\n\nexport const useSaveSettings = (scope: SettingsScope = \"personal\") => {\n const { trackMcpConfigUpdated } = useTracking();\n const queryClient = useQueryClient();\n const { data: currentSettings } = useSettings(scope);\n\n return useMutation({\n mutationFn: async (settings: SettingsUpdate) => {\n const nextMcpConfig = settings.mcp_config as MCPConfig | undefined;\n const currentMcpConfig = currentSettings?.mcp_config as\n | MCPConfig\n | undefined;\n\n if (nextMcpConfig && currentMcpConfig !== nextMcpConfig) {\n trackMcpConfigUpdated({\n sseServersCount: nextMcpConfig.sse_servers?.length ?? 0,\n stdioServersCount: nextMcpConfig.stdio_servers?.length ?? 0,\n });\n }\n\n await saveSettingsMutationFn(settings);\n },\n onSuccess: async () => {\n await queryClient.invalidateQueries({\n queryKey: SETTINGS_QUERY_KEYS.byScope(scope),\n });\n },\n meta: {\n disableToast: true,\n },\n });\n};\n"],"mappings":"kZAcA,IAAM,EAAyB,KAAO,IAA6B,CACjE,IAAM,EAAiC,CAAE,GAAG,EAAU,CACtD,OAAO,EAAe,sBACtB,OAAO,EAAe,6BAEtB,IAAM,EAAuB,CAC3B,GAAK,EAAe,4BAGd,EAAE,CACT,CAEG,OAAO,KAAK,EAAqB,CAAC,OAAS,EAC7C,EAAe,2BAA6B,EAE5C,OAAO,EAAe,2BAExB,OAAO,EAAe,sBAEtB,IAAM,EAAgB,EAAe,oBAG/B,EAAc,GAAe,IACnC,GAAI,GAAe,OAAO,EAAY,SAAY,SAAU,CAC1D,IAAM,EAAS,EAAY,QAAQ,MAAM,CACzC,EAAY,QAAU,IAAW,GAAK,GAAK,EAEzC,GAAiB,OAAO,KAAK,EAAc,CAAC,OAAS,EACvD,EAAe,oBAAsB,EAErC,OAAO,EAAe,oBAExB,OAAO,EAAe,eAElB,OAAO,EAAe,gBAAmB,WAC3C,EAAe,eAAiB,EAAe,eAAe,MAAM,EAElE,OAAO,EAAe,eAAkB,WAC1C,EAAe,cAAgB,EAAe,cAAc,MAAM,EAEhE,OAAO,EAAe,gBAAmB,WAC3C,EAAe,eAAiB,EAAe,eAAe,MAAM,EAGtE,MAAM,EAAA,QAAgB,aAAa,EAAe,EAGvC,GAAmB,EAAuB,aAAe,CACpE,GAAM,CAAE,yBAA0B,EAAA,aAAa,CACzC,EAAc,EAAA,gBAAgB,CAC9B,CAAE,KAAM,GAAoB,EAAA,YAAY,EAAM,CAEpD,OAAO,EAAA,YAAY,CACjB,WAAY,KAAO,IAA6B,CAC9C,IAAM,EAAgB,EAAS,WACzB,EAAmB,GAAiB,WAItC,GAAiB,IAAqB,GACxC,EAAsB,CACpB,gBAAiB,EAAc,aAAa,QAAU,EACtD,kBAAmB,EAAc,eAAe,QAAU,EAC3D,CAAC,CAGJ,MAAM,EAAuB,EAAS,EAExC,UAAW,SAAY,CACrB,MAAM,EAAY,kBAAkB,CAClC,SAAU,EAAA,oBAAoB,QAAQ,EAAM,CAC7C,CAAC,EAEJ,KAAM,CACJ,aAAc,GACf,CACF,CAAC"}
|
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
import { useQueryClient as e } from "../../node_modules/@tanstack/react-query/build/modern/QueryClientProvider.js";
|
|
2
2
|
import { useMutation as t } from "../../node_modules/@tanstack/react-query/build/modern/useMutation.js";
|
|
3
|
-
import
|
|
4
|
-
import r from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import n from "../../api/settings-service/settings-service.api.js";
|
|
4
|
+
import { SETTINGS_QUERY_KEYS as r } from "../query/query-keys.js";
|
|
5
|
+
import { useSettings as i } from "../query/use-settings.js";
|
|
6
|
+
import { useTracking as a } from "../use-tracking.js";
|
|
7
7
|
//#region src/hooks/mutation/use-save-settings.ts
|
|
8
8
|
var o = async (e) => {
|
|
9
9
|
let t = { ...e };
|
|
10
10
|
delete t.agent_settings_schema, delete t.conversation_settings_schema;
|
|
11
|
-
let
|
|
12
|
-
Object.keys(
|
|
11
|
+
let r = { ...t.conversation_settings_diff ?? {} };
|
|
12
|
+
Object.keys(r).length > 0 ? t.conversation_settings_diff = r : delete t.conversation_settings_diff, delete t.conversation_settings;
|
|
13
13
|
let i = t.agent_settings_diff, a = i?.llm;
|
|
14
14
|
if (a && typeof a.api_key == "string") {
|
|
15
15
|
let e = a.api_key.trim();
|
|
16
16
|
a.api_key = e === "" ? "" : e;
|
|
17
17
|
}
|
|
18
|
-
i && Object.keys(i).length > 0 ? t.agent_settings_diff = i : delete t.agent_settings_diff, delete t.agent_settings, typeof t.search_api_key == "string" && (t.search_api_key = t.search_api_key.trim()), typeof t.git_user_name == "string" && (t.git_user_name = t.git_user_name.trim()), typeof t.git_user_email == "string" && (t.git_user_email = t.git_user_email.trim()), await
|
|
19
|
-
}, s = (
|
|
20
|
-
let s =
|
|
18
|
+
i && Object.keys(i).length > 0 ? t.agent_settings_diff = i : delete t.agent_settings_diff, delete t.agent_settings, typeof t.search_api_key == "string" && (t.search_api_key = t.search_api_key.trim()), typeof t.git_user_name == "string" && (t.git_user_name = t.git_user_name.trim()), typeof t.git_user_email == "string" && (t.git_user_email = t.git_user_email.trim()), await n.saveSettings(t);
|
|
19
|
+
}, s = (n = "personal") => {
|
|
20
|
+
let { trackMcpConfigUpdated: s } = a(), c = e(), { data: l } = i(n);
|
|
21
21
|
return t({
|
|
22
22
|
mutationFn: async (e) => {
|
|
23
23
|
let t = e.mcp_config, n = l?.mcp_config;
|
|
24
|
-
t && n !== t && s
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
stdio_servers_count: t.stdio_servers?.length || 0
|
|
24
|
+
t && n !== t && s({
|
|
25
|
+
sseServersCount: t.sse_servers?.length ?? 0,
|
|
26
|
+
stdioServersCount: t.stdio_servers?.length ?? 0
|
|
28
27
|
}), await o(e);
|
|
29
28
|
},
|
|
30
29
|
onSuccess: async () => {
|
|
31
|
-
await c.invalidateQueries({ queryKey:
|
|
30
|
+
await c.invalidateQueries({ queryKey: r.byScope(n) });
|
|
32
31
|
},
|
|
33
32
|
meta: { disableToast: !0 }
|
|
34
33
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-save-settings.js","names":[],"sources":["../../../src/hooks/mutation/use-save-settings.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport {
|
|
1
|
+
{"version":3,"file":"use-save-settings.js","names":[],"sources":["../../../src/hooks/mutation/use-save-settings.ts"],"sourcesContent":["import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport SettingsService from \"#/api/settings-service/settings-service.api\";\nimport {\n MCPConfig,\n Settings,\n SettingsScope,\n SettingsValue,\n} from \"#/types/settings\";\nimport { useSettings } from \"../query/use-settings\";\nimport { SETTINGS_QUERY_KEYS } from \"../query/query-keys\";\n\ntype SettingsUpdate = Partial<Settings> & Record<string, unknown>;\n\nconst saveSettingsMutationFn = async (settings: SettingsUpdate) => {\n const settingsToSave: SettingsUpdate = { ...settings };\n delete settingsToSave.agent_settings_schema;\n delete settingsToSave.conversation_settings_schema;\n\n const conversationSettings = {\n ...((settingsToSave.conversation_settings_diff as Record<\n string,\n SettingsValue\n >) ?? {}),\n };\n\n if (Object.keys(conversationSettings).length > 0) {\n settingsToSave.conversation_settings_diff = conversationSettings;\n } else {\n delete settingsToSave.conversation_settings_diff;\n }\n delete settingsToSave.conversation_settings;\n\n const agentSettings = settingsToSave.agent_settings_diff as\n | Record<string, unknown>\n | undefined;\n const llmSettings = agentSettings?.llm as Record<string, unknown> | undefined;\n if (llmSettings && typeof llmSettings.api_key === \"string\") {\n const apiKey = llmSettings.api_key.trim();\n llmSettings.api_key = apiKey === \"\" ? \"\" : apiKey;\n }\n if (agentSettings && Object.keys(agentSettings).length > 0) {\n settingsToSave.agent_settings_diff = agentSettings;\n } else {\n delete settingsToSave.agent_settings_diff;\n }\n delete settingsToSave.agent_settings;\n\n if (typeof settingsToSave.search_api_key === \"string\") {\n settingsToSave.search_api_key = settingsToSave.search_api_key.trim();\n }\n if (typeof settingsToSave.git_user_name === \"string\") {\n settingsToSave.git_user_name = settingsToSave.git_user_name.trim();\n }\n if (typeof settingsToSave.git_user_email === \"string\") {\n settingsToSave.git_user_email = settingsToSave.git_user_email.trim();\n }\n\n await SettingsService.saveSettings(settingsToSave);\n};\n\nexport const useSaveSettings = (scope: SettingsScope = \"personal\") => {\n const { trackMcpConfigUpdated } = useTracking();\n const queryClient = useQueryClient();\n const { data: currentSettings } = useSettings(scope);\n\n return useMutation({\n mutationFn: async (settings: SettingsUpdate) => {\n const nextMcpConfig = settings.mcp_config as MCPConfig | undefined;\n const currentMcpConfig = currentSettings?.mcp_config as\n | MCPConfig\n | undefined;\n\n if (nextMcpConfig && currentMcpConfig !== nextMcpConfig) {\n trackMcpConfigUpdated({\n sseServersCount: nextMcpConfig.sse_servers?.length ?? 0,\n stdioServersCount: nextMcpConfig.stdio_servers?.length ?? 0,\n });\n }\n\n await saveSettingsMutationFn(settings);\n },\n onSuccess: async () => {\n await queryClient.invalidateQueries({\n queryKey: SETTINGS_QUERY_KEYS.byScope(scope),\n });\n },\n meta: {\n disableToast: true,\n },\n });\n};\n"],"mappings":";;;;;;;AAcA,IAAM,IAAyB,OAAO,MAA6B;CACjE,IAAM,IAAiC,EAAE,GAAG,GAAU;AAEtD,CADA,OAAO,EAAe,uBACtB,OAAO,EAAe;CAEtB,IAAM,IAAuB,EAC3B,GAAK,EAAe,8BAGd,EAAE,EACT;AAOD,CALI,OAAO,KAAK,EAAqB,CAAC,SAAS,IAC7C,EAAe,6BAA6B,IAE5C,OAAO,EAAe,4BAExB,OAAO,EAAe;CAEtB,IAAM,IAAgB,EAAe,qBAG/B,IAAc,GAAe;AACnC,KAAI,KAAe,OAAO,EAAY,WAAY,UAAU;EAC1D,IAAM,IAAS,EAAY,QAAQ,MAAM;AACzC,IAAY,UAAU,MAAW,KAAK,KAAK;;AAmB7C,CAjBI,KAAiB,OAAO,KAAK,EAAc,CAAC,SAAS,IACvD,EAAe,sBAAsB,IAErC,OAAO,EAAe,qBAExB,OAAO,EAAe,gBAElB,OAAO,EAAe,kBAAmB,aAC3C,EAAe,iBAAiB,EAAe,eAAe,MAAM,GAElE,OAAO,EAAe,iBAAkB,aAC1C,EAAe,gBAAgB,EAAe,cAAc,MAAM,GAEhE,OAAO,EAAe,kBAAmB,aAC3C,EAAe,iBAAiB,EAAe,eAAe,MAAM,GAGtE,MAAM,EAAgB,aAAa,EAAe;GAGvC,KAAmB,IAAuB,eAAe;CACpE,IAAM,EAAE,6BAA0B,GAAa,EACzC,IAAc,GAAgB,EAC9B,EAAE,MAAM,MAAoB,EAAY,EAAM;AAEpD,QAAO,EAAY;EACjB,YAAY,OAAO,MAA6B;GAC9C,IAAM,IAAgB,EAAS,YACzB,IAAmB,GAAiB;AAW1C,GAPI,KAAiB,MAAqB,KACxC,EAAsB;IACpB,iBAAiB,EAAc,aAAa,UAAU;IACtD,mBAAmB,EAAc,eAAe,UAAU;IAC3D,CAAC,EAGJ,MAAM,EAAuB,EAAS;;EAExC,WAAW,YAAY;AACrB,SAAM,EAAY,kBAAkB,EAClC,UAAU,EAAoB,QAAQ,EAAM,EAC7C,CAAC;;EAEJ,MAAM,EACJ,cAAc,IACf;EACF,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../contexts/active-backend-context.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useQuery.cjs`),n=require(`../../api/profiles-service/profiles-service.api.cjs`)
|
|
1
|
+
require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../contexts/active-backend-context.cjs`),t=require(`../../node_modules/@tanstack/react-query/build/modern/useQuery.cjs`),n=require(`./query-keys.cjs`),r=require(`../../api/profiles-service/profiles-service.api.cjs`);function i(i={}){let{backend:a,orgId:o}=e.useActiveBackend();return t.useQuery({queryKey:[...n.LLM_PROFILES_QUERY_KEYS.all,a.id,o],queryFn:r.default.listProfiles,...n.CONFIG_CACHE_OPTIONS,enabled:i.enabled??!0,meta:{disableToast:!0}})}exports.useLlmProfiles=i;
|
|
2
2
|
//# sourceMappingURL=use-llm-profiles.cjs.map
|