@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
package/dist/components/features/conversation-panel/conversation-card/conversation-card.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation-card.js","names":[],"sources":["../../../../../src/components/features/conversation-panel/conversation-card/conversation-card.tsx"],"sourcesContent":["import React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"conversation-card.js","names":[],"sources":["../../../../../src/components/features/conversation-panel/conversation-card/conversation-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTracking } from \"#/hooks/use-tracking\";\nimport { cn } from \"#/utils/utils\";\nimport { transformVSCodeUrl } from \"#/utils/vscode-url-helper\";\nimport ConversationService from \"#/api/conversation-service/conversation-service.api\";\nimport { ExecutionStatus } from \"#/types/agent-server/core/base/common\";\nimport { SandboxStatus } from \"#/api/conversation-service/agent-server-conversation-service.types\";\nimport { RepositorySelection } from \"#/api/open-hands.types\";\nimport { formatTimeDelta } from \"#/utils/format-time-delta\";\nimport { ConversationCardHeader } from \"./conversation-card-header\";\nimport { ConversationCardActions } from \"./conversation-card-actions\";\nimport { ConversationCardFooter } from \"./conversation-card-footer\";\nimport { ConversationStatusBadges } from \"./conversation-status-badges\";\nimport { useDownloadConversation } from \"#/hooks/use-download-conversation\";\n\ninterface ConversationCardProps {\n onClick?: () => void;\n onDelete?: () => void;\n onStop?: () => void;\n onChangeTitle?: (title: string) => void;\n showOptions?: boolean;\n title: string;\n selectedRepository: RepositorySelection | null;\n lastUpdatedAt: string;\n createdAt?: string;\n executionStatus?: ExecutionStatus | null;\n sandboxStatus?: SandboxStatus | null;\n conversationId?: string;\n contextMenuOpen?: boolean;\n onContextMenuToggle?: (isOpen: boolean) => void;\n isActive?: boolean;\n workspaceWorkingDir?: string | null;\n showRepositoryMetadata?: boolean;\n llmModel?: string | null;\n showLlmProfiles?: boolean;\n agentKind?: \"openhands\" | \"acp\" | null;\n acpServer?: string | null;\n}\n\nexport function ConversationCard({\n onClick,\n onDelete,\n onStop,\n onChangeTitle,\n showOptions,\n title,\n selectedRepository,\n lastUpdatedAt,\n createdAt,\n conversationId,\n executionStatus,\n sandboxStatus,\n contextMenuOpen = false,\n onContextMenuToggle,\n isActive = false,\n workspaceWorkingDir,\n showRepositoryMetadata = true,\n llmModel = null,\n showLlmProfiles = false,\n agentKind = null,\n acpServer = null,\n}: ConversationCardProps) {\n const { trackDownloadVsCodeButtonClicked } = useTracking();\n const [titleMode, setTitleMode] = React.useState<\"view\" | \"edit\">(\"view\");\n const { mutateAsync: downloadConversation } = useDownloadConversation();\n\n const onTitleSave = (newTitle: string) => {\n if (newTitle !== \"\" && newTitle !== title) {\n onChangeTitle?.(newTitle);\n }\n setTitleMode(\"view\");\n };\n\n const handleDelete = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onDelete?.();\n onContextMenuToggle?.(false);\n };\n\n const handleStop = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n onStop?.();\n onContextMenuToggle?.(false);\n };\n\n const handleEdit = (event: React.MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n setTitleMode(\"edit\");\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadViaVSCode = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n trackDownloadVsCodeButtonClicked();\n\n // Fetch the VS Code URL from the API\n if (conversationId) {\n try {\n const data = await ConversationService.getVSCodeUrl(conversationId);\n if (data.vscode_url) {\n const transformedUrl = transformVSCodeUrl(data.vscode_url);\n if (transformedUrl) {\n window.open(transformedUrl, \"_blank\");\n }\n }\n // VS Code URL not available\n } catch {\n // Failed to fetch VS Code URL\n }\n }\n\n onContextMenuToggle?.(false);\n };\n\n const handleDownloadConversation = async (\n event: React.MouseEvent<HTMLButtonElement>,\n ) => {\n event.preventDefault();\n event.stopPropagation();\n\n if (conversationId) {\n await downloadConversation(conversationId);\n }\n onContextMenuToggle?.(false);\n };\n\n const hasContextMenu = !!(onDelete || onChangeTitle || showOptions);\n const shouldRenderFooter =\n showRepositoryMetadata ||\n (showLlmProfiles && (agentKind === \"acp\" || !!llmModel));\n\n return (\n <div\n data-testid=\"conversation-card\"\n data-context-menu-open={contextMenuOpen.toString()}\n data-active={isActive ? \"true\" : \"false\"}\n onClick={onClick}\n className={cn(\n \"group relative h-auto w-full cursor-pointer rounded-md py-1 pl-2 pr-1 transition-colors\",\n \"data-[context-menu-open=false]:hover:bg-[var(--oh-surface)]\",\n \"data-[active=true]:bg-[var(--oh-surface)]\",\n )}\n >\n <div className=\"flex items-center w-full min-w-0\">\n <div className=\"flex items-center gap-2 flex-1 min-w-0 overflow-hidden\">\n <ConversationCardHeader\n title={title}\n titleMode={titleMode}\n onTitleSave={onTitleSave}\n executionStatus={executionStatus}\n sandboxStatus={sandboxStatus}\n />\n {sandboxStatus === \"ERROR\" && <ConversationStatusBadges />}\n </div>\n\n <div className=\"relative ml-auto pl-2 flex items-center justify-end shrink-0\">\n {(createdAt ?? lastUpdatedAt) && (\n <p\n className={cn(\n \"text-xs text-[var(--oh-muted)] text-right whitespace-nowrap transition-opacity -translate-x-1.5\",\n hasContextMenu &&\n \"group-hover:opacity-0 group-focus-within:opacity-0\",\n contextMenuOpen && \"opacity-0\",\n )}\n >\n <time>{formatTimeDelta(lastUpdatedAt ?? createdAt)}</time>\n </p>\n )}\n\n {hasContextMenu && (\n <div\n className={cn(\n \"absolute right-0 top-1/2 -translate-y-1/2 transition-opacity\",\n \"opacity-0 invisible group-hover:opacity-100 group-hover:visible\",\n contextMenuOpen && \"visible opacity-100\",\n )}\n >\n <ConversationCardActions\n contextMenuOpen={contextMenuOpen}\n onContextMenuToggle={onContextMenuToggle || (() => {})}\n onDelete={onDelete && handleDelete}\n onStop={onStop && handleStop}\n onEdit={onChangeTitle && handleEdit}\n onDownloadViaVSCode={handleDownloadViaVSCode}\n onDownloadConversation={handleDownloadConversation}\n executionStatus={executionStatus}\n conversationId={conversationId}\n showOptions={showOptions}\n />\n </div>\n )}\n </div>\n </div>\n\n {shouldRenderFooter && (\n <ConversationCardFooter\n selectedRepository={selectedRepository}\n lastUpdatedAt={lastUpdatedAt}\n createdAt={createdAt}\n executionStatus={executionStatus}\n workspaceWorkingDir={workspaceWorkingDir}\n showRepositoryMetadata={showRepositoryMetadata}\n showTimestamp={false}\n llmModel={llmModel}\n showAgentChip={showLlmProfiles}\n agentKind={agentKind}\n acpServer={acpServer}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuCA,SAAgB,EAAiB,EAC/B,YACA,aACA,WACA,kBACA,gBACA,UACA,uBACA,kBACA,cACA,mBACA,oBACA,kBACA,qBAAkB,IAClB,wBACA,cAAW,IACX,wBACA,4BAAyB,IACzB,cAAW,MACX,qBAAkB,IAClB,eAAY,MACZ,eAAY,QACY;CACxB,IAAM,EAAE,wCAAqC,GAAa,EACpD,CAAC,GAAW,KAAgB,EAAM,SAA0B,OAAO,EACnE,EAAE,aAAa,MAAyB,GAAyB,EAEjE,KAAe,MAAqB;AAIxC,EAHI,MAAa,MAAM,MAAa,KAClC,IAAgB,EAAS,EAE3B,EAAa,OAAO;IAGhB,KAAgB,MAA+C;AAInE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAY,EACZ,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,KAAU,EACV,IAAsB,GAAM;IAGxB,KAAc,MAA+C;AAIjE,EAHA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,EAAa,OAAO,EACpB,IAAsB,GAAM;IAGxB,IAA0B,OAC9B,MACG;AAMH,MALA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EACvB,GAAkC,EAG9B,EACF,KAAI;GACF,IAAM,IAAO,MAAM,EAAoB,aAAa,EAAe;AACnE,OAAI,EAAK,YAAY;IACnB,IAAM,IAAiB,EAAmB,EAAK,WAAW;AAC1D,IAAI,KACF,OAAO,KAAK,GAAgB,SAAS;;UAInC;AAKV,MAAsB,GAAM;IAGxB,IAA6B,OACjC,MACG;AAOH,EANA,EAAM,gBAAgB,EACtB,EAAM,iBAAiB,EAEnB,KACF,MAAM,EAAqB,EAAe,EAE5C,IAAsB,GAAM;IAGxB,IAAiB,CAAC,EAAE,KAAY,KAAiB,IACjD,IACJ,KACC,MAAoB,MAAc,SAAS,CAAC,CAAC;AAEhD,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,0BAAwB,EAAgB,UAAU;EAClD,eAAa,IAAW,SAAS;EACxB;EACT,WAAW,EACT,2FACA,+DACA,4CACD;YATH,CAWE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACS;KACI;KACE;KACI;KACF;KACf,CAAA,EACD,MAAkB,WAAW,kBAAC,GAAD,EAA4B,CAAA,CACtD;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,EACI,KAAa,MACb,kBAAC,KAAD;KACE,WAAW,EACT,mGACA,KACE,sDACF,KAAmB,YACpB;eAED,kBAAC,QAAD,EAAA,UAAO,EAAgB,KAAiB,EAAU,EAAQ,CAAA;KACxD,CAAA,EAGL,KACC,kBAAC,OAAD;KACE,WAAW,EACT,gEACA,mEACA,KAAmB,sBACpB;eAED,kBAAC,GAAD;MACmB;MACjB,qBAAqB,YAA8B;MACnD,UAAU,KAAY;MACtB,QAAQ,KAAU;MAClB,QAAQ,KAAiB;MACzB,qBAAqB;MACrB,wBAAwB;MACP;MACD;MACH;MACb,CAAA;KACE,CAAA,CAEJ;MACF;MAEL,KACC,kBAAC,GAAD;GACsB;GACL;GACJ;GACM;GACI;GACG;GACxB,eAAe;GACL;GACV,eAAe;GACJ;GACA;GACX,CAAA,CAEA"}
|
|
@@ -2,3 +2,4 @@ export { OnboardingModal } from "./onboarding-modal";
|
|
|
2
2
|
export { OnboardingHost } from "./onboarding-host";
|
|
3
3
|
export { OnboardingProgressBar } from "./onboarding-progress-bar";
|
|
4
4
|
export { useOnboardingCompletion, ONBOARDING_COMPLETED_STORAGE_KEY, } from "./use-onboarding-completion";
|
|
5
|
+
export { ONBOARDING_PREVIEW_STEP_QUERY_PARAM, isOnboardingPreviewActive, readOnboardingPreviewStep, } from "./onboarding-preview";
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* isn't set yet). Closing or completing the flow marks it done so the
|
|
5
5
|
* modal won't re-appear on subsequent visits.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* With `?previewOnboardingStep=<0-3>` the modal opens on that slide for
|
|
8
|
+
* design review without persisting completion (works on any route when
|
|
9
|
+
* mounted from the root layout).
|
|
8
10
|
*/
|
|
9
11
|
export declare function OnboardingHost(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
interface OnboardingModalProps {
|
|
2
2
|
/** Called when the user dismisses the modal (skip / X / launch). */
|
|
3
3
|
onClose: () => void;
|
|
4
|
+
/** Optional slide index for dev preview (`?previewOnboardingStep=`). */
|
|
5
|
+
initialStep?: number;
|
|
6
|
+
/** When true, skip/close does not persist onboarding completion. */
|
|
7
|
+
isPreview?: boolean;
|
|
4
8
|
}
|
|
5
9
|
/**
|
|
6
10
|
* Top-level onboarding modal for first-time users.
|
|
7
11
|
*
|
|
8
12
|
* The flow is a fixed sequence of four steps:
|
|
9
|
-
* 0.
|
|
10
|
-
* 1.
|
|
13
|
+
* 0. Choose agent
|
|
14
|
+
* 1. Check backend
|
|
11
15
|
* 2. Set up LLM
|
|
12
16
|
* 3. Say hello (creates a fresh conversation, then closes)
|
|
13
17
|
*
|
|
@@ -15,5 +19,5 @@ interface OnboardingModalProps {
|
|
|
15
19
|
* the rail is translated horizontally by step index, so transitioning
|
|
16
20
|
* between steps animates the new step in from the right.
|
|
17
21
|
*/
|
|
18
|
-
export declare function OnboardingModal({ onClose }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function OnboardingModal({ onClose, initialStep, isPreview, }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
|
|
19
23
|
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const ONBOARDING_PREVIEW_STEP_QUERY_PARAM = "previewOnboardingStep";
|
|
2
|
+
/** Reads `?previewOnboardingStep=<0-3>` for dev/design review of a single slide. */
|
|
3
|
+
export declare function readOnboardingPreviewStep(search?: string): number | null;
|
|
4
|
+
export declare function isOnboardingPreviewActive(search?: string): boolean;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
interface SayHelloStepProps {
|
|
2
2
|
onBack: () => void;
|
|
3
|
+
/** Dismisses onboarding without launching a conversation. */
|
|
4
|
+
onClose: () => void;
|
|
3
5
|
/** Called once the conversation has been created — used by the parent
|
|
4
6
|
* modal to mark the onboarding as complete before unmounting. */
|
|
5
7
|
onLaunched: () => void;
|
|
@@ -9,5 +11,5 @@ interface SayHelloStepProps {
|
|
|
9
11
|
* launches a brand-new conversation with no workspace and navigates
|
|
10
12
|
* to it. Completing this step finishes the onboarding flow.
|
|
11
13
|
*/
|
|
12
|
-
export declare function SayHelloStep({ onBack, onLaunched }: SayHelloStepProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function SayHelloStep({ onBack, onClose, onLaunched, }: SayHelloStepProps): import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`);require(`../../../../utils/custom-toast-handlers.cjs`),require(`../../../../api/profiles-service/profiles-service.api.cjs`),require(`../../../../hooks/query/use-llm-profiles.cjs`),require(`../../../../
|
|
1
|
+
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`);require(`../../../../utils/custom-toast-handlers.cjs`),require(`../../../../hooks/query/use-settings.cjs`),require(`../../../../api/profiles-service/profiles-service.api.cjs`),require(`../../../../hooks/query/use-llm-profiles.cjs`),require(`../../../../ui/typography.cjs`),require(`../brand-button.cjs`),require(`../../../../hooks/query/use-agent-settings-schema.cjs`),require(`./profile-name-input.cjs`),require(`../../../../hooks/mutation/use-activate-llm-profile.cjs`),require(`./llm-profiles-manager.cjs`),require(`../../../../hooks/mutation/use-save-llm-profile.cjs`),require(`../../../shared/buttons/back-nav-button.cjs`),require(`../../../../contexts/settings-section-header-context.cjs`),require(`../../../../routes/llm-settings.cjs`);let t=require(`react`);t=e.__toESM(t,1),require(`react/jsx-runtime`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../../utils/custom-toast-handlers.js";
|
|
2
|
+
import "../../../../hooks/query/use-settings.js";
|
|
2
3
|
import "../../../../api/profiles-service/profiles-service.api.js";
|
|
3
4
|
import "../../../../hooks/query/use-llm-profiles.js";
|
|
4
|
-
import "../../../../hooks/query/use-settings.js";
|
|
5
5
|
import "../../../../ui/typography.js";
|
|
6
6
|
import "../brand-button.js";
|
|
7
7
|
import "../../../../hooks/query/use-agent-settings-schema.js";
|
|
@@ -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/custom-toast-handlers.cjs`),i=require(`../../../../node_modules/axios/index.cjs`),
|
|
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/custom-toast-handlers.cjs`),i=require(`../../../../node_modules/axios/index.cjs`),ee=require(`../../../../hooks/query/use-settings.cjs`),a=require(`../../../../ui/typography.cjs`),o=require(`../brand-button.cjs`),te=require(`../../../../hooks/mutation/use-save-settings.cjs`),ne=require(`../../../../utils/retrieve-axios-error-message.cjs`),s=require(`../../../../hooks/query/use-agent-settings-schema.cjs`),c=require(`../llm-settings/llm-settings-inputs-skeleton.cjs`),l=require(`../../../../utils/sdk-settings-schema.cjs`),u=require(`./schema-field.cjs`),d=require(`./view-toggle.cjs`);let f=require(`react`);f=e.__toESM(f,1);let p=require(`react/jsx-runtime`);var re=new Set,m={basic:0,advanced:1,all:2},ie=(e,t)=>m[t]<m[e]?t:e,h=(e,{showAdvanced:t,showAll:n})=>e===`all`?n?`all`:t?`advanced`:`basic`:e===`advanced`?t?`advanced`:n?`all`:`basic`:`basic`,g=(e,t)=>e instanceof i.AxiosError?e.response?.status===401?`${t} 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.`:e.response?.status===404?`${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.`:t:t;function _({sectionKeys:e,excludeKeys:i=re,scope:m=`personal`,settingsSource:_=`agent_settings`,header:v,extraDirty:y=!1,buildPayload:b,onSaveSuccess:x,getInitialView:S,forceShowAdvancedView:C=!1,allowAllView:ae=!0,initialValueOverrides:w,embedded:oe=!1,hideSaveButton:se=!1,suppressSuccessToast:ce=!1,onSaveControlChange:T,testId:le=`sdk-section-settings-screen`}){let{t:E}=t.useTranslation(`openhands`),{mutate:ue,isPending:D}=te.useSaveSettings(m),{data:O,isLoading:de,isFetching:fe}=ee.useSettings(m),k=s.useAgentSettingsSchema(O?.agent_settings_schema),A=s.useConversationSettingsSchema(O?.conversation_settings_schema),j=_===`conversation_settings`?A:k,M=j.data,N=j.isLoading,[P,F]=f.default.useState(`basic`),[I,L]=f.default.useState({}),[R,z]=f.default.useState({}),B=f.default.useRef(!1),V=f.default.useMemo(()=>JSON.stringify(e),[e]),H=f.default.useMemo(()=>JSON.parse(V),[V]),U=f.default.useMemo(()=>{if(!l.isValidSettingsSchema(M))return null;let e=new Set(H);return{...M,sections:M.sections.filter(t=>e.has(t.key))}},[M,H]),W=C||l.hasAdvancedSettings(U),G=ae&&l.hasMinorSettings(U),pe=f.default.useMemo(()=>g(j.error,E(n.I18nKey.SETTINGS$SDK_SCHEMA_UNAVAILABLE)),[j.error,E]),me=f.default.useMemo(()=>w?JSON.stringify(w):``,[w]),K=f.default.useMemo(()=>{if(!O||!U)return null;let e=l.buildInitialSettingsFormValues(O,U,_);return w?{...e,...w}:e},[O,U,_,me]),q=f.default.useMemo(()=>!O||!U?null:h(S?S(O,U):l.inferInitialView(O,U,_),{showAdvanced:W,showAll:G}),[O,U,S,_,W,G]);f.default.useEffect(()=>{B.current=!1,F(`basic`),L({}),z({})},[m,_,V]),f.default.useEffect(()=>{!K||!q||(L(K),z(w?Object.fromEntries(Object.keys(w).map(e=>[e,!0])):{}),F(e=>B.current?ie(e,q):(B.current=!0,q)))},[K,q]);let he=f.default.useMemo(()=>U?l.getVisibleSettingsSections(U,I,P,i):[],[U,I,P,i]),J=f.default.useCallback((e,t)=>{L(n=>({...n,[e]:t})),z(t=>({...t,[e]:!0}))},[]),ge=f.default.useCallback(e=>{r.displayErrorToast(ne.retrieveAxiosErrorMessage(e)||E(n.I18nKey.ERROR$GENERIC))},[E]),Y=f.default.useRef(()=>{}),X=f.default.useCallback(()=>{Y.current()},[]),Z=f.default.useRef(()=>({})),_e=f.default.useCallback(()=>Z.current(),[]),Q=()=>{if(!U)return;let e;try{let t=l.buildSdkSettingsPayloadForView(U,I,R,P),n;n=_===`conversation_settings`?{conversation_settings_diff:t}:{agent_settings_diff:t},e=b?b(t,{values:I,dirty:R,view:P}):n}catch(e){r.displayErrorToast(e instanceof Error?e.message:E(n.I18nKey.ERROR$GENERIC));return}Object.keys(e).length!==0&&ue(e,{onError:ge,onSuccess:()=>{ce||r.displaySuccessToast(E(n.I18nKey.SETTINGS$SAVED_WARNING)),z({}),x?.()}})};Y.current=Q,Z.current=()=>U?l.buildSdkSettingsPayload(U,I,R):{};let $=Object.keys(R).length>0||y;return f.default.useEffect(()=>{T&&T({save:X,isSaving:D,isDirty:$,values:I,view:P,getDirtyPayload:_e})},[D,$,I,P]),(de||fe)&&!O||N?(0,p.jsx)(c.LlmSettingsInputsSkeleton,{}):!U||U.sections.length===0?(0,p.jsx)(a.Typography.Paragraph,{className:`text-tertiary-alt`,children:pe}):Object.keys(I).length===0?(0,p.jsx)(c.LlmSettingsInputsSkeleton,{}):(0,p.jsxs)(`div`,{"data-testid":le,className:oe?`relative flex min-h-0 w-full flex-1 flex-col`:`relative w-full min-h-0`,children:[(0,p.jsx)(d.ViewToggle,{view:P,setView:F,showAdvanced:W,showAll:G,isDisabled:!1}),(0,p.jsxs)(`div`,{className:`flex flex-col gap-8`,children:[v?.({values:I,isDisabled:!1,view:P,onChange:J}),he.map((e,t)=>(0,p.jsx)(`section`,{className:`flex flex-col gap-4`,children:(0,p.jsx)(`div`,{className:`flex flex-col gap-4`,children:e.fields.map(e=>(0,p.jsx)(u.SchemaField,{field:e,value:I[e.key],isDisabled:!1,onChange:t=>J(e.key,t)},e.key))})},`${e.key}-${t}`)),se?null:(0,p.jsx)(`div`,{className:`flex justify-start pt-2`,children:(0,p.jsx)(o.BrandButton,{testId:`save-button`,type:`button`,variant:`primary`,isDisabled:D||Object.keys(R).length===0&&!y,onClick:Q,children:E(D?n.I18nKey.SETTINGS$SAVING:n.I18nKey.SETTINGS$SAVE_CHANGES)})})]})]})}exports.SdkSectionPage=_;
|
|
2
2
|
//# sourceMappingURL=sdk-section-page.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-section-page.cjs","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.cjs","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":"+2BAoCA,IAAM,GAAqB,IAAI,IAEzB,EAA2C,CAC/C,MAAO,EACP,SAAU,EACV,IAAK,EACN,CAEK,IACJ,EACA,IAEA,EAAW,GAAY,EAAW,GAAe,EAAW,EAExD,GACJ,EACA,CACE,eACA,aAME,IAAS,MACP,EACK,MAGF,EAAe,WAAa,QAGjC,IAAS,WACP,EACK,WAGF,EAAU,MAAQ,QAGpB,QAGH,GACJ,EACA,IAEM,aAAiB,EAAA,WAInB,EAAM,UAAU,SAAW,IACtB,GAAG,EAAgB,yKAGxB,EAAM,UAAU,SAAW,IACtB,GAAG,EAAgB,qHAGrB,EAXE,EAwDX,SAAgB,EAAe,CAC7B,cACA,cAAc,GACd,QAAQ,WACR,iBAAiB,iBACjB,SACA,aAAa,GACb,eACA,gBACA,iBACA,wBAAwB,GACxB,gBAAe,GACf,wBACA,YAAW,GACX,kBAAiB,GACjB,wBAAuB,GACvB,sBACA,UAAS,+BAuDR,CACD,GAAM,CAAE,KAAM,EAAA,eAAe,YAAY,CACnC,CAAE,OAAQ,GAAc,aAAc,GAAA,gBAAgB,EAAM,CAC5D,CAAE,KAAM,EAAU,aAAW,eAAe,GAAA,YAAY,EAAM,CAC9D,EAAmB,EAAA,uBACvB,GAAU,sBACX,CACK,EAA0B,EAAA,8BAC9B,GAAU,6BACX,CACK,EACJ,IAAmB,wBACf,EACA,EACA,EAAS,EAAkB,KAC3B,EAAkB,EAAkB,UAGpC,CAAC,EAAM,GAAW,EAAA,QAAM,SAAuB,QAAQ,CACvD,CAAC,EAAQ,GAAa,EAAA,QAAM,SAA6B,EAAE,CAAC,CAC5D,CAAC,EAAO,GAAY,EAAA,QAAM,SAA6B,EAAE,CAAC,CAC1D,EAAqB,EAAA,QAAM,OAAO,GAAM,CAExC,EAAuB,EAAA,QAAM,YAC3B,KAAK,UAAU,EAAY,CACjC,CAAC,EAAY,CACd,CACK,EAAoB,EAAA,QAAM,YACxB,KAAK,MAAM,EAAqB,CACtC,CAAC,EAAqB,CACvB,CASK,EAAiB,EAAA,QAAM,YAAc,CACzC,GAAI,CAAC,EAAA,sBAAsB,EAAO,CAAE,OAAO,KAC3C,IAAM,EAAa,IAAI,IAAI,EAAkB,CAC7C,MAAO,CACL,GAAG,EACH,SAAU,EAAO,SAAS,OAAQ,GAAM,EAAW,IAAI,EAAE,IAAI,CAAC,CAC/D,EACA,CAAC,EAAQ,EAAkB,CAAC,CAEzB,EACJ,GAAyB,EAAA,oBAAoB,EAAe,CACxD,EAAU,IAAgB,EAAA,iBAAiB,EAAe,CAC1D,GAA2B,EAAA,QAAM,YAEnC,EACE,EAAkB,MAClB,EAAE,EAAA,QAAQ,gCAAgC,CAC3C,CACH,CAAC,EAAkB,MAAO,EAAE,CAC7B,CAEK,GAAqB,EAAA,QAAM,YACxB,EAAwB,KAAK,UAAU,EAAsB,CAAG,GACvE,CAAC,EAAsB,CACxB,CAEK,EAAgB,EAAA,QAAM,YAAc,CACxC,GAAI,CAAC,GAAY,CAAC,EAAgB,OAAO,KACzC,IAAM,EAAO,EAAA,+BACX,EACA,EACA,EACD,CAED,OADK,EACE,CAAE,GAAG,EAAM,GAAG,EAAuB,CADT,GAIlC,CAAC,EAAU,EAAgB,EAAgB,GAAmB,CAAC,CAE5D,EAAc,EAAA,QAAM,YACpB,CAAC,GAAY,CAAC,EAAuB,KAMlC,EAJqB,EACxB,EAAe,EAAU,EAAe,CACxC,EAAA,iBAAiB,EAAU,EAAgB,EAAe,CAEpB,CAAE,eAAc,UAAS,CAAC,CACnE,CACD,EACA,EACA,EACA,EACA,EACA,EACD,CAAC,CAEF,EAAA,QAAM,cAAgB,CACpB,EAAmB,QAAU,GAC7B,EAAQ,QAAQ,CAChB,EAAU,EAAE,CAAC,CACb,EAAS,EAAE,CAAC,EACX,CAAC,EAAO,EAAgB,EAAqB,CAAC,CAEjD,EAAA,QAAM,cAAgB,CAChB,CAAC,GAAiB,CAAC,IAEvB,EAAU,EAAc,CAUxB,EAL0C,EACtC,OAAO,YACL,OAAO,KAAK,EAAsB,CAAC,IAAK,GAAQ,CAAC,EAAK,GAAK,CAAC,CAC7D,CACD,EAAE,CACiB,CACvB,EAAS,GACF,EAAmB,QAKjB,GAAoB,EAAa,EAAY,EAJlD,EAAmB,QAAU,GACtB,GAIT,GAID,CAAC,EAAe,EAAY,CAAC,CAEhC,IAAM,GAAkB,EAAA,QAAM,YACvB,EACE,EAAA,2BACL,EACA,EACA,EACA,EACD,CAN2B,EAAE,CAO7B,CAAC,EAAgB,EAAQ,EAAM,EAAY,CAAC,CAEzC,EAAoB,EAAA,QAAM,aAC7B,EAAkB,IAAgC,CACjD,EAAW,IAAU,CAAE,GAAG,GAAO,GAAW,EAAW,EAAE,CACzD,EAAU,IAAU,CAAE,GAAG,GAAO,GAAW,GAAM,EAAE,EAErD,EAAE,CACH,CAEK,GAAc,EAAA,QAAM,YACvB,GAAsB,CAErB,EAAA,kBADY,GAAA,0BAA0B,EACpB,EAAO,EAAE,EAAA,QAAQ,cAAc,CAAC,EAEpD,CAAC,EAAE,CACJ,CAKK,EAAgB,EAAA,QAAM,WAAyB,GAAG,CAClD,EAAa,EAAA,QAAM,gBAAkB,CACzC,EAAc,SAAS,EACtB,EAAE,CAAC,CAKA,EAAuB,EAAA,QAAM,YAC1B,EAAE,EACV,CACK,GAAwB,EAAA,QAAM,gBAC5B,EAAqB,SAAS,CACpC,EAAE,CACH,CAEK,MAAmB,CACvB,GAAI,CAAC,EAA8B,OAEnC,IAAI,EACJ,GAAI,CACF,IAAM,EAAc,EAAA,+BAClB,EACA,EACA,EACA,EACD,CACG,EACJ,AAGE,EAHE,IAAmB,wBACJ,CAAE,2BAA4B,EAAa,CAE3C,CAAE,oBAAqB,EAAa,CAEvD,EAAU,EACN,EAAa,EAAa,CAAE,SAAQ,QAAO,OAAM,CAAC,CAClD,QACG,EAAO,CACd,EAAA,kBACE,aAAiB,MAAQ,EAAM,QAAU,EAAE,EAAA,QAAQ,cAAc,CAClE,CACD,OAGE,OAAO,KAAK,EAAQ,CAAC,SAAW,GAEpC,GAAa,EAAS,CACpB,QAAS,GACT,cAAiB,CACV,IACH,EAAA,oBAAoB,EAAE,EAAA,QAAQ,uBAAuB,CAAC,CAExD,EAAS,EAAE,CAAC,CACZ,KAAiB,EAEpB,CAAC,EAGJ,EAAc,QAAU,EAKxB,EAAqB,YACnB,EACI,EAAA,wBAAwB,EAAgB,EAAQ,EAAM,CACtD,EAAE,CAQR,IAAM,EAAqB,OAAO,KAAK,EAAM,CAAC,OAAS,GAAK,EAkC5D,OAjCA,EAAA,QAAM,cAAgB,CACf,GACL,EAAoB,CAClB,KAAM,EACN,SAAU,EACV,QAAS,EACT,SACA,OACA,gBAAiB,GAClB,CAAC,EACD,CAAC,EAAW,EAAoB,EAAQ,EAAK,CAAC,EAIlB,IAAa,KAAe,CAAC,GAC/B,GACpB,EAAA,EAAA,KAAC,EAAA,0BAAD,EAA6B,CAAA,CAGlC,CAAC,GAAkB,EAAe,SAAS,SAAW,GAEtD,EAAA,EAAA,KAAC,EAAA,WAAW,UAAZ,CAAsB,UAAU,6BAC7B,GACoB,CAAA,CAIvB,OAAO,KAAK,EAAO,CAAC,SAAW,GAAU,EAAA,EAAA,KAAC,EAAA,0BAAD,EAA6B,CAAA,EAOxE,EAAA,EAAA,MAAC,MAAD,CACE,cAAa,GACb,UACE,GACI,+CACA,mCALR,EAQE,EAAA,EAAA,KAAC,EAAA,WAAD,CACQ,OACG,UACK,eACL,UACT,WAAY,GACZ,CAAA,EAEF,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,+BAAhB,CACG,IAAS,CACR,SACA,WAAY,GACZ,OACA,SAAU,EACX,CAAC,CAED,GAAgB,KAAK,EAAS,KAC7B,EAAA,EAAA,KAAC,UAAD,CAEE,UAAU,gCAEV,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,+BACZ,EAAQ,OAAO,IAAK,IACnB,EAAA,EAAA,KAAC,EAAA,YAAD,CAES,QACP,MAAO,EAAO,EAAM,KACpB,WAAY,GACZ,SAAW,GACT,EAAkB,EAAM,IAAK,EAAU,CAEzC,CAPK,EAAM,IAOX,CACF,CACE,CAAA,CACE,CAhBH,GAAG,EAAQ,IAAI,GAAG,IAgBf,CACV,CAEe,GAgBb,MAfF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oCACb,EAAA,EAAA,KAAC,EAAA,YAAD,CACE,OAAO,cACP,KAAK,SACL,QAAQ,UACR,WACE,GAAc,OAAO,KAAK,EAAM,CAAC,SAAW,GAAK,CAAC,EAEpD,QAAS,WAGL,EADH,EACK,EAAA,QAAQ,gBACR,EAAA,QAAQ,sBAAsB,CACxB,CAAA,CACV,CAAA,CAEJ,GACF"}
|
|
@@ -41,7 +41,7 @@ export interface SdkSectionSaveControl {
|
|
|
41
41
|
* @param header - optional render prop receiving shared state to render above fields
|
|
42
42
|
* @param testId - data-testid for the page wrapper
|
|
43
43
|
*/
|
|
44
|
-
export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settingsSource, header, extraDirty, buildPayload, onSaveSuccess, getInitialView, forceShowAdvancedView, allowAllView, initialValueOverrides, embedded, hideSaveButton, onSaveControlChange, testId, }: {
|
|
44
|
+
export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settingsSource, header, extraDirty, buildPayload, onSaveSuccess, getInitialView, forceShowAdvancedView, allowAllView, initialValueOverrides, embedded, hideSaveButton, suppressSuccessToast, onSaveControlChange, testId, }: {
|
|
45
45
|
sectionKeys: string[];
|
|
46
46
|
excludeKeys?: Set<string>;
|
|
47
47
|
scope?: SettingsScope;
|
|
@@ -78,6 +78,8 @@ export declare function SdkSectionPage({ sectionKeys, excludeKeys, scope, settin
|
|
|
78
78
|
* action (e.g. an onboarding "Next" button).
|
|
79
79
|
*/
|
|
80
80
|
hideSaveButton?: boolean;
|
|
81
|
+
/** Suppress the default success toast after save completes. */
|
|
82
|
+
suppressSuccessToast?: boolean;
|
|
81
83
|
/**
|
|
82
84
|
* Fires whenever the save state changes (a mutation starts/finishes,
|
|
83
85
|
* dirty status flips). Provides a stable `save()` callback the
|
|
@@ -3,69 +3,69 @@ import { I18nKey as t } from "../../../../i18n/declaration.js";
|
|
|
3
3
|
import { displayErrorToast as n, displaySuccessToast as ee } from "../../../../utils/custom-toast-handlers.js";
|
|
4
4
|
import { AxiosError as r } from "../../../../node_modules/axios/index.js";
|
|
5
5
|
import { useSettings as te } from "../../../../hooks/query/use-settings.js";
|
|
6
|
-
import { Typography as
|
|
7
|
-
import { BrandButton as
|
|
8
|
-
import { useSaveSettings as
|
|
6
|
+
import { Typography as ne } from "../../../../ui/typography.js";
|
|
7
|
+
import { BrandButton as re } from "../brand-button.js";
|
|
8
|
+
import { useSaveSettings as i } from "../../../../hooks/mutation/use-save-settings.js";
|
|
9
9
|
import { retrieveAxiosErrorMessage as ie } from "../../../../utils/retrieve-axios-error-message.js";
|
|
10
|
-
import { useAgentSettingsSchema as
|
|
11
|
-
import { LlmSettingsInputsSkeleton as
|
|
12
|
-
import { buildInitialSettingsFormValues as
|
|
13
|
-
import { SchemaField as
|
|
14
|
-
import { ViewToggle as
|
|
15
|
-
import
|
|
16
|
-
import { jsx as
|
|
10
|
+
import { useAgentSettingsSchema as ae, useConversationSettingsSchema as a } from "../../../../hooks/query/use-agent-settings-schema.js";
|
|
11
|
+
import { LlmSettingsInputsSkeleton as o } from "../llm-settings/llm-settings-inputs-skeleton.js";
|
|
12
|
+
import { buildInitialSettingsFormValues as s, buildSdkSettingsPayload as c, buildSdkSettingsPayloadForView as l, getVisibleSettingsSections as oe, hasAdvancedSettings as se, hasMinorSettings as ce, inferInitialView as le, isValidSettingsSchema as ue } from "../../../../utils/sdk-settings-schema.js";
|
|
13
|
+
import { SchemaField as de } from "./schema-field.js";
|
|
14
|
+
import { ViewToggle as fe } from "./view-toggle.js";
|
|
15
|
+
import u from "react";
|
|
16
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
17
17
|
//#region src/components/features/settings/sdk-settings/sdk-section-page.tsx
|
|
18
|
-
var
|
|
18
|
+
var pe = /* @__PURE__ */ new Set(), p = {
|
|
19
19
|
basic: 0,
|
|
20
20
|
advanced: 1,
|
|
21
21
|
all: 2
|
|
22
|
-
},
|
|
23
|
-
function
|
|
24
|
-
let { t: T } = e("openhands"), { mutate: E, isPending: D } =
|
|
22
|
+
}, me = (e, t) => p[t] < p[e] ? t : e, he = (e, { showAdvanced: t, showAll: n }) => e === "all" ? n ? "all" : t ? "advanced" : "basic" : e === "advanced" ? t ? "advanced" : n ? "all" : "basic" : "basic", m = (e, t) => e instanceof r ? e.response?.status === 401 ? `${t} 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.` : e.response?.status === 404 ? `${t} This backend does not expose /api/settings/* schema endpoints. Upgrade to a recent openhands-agent-server release.` : t : t;
|
|
23
|
+
function h({ sectionKeys: r, excludeKeys: p = pe, scope: h = "personal", settingsSource: g = "agent_settings", header: ge, extraDirty: _ = !1, buildPayload: v, onSaveSuccess: _e, getInitialView: y, forceShowAdvancedView: ve = !1, allowAllView: ye = !0, initialValueOverrides: b, embedded: be = !1, hideSaveButton: x = !1, suppressSuccessToast: S = !1, onSaveControlChange: C, testId: w = "sdk-section-settings-screen" }) {
|
|
24
|
+
let { t: T } = e("openhands"), { mutate: E, isPending: D } = i(h), { data: O, isLoading: k, isFetching: A } = te(h), j = ae(O?.agent_settings_schema), M = a(O?.conversation_settings_schema), N = g === "conversation_settings" ? M : j, P = N.data, xe = N.isLoading, [F, I] = u.useState("basic"), [L, R] = u.useState({}), [z, B] = u.useState({}), V = u.useRef(!1), H = u.useMemo(() => JSON.stringify(r), [r]), U = u.useMemo(() => JSON.parse(H), [H]), W = u.useMemo(() => {
|
|
25
25
|
if (!ue(P)) return null;
|
|
26
26
|
let e = new Set(U);
|
|
27
27
|
return {
|
|
28
28
|
...P,
|
|
29
29
|
sections: P.sections.filter((t) => e.has(t.key))
|
|
30
30
|
};
|
|
31
|
-
}, [P, U]), G =
|
|
31
|
+
}, [P, U]), G = ve || se(W), K = ye && ce(W), Se = u.useMemo(() => m(N.error, T(t.SETTINGS$SDK_SCHEMA_UNAVAILABLE)), [N.error, T]), Ce = u.useMemo(() => b ? JSON.stringify(b) : "", [b]), q = u.useMemo(() => {
|
|
32
32
|
if (!O || !W) return null;
|
|
33
|
-
let e =
|
|
34
|
-
return
|
|
33
|
+
let e = s(O, W, g);
|
|
34
|
+
return b ? {
|
|
35
35
|
...e,
|
|
36
|
-
...
|
|
36
|
+
...b
|
|
37
37
|
} : e;
|
|
38
38
|
}, [
|
|
39
39
|
O,
|
|
40
40
|
W,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
]), J =
|
|
41
|
+
g,
|
|
42
|
+
Ce
|
|
43
|
+
]), J = u.useMemo(() => !O || !W ? null : he(y ? y(O, W) : le(O, W, g), {
|
|
44
44
|
showAdvanced: G,
|
|
45
45
|
showAll: K
|
|
46
46
|
}), [
|
|
47
47
|
O,
|
|
48
48
|
W,
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
y,
|
|
50
|
+
g,
|
|
51
51
|
G,
|
|
52
52
|
K
|
|
53
53
|
]);
|
|
54
|
-
|
|
54
|
+
u.useEffect(() => {
|
|
55
55
|
V.current = !1, I("basic"), R({}), B({});
|
|
56
56
|
}, [
|
|
57
|
+
h,
|
|
57
58
|
g,
|
|
58
|
-
_,
|
|
59
59
|
H
|
|
60
|
-
]),
|
|
61
|
-
!q || !J || (R(q), B(
|
|
60
|
+
]), u.useEffect(() => {
|
|
61
|
+
!q || !J || (R(q), B(b ? Object.fromEntries(Object.keys(b).map((e) => [e, !0])) : {}), I((e) => V.current ? me(e, J) : (V.current = !0, J)));
|
|
62
62
|
}, [q, J]);
|
|
63
|
-
let
|
|
63
|
+
let we = u.useMemo(() => W ? oe(W, L, F, p) : [], [
|
|
64
64
|
W,
|
|
65
65
|
L,
|
|
66
66
|
F,
|
|
67
|
-
|
|
68
|
-
]), Y =
|
|
67
|
+
p
|
|
68
|
+
]), Y = u.useCallback((e, t) => {
|
|
69
69
|
R((n) => ({
|
|
70
70
|
...n,
|
|
71
71
|
[e]: t
|
|
@@ -73,16 +73,16 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
|
|
|
73
73
|
...t,
|
|
74
74
|
[e]: !0
|
|
75
75
|
}));
|
|
76
|
-
}, []),
|
|
76
|
+
}, []), Te = u.useCallback((e) => {
|
|
77
77
|
n(ie(e) || T(t.ERROR$GENERIC));
|
|
78
|
-
}, [T]), X =
|
|
78
|
+
}, [T]), X = u.useRef(() => {}), Ee = u.useCallback(() => {
|
|
79
79
|
X.current();
|
|
80
|
-
}, []), Z =
|
|
80
|
+
}, []), Z = u.useRef(() => ({})), De = u.useCallback(() => Z.current(), []), Q = () => {
|
|
81
81
|
if (!W) return;
|
|
82
82
|
let e;
|
|
83
83
|
try {
|
|
84
|
-
let t =
|
|
85
|
-
n =
|
|
84
|
+
let t = l(W, L, z, F), n;
|
|
85
|
+
n = g === "conversation_settings" ? { conversation_settings_diff: t } : { agent_settings_diff: t }, e = v ? v(t, {
|
|
86
86
|
values: L,
|
|
87
87
|
dirty: z,
|
|
88
88
|
view: F
|
|
@@ -92,54 +92,54 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
|
|
|
92
92
|
return;
|
|
93
93
|
}
|
|
94
94
|
Object.keys(e).length !== 0 && E(e, {
|
|
95
|
-
onError:
|
|
95
|
+
onError: Te,
|
|
96
96
|
onSuccess: () => {
|
|
97
|
-
ee(T(t.SETTINGS$SAVED_WARNING)), B({}),
|
|
97
|
+
S || ee(T(t.SETTINGS$SAVED_WARNING)), B({}), _e?.();
|
|
98
98
|
}
|
|
99
99
|
});
|
|
100
100
|
};
|
|
101
|
-
X.current = Q, Z.current = () => W ?
|
|
102
|
-
let $ = Object.keys(z).length > 0 ||
|
|
103
|
-
return
|
|
101
|
+
X.current = Q, Z.current = () => W ? c(W, L, z) : {};
|
|
102
|
+
let $ = Object.keys(z).length > 0 || _;
|
|
103
|
+
return u.useEffect(() => {
|
|
104
104
|
C && C({
|
|
105
|
-
save:
|
|
105
|
+
save: Ee,
|
|
106
106
|
isSaving: D,
|
|
107
107
|
isDirty: $,
|
|
108
108
|
values: L,
|
|
109
109
|
view: F,
|
|
110
|
-
getDirtyPayload:
|
|
110
|
+
getDirtyPayload: De
|
|
111
111
|
});
|
|
112
112
|
}, [
|
|
113
113
|
D,
|
|
114
114
|
$,
|
|
115
115
|
L,
|
|
116
116
|
F
|
|
117
|
-
]), k || A ||
|
|
117
|
+
]), (k || A) && !O || xe ? /* @__PURE__ */ d(o, {}) : !W || W.sections.length === 0 ? /* @__PURE__ */ d(ne.Paragraph, {
|
|
118
118
|
className: "text-tertiary-alt",
|
|
119
|
-
children:
|
|
120
|
-
}) : Object.keys(L).length === 0 ? /* @__PURE__ */
|
|
119
|
+
children: Se
|
|
120
|
+
}) : Object.keys(L).length === 0 ? /* @__PURE__ */ d(o, {}) : /* @__PURE__ */ f("div", {
|
|
121
121
|
"data-testid": w,
|
|
122
|
-
className:
|
|
123
|
-
children: [/* @__PURE__ */
|
|
122
|
+
className: be ? "relative flex min-h-0 w-full flex-1 flex-col" : "relative w-full min-h-0",
|
|
123
|
+
children: [/* @__PURE__ */ d(fe, {
|
|
124
124
|
view: F,
|
|
125
125
|
setView: I,
|
|
126
126
|
showAdvanced: G,
|
|
127
127
|
showAll: K,
|
|
128
128
|
isDisabled: !1
|
|
129
|
-
}), /* @__PURE__ */
|
|
129
|
+
}), /* @__PURE__ */ f("div", {
|
|
130
130
|
className: "flex flex-col gap-8",
|
|
131
131
|
children: [
|
|
132
|
-
|
|
132
|
+
ge?.({
|
|
133
133
|
values: L,
|
|
134
134
|
isDisabled: !1,
|
|
135
135
|
view: F,
|
|
136
136
|
onChange: Y
|
|
137
137
|
}),
|
|
138
|
-
|
|
138
|
+
we.map((e, t) => /* @__PURE__ */ d("section", {
|
|
139
139
|
className: "flex flex-col gap-4",
|
|
140
|
-
children: /* @__PURE__ */
|
|
140
|
+
children: /* @__PURE__ */ d("div", {
|
|
141
141
|
className: "flex flex-col gap-4",
|
|
142
|
-
children: e.fields.map((e) => /* @__PURE__ */
|
|
142
|
+
children: e.fields.map((e) => /* @__PURE__ */ d(de, {
|
|
143
143
|
field: e,
|
|
144
144
|
value: L[e.key],
|
|
145
145
|
isDisabled: !1,
|
|
@@ -147,13 +147,13 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
|
|
|
147
147
|
}, e.key))
|
|
148
148
|
})
|
|
149
149
|
}, `${e.key}-${t}`)),
|
|
150
|
-
|
|
150
|
+
x ? null : /* @__PURE__ */ d("div", {
|
|
151
151
|
className: "flex justify-start pt-2",
|
|
152
|
-
children: /* @__PURE__ */
|
|
152
|
+
children: /* @__PURE__ */ d(re, {
|
|
153
153
|
testId: "save-button",
|
|
154
154
|
type: "button",
|
|
155
155
|
variant: "primary",
|
|
156
|
-
isDisabled: D || Object.keys(z).length === 0 && !
|
|
156
|
+
isDisabled: D || Object.keys(z).length === 0 && !_,
|
|
157
157
|
onClick: Q,
|
|
158
158
|
children: T(D ? t.SETTINGS$SAVING : t.SETTINGS$SAVE_CHANGES)
|
|
159
159
|
})
|
|
@@ -163,6 +163,6 @@ function g({ sectionKeys: r, excludeKeys: m = fe, scope: g = "personal", setting
|
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
165
|
//#endregion
|
|
166
|
-
export {
|
|
166
|
+
export { h as SdkSectionPage };
|
|
167
167
|
|
|
168
168
|
//# sourceMappingURL=sdk-section-page.js.map
|