@openhands/agent-canvas 1.0.0-rc.11 → 1.0.0-rc.12
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 +46 -31
- package/README.windows.md +2 -2
- package/bin/agent-canvas.mjs +3 -1
- package/build/assets/Trans-CBypf0vt.js +1 -0
- package/build/assets/{acp-providers-Dzb4nxxB.js → acp-providers-BMyF5WII.js} +1 -1
- package/build/assets/active-backend-context-Dbaag70x.js +1 -0
- package/build/assets/add-backend-modal-C-Tr8-CM.js +1 -0
- package/build/assets/{agent-server-client-options-wXLeJYeM.js → agent-server-client-options-FoO1qgAQ.js} +1 -1
- package/build/assets/agent-server-conversation-service.api-8QGAuLAR.js +5 -0
- package/build/assets/{agent-settings-Blipgztd.js → agent-settings-iWfcEdL0.js} +2 -2
- package/build/assets/{alert-banner-Bsvys-hT.js → alert-banner-BHmoArV2.js} +1 -1
- package/build/assets/{analytics-consent-form-modal-D0domcuF.js → analytics-consent-form-modal-DeNk531m.js} +1 -1
- package/build/assets/api-key-entry-screen-BwtreCzj.js +1 -0
- package/build/assets/app-settings-BVi4XfBW.js +1 -0
- package/build/assets/automation-detail-HYDy74SR.js +1 -0
- package/build/assets/automations-list-BeEmkf4X.js +1 -0
- package/build/assets/{back-nav-button-D20Avel_.js → back-nav-button-Bckz5Wh6.js} +1 -1
- package/build/assets/backend-form-modal-CMKq85sE.js +1 -0
- package/build/assets/{backend-synced-settings-badge-Da0G6Lwv.js → backend-synced-settings-badge-Bh7rfsqx.js} +1 -1
- package/build/assets/{base-modal-DvuGYyu1.js → base-modal-7QRNzf6r.js} +1 -1
- package/build/assets/{brand-button-9SOzmqPP.js → brand-button-CKLvirxz.js} +1 -1
- package/build/assets/browser-D1ZybR7v.js +5 -0
- package/build/assets/browser-store-hzasvz9c.js +1 -0
- package/build/assets/{browser-tab-bveyJhG9.js → browser-tab-iOQjXzmI.js} +1 -1
- package/build/assets/chat-send-button-wm92Fowv.js +1 -0
- package/build/assets/check-DfvhVBub.js +1 -0
- package/build/assets/{checkmark--JWAesua.js → checkmark-BHPhb50L.js} +1 -1
- package/build/assets/{chevron-down-B9j6lcFg.js → chevron-down-CMkqyPEY.js} +1 -1
- package/build/assets/{circle-plus-check-toggle-AO9DWyDX.js → circle-plus-check-toggle-ChmnRlpR.js} +1 -1
- package/build/assets/{close--W-tHn1h.js → close-DBs90sI6.js} +1 -1
- package/build/assets/{code-tag-chmctf4w.js → code-tag-BtHOqHwB.js} +1 -1
- package/build/assets/{color-themes-0biOprdo.js → color-themes-CBikRn3w.js} +1 -1
- package/build/assets/{combobox-caret-C9BNHfSu.js → combobox-caret-evUAh6YW.js} +1 -1
- package/build/assets/{command-store-UzKGSUC2.js → command-store-DZfR8QtE.js} +1 -1
- package/build/assets/condenser-settings-DRipkbWe.js +1 -0
- package/build/assets/{confirmation-modal-Cq3eqvqH.js → confirmation-modal-DWuxe1zG.js} +1 -1
- package/build/assets/{context-menu-list-item-BQU0jZPq.js → context-menu-list-item-BbHFxHaq.js} +1 -1
- package/build/assets/conversation-C8c9c80b.js +1 -0
- package/build/assets/conversation-MUSRJNcs.js +19 -0
- package/build/assets/{conversation-local-storage-an3MiIiJ.js → conversation-local-storage-Btum2xBJ.js} +1 -1
- package/build/assets/conversation-panel-DC6L9i_c.js +1 -0
- package/build/assets/conversation-service.api-DSa_gYtg.js +1 -0
- package/build/assets/conversation-state-store-DmuPn875.js +1 -0
- package/build/assets/{conversation-store-FQmakEd-.js → conversation-store-Bu89Yxg1.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-C8tztloo.js → conversation-tab-empty-state-7js7FjYM.js} +1 -1
- package/build/assets/{copy-CdKN5rtJ.js → copy-B0SkXenR.js} +1 -1
- package/build/assets/copy-to-clipboard-button-CfH2EQz9.js +1 -0
- package/build/assets/{createLucideIcon-CkGTf9Qj.js → createLucideIcon-Bazr-V-B.js} +1 -1
- package/build/assets/declaration-Cn-NXHEy.js +1 -0
- package/build/assets/{device-verify-YuGXnpRk.js → device-verify-CWKyQ680.js} +1 -1
- package/build/assets/{dist-5dObF4p4.js → dist-Cbu6eGx8.js} +1 -1
- package/build/assets/dist-Dg2JWLGc.js +1 -0
- package/build/assets/{dropdown-classes-CVp0kVdt.js → dropdown-classes-BI1bI1ho.js} +1 -1
- package/build/assets/edit-automation-modal-Dqkfcq9A.js +1 -0
- package/build/assets/{ellipsis-button-k7HLwYth.js → ellipsis-button-DdCsOBHV.js} +1 -1
- package/build/assets/entry.client-B9pmN700.js +2 -0
- package/build/assets/{enum-filter-dropdown-COqUq3mB.js → enum-filter-dropdown-WROAIeys.js} +1 -1
- package/build/assets/{environment-switch-overlay-wB5LxfYZ.js → environment-switch-overlay-Dv0imPE6.js} +1 -1
- package/build/assets/{extensions-hub-BYCLWP3d.js → extensions-hub-BBnnYspW.js} +1 -1
- package/build/assets/{extensions-navigation-3FLKfb6g.js → extensions-navigation-CpSuf1cO.js} +1 -1
- package/build/assets/{external-link-BATfjnkz.js → external-link-FsutnU75.js} +1 -1
- package/build/assets/files-tab-CD3kdIo4.js +1 -0
- package/build/assets/files-tab-store-SyvkH3ic.js +1 -0
- package/build/assets/{folder-DPTBlxWb.js → folder-DusyBXDE.js} +1 -1
- package/build/assets/{globe-Dpgjreyy.js → globe-BUcin4kT.js} +1 -1
- package/build/assets/home-BVmRaBEJ.js +1 -0
- package/build/assets/{iconBase-BVhFI-0E.js → iconBase-B6CXDDaE.js} +1 -1
- package/build/assets/index-redirect-nMYgOTBX.js +1 -0
- package/build/assets/install-server-modal-Bgk8nar-.js +1 -0
- package/build/assets/{launch-D3MjtcA-.js → launch-C2gF0Mkw.js} +1 -1
- package/build/assets/lesson-plan-BTPqWdY7.js +3 -0
- package/build/assets/{lightbulb-S616sGEL.js → lightbulb-BJ5tWmAh.js} +1 -1
- package/build/assets/{link-external-ooNztGLp.js → link-external-DUtmHAHi.js} +1 -1
- package/build/assets/{list-todo-nCa9zxVE.js → list-todo-C-gekh-4.js} +1 -1
- package/build/assets/{llm-client-D6EtdLBs.js → llm-client-BZUkZYlc.js} +1 -1
- package/build/assets/llm-not-configured-banner-DVqNsunp.js +27 -0
- package/build/assets/llm-settings-BcSSimrb.js +1 -0
- package/build/assets/llm-settings-CdUJTdDr.js +1 -0
- package/build/assets/llm-subscription-Bvu8BLXc.js +1 -0
- package/build/assets/llm-subscription-service-Bq6z3Wkv.js +1 -0
- package/build/assets/loader-circle-Cw7_q9hg.js +1 -0
- package/build/assets/{loading-spinner-D7bOU6I7.js → loading-spinner-RF3IlMF5.js} +1 -1
- package/build/assets/manage-backends-modal-CAaBa07h.js +1 -0
- package/build/assets/manifest-961e7d04.js +1 -0
- package/build/assets/markdown-renderer-Tw6FR2ad.js +2 -0
- package/build/assets/mcp-C9c_KlHQ.js +9 -0
- package/build/assets/mcp-client-ppbYplKX.js +1 -0
- package/build/assets/messages-C8-2eWKX.js +41 -0
- package/build/assets/{modal-backdrop-_VbcKk5K.js → modal-backdrop-DRpBVVW5.js} +1 -1
- package/build/assets/{modal-body-Cd-PtMHr.js → modal-body-CEV2O67p.js} +1 -1
- package/build/assets/{modal-classes-CNm4ovfm.js → modal-classes-B2DuQ9qD.js} +1 -1
- package/build/assets/{modal-close-button-Dbo0NAMt.js → modal-close-button-gtb7RHFB.js} +1 -1
- package/build/assets/model-selector-CAv3RrJ3.js +1 -0
- package/build/assets/{mouse-pointer-click-D0QNGSIo.js → mouse-pointer-click-B3i6HcaF.js} +1 -1
- package/build/assets/{navigation-context-BpAOh_t5.js → navigation-context-CM9JmTvm.js} +1 -1
- package/build/assets/{navigation-link-Dci7Nuyf.js → navigation-link-FmXzqR1J.js} +1 -1
- package/build/assets/onboarding-CVxvHm-z.js +1 -0
- package/build/assets/{openhands-logo-Dzm-d_V_.js → openhands-logo-B4aEO2sf.js} +1 -1
- package/build/assets/option-service.api-QaEq5hDS.js +1 -0
- package/build/assets/organization-service.api-CXTKpFnV.js +1 -0
- package/build/assets/{path-utils-CokieX_o.js → path-utils-wHZluw1s.js} +1 -1
- package/build/assets/{pencil-DPEtl5QD.js → pencil-bWrxRWlr.js} +1 -1
- package/build/assets/{plan-components-CutRBi0G.js → plan-components-BF-X7vnQ.js} +1 -1
- package/build/assets/{planner-tab-CSe7tZO-.js → planner-tab-D3X1v5ar.js} +1 -1
- package/build/assets/plus-BTCK8WtR.js +1 -0
- package/build/assets/{profiles-client-BjUo3q05.js → profiles-client-CQ9L1yHR.js} +1 -1
- package/build/assets/providers-CBa2Remn.js +1 -0
- package/build/assets/proxy-BOcEWkCD.js +1 -0
- package/build/assets/{react-dom-hVBnwgwZ.js → react-dom-BBXlXOZX.js} +1 -1
- package/build/assets/{react-CM_dJw1Z.js → react-uQK8du1l.js} +1 -1
- package/build/assets/{react-Dy05vyj5.js → react-x84lbX6s.js} +1 -1
- package/build/assets/{recommended-automations-launcher-DoWDXj6R.js → recommended-automations-launcher-D50wLWD_.js} +5 -5
- package/build/assets/root-BAO9x6fg.js +2 -0
- package/build/assets/root-PB2Jnj61.css +1 -0
- package/build/assets/root-layout-DqRvQdOF.js +2 -0
- package/build/assets/{runtime-waiting-state-8i0Z3A_i.js → runtime-waiting-state-C1hJpXxl.js} +1 -1
- package/build/assets/sdk-section-page-BMlZydu1.js +1 -0
- package/build/assets/sdk-settings-schema-z51bBmMl.js +1 -0
- package/build/assets/{search-C_l_XW4e.js → search-Dxm1MUMi.js} +1 -1
- package/build/assets/{secrets-service-Skzza9sx.js → secrets-service-DlScPUwy.js} +1 -1
- package/build/assets/secrets-settings-Cn4EnhYf.js +1 -0
- package/build/assets/settings-C0Uoj_UA.js +1 -0
- package/build/assets/{settings-dropdown-input-BP-arqjU.js → settings-dropdown-input-hIIAlmHb.js} +1 -1
- package/build/assets/{settings-gear-f-zWpxfI.js → settings-gear-DQLTCnFx.js} +1 -1
- package/build/assets/{settings-index-BLfmrKRl.js → settings-index-DhFGpIST.js} +1 -1
- package/build/assets/{settings-input-BM8ANxDb.js → settings-input-BlOzCtP3.js} +1 -1
- package/build/assets/{settings-list-classes-B9uo5WES.js → settings-list-classes-BFRbCy4U.js} +1 -1
- package/build/assets/settings-modal-HFAOyyeq.js +1 -0
- package/build/assets/{settings-section-header-context-Cid25HM2.js → settings-section-header-context-iz4Go0dL.js} +1 -1
- package/build/assets/settings-service.api-DVLwi82B.js +1 -0
- package/build/assets/{settings-switch-xa6q4M6j.js → settings-switch-6cXIH-UE.js} +1 -1
- package/build/assets/{settings-utils--H_EvFjx.js → settings-utils-CfScEaPn.js} +1 -1
- package/build/assets/shared-conversation-CQ2xhLBe.js +1 -0
- package/build/assets/sidebar-mobile-menu-toggle-CCorx3e6.js +1 -0
- package/build/assets/{sidebar-nav-link-BekRAssb.js → sidebar-nav-link-DFPrrDCu.js} +1 -1
- package/build/assets/{skill-card-pill-row-DeodrwPG.js → skill-card-pill-row-D13WRKIE.js} +1 -1
- package/build/assets/{skills-BE5HJuGM.js → skills-NpRk6v79.js} +1 -1
- package/build/assets/{skills-client-CgraS-wA.js → skills-client-DsqwQEwj.js} +1 -1
- package/build/assets/{skills-plugins-rIza_fUf.js → skills-plugins-DBTBZvdO.js} +1 -1
- package/build/assets/{skills-settings-gcnVrSpU.js → skills-settings-DHfhCQza.js} +2 -2
- package/build/assets/{square-chevron-right-BWAB7NPp.js → square-chevron-right-DxZKcVq4.js} +1 -1
- package/build/assets/{styled-tooltip-X61SEwqk.js → styled-tooltip-DG1ofAcS.js} +1 -1
- package/build/assets/suspense-sOGeme-f.js +1 -0
- package/build/assets/{switch-skeleton-BbIWemkK.js → switch-skeleton-CZ6XCVZk.js} +1 -1
- package/build/assets/{task-list-tab-BFnyHGsn.js → task-list-tab-CddMPNCD.js} +1 -1
- package/build/assets/telemetry-wqIi5m85.js +2 -0
- package/build/assets/{terminal-C8qpEPQ1.js → terminal-67fy8_-t.js} +1 -1
- package/build/assets/{terminal-B92mACR5.js → terminal-DbtwHqt4.js} +1 -1
- package/build/assets/{toggle-switch-CL_wRiGs.js → toggle-switch-C0t6ge2m.js} +1 -1
- package/build/assets/{trash-2-C-RvV8WA.js → trash-2-Dmprz0A0.js} +1 -1
- package/build/assets/{typography-BLSEGjph.js → typography-CNHbO1eE.js} +1 -1
- package/build/assets/{u-check-circle-dG_VJqx5.js → u-check-circle-CX66WzfT.js} +1 -1
- package/build/assets/{u-check-circle-half-D-5ZPRnd.js → u-check-circle-half-Bj853Ub0.js} +1 -1
- package/build/assets/{u-circuit-BXoisXOA.js → u-circuit-B9bLCP7N.js} +1 -1
- package/build/assets/{u-edit-DIgADxLH.js → u-edit-D7JyvoWm.js} +1 -1
- package/build/assets/use-acp-credential-form-T3zNfBsj.js +1 -0
- package/build/assets/{use-active-conversation-TDXAnMi8.js → use-active-conversation-CsZjR4Fe.js} +1 -1
- package/build/assets/use-agent-settings-schema-C9cpCbDO.js +1 -0
- package/build/assets/{use-agent-state-CLmOVbXa.js → use-agent-state-B42GkgkV.js} +1 -1
- package/build/assets/{use-breakpoint-DpxHDmuH.js → use-breakpoint-Cent5lpI.js} +1 -1
- package/build/assets/{use-click-outside-element-DhxCUyWl.js → use-click-outside-element-DOYR26nw.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-CSm3kgqy.js → use-cloud-current-user-id-zqhuggY4.js} +1 -1
- package/build/assets/use-config-BZbOI79k.js +1 -0
- package/build/assets/use-create-conversation-DKDBT-jR.js +1 -0
- package/build/assets/{use-create-secret-LObNBU3M.js → use-create-secret-nNHqwnov.js} +1 -1
- package/build/assets/{use-event-store-DNSmyzUh.js → use-event-store-Nv92IYMU.js} +1 -1
- package/build/assets/use-handle-plan-click-JN-6bWzz.js +1 -0
- package/build/assets/use-is-authed-mnJtd2bw.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-BTgXIu3N.js → use-launch-skill-in-chat-NDUo_UCA.js} +1 -1
- package/build/assets/use-llm-profiles--ZFR-3Wc.js +1 -0
- package/build/assets/use-runtime-is-ready-D3wdvgXm.js +1 -0
- package/build/assets/use-save-settings-D7-H8Jzg.js +1 -0
- package/build/assets/use-settings-CywotK_Q.js +1 -0
- package/build/assets/{use-settings-nav-items-ykMjd_NG.js → use-settings-nav-items-CmfCfBVe.js} +2 -2
- package/build/assets/{use-skills-BDreb1l1.js → use-skills-B9gOHrOj.js} +1 -1
- package/build/assets/{use-task-list-E5t-jtgs.js → use-task-list-DLKPnq3I.js} +1 -1
- package/build/assets/{use-tracking-C9P88zSo.js → use-tracking-C3Hy1lVb.js} +1 -1
- package/build/assets/{use-user-conversation-BOaassZf.js → use-user-conversation-CbMwT5GW.js} +1 -1
- package/build/assets/useMutation-cXADjWAv.js +1 -0
- package/build/assets/useQuery-BQr6A6ry.js +1 -0
- package/build/assets/useTranslation-Bp1btAjp.js +1 -0
- package/build/assets/{utils-eXk6yerZ.js → utils-o-OXNtEy.js} +1 -1
- package/build/assets/v4-DOSjXdIn.js +1 -0
- package/build/assets/{vendor~browser-tab-BGJDGHyS.js → vendor~browser-tab-642bOcE1.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation-D98u43rl.js → vendor~conversation-panel~conversation-DqmbnXRn.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CtjHOMO_.js → vendor~conversation-panel~conversation~alert-banner-CSDVP1nw.js} +1 -1
- package/build/assets/{vendor~conversation-panel~conversation~index-BXt2-3Cc.js → vendor~conversation-panel~conversation~index-DITarr3F.js} +1 -1
- package/build/assets/{vendor~entry.client-DrAdOKqA.js → vendor~entry.client-CQ77DucR.js} +1 -1
- package/build/assets/{vendor~entry.client-EcEhmoJW.js → vendor~entry.client-ePAFmSwg.js} +1 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~f0pn7nss-DUk-MwlC.js +177 -0
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~lb3qbbk3-BvmOva8I.js +1 -0
- package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-Cl4h-NSi.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~lpdshwee-BkQQxq_q.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-BmOMM-6e.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~skills-set~oli4dvxu-8xF3WeB9.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~cnj3raoq-BjMt2JeR.js → vendor~entry.client~root~root-layout~index-redirect~home~conversation-panel~conversation~la~nyk4vv4g-UzR6fe3Y.js} +1 -1
- package/build/assets/{vendor~files-tab--640YzQO.js → vendor~files-tab-Cko7Kr5k.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation-dhKA2JVJ.js → vendor~home~conversation-panel~conversation-D3otw5Jn.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DMOoHVBy.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-CMdKUYP2.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BoE6JRJj.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DSR6Mugx.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dqpi2xyZ.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DdOzMvB1.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DX2CmDJ0.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-Dj2eezvL.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BNExlCqT.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DyN8jeZz.js} +1 -1
- package/build/assets/{vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DCn1M97v.js → vendor~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-lpEWrbMA.js} +1 -1
- package/build/assets/{vendor~launch-C0VvUe2W.js → vendor~launch-DoYO54df.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-COLUW-6M.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-BGwU2SbU.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation-eG1kjEbj.js → vendor~root-layout~home~conversation-panel~conversation-Iqs0j4Wo.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-7eqKdLSQ.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BdS6bbw9.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-BP3MGAAY.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~bok0tgtf-Fd3F3jth.js} +1 -1
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Dkd2wxJA.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ceijy54y-Cg0AqwMN.js} +2 -2
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-_LydBB1e.js → vendor~root-layout~home~conversation-panel~conversation~launch~extensions-hub~skills-settin~bxn4ldi1-BlsbqRyZ.js} +1 -1
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~settings~settings-index~agen~ec6pk3ix-CBICqfKC.js +48 -0
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~mcp~automati~dou5smdo-DPWYsRFL.js → vendor~root-layout~home~conversation-panel~conversation~launch~skills-settings~automations-~nv6afr11-BYNoKMU0.js} +15 -6
- package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-CsO1gYxF.js → vendor~root-layout~home~conversation-panel~conversation~shared-conversation~alert-banner~pl~rqjteh0a-BspUuSsP.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~automations-list-D40jgugf.js → vendor~root-layout~home~mcp~automations-list-C9U_eOqU.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~automations-list-cNHi83v_.js → vendor~root-layout~home~mcp~automations-list-DhQ3LPVw.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-xCM3k6Rd.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BEbhHQYg.js} +1 -1
- package/build/assets/{vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-BIm99UaF.js → vendor~root-layout~home~mcp~llm-settings~agent-settings~condenser-settings~verification-set~o7tv66sg-DdgDNzMc.js} +2 -2
- package/build/assets/{verification-settings-EUkt_CkZ.js → verification-settings-ClzsPf1W.js} +1 -1
- package/build/assets/x-DCZg87p7.js +1 -0
- package/build/assets/{x-mark-C42svtnu.js → x-mark-jrBTJbnP.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +22 -0
- package/build/locales/ca/openhands.json +22 -0
- package/build/locales/de/openhands.json +22 -0
- package/build/locales/en/openhands.json +22 -0
- package/build/locales/es/openhands.json +22 -0
- package/build/locales/fr/openhands.json +22 -0
- package/build/locales/it/openhands.json +22 -0
- package/build/locales/ja/openhands.json +22 -0
- package/build/locales/ko-KR/openhands.json +22 -0
- package/build/locales/no/openhands.json +22 -0
- package/build/locales/pt/openhands.json +22 -0
- package/build/locales/tr/openhands.json +22 -0
- package/build/locales/uk/openhands.json +22 -0
- package/build/locales/zh-CN/openhands.json +22 -0
- package/build/locales/zh-TW/openhands.json +22 -0
- package/config/defaults.json +4 -2
- package/dist/api/agent-server-adapter.cjs +3 -3
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.d.ts +8 -0
- package/dist/api/agent-server-adapter.js +82 -80
- package/dist/api/agent-server-adapter.js.map +1 -1
- package/dist/api/agent-server-compatibility.cjs +1 -1
- package/dist/api/agent-server-compatibility.cjs.map +1 -1
- package/dist/api/agent-server-compatibility.d.ts +10 -0
- package/dist/api/agent-server-compatibility.js +69 -25
- package/dist/api/agent-server-compatibility.js.map +1 -1
- package/dist/api/backend-registry/default-backend.cjs +1 -1
- package/dist/api/backend-registry/default-backend.cjs.map +1 -1
- package/dist/api/backend-registry/default-backend.d.ts +6 -5
- package/dist/api/backend-registry/default-backend.js +1 -1
- package/dist/api/backend-registry/default-backend.js.map +1 -1
- package/dist/api/backend-registry/storage.cjs +1 -1
- package/dist/api/backend-registry/storage.cjs.map +1 -1
- package/dist/api/backend-registry/storage.js +38 -68
- package/dist/api/backend-registry/storage.js.map +1 -1
- package/dist/api/cloud/proxy.cjs +1 -1
- package/dist/api/cloud/proxy.cjs.map +1 -1
- package/dist/api/cloud/proxy.d.ts +3 -16
- package/dist/api/cloud/proxy.js +1 -1
- package/dist/api/cloud/proxy.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 +75 -75
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/llm-subscription-service.cjs +2 -0
- package/dist/api/llm-subscription-service.cjs.map +1 -0
- package/dist/api/llm-subscription-service.d.ts +23 -0
- package/dist/api/llm-subscription-service.js +109 -0
- package/dist/api/llm-subscription-service.js.map +1 -0
- package/dist/api/mcp-service/mcp-service.api.cjs +1 -1
- package/dist/api/mcp-service/mcp-service.api.cjs.map +1 -1
- package/dist/api/mcp-service/mcp-service.api.d.ts +2 -3
- package/dist/api/mcp-service/mcp-service.api.js +38 -13
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
- package/dist/api/settings-service/settings-service.api.cjs +1 -1
- package/dist/api/settings-service/settings-service.api.cjs.map +1 -1
- package/dist/api/settings-service/settings-service.api.js +41 -42
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/conversation-events/chat/messages.cjs +1 -1
- package/dist/components/conversation-events/chat/messages.cjs.map +1 -1
- package/dist/components/conversation-events/chat/messages.js +4 -4
- package/dist/components/conversation-events/chat/messages.js.map +1 -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.js +136 -135
- package/dist/components/features/backends/backend-form-modal.js.map +1 -1
- package/dist/components/features/backends/backend-selector.cjs +1 -1
- package/dist/components/features/backends/backend-selector.cjs.map +1 -1
- package/dist/components/features/backends/backend-selector.js +103 -91
- package/dist/components/features/backends/backend-selector.js.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs +1 -1
- package/dist/components/features/backends/manage-backends-modal.cjs.map +1 -1
- package/dist/components/features/backends/manage-backends-modal.js +14 -8
- package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.cjs.map +1 -1
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js +77 -66
- package/dist/components/features/home/workspace-dropdown/folder-browser-modal.js.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.cjs.map +1 -1
- package/dist/components/features/mcp-page/custom-server-editor.js +1 -0
- package/dist/components/features/mcp-page/custom-server-editor.js.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs +1 -1
- package/dist/components/features/mcp-page/install-server-modal.cjs.map +1 -1
- package/dist/components/features/mcp-page/install-server-modal.js +73 -46
- package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
- package/dist/components/features/settings/brand-button.cjs +1 -1
- package/dist/components/features/settings/brand-button.cjs.map +1 -1
- package/dist/components/features/settings/brand-button.js +1 -1
- package/dist/components/features/settings/brand-button.js.map +1 -1
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs +2 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.cjs.map +1 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.d.ts +5 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js +167 -0
- package/dist/components/features/settings/llm-settings/openai-subscription-auth-card.js.map +1 -0
- package/dist/components/shared/modals/settings/model-selector.cjs +1 -1
- package/dist/components/shared/modals/settings/model-selector.cjs.map +1 -1
- package/dist/components/shared/modals/settings/model-selector.d.ts +1 -2
- package/dist/components/shared/modals/settings/model-selector.js +59 -65
- package/dist/components/shared/modals/settings/model-selector.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 +1 -2
- package/dist/components/shared/modals/settings/settings-form.js.map +1 -1
- package/dist/config/defaults.cjs +2 -0
- package/dist/config/defaults.cjs.map +1 -0
- package/dist/config/defaults.js +35 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/constants/llm-subscription.cjs +2 -0
- package/dist/constants/llm-subscription.cjs.map +1 -0
- package/dist/constants/llm-subscription.d.ts +16 -0
- package/dist/constants/llm-subscription.js +47 -0
- package/dist/constants/llm-subscription.js.map +1 -0
- package/dist/contexts/conversation-websocket-context.cjs +1 -1
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +1 -1
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/mutation/use-llm-subscription-auth.cjs +2 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.cjs.map +1 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.d.ts +3 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.js +30 -0
- package/dist/hooks/mutation/use-llm-subscription-auth.js.map +1 -0
- package/dist/hooks/mutation/use-save-fields-as-secrets.cjs +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.cjs.map +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.d.ts +8 -6
- package/dist/hooks/mutation/use-save-fields-as-secrets.js +1 -1
- package/dist/hooks/mutation/use-save-fields-as-secrets.js.map +1 -1
- package/dist/hooks/mutation/use-test-mcp-server.d.ts +1 -1
- package/dist/hooks/query/query-keys.cjs +1 -1
- package/dist/hooks/query/query-keys.cjs.map +1 -1
- package/dist/hooks/query/query-keys.d.ts +5 -0
- package/dist/hooks/query/query-keys.js +14 -2
- package/dist/hooks/query/query-keys.js.map +1 -1
- package/dist/hooks/query/use-agent-settings-schema.cjs +1 -1
- package/dist/hooks/query/use-agent-settings-schema.cjs.map +1 -1
- package/dist/hooks/query/use-agent-settings-schema.d.ts +2 -2
- package/dist/hooks/query/use-agent-settings-schema.js +21 -19
- package/dist/hooks/query/use-agent-settings-schema.js.map +1 -1
- package/dist/hooks/query/use-backends-health.cjs +1 -1
- package/dist/hooks/query/use-backends-health.cjs.map +1 -1
- package/dist/hooks/query/use-backends-health.js +38 -36
- package/dist/hooks/query/use-backends-health.js.map +1 -1
- package/dist/hooks/query/use-llm-subscription-models.cjs +2 -0
- package/dist/hooks/query/use-llm-subscription-models.cjs.map +1 -0
- package/dist/hooks/query/use-llm-subscription-models.d.ts +3 -0
- package/dist/hooks/query/use-llm-subscription-models.js +19 -0
- package/dist/hooks/query/use-llm-subscription-models.js.map +1 -0
- package/dist/hooks/query/use-llm-subscription-status.cjs +2 -0
- package/dist/hooks/query/use-llm-subscription-status.cjs.map +1 -0
- package/dist/hooks/query/use-llm-subscription-status.d.ts +3 -0
- package/dist/hooks/query/use-llm-subscription-status.js +19 -0
- package/dist/hooks/query/use-llm-subscription-status.js.map +1 -0
- package/dist/hooks/use-websocket.cjs +1 -1
- package/dist/hooks/use-websocket.cjs.map +1 -1
- package/dist/hooks/use-websocket.d.ts +0 -1
- package/dist/hooks/use-websocket.js +37 -38
- package/dist/hooks/use-websocket.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 +22 -0
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +2 -2
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +374 -0
- package/dist/i18n/translation.js.map +1 -1
- package/dist/locales/ar/openhands.json +22 -0
- package/dist/locales/ca/openhands.json +22 -0
- package/dist/locales/de/openhands.json +22 -0
- package/dist/locales/en/openhands.json +22 -0
- package/dist/locales/es/openhands.json +22 -0
- package/dist/locales/fr/openhands.json +22 -0
- package/dist/locales/it/openhands.json +22 -0
- package/dist/locales/ja/openhands.json +22 -0
- package/dist/locales/ko-KR/openhands.json +22 -0
- package/dist/locales/no/openhands.json +22 -0
- package/dist/locales/pt/openhands.json +22 -0
- package/dist/locales/tr/openhands.json +22 -0
- package/dist/locales/uk/openhands.json +22 -0
- package/dist/locales/zh-CN/openhands.json +22 -0
- package/dist/locales/zh-TW/openhands.json +22 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js +10 -22
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +15 -6
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +3 -5
- package/dist/package.js.map +1 -1
- package/dist/routes/files-tab.cjs +1 -1
- package/dist/routes/files-tab.cjs.map +1 -1
- package/dist/routes/files-tab.js +28 -17
- package/dist/routes/files-tab.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.js +143 -86
- package/dist/routes/llm-settings.js.map +1 -1
- package/dist/services/canvas-ui.cjs +1 -1
- package/dist/services/canvas-ui.cjs.map +1 -1
- package/dist/services/canvas-ui.d.ts +1 -1
- package/dist/services/canvas-ui.js +2 -2
- package/dist/services/canvas-ui.js.map +1 -1
- package/dist/stores/files-tab-store.cjs +1 -1
- package/dist/stores/files-tab-store.cjs.map +1 -1
- package/dist/stores/files-tab-store.d.ts +2 -1
- package/dist/stores/files-tab-store.js +5 -1
- package/dist/stores/files-tab-store.js.map +1 -1
- package/dist/stores/use-event-store.cjs +1 -1
- package/dist/stores/use-event-store.cjs.map +1 -1
- package/dist/stores/use-event-store.js +39 -34
- package/dist/stores/use-event-store.js.map +1 -1
- package/dist/types/mcp-server.d.ts +21 -0
- package/dist/ui/dropdown/dropdown.cjs +1 -1
- package/dist/ui/dropdown/dropdown.cjs.map +1 -1
- package/dist/ui/dropdown/dropdown.js +6 -2
- package/dist/ui/dropdown/dropdown.js.map +1 -1
- package/dist/utils/handle-event-for-ui.cjs +1 -1
- package/dist/utils/handle-event-for-ui.cjs.map +1 -1
- package/dist/utils/handle-event-for-ui.d.ts +2 -0
- package/dist/utils/handle-event-for-ui.js +1 -1
- package/dist/utils/handle-event-for-ui.js.map +1 -1
- package/dist/utils/llm-subscription-schema.cjs +2 -0
- package/dist/utils/llm-subscription-schema.cjs.map +1 -0
- package/dist/utils/llm-subscription-schema.d.ts +2 -0
- package/dist/utils/llm-subscription-schema.js +22 -0
- package/dist/utils/llm-subscription-schema.js.map +1 -0
- package/dist/utils/mcp-config.cjs +1 -1
- package/dist/utils/mcp-config.cjs.map +1 -1
- package/dist/utils/mcp-config.js +32 -17
- package/dist/utils/mcp-config.js.map +1 -1
- package/dist/utils/mcp-credential-validation.cjs +2 -0
- package/dist/utils/mcp-credential-validation.cjs.map +1 -0
- package/dist/utils/mcp-credential-validation.d.ts +22 -0
- package/dist/utils/mcp-credential-validation.js +31 -0
- package/dist/utils/mcp-credential-validation.js.map +1 -0
- package/dist/utils/mcp-marketplace-utils.cjs +1 -1
- package/dist/utils/mcp-marketplace-utils.cjs.map +1 -1
- package/dist/utils/mcp-marketplace-utils.d.ts +7 -2
- package/dist/utils/mcp-marketplace-utils.js +33 -48
- package/dist/utils/mcp-marketplace-utils.js.map +1 -1
- package/dist/utils/sdk-settings-schema.cjs +1 -1
- package/dist/utils/sdk-settings-schema.cjs.map +1 -1
- package/dist/utils/sdk-settings-schema.js +64 -61
- package/dist/utils/sdk-settings-schema.js.map +1 -1
- package/package.json +3 -5
- package/scripts/check-sdk-version-sync.mjs +9 -27
- package/scripts/dev-with-automation.mjs +1 -3
- package/scripts/docker-build.mjs +0 -4
- package/scripts/run-staged-typecheck.mjs +44 -0
- package/build/assets/QueryClientProvider-XcSjsfpb.js +0 -1
- package/build/assets/Trans-sy4l4TyQ.js +0 -1
- package/build/assets/active-backend-context-B2OSC-qe.js +0 -1
- package/build/assets/add-backend-modal-lG8XDYjr.js +0 -1
- package/build/assets/agent-server-adapter-B2emh2bd.js +0 -5
- package/build/assets/agent-server-conversation-service.api-QJAmctjl.js +0 -1
- package/build/assets/api-key-entry-screen-BarZU9nr.js +0 -1
- package/build/assets/app-settings-CofRfixq.js +0 -1
- package/build/assets/automation-detail-BIaQg3B1.js +0 -1
- package/build/assets/automations-list-NqyWbUTK.js +0 -1
- package/build/assets/backend-form-modal-B3BCZDPq.js +0 -1
- package/build/assets/browser-store-JRrcGdlk.js +0 -1
- package/build/assets/browser-wz8UzRmF.js +0 -5
- package/build/assets/chat-send-button-DdFU42vc.js +0 -1
- package/build/assets/check-BhnsMsWy.js +0 -1
- package/build/assets/condenser-settings-Bo07FAEi.js +0 -1
- package/build/assets/context-CI9FqkUp.js +0 -1
- package/build/assets/conversation-IS51UprA.js +0 -1
- package/build/assets/conversation-QDDJhI3U.js +0 -19
- package/build/assets/conversation-panel-BOSaPWpE.js +0 -1
- package/build/assets/conversation-service.api-CYR48oH0.js +0 -1
- package/build/assets/conversation-state-store-NEktJKfL.js +0 -1
- package/build/assets/declaration-D9ucT0fq.js +0 -1
- package/build/assets/dist-BCpEDEJq.js +0 -1
- package/build/assets/edit-automation-modal-CpA_JKLY.js +0 -1
- package/build/assets/entry.client-DUpefbBp.js +0 -2
- package/build/assets/files-tab-DZo59vtd.js +0 -1
- package/build/assets/files-tab-store-DSKUhziI.js +0 -1
- package/build/assets/home-DwZNg297.js +0 -1
- package/build/assets/index-redirect-BQ_55qN6.js +0 -1
- package/build/assets/install-server-modal-DBD6kDy0.js +0 -1
- package/build/assets/lesson-plan-Dz838P7k.js +0 -3
- package/build/assets/llm-not-configured-banner-DnrJFzRk.js +0 -27
- package/build/assets/llm-settings-BCwmvxk9.js +0 -1
- package/build/assets/llm-settings-DjZdxCR0.js +0 -1
- package/build/assets/loader-circle-1XB9nbwF.js +0 -1
- package/build/assets/manage-backends-modal-v5POMal5.js +0 -1
- package/build/assets/manifest-3def662b.js +0 -1
- package/build/assets/markdown-renderer-z446oW0Z.js +0 -2
- package/build/assets/mcp-B7K5rfzz.js +0 -9
- package/build/assets/mcp-settings-redirect-l3Zbmc0F.js +0 -1
- package/build/assets/messages-CKiNUUz1.js +0 -41
- package/build/assets/model-selector-aFK4OhGB.js +0 -1
- package/build/assets/onboarding-BXTpr86T.js +0 -1
- package/build/assets/option-service.api-CdYnKVsu.js +0 -1
- package/build/assets/organization-service.api-CzMvXIQT.js +0 -1
- package/build/assets/plus-DKUID4kd.js +0 -1
- package/build/assets/providers-CbpQft-X.js +0 -1
- package/build/assets/proxy-Bx3NeKeo.js +0 -1
- package/build/assets/query-client-config-Ca3tW1AH.js +0 -1
- package/build/assets/root-CRkz_h2T.css +0 -1
- package/build/assets/root-CWzVAsvD.js +0 -2
- package/build/assets/root-layout-BrKjMGHZ.js +0 -2
- package/build/assets/sdk-section-page-DPBwwLle.js +0 -1
- package/build/assets/sdk-settings-schema-Big50zDH.js +0 -1
- package/build/assets/secrets-settings-DmpsTC9V.js +0 -1
- package/build/assets/settings-ChsRtIJQ.js +0 -1
- package/build/assets/settings-modal-uHPPWYSS.js +0 -1
- package/build/assets/settings-service.api-CcpckquT.js +0 -1
- package/build/assets/shared-conversation-DJDrV3Gn.js +0 -1
- package/build/assets/sidebar-mobile-menu-toggle-hWfhojwa.js +0 -1
- package/build/assets/suspense-Bqb0V0q1.js +0 -1
- package/build/assets/telemetry-BPbYj5YU.js +0 -2
- package/build/assets/use-acp-credential-form-Dj7Jkhgp.js +0 -1
- package/build/assets/use-agent-settings-schema-Lf_lBAky.js +0 -1
- package/build/assets/use-config-DVU9HaPf.js +0 -1
- package/build/assets/use-create-conversation-DR9x_AZF.js +0 -1
- package/build/assets/use-handle-plan-click-Dx4MJQoh.js +0 -1
- package/build/assets/use-is-authed-B8eLO-Xq.js +0 -1
- package/build/assets/use-llm-profiles-BBTR-OsK.js +0 -1
- package/build/assets/use-runtime-is-ready-Bu6I0EBx.js +0 -1
- package/build/assets/use-save-settings-7_MLft-Y.js +0 -1
- package/build/assets/use-settings-CNsxccvQ.js +0 -1
- package/build/assets/useMutation-Dm84WAKR.js +0 -1
- package/build/assets/useQuery-DGRSm7IT.js +0 -1
- package/build/assets/useTranslation-CL6FTf1b.js +0 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~dqseey1n-D_BSEDk4.js +0 -1
- package/build/assets/vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~jfbjdnyv-C5ZIbuq8.js +0 -177
- package/build/assets/vendor~root-layout~home~conversation-panel~conversation~launch~mcp~settings~settings-index~~m3acswdn-DQE89epK.js +0 -48
- package/build/assets/x-CCfDppg5.js +0 -1
- package/dist/api/settings-service/legacy-app-preferences-migration.cjs +0 -2
- package/dist/api/settings-service/legacy-app-preferences-migration.cjs.map +0 -1
- package/dist/api/settings-service/legacy-app-preferences-migration.d.ts +0 -34
- package/dist/api/settings-service/legacy-app-preferences-migration.js +0 -52
- package/dist/api/settings-service/legacy-app-preferences-migration.js.map +0 -1
- package/dist/hooks/query/use-openhands-verified-models.cjs +0 -2
- package/dist/hooks/query/use-openhands-verified-models.cjs.map +0 -1
- package/dist/hooks/query/use-openhands-verified-models.d.ts +0 -1
- package/dist/hooks/query/use-openhands-verified-models.js +0 -14
- package/dist/hooks/query/use-openhands-verified-models.js.map +0 -1
- package/dist/utils/normalize-display-model.cjs +0 -2
- package/dist/utils/normalize-display-model.cjs.map +0 -1
- package/dist/utils/normalize-display-model.d.ts +0 -9
- package/dist/utils/normalize-display-model.js +0 -13
- package/dist/utils/normalize-display-model.js.map +0 -1
- package/dist/utils/openhands-llm.cjs +0 -2
- package/dist/utils/openhands-llm.cjs.map +0 -1
- package/dist/utils/openhands-llm.d.ts +0 -6
- package/dist/utils/openhands-llm.js +0 -9
- package/dist/utils/openhands-llm.js.map +0 -1
- /package/build/assets/{agent-server-ui-style-scope-BwIZYdC1.js → agent-server-ui-style-scope-1MuaCC1k.js} +0 -0
- /package/build/assets/{common-Dh7OqABE.js → common-DqjLSBOt.js} +0 -0
- /package/build/assets/{environment-switch-store-CiurvTtK.js → environment-switch-store-CBXkf5bS.js} +0 -0
- /package/build/assets/{extension-module-card-classes-DP5J6ngE.js → extension-module-card-classes-CVGfXtoL.js} +0 -0
- /package/build/assets/{git-status-mapper-BI8FyUVp.js → git-status-mapper-DVFXF1_X.js} +0 -0
- /package/build/assets/{handle-capture-consent-CPMXU29K.js → handle-capture-consent-BTvatyfE.js} +0 -0
- /package/build/assets/{map-provider-BM2SJarp.js → map-provider-COgsZR9p.js} +0 -0
- /package/build/assets/{objectWithoutPropertiesLoose-DSQKyRhw.js → objectWithoutPropertiesLoose-B80nTzVc.js} +0 -0
- /package/build/assets/{preload-helper-CT1Z6Pdu.js → preload-helper-D_sPnjeL.js} +0 -0
- /package/build/assets/{rolldown-runtime-BFRubm34.js → rolldown-runtime-wFmyQBCi.js} +0 -0
- /package/build/assets/{sdk-settings-field-metadata-p2GVlft7.js → sdk-settings-field-metadata-Cc4D-ut7.js} +0 -0
- /package/build/assets/{settings-wh2sLLJM.js → settings-1287uR2J.js} +0 -0
- /package/build/assets/{vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~nh19ovoo-DJTFnsA1.js → vendor~entry.client~root~root-layout~home~conversation-panel~conversation~launch~extensions~cg1m3bv7-aUIHudsf.js} +0 -0
- /package/build/assets/{vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-BmZcy_kH.js → vendor~root-layout~home~conversation-panel~conversation~extensions-hub~skills-settings~mcp~~ntycl9e1-DPPGSgT1.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-server-modal.js","names":[],"sources":["../../../../src/components/features/mcp-page/install-server-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { AxiosError } from \"axios\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport type { MCPTestFailure } from \"@openhands/typescript-client\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SaveAsSecretToggle } from \"#/components/features/mcp-page/save-as-secret-toggle\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type { IntegrationCatalogEntry as MarketplaceEntry } from \"@openhands/extensions/integrations\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { MCPServerConfig } from \"#/types/mcp-server\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { displaySuccessToast } from \"#/utils/custom-toast-handlers\";\nimport {\n getInstallableMcpConnectionOption,\n type McpMarketplaceConnectionOption,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { useSaveFieldsAsSecrets } from \"#/hooks/mutation/use-save-fields-as-secrets\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\n\n/**\n * Renders a helperText string as React nodes, converting any `[text](url)`\n * markdown links into real `<a>` elements. Plain text segments are left as-is.\n * Only `http:` and `https:` URLs are rendered as links; anything else falls\n * back to `#` to guard against `javascript:` / `data:` XSS vectors.\n */\nfunction renderHelperText(text: string): React.ReactNode {\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n for (const match of text.matchAll(linkPattern)) {\n if (match.index > lastIndex) {\n parts.push(text.slice(lastIndex, match.index));\n }\n parts.push(\n <a\n key={match.index}\n href={/^https?:\\/\\//i.test(match[2]) ? match[2] : \"#\"}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"underline hover:text-white transition-colors\"\n >\n {match[1]}\n </a>,\n );\n lastIndex = match.index + match[0].length;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts;\n}\n\ninterface InstallServerModalProps {\n entry: MarketplaceEntry;\n onClose: () => void;\n onSuccess?: (entry: MarketplaceEntry) => void;\n}\n\ninterface FieldState {\n values: Record<string, string>;\n errors: Record<string, string | null>;\n savedAsSecret: Record<string, boolean>;\n}\n\nfunction optionNeedsCredentialField(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return false;\n }\n return [\"api_key\", \"bearer\", \"basic\"].includes(option.auth.strategy);\n}\n\nfunction isCredentialOptional(option: McpMarketplaceConnectionOption): boolean {\n if (option.transport.kind === \"stdio\") {\n return option.auth.apiKeyOptional ?? false;\n }\n return option.auth.apiKeyOptional ?? option.transport.apiKeyOptional ?? false;\n}\n\nfunction makeInitialState(entry: MarketplaceEntry): FieldState {\n const values: Record<string, string> = {};\n const savedAsSecret: Record<string, boolean> = {};\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n if (template?.kind === \"stdio\") {\n for (const field of template.envFields ?? []) {\n values[field.key] = \"\";\n // Pre-check password fields; non-password fields default to off.\n savedAsSecret[field.key] = field.type === \"password\";\n }\n for (const field of template.argFields ?? []) {\n values[field.key] = \"\";\n }\n } else if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n }\n return { values, errors: {}, savedAsSecret };\n}\n\n// The marketplace install modal is intentionally add-only: clicking\n// a catalog tile always appends a new server (the user might want\n// two Slack workspaces, two Postgres connections, etc.) even when\n// one of the same template kind is already installed. Editing an\n// existing server is reached via the installed-server-card's edit\n// button, which opens `CustomServerEditor` instead.\nexport function InstallServerModal({\n entry,\n onClose,\n onSuccess,\n}: InstallServerModalProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: testMcpServer, isPending: isTesting } = useTestMcpServer();\n const saveFieldsAsSecrets = useSaveFieldsAsSecrets();\n\n const [state, setState] = React.useState<FieldState>(() =>\n makeInitialState(entry),\n );\n // Always holds the latest state so async callbacks (onSuccess) never read\n // stale closure values, even under React concurrent-mode scheduling.\n const stateRef = React.useRef(state);\n stateRef.current = state;\n\n const [globalError, setGlobalError] = React.useState<string | null>(null);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending = isTesting || isAdding;\n\n const setValue = (key: string, value: string) => {\n setState((prev) => ({\n ...prev,\n values: { ...prev.values, [key]: value },\n errors: { ...prev.errors, [key]: null },\n }));\n setGlobalError(null);\n };\n\n const toggleSecret = (key: string, value: boolean) => {\n setState((prev) => ({\n ...prev,\n savedAsSecret: { ...prev.savedAsSecret, [key]: value },\n }));\n };\n\n const makeTestErrorMessage = (failure: MCPTestFailure): string => {\n switch (failure.error_kind) {\n case \"timeout\":\n return t(I18nKey.MCP$TEST_ERROR_TIMEOUT);\n case \"connection\":\n return t(I18nKey.MCP$TEST_ERROR_CONNECTION);\n default:\n return t(I18nKey.MCP$TEST_ERROR_UNKNOWN, { error: failure.error });\n }\n };\n\n const submitServer = (payload: MCPServerConfig) => {\n testMcpServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n setGlobalError(makeTestErrorMessage(result));\n // Modal stays open — do NOT call onClose.\n return;\n }\n addMcpServer(payload, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n onSuccess?.(entry);\n onClose();\n\n // Save checked envFields as secrets in the background so the\n // Automation Server can access them without a separate manual step.\n // Runs after onClose so failures don't block the modal from closing.\n // Uses stateRef.current to avoid reading a stale closure snapshot.\n if (template?.kind === \"stdio\") {\n saveFieldsAsSecrets(\n template.envFields ?? [],\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n );\n }\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n };\n\n // ------------------------------------------------------------------\n // Per-template submit handlers. Each is small and self-contained:\n // validate user input, build the payload, then hand off to\n // submitServer.\n // ------------------------------------------------------------------\n const handleHttpServerSubmit = () => {\n // TS narrows this branch to shttp|sse; the equality guard is a\n // runtime/defensive belt to make the helper safe in isolation.\n if (template?.kind !== \"shttp\" && template?.kind !== \"sse\") {\n return;\n }\n if (!option) return;\n const apiKey = state.values.api_key?.trim() ?? \"\";\n const needsCredential = optionNeedsCredentialField(option);\n if (needsCredential && !isCredentialOptional(option) && !apiKey) {\n setState((prev) => ({\n ...prev,\n errors: { api_key: t(I18nKey.MCP$ERROR_FIELD_REQUIRED) },\n }));\n return;\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n url: template.url,\n ...(needsCredential && apiKey && { api_key: apiKey }),\n };\n submitServer(payload);\n };\n\n const handleStdioSubmit = () => {\n if (template?.kind !== \"stdio\") return;\n const stdio = template;\n const errors: Record<string, string | null> = {};\n\n for (const field of stdio.envFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n for (const field of stdio.argFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (Object.values(errors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors }));\n return;\n }\n\n const env: Record<string, string> = {};\n for (const field of stdio.envFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) env[field.key] = v;\n }\n const extraArgs: string[] = [];\n for (const field of stdio.argFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) {\n // Filesystem-style multi-token input: split on whitespace.\n for (const token of v.split(/\\s+/)) {\n if (token) extraArgs.push(token);\n }\n }\n }\n\n const payload: MCPServerConfig = {\n id: `stdio-${uuidv4()}`,\n type: \"stdio\",\n name: stdio.serverName,\n command: stdio.command,\n args: [...stdio.args, ...extraArgs],\n ...(Object.keys(env).length > 0 && { env }),\n };\n submitServer(payload);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setGlobalError(null);\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return handleHttpServerSubmit();\n }\n return handleStdioSubmit();\n };\n\n const renderFields = () => {\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-url\"\n name=\"url\"\n type=\"url\"\n label={t(I18nKey.SETTINGS$MCP_URL)}\n value={template.url}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {shouldRenderCredential ? (\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"mcp-install-field-api_key\"\n name=\"api_key\"\n type=\"password\"\n label={t(I18nKey.SETTINGS$MCP_API_KEY)}\n value={state.values.api_key ?? \"\"}\n onChange={(v) => setValue(\"api_key\", v)}\n placeholder={t(I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER)}\n showOptionalTag={apiKeyOptional}\n required={!apiKeyOptional}\n className=\"w-full\"\n />\n {state.errors.api_key && (\n <p className=\"text-xs text-red-500\">{state.errors.api_key}</p>\n )}\n </div>\n ) : null}\n </>\n );\n }\n\n if (template?.kind !== \"stdio\") return null;\n const stdio = template;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-command-readonly\"\n name=\"command-readonly\"\n type=\"text\"\n label={t(I18nKey.MCP$COMMAND_LABEL)}\n value={`${stdio.command} ${stdio.args.join(\" \")}`.trim()}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {(stdio.envFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key]}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {/* argFields are CLI arguments, not credentials — they don't need\n a \"save as secret\" toggle and are excluded from savedAsSecret. */}\n {(stdio.argFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n </div>\n ))}\n </>\n );\n };\n\n return (\n <ModalBackdrop onClose={onClose} aria-label={entry.name}>\n <form\n data-testid=\"mcp-install-modal\"\n data-marketplace-id={entry.id}\n onSubmit={handleSubmit}\n className=\"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[85vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-install-modal-close\"\n disabled={isPending}\n />\n <div className=\"flex items-start gap-3 pr-6\">\n <McpLogoBadge entry={entry} />\n <div className=\"flex flex-col flex-1\">\n <h2 className={modalTitleLgClassName}>{entry.name}</h2>\n <p className=\"text-xs text-tertiary-light\">{entry.description}</p>\n </div>\n </div>\n\n {entry.installHint && (\n <p className=\"text-xs text-tertiary-light\">{entry.installHint}</p>\n )}\n\n {entry.docsUrl && (\n <a\n href={entry.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors\"\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n )}\n\n <div className=\"flex flex-col gap-3\">{renderFields()}</div>\n\n {globalError && (\n <p\n data-testid=\"mcp-install-modal-error\"\n className=\"text-sm text-red-500 whitespace-pre-wrap\"\n >\n {globalError}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 mt-2\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n testId=\"mcp-install-cancel\"\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={isPending}\n testId=\"mcp-install-submit\"\n >\n {isTesting\n ? t(I18nKey.MCP$VERIFYING)\n : isAdding\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.MCP$INSTALL_BUTTON)}\n </BrandButton>\n </div>\n </form>\n </ModalBackdrop>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"install-server-modal.js","names":[],"sources":["../../../../src/components/features/mcp-page/install-server-modal.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { AxiosError } from \"axios\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { SettingsInput } from \"#/components/features/settings/settings-input\";\nimport { SaveAsSecretToggle } from \"#/components/features/mcp-page/save-as-secret-toggle\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport type {\n IntegrationCatalogEntry as MarketplaceEntry,\n MarketplaceField,\n} from \"@openhands/extensions/integrations\";\nimport { McpLogoBadge } from \"#/components/features/mcp-logo-badge\";\nimport { ExtendedMCPTestFailure, MCPServerConfig } from \"#/types/mcp-server\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { displaySuccessToast } from \"#/utils/custom-toast-handlers\";\nimport {\n getInstallableMcpConnectionOption,\n type McpMarketplaceConnectionOption,\n} from \"#/utils/mcp-marketplace-utils\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { useSaveFieldsAsSecrets } from \"#/hooks/mutation/use-save-fields-as-secrets\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\n\n/**\n * Renders a helperText string as React nodes, converting any `[text](url)`\n * markdown links into real `<a>` elements. Plain text segments are left as-is.\n * Only `http:` and `https:` URLs are rendered as links; anything else falls\n * back to `#` to guard against `javascript:` / `data:` XSS vectors.\n */\nfunction renderHelperText(text: string): React.ReactNode {\n const linkPattern = /\\[([^\\]]+)\\]\\(([^)]+)\\)/g;\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n for (const match of text.matchAll(linkPattern)) {\n if (match.index > lastIndex) {\n parts.push(text.slice(lastIndex, match.index));\n }\n parts.push(\n <a\n key={match.index}\n href={/^https?:\\/\\//i.test(match[2]) ? match[2] : \"#\"}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"underline hover:text-white transition-colors\"\n >\n {match[1]}\n </a>,\n );\n lastIndex = match.index + match[0].length;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts;\n}\n\ninterface InstallServerModalProps {\n entry: MarketplaceEntry;\n onClose: () => void;\n onSuccess?: (entry: MarketplaceEntry) => void;\n}\n\ninterface FieldState {\n values: Record<string, string>;\n errors: Record<string, string | null>;\n savedAsSecret: Record<string, boolean>;\n}\n\nfunction optionNeedsCredentialField(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return false;\n }\n return [\"api_key\", \"bearer\", \"basic\"].includes(option.auth.strategy);\n}\n\nfunction isCredentialOptional(option: McpMarketplaceConnectionOption): boolean {\n if (option.transport.kind === \"stdio\") {\n return option.auth.apiKeyOptional ?? false;\n }\n return option.auth.apiKeyOptional ?? option.transport.apiKeyOptional ?? false;\n}\n\nfunction makeInitialState(entry: MarketplaceEntry): FieldState {\n const values: Record<string, string> = {};\n const savedAsSecret: Record<string, boolean> = {};\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n if (template?.kind === \"stdio\") {\n for (const field of template.envFields ?? []) {\n values[field.key] = \"\";\n // Pre-check password fields; non-password fields default to off.\n savedAsSecret[field.key] = field.type === \"password\";\n }\n for (const field of template.argFields ?? []) {\n values[field.key] = \"\";\n }\n } else if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n if (option?.auth.credentialSecretName) {\n savedAsSecret.api_key =\n option.auth.saveCredentialAsSecretByDefault ?? false;\n }\n }\n return { values, errors: {}, savedAsSecret };\n}\n\n// The marketplace install modal is intentionally add-only: clicking\n// a catalog tile always appends a new server (the user might want\n// two Slack workspaces, two Postgres connections, etc.) even when\n// one of the same template kind is already installed. Editing an\n// existing server is reached via the installed-server-card's edit\n// button, which opens `CustomServerEditor` instead.\nexport function InstallServerModal({\n entry,\n onClose,\n onSuccess,\n}: InstallServerModalProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: testMcpServer, isPending: isTesting } = useTestMcpServer();\n const saveFieldsAsSecrets = useSaveFieldsAsSecrets();\n\n const [state, setState] = React.useState<FieldState>(() =>\n makeInitialState(entry),\n );\n // Always holds the latest state so async callbacks (onSuccess) never read\n // stale closure values, even under React concurrent-mode scheduling.\n const stateRef = React.useRef(state);\n stateRef.current = state;\n\n const [globalError, setGlobalError] = React.useState<string | null>(null);\n const [isFinalizingInstall, setIsFinalizingInstall] = React.useState(false);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending = isTesting || isAdding || isFinalizingInstall;\n\n const setValue = (key: string, value: string) => {\n setState((prev) => ({\n ...prev,\n values: { ...prev.values, [key]: value },\n errors: { ...prev.errors, [key]: null },\n }));\n setGlobalError(null);\n };\n\n const toggleSecret = (key: string, value: boolean) => {\n setState((prev) => ({\n ...prev,\n savedAsSecret: { ...prev.savedAsSecret, [key]: value },\n }));\n };\n\n const saveHostedCredentialAsSecret = (): Promise<void> => {\n const secretName = option?.auth.credentialSecretName;\n const apiKey = stateRef.current.values.api_key?.trim();\n if (!secretName || !apiKey || !stateRef.current.savedAsSecret.api_key) {\n return Promise.resolve();\n }\n\n const field: MarketplaceField = {\n key: secretName,\n label: option.auth.credentialLabel ?? secretName,\n type: \"password\",\n };\n return saveFieldsAsSecrets(\n [field],\n { [secretName]: apiKey },\n { [secretName]: true },\n );\n };\n\n const saveSelectedSecrets = (): Promise<void> => {\n if (template?.kind === \"stdio\") {\n return saveFieldsAsSecrets(\n template.envFields ?? [],\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n );\n }\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return saveHostedCredentialAsSecret();\n }\n return Promise.resolve();\n };\n\n const makeTestErrorMessage = (failure: ExtendedMCPTestFailure): string => {\n switch (failure.error_kind) {\n case \"timeout\":\n return t(I18nKey.MCP$TEST_ERROR_TIMEOUT);\n case \"connection\":\n return t(I18nKey.MCP$TEST_ERROR_CONNECTION);\n case \"credentials\":\n return t(I18nKey.MCP$TEST_ERROR_CREDENTIALS, { error: failure.error });\n default:\n return t(I18nKey.MCP$TEST_ERROR_UNKNOWN, { error: failure.error });\n }\n };\n\n const submitServer = (payload: MCPServerConfig) => {\n testMcpServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n setGlobalError(makeTestErrorMessage(result));\n // Modal stays open — do NOT call onClose.\n return;\n }\n addMcpServer(payload, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$INSTALL_SUCCESS));\n setIsFinalizingInstall(true);\n void (async () => {\n try {\n await saveSelectedSecrets();\n } finally {\n onSuccess?.(entry);\n onClose();\n }\n })();\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n },\n onError: (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n },\n });\n };\n\n // ------------------------------------------------------------------\n // Per-template submit handlers. Each is small and self-contained:\n // validate user input, build the payload, then hand off to\n // submitServer.\n // ------------------------------------------------------------------\n const handleHttpServerSubmit = () => {\n // TS narrows this branch to shttp|sse; the equality guard is a\n // runtime/defensive belt to make the helper safe in isolation.\n if (template?.kind !== \"shttp\" && template?.kind !== \"sse\") {\n return;\n }\n if (!option) return;\n const apiKey = state.values.api_key?.trim() ?? \"\";\n const needsCredential = optionNeedsCredentialField(option);\n if (needsCredential && !isCredentialOptional(option) && !apiKey) {\n setState((prev) => ({\n ...prev,\n errors: { api_key: t(I18nKey.MCP$ERROR_FIELD_REQUIRED) },\n }));\n return;\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n url: template.url,\n ...(needsCredential && apiKey && { api_key: apiKey }),\n };\n submitServer(payload);\n };\n\n const handleStdioSubmit = () => {\n if (template?.kind !== \"stdio\") return;\n const stdio = template;\n const errors: Record<string, string | null> = {};\n\n for (const field of stdio.envFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n for (const field of stdio.argFields ?? []) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n errors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (Object.values(errors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors }));\n return;\n }\n\n const env: Record<string, string> = {};\n for (const field of stdio.envFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) env[field.key] = v;\n }\n const extraArgs: string[] = [];\n for (const field of stdio.argFields ?? []) {\n const v = state.values[field.key]?.trim();\n if (v) {\n // Filesystem-style multi-token input: split on whitespace.\n for (const token of v.split(/\\s+/)) {\n if (token) extraArgs.push(token);\n }\n }\n }\n\n const payload: MCPServerConfig = {\n id: `stdio-${uuidv4()}`,\n type: \"stdio\",\n name: stdio.serverName,\n command: stdio.command,\n args: [...stdio.args, ...extraArgs],\n ...(Object.keys(env).length > 0 && { env }),\n };\n submitServer(payload);\n };\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setGlobalError(null);\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n return handleHttpServerSubmit();\n }\n return handleStdioSubmit();\n };\n\n const renderFields = () => {\n if (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n const credentialSecretName = option?.auth.credentialSecretName;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-url\"\n name=\"url\"\n type=\"url\"\n label={t(I18nKey.SETTINGS$MCP_URL)}\n value={template.url}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {shouldRenderCredential ? (\n <div className=\"flex flex-col gap-1\">\n <SettingsInput\n testId=\"mcp-install-field-api_key\"\n name=\"api_key\"\n type=\"password\"\n label={\n option?.auth.credentialLabel ??\n t(I18nKey.SETTINGS$MCP_API_KEY)\n }\n value={state.values.api_key ?? \"\"}\n onChange={(v) => setValue(\"api_key\", v)}\n placeholder={\n option?.auth.credentialPlaceholder ??\n t(I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER)\n }\n showOptionalTag={apiKeyOptional}\n required={!apiKeyOptional}\n className=\"w-full\"\n />\n {option?.auth.credentialHelp && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(option.auth.credentialHelp)}\n </p>\n )}\n {state.errors.api_key && (\n <p className=\"text-xs text-red-500\">{state.errors.api_key}</p>\n )}\n {credentialSecretName && (\n <SaveAsSecretToggle\n fieldKey={credentialSecretName}\n checked={state.savedAsSecret.api_key ?? false}\n onToggle={(v) => toggleSecret(\"api_key\", v)}\n />\n )}\n </div>\n ) : null}\n </>\n );\n }\n\n if (template?.kind !== \"stdio\") return null;\n const stdio = template;\n return (\n <>\n <SettingsInput\n testId=\"mcp-install-field-command-readonly\"\n name=\"command-readonly\"\n type=\"text\"\n label={t(I18nKey.MCP$COMMAND_LABEL)}\n value={`${stdio.command} ${stdio.args.join(\" \")}`.trim()}\n onChange={() => {}}\n isDisabled\n className=\"w-full\"\n />\n {(stdio.envFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key]}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {/* argFields are CLI arguments, not credentials — they don't need\n a \"save as secret\" toggle and are excluded from savedAsSecret. */}\n {(stdio.argFields ?? []).map((field) => (\n <div key={field.key} className=\"flex flex-col gap-1\">\n <SettingsInput\n testId={`mcp-install-field-${field.key}`}\n name={field.key}\n type={field.type === \"password\" ? \"password\" : \"text\"}\n label={field.label}\n value={state.values[field.key] ?? \"\"}\n onChange={(v) => setValue(field.key, v)}\n placeholder={field.placeholder}\n required={field.required}\n showOptionalTag={!field.required}\n className=\"w-full\"\n />\n {field.helperText && (\n <p className=\"text-xs text-tertiary-alt\">\n {renderHelperText(field.helperText)}\n </p>\n )}\n {state.errors[field.key] && (\n <p className=\"text-xs text-red-500\">{state.errors[field.key]}</p>\n )}\n </div>\n ))}\n </>\n );\n };\n\n return (\n <ModalBackdrop onClose={onClose} aria-label={entry.name}>\n <form\n data-testid=\"mcp-install-modal\"\n data-marketplace-id={entry.id}\n onSubmit={handleSubmit}\n className=\"relative bg-base-secondary p-6 rounded-xl flex flex-col gap-4 border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[85vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-install-modal-close\"\n disabled={isPending}\n />\n <div className=\"flex items-start gap-3 pr-6\">\n <McpLogoBadge entry={entry} />\n <div className=\"flex flex-col flex-1\">\n <h2 className={modalTitleLgClassName}>{entry.name}</h2>\n <p className=\"text-xs text-tertiary-light\">{entry.description}</p>\n </div>\n </div>\n\n {entry.installHint && (\n <p className=\"text-xs text-tertiary-light\">{entry.installHint}</p>\n )}\n\n {entry.docsUrl && (\n <a\n href={entry.docsUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors\"\n >\n {t(I18nKey.MCP$VIEW_DOCS)}\n </a>\n )}\n\n <div className=\"flex flex-col gap-3\">{renderFields()}</div>\n\n {globalError && (\n <p\n data-testid=\"mcp-install-modal-error\"\n className=\"text-sm text-red-500 whitespace-pre-wrap\"\n >\n {globalError}\n </p>\n )}\n\n <div className=\"flex justify-end gap-2 mt-2\">\n <BrandButton\n type=\"button\"\n variant=\"secondary\"\n onClick={onClose}\n testId=\"mcp-install-cancel\"\n isDisabled={isPending}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n <BrandButton\n type=\"submit\"\n variant=\"primary\"\n isDisabled={isPending}\n testId=\"mcp-install-submit\"\n >\n {isTesting\n ? t(I18nKey.MCP$VERIFYING)\n : isAdding || isFinalizingInstall\n ? t(I18nKey.SETTINGS$SAVING)\n : t(I18nKey.MCP$INSTALL_BUTTON)}\n </BrandButton>\n </div>\n </form>\n </ModalBackdrop>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../utils/utils.cjs`),t=require(`../../../utils/form-control-classes.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);var i=(0,n.forwardRef)(function({testId:n,name:i,children:a,variant:o,type:s,isDisabled:c,className:l,onClick:u,startContent:d,ariaLabel:f,"aria-busy":p},m){return(0,r.jsxs)(`button`,{ref:m,name:i,"data-testid":n,disabled:c,type:s,onClick:u,"aria-label":f,"aria-busy":p,className:e.cn(t.formControlButtonClassName,o===`primary`&&`bg-primary text-[var(--oh-color-base)] hover:opacity-80`,o===`secondary`&&`border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised`,o===`tertiary`&&`bg-[var(--oh-interactive-hover)] text-white hover:opacity-80`,o===`danger`&&`bg-red-600 text-white hover:bg-red-700`,o===`ghost-danger`&&`h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal`,d&&`flex items-center justify-center gap-2`,l),children:[d,a]})});exports.BrandButton=i;
|
|
1
|
+
require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../utils/utils.cjs`),t=require(`../../../utils/form-control-classes.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);var i=(0,n.forwardRef)(function({testId:n,name:i,children:a,variant:o,type:s,isDisabled:c,className:l,onClick:u,startContent:d,ariaLabel:f,"aria-busy":p},m){return(0,r.jsxs)(`button`,{ref:m,name:i,"data-testid":n,disabled:c,type:s,onClick:u,"aria-label":f,"aria-busy":p,className:e.cn(t.formControlButtonClassName,o===`primary`&&`bg-primary text-[var(--oh-color-base)] hover:opacity-80 disabled:bg-[var(--oh-interactive-hover)] disabled:text-[var(--oh-muted)] disabled:opacity-100`,o===`secondary`&&`border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised`,o===`tertiary`&&`bg-[var(--oh-interactive-hover)] text-white hover:opacity-80`,o===`danger`&&`bg-red-600 text-white hover:bg-red-700`,o===`ghost-danger`&&`h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal`,d&&`flex items-center justify-center gap-2`,l),children:[d,a]})});exports.BrandButton=i;
|
|
2
2
|
//# sourceMappingURL=brand-button.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brand-button.cjs","names":[],"sources":["../../../../src/components/features/settings/brand-button.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlButtonClassName } from \"#/utils/form-control-classes\";\n\ninterface BrandButtonProps {\n testId?: string;\n name?: string;\n variant: \"primary\" | \"secondary\" | \"tertiary\" | \"danger\" | \"ghost-danger\";\n type: React.ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n isDisabled?: boolean;\n className?: string;\n onClick?: (event?: React.MouseEvent<HTMLButtonElement>) => void;\n startContent?: React.ReactNode;\n /** Accessible label for icon-only buttons */\n ariaLabel?: string;\n /** Indicates busy/loading state for screen readers */\n \"aria-busy\"?: boolean;\n}\n\nexport const BrandButton = forwardRef<\n HTMLButtonElement,\n React.PropsWithChildren<BrandButtonProps>\n>(function BrandButton(\n {\n testId,\n name,\n children,\n variant,\n type,\n isDisabled,\n className,\n onClick,\n startContent,\n ariaLabel,\n \"aria-busy\": ariaBusy,\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n name={name}\n data-testid={testId}\n disabled={isDisabled}\n // The type is already passed as a prop to the button component\n\n type={type}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-busy={ariaBusy}\n className={cn(\n formControlButtonClassName,\n variant === \"primary\" &&\n \"bg-primary text-[var(--oh-color-base)] hover:opacity-80\",\n variant === \"secondary\" &&\n \"border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised\",\n variant === \"tertiary\" &&\n \"bg-[var(--oh-interactive-hover)] text-white hover:opacity-80\",\n variant === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n variant === \"ghost-danger\" &&\n \"h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal\",\n startContent && \"flex items-center justify-center gap-2\",\n className,\n )}\n >\n {startContent}\n {children}\n </button>\n );\n});\n"],"mappings":"0MAmBA,IAAa,GAAA,EAAA,EAAA,YAGX,SACA,CACE,SACA,OACA,WACA,UACA,OACA,aACA,YACA,UACA,eACA,YACA,YAAa,GAEf,EACA,CACA,OACE,EAAA,EAAA,MAAC,SAAD,CACO,MACC,OACN,cAAa,EACb,SAAU,EAGJ,OACG,UACT,aAAY,EACZ,YAAW,EACX,UAAW,EAAA,GACT,EAAA,2BACA,IAAY,WACV,
|
|
1
|
+
{"version":3,"file":"brand-button.cjs","names":[],"sources":["../../../../src/components/features/settings/brand-button.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlButtonClassName } from \"#/utils/form-control-classes\";\n\ninterface BrandButtonProps {\n testId?: string;\n name?: string;\n variant: \"primary\" | \"secondary\" | \"tertiary\" | \"danger\" | \"ghost-danger\";\n type: React.ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n isDisabled?: boolean;\n className?: string;\n onClick?: (event?: React.MouseEvent<HTMLButtonElement>) => void;\n startContent?: React.ReactNode;\n /** Accessible label for icon-only buttons */\n ariaLabel?: string;\n /** Indicates busy/loading state for screen readers */\n \"aria-busy\"?: boolean;\n}\n\nexport const BrandButton = forwardRef<\n HTMLButtonElement,\n React.PropsWithChildren<BrandButtonProps>\n>(function BrandButton(\n {\n testId,\n name,\n children,\n variant,\n type,\n isDisabled,\n className,\n onClick,\n startContent,\n ariaLabel,\n \"aria-busy\": ariaBusy,\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n name={name}\n data-testid={testId}\n disabled={isDisabled}\n // The type is already passed as a prop to the button component\n\n type={type}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-busy={ariaBusy}\n className={cn(\n formControlButtonClassName,\n variant === \"primary\" &&\n \"bg-primary text-[var(--oh-color-base)] hover:opacity-80 disabled:bg-[var(--oh-interactive-hover)] disabled:text-[var(--oh-muted)] disabled:opacity-100\",\n variant === \"secondary\" &&\n \"border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised\",\n variant === \"tertiary\" &&\n \"bg-[var(--oh-interactive-hover)] text-white hover:opacity-80\",\n variant === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n variant === \"ghost-danger\" &&\n \"h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal\",\n startContent && \"flex items-center justify-center gap-2\",\n className,\n )}\n >\n {startContent}\n {children}\n </button>\n );\n});\n"],"mappings":"0MAmBA,IAAa,GAAA,EAAA,EAAA,YAGX,SACA,CACE,SACA,OACA,WACA,UACA,OACA,aACA,YACA,UACA,eACA,YACA,YAAa,GAEf,EACA,CACA,OACE,EAAA,EAAA,MAAC,SAAD,CACO,MACC,OACN,cAAa,EACb,SAAU,EAGJ,OACG,UACT,aAAY,EACZ,YAAW,EACX,UAAW,EAAA,GACT,EAAA,2BACA,IAAY,WACV,yJACF,IAAY,aACV,wFACF,IAAY,YACV,+DACF,IAAY,UAAY,yCACxB,IAAY,gBACV,8GACF,GAAgB,yCAChB,EACD,UAxBH,CA0BG,EACA,EACM,IAEX"}
|
|
@@ -13,7 +13,7 @@ var i = n(function({ testId: n, name: i, children: a, variant: o, type: s, isDis
|
|
|
13
13
|
onClick: u,
|
|
14
14
|
"aria-label": f,
|
|
15
15
|
"aria-busy": p,
|
|
16
|
-
className: e(t, o === "primary" && "bg-primary text-[var(--oh-color-base)] hover:opacity-80", o === "secondary" && "border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised", o === "tertiary" && "bg-[var(--oh-interactive-hover)] text-white hover:opacity-80", o === "danger" && "bg-red-600 text-white hover:bg-red-700", o === "ghost-danger" && "h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal", d && "flex items-center justify-center gap-2", l),
|
|
16
|
+
className: e(t, o === "primary" && "bg-primary text-[var(--oh-color-base)] hover:opacity-80 disabled:bg-[var(--oh-interactive-hover)] disabled:text-[var(--oh-muted)] disabled:opacity-100", o === "secondary" && "border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised", o === "tertiary" && "bg-[var(--oh-interactive-hover)] text-white hover:opacity-80", o === "danger" && "bg-red-600 text-white hover:bg-red-700", o === "ghost-danger" && "h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal", d && "flex items-center justify-center gap-2", l),
|
|
17
17
|
children: [d, a]
|
|
18
18
|
});
|
|
19
19
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brand-button.js","names":[],"sources":["../../../../src/components/features/settings/brand-button.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlButtonClassName } from \"#/utils/form-control-classes\";\n\ninterface BrandButtonProps {\n testId?: string;\n name?: string;\n variant: \"primary\" | \"secondary\" | \"tertiary\" | \"danger\" | \"ghost-danger\";\n type: React.ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n isDisabled?: boolean;\n className?: string;\n onClick?: (event?: React.MouseEvent<HTMLButtonElement>) => void;\n startContent?: React.ReactNode;\n /** Accessible label for icon-only buttons */\n ariaLabel?: string;\n /** Indicates busy/loading state for screen readers */\n \"aria-busy\"?: boolean;\n}\n\nexport const BrandButton = forwardRef<\n HTMLButtonElement,\n React.PropsWithChildren<BrandButtonProps>\n>(function BrandButton(\n {\n testId,\n name,\n children,\n variant,\n type,\n isDisabled,\n className,\n onClick,\n startContent,\n ariaLabel,\n \"aria-busy\": ariaBusy,\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n name={name}\n data-testid={testId}\n disabled={isDisabled}\n // The type is already passed as a prop to the button component\n\n type={type}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-busy={ariaBusy}\n className={cn(\n formControlButtonClassName,\n variant === \"primary\" &&\n \"bg-primary text-[var(--oh-color-base)] hover:opacity-80\",\n variant === \"secondary\" &&\n \"border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised\",\n variant === \"tertiary\" &&\n \"bg-[var(--oh-interactive-hover)] text-white hover:opacity-80\",\n variant === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n variant === \"ghost-danger\" &&\n \"h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal\",\n startContent && \"flex items-center justify-center gap-2\",\n className,\n )}\n >\n {startContent}\n {children}\n </button>\n );\n});\n"],"mappings":";;;;;AAmBA,IAAa,IAAc,EAGzB,SACA,EACE,WACA,SACA,aACA,YACA,SACA,eACA,cACA,YACA,iBACA,cACA,aAAa,KAEf,GACA;AACA,QACE,kBAAC,UAAD;EACO;EACC;EACN,eAAa;EACb,UAAU;EAGJ;EACG;EACT,cAAY;EACZ,aAAW;EACX,WAAW,EACT,GACA,MAAY,aACV,
|
|
1
|
+
{"version":3,"file":"brand-button.js","names":[],"sources":["../../../../src/components/features/settings/brand-button.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlButtonClassName } from \"#/utils/form-control-classes\";\n\ninterface BrandButtonProps {\n testId?: string;\n name?: string;\n variant: \"primary\" | \"secondary\" | \"tertiary\" | \"danger\" | \"ghost-danger\";\n type: React.ButtonHTMLAttributes<HTMLButtonElement>[\"type\"];\n isDisabled?: boolean;\n className?: string;\n onClick?: (event?: React.MouseEvent<HTMLButtonElement>) => void;\n startContent?: React.ReactNode;\n /** Accessible label for icon-only buttons */\n ariaLabel?: string;\n /** Indicates busy/loading state for screen readers */\n \"aria-busy\"?: boolean;\n}\n\nexport const BrandButton = forwardRef<\n HTMLButtonElement,\n React.PropsWithChildren<BrandButtonProps>\n>(function BrandButton(\n {\n testId,\n name,\n children,\n variant,\n type,\n isDisabled,\n className,\n onClick,\n startContent,\n ariaLabel,\n \"aria-busy\": ariaBusy,\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n name={name}\n data-testid={testId}\n disabled={isDisabled}\n // The type is already passed as a prop to the button component\n\n type={type}\n onClick={onClick}\n aria-label={ariaLabel}\n aria-busy={ariaBusy}\n className={cn(\n formControlButtonClassName,\n variant === \"primary\" &&\n \"bg-primary text-[var(--oh-color-base)] hover:opacity-80 disabled:bg-[var(--oh-interactive-hover)] disabled:text-[var(--oh-muted)] disabled:opacity-100\",\n variant === \"secondary\" &&\n \"border border-[var(--oh-border)] bg-base-secondary text-white hover:bg-surface-raised\",\n variant === \"tertiary\" &&\n \"bg-[var(--oh-interactive-hover)] text-white hover:opacity-80\",\n variant === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n variant === \"ghost-danger\" &&\n \"h-auto min-h-0 bg-transparent px-0 text-red-600 underline hover:text-red-700 hover:no-underline font-normal\",\n startContent && \"flex items-center justify-center gap-2\",\n className,\n )}\n >\n {startContent}\n {children}\n </button>\n );\n});\n"],"mappings":";;;;;AAmBA,IAAa,IAAc,EAGzB,SACA,EACE,WACA,SACA,aACA,YACA,SACA,eACA,cACA,YACA,iBACA,cACA,aAAa,KAEf,GACA;AACA,QACE,kBAAC,UAAD;EACO;EACC;EACN,eAAa;EACb,UAAU;EAGJ;EACG;EACT,cAAY;EACZ,aAAW;EACX,WAAW,EACT,GACA,MAAY,aACV,0JACF,MAAY,eACV,yFACF,MAAY,cACV,gEACF,MAAY,YAAY,0CACxB,MAAY,kBACV,+GACF,KAAgB,0CAChB,EACD;YAxBH,CA0BG,GACA,EACM;;EAEX"}
|
|
@@ -0,0 +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(`../../../../node_modules/lucide-react/dist/esm/icons/external-link.cjs`),i=require(`../../../../utils/custom-toast-handlers.cjs`),a=require(`../../../shared/buttons/copy-to-clipboard-button.cjs`),o=require(`../../../../ui/typography.cjs`),s=require(`../brand-button.cjs`),c=require(`../../../../hooks/mutation/use-llm-subscription-auth.cjs`),l=require(`../../../../hooks/query/use-llm-subscription-status.cjs`);let u=require(`react`);u=e.__toESM(u,1);let d=require(`react/jsx-runtime`);var f=5,p=1;function m(e){let t=e.verificationUriComplete??e.verificationUri;window.open(t,`_blank`,`noopener,noreferrer`)}function h({isDisabled:e=!1}){let{t:h}=t.useTranslation(`openhands`),g=l.useOpenAISubscriptionStatus(),_=c.useStartOpenAISubscriptionLogin(),v=c.usePollOpenAISubscriptionLogin(),y=c.useLogoutOpenAISubscription(),[b,x]=u.default.useState(null),[S,C]=u.default.useState(!1),[w,T]=u.default.useState(!1),E=u.default.useRef(null),D=u.default.useCallback(()=>{E.current!==null&&(window.clearTimeout(E.current),E.current=null)},[]),O=()=>{b&&(navigator.clipboard.writeText(b.userCode),C(!0),setTimeout(()=>C(!1),2e3))},k=_.isPending||v.isPending||y.isPending,A=!!g.data?.connected,j=u.default.useCallback(async e=>{try{return(await v.mutateAsync(e)).connected?(x(null),T(!1),i.displaySuccessToast(h(n.I18nKey.SETTINGS$SUBSCRIPTION_CONNECTED_TOAST)),!0):(T(!0),!1)}catch{return i.displayErrorToast(h(n.I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR)),!0}},[v,h]);return u.default.useEffect(()=>{if(!b||A||e)return;let t=!1,n=Math.max(b.intervalSeconds??f,p),r=()=>{D(),E.current=window.setTimeout(async()=>{if(t)return;let e=await j(b.deviceCode);!t&&!e&&r()},n*1e3)};return r(),()=>{t=!0,D()}},[b,D,A,e,j]),(0,d.jsxs)(`section`,{"data-testid":`openai-subscription-auth-card`,className:`flex flex-col gap-4 rounded-xl border border-[var(--oh-border)] bg-[var(--oh-surface-raised)] p-4`,children:[(0,d.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,d.jsx)(o.Typography.H3,{children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_CARD_TITLE)}),(0,d.jsx)(o.Typography.Paragraph,{className:`text-tertiary-alt text-sm leading-5`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_CARD_DESCRIPTION)})]}),(0,d.jsx)(`div`,{className:`flex flex-col gap-1 text-sm`,"data-testid":`subscription-status`,children:g.isLoading?(0,d.jsx)(`span`,{className:`text-tertiary-light`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CHECKING)}):g.isError?(0,d.jsx)(`span`,{className:`text-danger`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_STATUS_UNAVAILABLE)}):A?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`span`,{className:`text-success`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CONNECTED)}),g.data?.accountEmail?(0,d.jsx)(`span`,{className:`text-tertiary-light`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_ACCOUNT,{account:g.data.accountEmail})}):null]}):(0,d.jsx)(`span`,{className:`text-warning`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_STATUS_DISCONNECTED)})}),b?(0,d.jsxs)(`div`,{"data-testid":`subscription-device-challenge`,className:`flex flex-col gap-2 rounded-lg border border-[var(--oh-border-subtle)] p-3 text-sm`,children:[(0,d.jsx)(`span`,{children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_DEVICE_INSTRUCTIONS)}),(0,d.jsxs)(`div`,{className:`flex items-center gap-2 rounded-lg bg-[var(--oh-surface-deep)] px-3 py-2 font-mono text-base text-[var(--oh-foreground)]`,children:[(0,d.jsx)(`span`,{className:`flex-1 select-all`,children:b.userCode}),(0,d.jsx)(a.CopyToClipboardButton,{isHidden:!1,isDisabled:!1,onClick:O,mode:S?`copied`:`copy`})]}),(0,d.jsxs)(`a`,{href:b.verificationUriComplete??b.verificationUri,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-sm text-[var(--oh-accent)] underline`,children:[h(n.I18nKey.SETTINGS$SUBSCRIPTION_OPEN_LOGIN),(0,d.jsx)(r.ExternalLink,{size:14,"aria-hidden":!0})]}),w?(0,d.jsx)(`span`,{className:`text-warning`,children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_PENDING_TOAST)}):null]}):null,(0,d.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[A?(0,d.jsx)(s.BrandButton,{testId:`subscription-disconnect`,type:`button`,variant:`tertiary`,isDisabled:e||k,onClick:async()=>{try{await y.mutateAsync(),D(),x(null),T(!1),i.displaySuccessToast(h(n.I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECTED_TOAST))}catch{i.displayErrorToast(h(n.I18nKey.ERROR$GENERIC))}},children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECT)}):(0,d.jsx)(s.BrandButton,{testId:`subscription-connect`,type:`button`,variant:`primary`,isDisabled:e||k,onClick:async()=>{try{let e=await _.mutateAsync();x(e),T(!0),m(e)}catch{i.displayErrorToast(h(n.I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR))}},children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_CONNECT)}),b?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(s.BrandButton,{testId:`subscription-poll`,type:`button`,variant:`secondary`,isDisabled:e||k,onClick:async()=>{b&&(D(),j(b.deviceCode))},children:h(n.I18nKey.SETTINGS$SUBSCRIPTION_FINISH_SIGN_IN)}),(0,d.jsx)(s.BrandButton,{testId:`subscription-cancel`,type:`button`,variant:`tertiary`,isDisabled:e||k,onClick:()=>{D(),x(null),T(!1)},children:h(n.I18nKey.BUTTON$CANCEL)})]}):null]})]})}exports.OpenAISubscriptionAuthCard=h;
|
|
2
|
+
//# sourceMappingURL=openai-subscription-auth-card.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-subscription-auth-card.cjs","names":[],"sources":["../../../../../src/components/features/settings/llm-settings/openai-subscription-auth-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ExternalLink } from \"lucide-react\";\nimport type { LLMSubscriptionDeviceChallenge } from \"#/api/llm-subscription-service\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { CopyToClipboardButton } from \"#/components/shared/buttons/copy-to-clipboard-button\";\nimport {\n useLogoutOpenAISubscription,\n usePollOpenAISubscriptionLogin,\n useStartOpenAISubscriptionLogin,\n} from \"#/hooks/mutation/use-llm-subscription-auth\";\nimport { useOpenAISubscriptionStatus } from \"#/hooks/query/use-llm-subscription-status\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\n\nconst DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;\nconst MIN_DEVICE_POLL_INTERVAL_SECONDS = 1;\n\ninterface OpenAISubscriptionAuthCardProps {\n isDisabled?: boolean;\n}\n\nfunction openVerificationUrl(challenge: LLMSubscriptionDeviceChallenge) {\n const url = challenge.verificationUriComplete ?? challenge.verificationUri;\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n}\n\nexport function OpenAISubscriptionAuthCard({\n isDisabled = false,\n}: OpenAISubscriptionAuthCardProps) {\n const { t } = useTranslation(\"openhands\");\n const status = useOpenAISubscriptionStatus();\n const startLogin = useStartOpenAISubscriptionLogin();\n const pollLogin = usePollOpenAISubscriptionLogin();\n const logout = useLogoutOpenAISubscription();\n const [challenge, setChallenge] =\n React.useState<LLMSubscriptionDeviceChallenge | null>(null);\n const [copied, setCopied] = React.useState(false);\n const [isPendingLogin, setIsPendingLogin] = React.useState(false);\n const pollTimeoutRef = React.useRef<number | null>(null);\n\n const clearPollTimeout = React.useCallback(() => {\n if (pollTimeoutRef.current !== null) {\n window.clearTimeout(pollTimeoutRef.current);\n pollTimeoutRef.current = null;\n }\n }, []);\n\n const handleCopyCode = () => {\n if (!challenge) return;\n navigator.clipboard.writeText(challenge.userCode);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const isBusy =\n startLogin.isPending || pollLogin.isPending || logout.isPending;\n const connected = Boolean(status.data?.connected);\n\n const pollDeviceLogin = React.useCallback(\n async (deviceCode: string) => {\n try {\n const nextStatus = await pollLogin.mutateAsync(deviceCode);\n if (nextStatus.connected) {\n setChallenge(null);\n setIsPendingLogin(false);\n displaySuccessToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECTED_TOAST));\n return true;\n }\n setIsPendingLogin(true);\n return false;\n } catch {\n displayErrorToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR));\n return true;\n }\n },\n [pollLogin, t],\n );\n\n React.useEffect(() => {\n if (!challenge || connected || isDisabled) {\n return undefined;\n }\n\n let cancelled = false;\n const intervalSeconds = Math.max(\n challenge.intervalSeconds ?? DEFAULT_DEVICE_POLL_INTERVAL_SECONDS,\n MIN_DEVICE_POLL_INTERVAL_SECONDS,\n );\n\n const schedulePoll = () => {\n clearPollTimeout();\n pollTimeoutRef.current = window.setTimeout(async () => {\n if (cancelled) {\n return;\n }\n\n const shouldStop = await pollDeviceLogin(challenge.deviceCode);\n if (!cancelled && !shouldStop) {\n schedulePoll();\n }\n }, intervalSeconds * 1000);\n };\n\n schedulePoll();\n\n return () => {\n cancelled = true;\n clearPollTimeout();\n };\n }, [challenge, clearPollTimeout, connected, isDisabled, pollDeviceLogin]);\n\n const handleStartLogin = async () => {\n try {\n const nextChallenge = await startLogin.mutateAsync();\n setChallenge(nextChallenge);\n setIsPendingLogin(true);\n openVerificationUrl(nextChallenge);\n } catch {\n displayErrorToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR));\n }\n };\n\n const handlePollLogin = async () => {\n if (!challenge) return;\n clearPollTimeout();\n void pollDeviceLogin(challenge.deviceCode);\n };\n\n const handleLogout = async () => {\n try {\n await logout.mutateAsync();\n clearPollTimeout();\n setChallenge(null);\n setIsPendingLogin(false);\n displaySuccessToast(t(I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECTED_TOAST));\n } catch {\n displayErrorToast(t(I18nKey.ERROR$GENERIC));\n }\n };\n\n const handleCancelLogin = () => {\n clearPollTimeout();\n setChallenge(null);\n setIsPendingLogin(false);\n };\n\n return (\n <section\n data-testid=\"openai-subscription-auth-card\"\n className=\"flex flex-col gap-4 rounded-xl border border-[var(--oh-border)] bg-[var(--oh-surface-raised)] p-4\"\n >\n <div className=\"flex flex-col gap-2\">\n <Typography.H3>\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CARD_TITLE)}\n </Typography.H3>\n <Typography.Paragraph className=\"text-tertiary-alt text-sm leading-5\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CARD_DESCRIPTION)}\n </Typography.Paragraph>\n </div>\n\n <div\n className=\"flex flex-col gap-1 text-sm\"\n data-testid=\"subscription-status\"\n >\n {status.isLoading ? (\n <span className=\"text-tertiary-light\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CHECKING)}\n </span>\n ) : status.isError ? (\n <span className=\"text-danger\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_UNAVAILABLE)}\n </span>\n ) : connected ? (\n <>\n <span className=\"text-success\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CONNECTED)}\n </span>\n {status.data?.accountEmail ? (\n <span className=\"text-tertiary-light\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_ACCOUNT, {\n account: status.data.accountEmail,\n })}\n </span>\n ) : null}\n </>\n ) : (\n <span className=\"text-warning\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_DISCONNECTED)}\n </span>\n )}\n </div>\n\n {challenge ? (\n <div\n data-testid=\"subscription-device-challenge\"\n className=\"flex flex-col gap-2 rounded-lg border border-[var(--oh-border-subtle)] p-3 text-sm\"\n >\n <span>{t(I18nKey.SETTINGS$SUBSCRIPTION_DEVICE_INSTRUCTIONS)}</span>\n <div className=\"flex items-center gap-2 rounded-lg bg-[var(--oh-surface-deep)] px-3 py-2 font-mono text-base text-[var(--oh-foreground)]\">\n <span className=\"flex-1 select-all\">{challenge.userCode}</span>\n <CopyToClipboardButton\n isHidden={false}\n isDisabled={false}\n onClick={handleCopyCode}\n mode={copied ? \"copied\" : \"copy\"}\n />\n </div>\n <a\n href={\n challenge.verificationUriComplete ?? challenge.verificationUri\n }\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm text-[var(--oh-accent)] underline\"\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_OPEN_LOGIN)}\n <ExternalLink size={14} aria-hidden />\n </a>\n {isPendingLogin ? (\n <span className=\"text-warning\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_PENDING_TOAST)}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"flex flex-wrap gap-2\">\n {connected ? (\n <BrandButton\n testId=\"subscription-disconnect\"\n type=\"button\"\n variant=\"tertiary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleLogout}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECT)}\n </BrandButton>\n ) : (\n <BrandButton\n testId=\"subscription-connect\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleStartLogin}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT)}\n </BrandButton>\n )}\n\n {challenge ? (\n <>\n <BrandButton\n testId=\"subscription-poll\"\n type=\"button\"\n variant=\"secondary\"\n isDisabled={isDisabled || isBusy}\n onClick={handlePollLogin}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_FINISH_SIGN_IN)}\n </BrandButton>\n <BrandButton\n testId=\"subscription-cancel\"\n type=\"button\"\n variant=\"tertiary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleCancelLogin}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n </>\n ) : null}\n </div>\n </section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { useTranslation as e } from "../../../../node_modules/react-i18next/dist/es/useTranslation.js";
|
|
2
|
+
import { I18nKey as t } from "../../../../i18n/declaration.js";
|
|
3
|
+
import { ExternalLink as n } from "../../../../node_modules/lucide-react/dist/esm/icons/external-link.js";
|
|
4
|
+
import { displayErrorToast as r, displaySuccessToast as i } from "../../../../utils/custom-toast-handlers.js";
|
|
5
|
+
import { CopyToClipboardButton as a } from "../../../shared/buttons/copy-to-clipboard-button.js";
|
|
6
|
+
import { Typography as o } from "../../../../ui/typography.js";
|
|
7
|
+
import { BrandButton as s } from "../brand-button.js";
|
|
8
|
+
import { useLogoutOpenAISubscription as c, usePollOpenAISubscriptionLogin as l, useStartOpenAISubscriptionLogin as u } from "../../../../hooks/mutation/use-llm-subscription-auth.js";
|
|
9
|
+
import { useOpenAISubscriptionStatus as d } from "../../../../hooks/query/use-llm-subscription-status.js";
|
|
10
|
+
import f from "react";
|
|
11
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
12
|
+
//#region src/components/features/settings/llm-settings/openai-subscription-auth-card.tsx
|
|
13
|
+
var g = 5, _ = 1;
|
|
14
|
+
function v(e) {
|
|
15
|
+
let t = e.verificationUriComplete ?? e.verificationUri;
|
|
16
|
+
window.open(t, "_blank", "noopener,noreferrer");
|
|
17
|
+
}
|
|
18
|
+
function y({ isDisabled: y = !1 }) {
|
|
19
|
+
let { t: b } = e("openhands"), x = d(), S = u(), C = l(), w = c(), [T, E] = f.useState(null), [D, O] = f.useState(!1), [k, A] = f.useState(!1), j = f.useRef(null), M = f.useCallback(() => {
|
|
20
|
+
j.current !== null && (window.clearTimeout(j.current), j.current = null);
|
|
21
|
+
}, []), N = () => {
|
|
22
|
+
T && (navigator.clipboard.writeText(T.userCode), O(!0), setTimeout(() => O(!1), 2e3));
|
|
23
|
+
}, P = S.isPending || C.isPending || w.isPending, F = !!x.data?.connected, I = f.useCallback(async (e) => {
|
|
24
|
+
try {
|
|
25
|
+
return (await C.mutateAsync(e)).connected ? (E(null), A(!1), i(b(t.SETTINGS$SUBSCRIPTION_CONNECTED_TOAST)), !0) : (A(!0), !1);
|
|
26
|
+
} catch {
|
|
27
|
+
return r(b(t.SETTINGS$SUBSCRIPTION_CONNECT_ERROR)), !0;
|
|
28
|
+
}
|
|
29
|
+
}, [C, b]);
|
|
30
|
+
return f.useEffect(() => {
|
|
31
|
+
if (!T || F || y) return;
|
|
32
|
+
let e = !1, t = Math.max(T.intervalSeconds ?? g, _), n = () => {
|
|
33
|
+
M(), j.current = window.setTimeout(async () => {
|
|
34
|
+
if (e) return;
|
|
35
|
+
let t = await I(T.deviceCode);
|
|
36
|
+
!e && !t && n();
|
|
37
|
+
}, t * 1e3);
|
|
38
|
+
};
|
|
39
|
+
return n(), () => {
|
|
40
|
+
e = !0, M();
|
|
41
|
+
};
|
|
42
|
+
}, [
|
|
43
|
+
T,
|
|
44
|
+
M,
|
|
45
|
+
F,
|
|
46
|
+
y,
|
|
47
|
+
I
|
|
48
|
+
]), /* @__PURE__ */ h("section", {
|
|
49
|
+
"data-testid": "openai-subscription-auth-card",
|
|
50
|
+
className: "flex flex-col gap-4 rounded-xl border border-[var(--oh-border)] bg-[var(--oh-surface-raised)] p-4",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ h("div", {
|
|
53
|
+
className: "flex flex-col gap-2",
|
|
54
|
+
children: [/* @__PURE__ */ m(o.H3, { children: b(t.SETTINGS$SUBSCRIPTION_CARD_TITLE) }), /* @__PURE__ */ m(o.Paragraph, {
|
|
55
|
+
className: "text-tertiary-alt text-sm leading-5",
|
|
56
|
+
children: b(t.SETTINGS$SUBSCRIPTION_CARD_DESCRIPTION)
|
|
57
|
+
})]
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ m("div", {
|
|
60
|
+
className: "flex flex-col gap-1 text-sm",
|
|
61
|
+
"data-testid": "subscription-status",
|
|
62
|
+
children: x.isLoading ? /* @__PURE__ */ m("span", {
|
|
63
|
+
className: "text-tertiary-light",
|
|
64
|
+
children: b(t.SETTINGS$SUBSCRIPTION_STATUS_CHECKING)
|
|
65
|
+
}) : x.isError ? /* @__PURE__ */ m("span", {
|
|
66
|
+
className: "text-danger",
|
|
67
|
+
children: b(t.SETTINGS$SUBSCRIPTION_STATUS_UNAVAILABLE)
|
|
68
|
+
}) : F ? /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("span", {
|
|
69
|
+
className: "text-success",
|
|
70
|
+
children: b(t.SETTINGS$SUBSCRIPTION_STATUS_CONNECTED)
|
|
71
|
+
}), x.data?.accountEmail ? /* @__PURE__ */ m("span", {
|
|
72
|
+
className: "text-tertiary-light",
|
|
73
|
+
children: b(t.SETTINGS$SUBSCRIPTION_ACCOUNT, { account: x.data.accountEmail })
|
|
74
|
+
}) : null] }) : /* @__PURE__ */ m("span", {
|
|
75
|
+
className: "text-warning",
|
|
76
|
+
children: b(t.SETTINGS$SUBSCRIPTION_STATUS_DISCONNECTED)
|
|
77
|
+
})
|
|
78
|
+
}),
|
|
79
|
+
T ? /* @__PURE__ */ h("div", {
|
|
80
|
+
"data-testid": "subscription-device-challenge",
|
|
81
|
+
className: "flex flex-col gap-2 rounded-lg border border-[var(--oh-border-subtle)] p-3 text-sm",
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ m("span", { children: b(t.SETTINGS$SUBSCRIPTION_DEVICE_INSTRUCTIONS) }),
|
|
84
|
+
/* @__PURE__ */ h("div", {
|
|
85
|
+
className: "flex items-center gap-2 rounded-lg bg-[var(--oh-surface-deep)] px-3 py-2 font-mono text-base text-[var(--oh-foreground)]",
|
|
86
|
+
children: [/* @__PURE__ */ m("span", {
|
|
87
|
+
className: "flex-1 select-all",
|
|
88
|
+
children: T.userCode
|
|
89
|
+
}), /* @__PURE__ */ m(a, {
|
|
90
|
+
isHidden: !1,
|
|
91
|
+
isDisabled: !1,
|
|
92
|
+
onClick: N,
|
|
93
|
+
mode: D ? "copied" : "copy"
|
|
94
|
+
})]
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ h("a", {
|
|
97
|
+
href: T.verificationUriComplete ?? T.verificationUri,
|
|
98
|
+
target: "_blank",
|
|
99
|
+
rel: "noreferrer",
|
|
100
|
+
className: "inline-flex items-center gap-1 text-sm text-[var(--oh-accent)] underline",
|
|
101
|
+
children: [b(t.SETTINGS$SUBSCRIPTION_OPEN_LOGIN), /* @__PURE__ */ m(n, {
|
|
102
|
+
size: 14,
|
|
103
|
+
"aria-hidden": !0
|
|
104
|
+
})]
|
|
105
|
+
}),
|
|
106
|
+
k ? /* @__PURE__ */ m("span", {
|
|
107
|
+
className: "text-warning",
|
|
108
|
+
children: b(t.SETTINGS$SUBSCRIPTION_PENDING_TOAST)
|
|
109
|
+
}) : null
|
|
110
|
+
]
|
|
111
|
+
}) : null,
|
|
112
|
+
/* @__PURE__ */ h("div", {
|
|
113
|
+
className: "flex flex-wrap gap-2",
|
|
114
|
+
children: [F ? /* @__PURE__ */ m(s, {
|
|
115
|
+
testId: "subscription-disconnect",
|
|
116
|
+
type: "button",
|
|
117
|
+
variant: "tertiary",
|
|
118
|
+
isDisabled: y || P,
|
|
119
|
+
onClick: async () => {
|
|
120
|
+
try {
|
|
121
|
+
await w.mutateAsync(), M(), E(null), A(!1), i(b(t.SETTINGS$SUBSCRIPTION_DISCONNECTED_TOAST));
|
|
122
|
+
} catch {
|
|
123
|
+
r(b(t.ERROR$GENERIC));
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
children: b(t.SETTINGS$SUBSCRIPTION_DISCONNECT)
|
|
127
|
+
}) : /* @__PURE__ */ m(s, {
|
|
128
|
+
testId: "subscription-connect",
|
|
129
|
+
type: "button",
|
|
130
|
+
variant: "primary",
|
|
131
|
+
isDisabled: y || P,
|
|
132
|
+
onClick: async () => {
|
|
133
|
+
try {
|
|
134
|
+
let e = await S.mutateAsync();
|
|
135
|
+
E(e), A(!0), v(e);
|
|
136
|
+
} catch {
|
|
137
|
+
r(b(t.SETTINGS$SUBSCRIPTION_CONNECT_ERROR));
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
children: b(t.SETTINGS$SUBSCRIPTION_CONNECT)
|
|
141
|
+
}), T ? /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m(s, {
|
|
142
|
+
testId: "subscription-poll",
|
|
143
|
+
type: "button",
|
|
144
|
+
variant: "secondary",
|
|
145
|
+
isDisabled: y || P,
|
|
146
|
+
onClick: async () => {
|
|
147
|
+
T && (M(), I(T.deviceCode));
|
|
148
|
+
},
|
|
149
|
+
children: b(t.SETTINGS$SUBSCRIPTION_FINISH_SIGN_IN)
|
|
150
|
+
}), /* @__PURE__ */ m(s, {
|
|
151
|
+
testId: "subscription-cancel",
|
|
152
|
+
type: "button",
|
|
153
|
+
variant: "tertiary",
|
|
154
|
+
isDisabled: y || P,
|
|
155
|
+
onClick: () => {
|
|
156
|
+
M(), E(null), A(!1);
|
|
157
|
+
},
|
|
158
|
+
children: b(t.BUTTON$CANCEL)
|
|
159
|
+
})] }) : null]
|
|
160
|
+
})
|
|
161
|
+
]
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
//#endregion
|
|
165
|
+
export { y as OpenAISubscriptionAuthCard };
|
|
166
|
+
|
|
167
|
+
//# sourceMappingURL=openai-subscription-auth-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-subscription-auth-card.js","names":[],"sources":["../../../../../src/components/features/settings/llm-settings/openai-subscription-auth-card.tsx"],"sourcesContent":["import React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ExternalLink } from \"lucide-react\";\nimport type { LLMSubscriptionDeviceChallenge } from \"#/api/llm-subscription-service\";\nimport { BrandButton } from \"#/components/features/settings/brand-button\";\nimport { CopyToClipboardButton } from \"#/components/shared/buttons/copy-to-clipboard-button\";\nimport {\n useLogoutOpenAISubscription,\n usePollOpenAISubscriptionLogin,\n useStartOpenAISubscriptionLogin,\n} from \"#/hooks/mutation/use-llm-subscription-auth\";\nimport { useOpenAISubscriptionStatus } from \"#/hooks/query/use-llm-subscription-status\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { Typography } from \"#/ui/typography\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\n\nconst DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;\nconst MIN_DEVICE_POLL_INTERVAL_SECONDS = 1;\n\ninterface OpenAISubscriptionAuthCardProps {\n isDisabled?: boolean;\n}\n\nfunction openVerificationUrl(challenge: LLMSubscriptionDeviceChallenge) {\n const url = challenge.verificationUriComplete ?? challenge.verificationUri;\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n}\n\nexport function OpenAISubscriptionAuthCard({\n isDisabled = false,\n}: OpenAISubscriptionAuthCardProps) {\n const { t } = useTranslation(\"openhands\");\n const status = useOpenAISubscriptionStatus();\n const startLogin = useStartOpenAISubscriptionLogin();\n const pollLogin = usePollOpenAISubscriptionLogin();\n const logout = useLogoutOpenAISubscription();\n const [challenge, setChallenge] =\n React.useState<LLMSubscriptionDeviceChallenge | null>(null);\n const [copied, setCopied] = React.useState(false);\n const [isPendingLogin, setIsPendingLogin] = React.useState(false);\n const pollTimeoutRef = React.useRef<number | null>(null);\n\n const clearPollTimeout = React.useCallback(() => {\n if (pollTimeoutRef.current !== null) {\n window.clearTimeout(pollTimeoutRef.current);\n pollTimeoutRef.current = null;\n }\n }, []);\n\n const handleCopyCode = () => {\n if (!challenge) return;\n navigator.clipboard.writeText(challenge.userCode);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const isBusy =\n startLogin.isPending || pollLogin.isPending || logout.isPending;\n const connected = Boolean(status.data?.connected);\n\n const pollDeviceLogin = React.useCallback(\n async (deviceCode: string) => {\n try {\n const nextStatus = await pollLogin.mutateAsync(deviceCode);\n if (nextStatus.connected) {\n setChallenge(null);\n setIsPendingLogin(false);\n displaySuccessToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECTED_TOAST));\n return true;\n }\n setIsPendingLogin(true);\n return false;\n } catch {\n displayErrorToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR));\n return true;\n }\n },\n [pollLogin, t],\n );\n\n React.useEffect(() => {\n if (!challenge || connected || isDisabled) {\n return undefined;\n }\n\n let cancelled = false;\n const intervalSeconds = Math.max(\n challenge.intervalSeconds ?? DEFAULT_DEVICE_POLL_INTERVAL_SECONDS,\n MIN_DEVICE_POLL_INTERVAL_SECONDS,\n );\n\n const schedulePoll = () => {\n clearPollTimeout();\n pollTimeoutRef.current = window.setTimeout(async () => {\n if (cancelled) {\n return;\n }\n\n const shouldStop = await pollDeviceLogin(challenge.deviceCode);\n if (!cancelled && !shouldStop) {\n schedulePoll();\n }\n }, intervalSeconds * 1000);\n };\n\n schedulePoll();\n\n return () => {\n cancelled = true;\n clearPollTimeout();\n };\n }, [challenge, clearPollTimeout, connected, isDisabled, pollDeviceLogin]);\n\n const handleStartLogin = async () => {\n try {\n const nextChallenge = await startLogin.mutateAsync();\n setChallenge(nextChallenge);\n setIsPendingLogin(true);\n openVerificationUrl(nextChallenge);\n } catch {\n displayErrorToast(t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT_ERROR));\n }\n };\n\n const handlePollLogin = async () => {\n if (!challenge) return;\n clearPollTimeout();\n void pollDeviceLogin(challenge.deviceCode);\n };\n\n const handleLogout = async () => {\n try {\n await logout.mutateAsync();\n clearPollTimeout();\n setChallenge(null);\n setIsPendingLogin(false);\n displaySuccessToast(t(I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECTED_TOAST));\n } catch {\n displayErrorToast(t(I18nKey.ERROR$GENERIC));\n }\n };\n\n const handleCancelLogin = () => {\n clearPollTimeout();\n setChallenge(null);\n setIsPendingLogin(false);\n };\n\n return (\n <section\n data-testid=\"openai-subscription-auth-card\"\n className=\"flex flex-col gap-4 rounded-xl border border-[var(--oh-border)] bg-[var(--oh-surface-raised)] p-4\"\n >\n <div className=\"flex flex-col gap-2\">\n <Typography.H3>\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CARD_TITLE)}\n </Typography.H3>\n <Typography.Paragraph className=\"text-tertiary-alt text-sm leading-5\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CARD_DESCRIPTION)}\n </Typography.Paragraph>\n </div>\n\n <div\n className=\"flex flex-col gap-1 text-sm\"\n data-testid=\"subscription-status\"\n >\n {status.isLoading ? (\n <span className=\"text-tertiary-light\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CHECKING)}\n </span>\n ) : status.isError ? (\n <span className=\"text-danger\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_UNAVAILABLE)}\n </span>\n ) : connected ? (\n <>\n <span className=\"text-success\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_CONNECTED)}\n </span>\n {status.data?.accountEmail ? (\n <span className=\"text-tertiary-light\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_ACCOUNT, {\n account: status.data.accountEmail,\n })}\n </span>\n ) : null}\n </>\n ) : (\n <span className=\"text-warning\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_STATUS_DISCONNECTED)}\n </span>\n )}\n </div>\n\n {challenge ? (\n <div\n data-testid=\"subscription-device-challenge\"\n className=\"flex flex-col gap-2 rounded-lg border border-[var(--oh-border-subtle)] p-3 text-sm\"\n >\n <span>{t(I18nKey.SETTINGS$SUBSCRIPTION_DEVICE_INSTRUCTIONS)}</span>\n <div className=\"flex items-center gap-2 rounded-lg bg-[var(--oh-surface-deep)] px-3 py-2 font-mono text-base text-[var(--oh-foreground)]\">\n <span className=\"flex-1 select-all\">{challenge.userCode}</span>\n <CopyToClipboardButton\n isHidden={false}\n isDisabled={false}\n onClick={handleCopyCode}\n mode={copied ? \"copied\" : \"copy\"}\n />\n </div>\n <a\n href={\n challenge.verificationUriComplete ?? challenge.verificationUri\n }\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm text-[var(--oh-accent)] underline\"\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_OPEN_LOGIN)}\n <ExternalLink size={14} aria-hidden />\n </a>\n {isPendingLogin ? (\n <span className=\"text-warning\">\n {t(I18nKey.SETTINGS$SUBSCRIPTION_PENDING_TOAST)}\n </span>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"flex flex-wrap gap-2\">\n {connected ? (\n <BrandButton\n testId=\"subscription-disconnect\"\n type=\"button\"\n variant=\"tertiary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleLogout}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_DISCONNECT)}\n </BrandButton>\n ) : (\n <BrandButton\n testId=\"subscription-connect\"\n type=\"button\"\n variant=\"primary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleStartLogin}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_CONNECT)}\n </BrandButton>\n )}\n\n {challenge ? (\n <>\n <BrandButton\n testId=\"subscription-poll\"\n type=\"button\"\n variant=\"secondary\"\n isDisabled={isDisabled || isBusy}\n onClick={handlePollLogin}\n >\n {t(I18nKey.SETTINGS$SUBSCRIPTION_FINISH_SIGN_IN)}\n </BrandButton>\n <BrandButton\n testId=\"subscription-cancel\"\n type=\"button\"\n variant=\"tertiary\"\n isDisabled={isDisabled || isBusy}\n onClick={handleCancelLogin}\n >\n {t(I18nKey.BUTTON$CANCEL)}\n </BrandButton>\n </>\n ) : null}\n </div>\n </section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../../node_modules/react-i18next/dist/es/useTranslation.cjs`),n=require(`../../../../i18n/declaration.cjs`),r=require(`../../../../utils/constants.cjs`),i=require(`../../../../utils/utils.cjs`),a=require(`../../../../utils/form-control-classes.cjs`),o=require(`../../../../node_modules/@heroui/listbox/dist/chunk-BJFJ4DRR.cjs`),s=require(`../../../../node_modules/@heroui/listbox/dist/chunk-ANTZPR32.cjs`),c=require(`../../../../node_modules/@heroui/autocomplete/dist/chunk-3QKDXXDY.cjs`),l=require(`../../../../ui/combobox-caret.cjs`),u=require(`../../../../utils/map-provider.cjs`),d=require(`../../../../utils/extract-model-and-provider.cjs`),f=require(`../../../../ui/help-link.cjs`),p=require(`../../../../hooks/query/use-search-providers.cjs`),m=require(`../../../../hooks/query/use-provider-models.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/constants.cjs`),i=require(`../../../../utils/utils.cjs`),a=require(`../../../../utils/form-control-classes.cjs`),o=require(`../../../../node_modules/@heroui/listbox/dist/chunk-BJFJ4DRR.cjs`),s=require(`../../../../node_modules/@heroui/listbox/dist/chunk-ANTZPR32.cjs`),c=require(`../../../../node_modules/@heroui/autocomplete/dist/chunk-3QKDXXDY.cjs`),l=require(`../../../../ui/combobox-caret.cjs`),u=require(`../../../../utils/map-provider.cjs`),d=require(`../../../../utils/extract-model-and-provider.cjs`),f=require(`../../../../ui/help-link.cjs`),p=require(`../../../../hooks/query/use-search-providers.cjs`),m=require(`../../../../hooks/query/use-provider-models.cjs`);let h=require(`react`);h=e.__toESM(h,1);let g=require(`react/jsx-runtime`);function _({isDisabled:e,currentModel:_,onChange:v,onDefaultValuesChanged:y,wrapperClassName:b,labelClassName:x}){let[,S]=h.default.useState(null),[C,w]=h.default.useState(null),[T,E]=h.default.useState(null),{data:D=[]}=p.useSearchProviders(),{data:O=[],isLoading:k,error:A}=m.useProviderModels(C),j=h.default.useMemo(()=>D.filter(e=>e.verified),[D]),M=h.default.useMemo(()=>D.filter(e=>!e.verified),[D]),N=h.default.useMemo(()=>O.filter(e=>e.verified),[O]),P=h.default.useMemo(()=>O.filter(e=>!e.verified),[O]);h.default.useEffect(()=>{if(_){let{provider:e,model:t}=d.extractModelAndProvider(_);S(_),w(e||null),E(t),y?.(e||null,t)}},[_]);let F=e=>{w(e),E(null),S(`${e}/`),v?.(e,null)},I=e=>{let t=`${C}/${e}`;C===`openai`&&(t=e),S(t),E(e),v?.(C,e)},L=()=>{w(null),S(null)},{t:R}=t.useTranslation(`openhands`);return(0,g.jsxs)(`div`,{className:i.cn(`flex flex-col md:flex-row w-full min-w-0 justify-between gap-4 md:gap-[46px]`,b),children:[(0,g.jsxs)(`fieldset`,{className:`flex flex-col gap-2.5 w-full`,children:[(0,g.jsx)(`label`,{className:i.cn(`text-sm`,x),children:R(n.I18nKey.LLM$PROVIDER)}),(0,g.jsxs)(c.autocomplete_default,{"data-testid":`llm-provider-input`,isRequired:!0,isVirtualized:!1,name:`llm-provider-input`,isDisabled:e,"aria-label":R(n.I18nKey.LLM$PROVIDER),isClearable:!1,onSelectionChange:e=>{e?.toString()&&F(e.toString())},onInputChange:e=>!e&&L(),defaultSelectedKey:C??void 0,selectedKey:C,classNames:{popoverContent:`bg-content1 rounded-xl border border-[var(--oh-border)]`,selectorButton:l.heroUiAutocompleteSelectorButtonClassName},selectorButtonProps:{disableRipple:!0},inputProps:{classNames:{inputWrapper:a.formControlSettingsFieldClassName}},children:[(0,g.jsx)(s.listbox_section_base_default,{title:R(n.I18nKey.MODEL_SELECTOR$VERIFIED),classNames:{heading:`text-[var(--oh-muted)]`},children:j.map(e=>(0,g.jsx)(o.listbox_item_base_default,{"data-testid":`provider-item-${e.name}`,children:u.mapProvider(e.name)},e.name))}),M.length>0?(0,g.jsx)(s.listbox_section_base_default,{title:R(n.I18nKey.MODEL_SELECTOR$OTHERS),classNames:{heading:`text-[var(--oh-muted)]`},children:M.map(e=>(0,g.jsx)(o.listbox_item_base_default,{children:u.mapProvider(e.name)},e.name))}):null]})]}),C===`openhands`&&(0,g.jsx)(f.HelpLink,{testId:`openhands-account-help`,text:R(n.I18nKey.SETTINGS$NEED_OPENHANDS_ACCOUNT),linkText:R(n.I18nKey.SETTINGS$CLICK_HERE),href:r.PRODUCT_URL.PRODUCTION,size:`settings`,linkColor:`white`}),(0,g.jsxs)(`fieldset`,{className:`flex flex-col gap-2.5 w-full`,children:[(0,g.jsx)(`label`,{className:i.cn(`text-sm`,x),children:R(n.I18nKey.LLM$MODEL)}),(0,g.jsxs)(c.autocomplete_default,{"data-testid":`llm-model-input`,isRequired:!0,isVirtualized:!1,isLoading:k,name:`llm-model-input`,"aria-label":R(n.I18nKey.LLM$MODEL),isClearable:!1,onSelectionChange:e=>{e?.toString()&&I(e.toString())},isDisabled:e||!C,selectedKey:T,defaultSelectedKey:T??void 0,classNames:{popoverContent:`bg-content1 rounded-xl border border-[var(--oh-border)]`,selectorButton:l.heroUiAutocompleteSelectorButtonClassName},selectorButtonProps:{disableRipple:!0},inputProps:{classNames:{inputWrapper:a.formControlSettingsFieldClassName}},children:[(0,g.jsx)(s.listbox_section_base_default,{title:R(n.I18nKey.MODEL_SELECTOR$VERIFIED),classNames:{heading:`text-[var(--oh-muted)]`},children:N.map(e=>(0,g.jsx)(o.listbox_item_base_default,{children:e.name},e.name))}),P.length>0?(0,g.jsx)(s.listbox_section_base_default,{title:R(n.I18nKey.MODEL_SELECTOR$OTHERS),classNames:{heading:`text-[var(--oh-muted)]`},children:P.map(e=>(0,g.jsx)(o.listbox_item_base_default,{"data-testid":`model-item-${e.name}`,children:e.name},e.name))}):null]}),A&&(0,g.jsx)(`p`,{"data-testid":`models-error`,className:`text-danger text-xs`,children:R(n.I18nKey.CONFIGURATION$ERROR_FETCH_MODELS)})]})]})}exports.ModelSelector=_;
|
|
2
2
|
//# sourceMappingURL=model-selector.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-selector.cjs","names":[],"sources":["../../../../../src/components/shared/modals/settings/model-selector.tsx"],"sourcesContent":["import {\n Autocomplete,\n AutocompleteItem,\n AutocompleteSection,\n} from \"@heroui/react\";\nimport React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { mapProvider } from \"#/utils/map-provider\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlSettingsFieldClassName } from \"#/utils/form-control-classes\";\nimport { heroUiAutocompleteSelectorButtonClassName } from \"#/ui/combobox-caret\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { PRODUCT_URL } from \"#/utils/constants\";\nimport { useSearchProviders } from \"#/hooks/query/use-search-providers\";\nimport { useProviderModels } from \"#/hooks/query/use-provider-models\";\nimport { useOpenhandsVerifiedModels } from \"#/hooks/query/use-openhands-verified-models\";\nimport { normalizeDisplayModel } from \"#/utils/normalize-display-model\";\n\ninterface ModelSelectorProps {\n isDisabled?: boolean;\n currentModel?: string;\n currentBaseUrl?: string;\n onChange?: (provider: string | null, model: string | null) => void;\n onDefaultValuesChanged?: (\n provider: string | null,\n model: string | null,\n ) => void;\n wrapperClassName?: string;\n labelClassName?: string;\n}\n\nexport function ModelSelector({\n isDisabled,\n currentModel,\n currentBaseUrl,\n onChange,\n onDefaultValuesChanged,\n wrapperClassName,\n labelClassName,\n}: ModelSelectorProps) {\n const [, setLitellmId] = React.useState<string | null>(null);\n const [selectedProvider, setSelectedProvider] = React.useState<string | null>(\n null,\n );\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null);\n\n const { data: providers = [] } = useSearchProviders();\n const { data: openhandsVerifiedModels } = useOpenhandsVerifiedModels();\n const {\n data: providerModels = [],\n isLoading: isLoadingModels,\n error: modelsError,\n } = useProviderModels(selectedProvider);\n\n const verifiedProviders = React.useMemo(\n () => providers.filter((p) => p.verified),\n [providers],\n );\n const unverifiedProviders = React.useMemo(\n () => providers.filter((p) => !p.verified),\n [providers],\n );\n\n const verifiedModels = React.useMemo(\n () => providerModels.filter((m) => m.verified),\n [providerModels],\n );\n const unverifiedModels = React.useMemo(\n () => providerModels.filter((m) => !m.verified),\n [providerModels],\n );\n\n React.useEffect(() => {\n // Wait for the openhands verified list before initializing — otherwise a\n // persisted `litellm_proxy/<m>` model would first land as `litellm_proxy`\n // and only later flip to `openhands`, triggering a redundant /api/llm/models\n // fetch for the throwaway provider value.\n if (currentModel && openhandsVerifiedModels !== undefined) {\n const displayModel = normalizeDisplayModel(\n currentModel,\n currentBaseUrl,\n openhandsVerifiedModels,\n );\n const { provider, model } = extractModelAndProvider(displayModel);\n\n setLitellmId(displayModel);\n setSelectedProvider(provider || null);\n setSelectedModel(model);\n onDefaultValuesChanged?.(provider || null, model);\n }\n }, [currentModel, currentBaseUrl, openhandsVerifiedModels]);\n\n const handleChangeProvider = (provider: string) => {\n setSelectedProvider(provider);\n setSelectedModel(null);\n setLitellmId(`${provider}/`);\n onChange?.(provider, null);\n };\n\n const handleChangeModel = (model: string) => {\n let fullModel = `${selectedProvider}/${model}`;\n if (selectedProvider === \"openai\") {\n fullModel = model;\n }\n setLitellmId(fullModel);\n setSelectedModel(model);\n onChange?.(selectedProvider, model);\n };\n\n const clear = () => {\n setSelectedProvider(null);\n setLitellmId(null);\n };\n\n const { t } = useTranslation(\"openhands\");\n\n return (\n <div\n className={cn(\n \"flex flex-col md:flex-row w-full min-w-0 justify-between gap-4 md:gap-[46px]\",\n wrapperClassName,\n )}\n >\n <fieldset className=\"flex flex-col gap-2.5 w-full\">\n <label className={cn(\"text-sm\", labelClassName)}>\n {t(I18nKey.LLM$PROVIDER)}\n </label>\n <Autocomplete\n data-testid=\"llm-provider-input\"\n isRequired\n isVirtualized={false}\n name=\"llm-provider-input\"\n isDisabled={isDisabled}\n aria-label={t(I18nKey.LLM$PROVIDER)}\n isClearable={false}\n onSelectionChange={(e) => {\n if (e?.toString()) handleChangeProvider(e.toString());\n }}\n onInputChange={(value) => !value && clear()}\n defaultSelectedKey={selectedProvider ?? undefined}\n selectedKey={selectedProvider}\n classNames={{\n popoverContent:\n \"bg-content1 rounded-xl border border-[var(--oh-border)]\",\n selectorButton: heroUiAutocompleteSelectorButtonClassName,\n }}\n selectorButtonProps={{ disableRipple: true }}\n inputProps={{\n classNames: {\n inputWrapper: formControlSettingsFieldClassName,\n },\n }}\n >\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$VERIFIED)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {verifiedProviders.map((provider) => (\n <AutocompleteItem\n data-testid={`provider-item-${provider.name}`}\n key={provider.name}\n >\n {mapProvider(provider.name)}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n {unverifiedProviders.length > 0 ? (\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$OTHERS)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {unverifiedProviders.map((provider) => (\n <AutocompleteItem key={provider.name}>\n {mapProvider(provider.name)}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n ) : null}\n </Autocomplete>\n </fieldset>\n\n {selectedProvider === \"openhands\" && (\n <HelpLink\n testId=\"openhands-account-help\"\n text={t(I18nKey.SETTINGS$NEED_OPENHANDS_ACCOUNT)}\n linkText={t(I18nKey.SETTINGS$CLICK_HERE)}\n href={PRODUCT_URL.PRODUCTION}\n size=\"settings\"\n linkColor=\"white\"\n />\n )}\n\n <fieldset className=\"flex flex-col gap-2.5 w-full\">\n <label className={cn(\"text-sm\", labelClassName)}>\n {t(I18nKey.LLM$MODEL)}\n </label>\n <Autocomplete\n data-testid=\"llm-model-input\"\n isRequired\n isVirtualized={false}\n isLoading={isLoadingModels}\n name=\"llm-model-input\"\n aria-label={t(I18nKey.LLM$MODEL)}\n isClearable={false}\n onSelectionChange={(e) => {\n if (e?.toString()) handleChangeModel(e.toString());\n }}\n isDisabled={isDisabled || !selectedProvider}\n selectedKey={selectedModel}\n defaultSelectedKey={selectedModel ?? undefined}\n classNames={{\n popoverContent:\n \"bg-content1 rounded-xl border border-[var(--oh-border)]\",\n selectorButton: heroUiAutocompleteSelectorButtonClassName,\n }}\n selectorButtonProps={{ disableRipple: true }}\n inputProps={{\n classNames: {\n inputWrapper: formControlSettingsFieldClassName,\n },\n }}\n >\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$VERIFIED)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {verifiedModels.map((model) => (\n <AutocompleteItem key={model.name}>{model.name}</AutocompleteItem>\n ))}\n </AutocompleteSection>\n {unverifiedModels.length > 0 ? (\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$OTHERS)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {unverifiedModels.map((model) => (\n <AutocompleteItem\n data-testid={`model-item-${model.name}`}\n key={model.name}\n >\n {model.name}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n ) : null}\n </Autocomplete>\n {modelsError && (\n <p data-testid=\"models-error\" className=\"text-danger text-xs\">\n {t(I18nKey.CONFIGURATION$ERROR_FETCH_MODELS)}\n </p>\n )}\n </fieldset>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model-selector.cjs","names":[],"sources":["../../../../../src/components/shared/modals/settings/model-selector.tsx"],"sourcesContent":["import {\n Autocomplete,\n AutocompleteItem,\n AutocompleteSection,\n} from \"@heroui/react\";\nimport React from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { mapProvider } from \"#/utils/map-provider\";\nimport { extractModelAndProvider } from \"#/utils/extract-model-and-provider\";\nimport { cn } from \"#/utils/utils\";\nimport { formControlSettingsFieldClassName } from \"#/utils/form-control-classes\";\nimport { heroUiAutocompleteSelectorButtonClassName } from \"#/ui/combobox-caret\";\nimport { HelpLink } from \"#/ui/help-link\";\nimport { PRODUCT_URL } from \"#/utils/constants\";\nimport { useSearchProviders } from \"#/hooks/query/use-search-providers\";\nimport { useProviderModels } from \"#/hooks/query/use-provider-models\";\n\ninterface ModelSelectorProps {\n isDisabled?: boolean;\n currentModel?: string;\n onChange?: (provider: string | null, model: string | null) => void;\n onDefaultValuesChanged?: (\n provider: string | null,\n model: string | null,\n ) => void;\n wrapperClassName?: string;\n labelClassName?: string;\n}\n\nexport function ModelSelector({\n isDisabled,\n currentModel,\n onChange,\n onDefaultValuesChanged,\n wrapperClassName,\n labelClassName,\n}: ModelSelectorProps) {\n const [, setLitellmId] = React.useState<string | null>(null);\n const [selectedProvider, setSelectedProvider] = React.useState<string | null>(\n null,\n );\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null);\n\n const { data: providers = [] } = useSearchProviders();\n const {\n data: providerModels = [],\n isLoading: isLoadingModels,\n error: modelsError,\n } = useProviderModels(selectedProvider);\n\n const verifiedProviders = React.useMemo(\n () => providers.filter((p) => p.verified),\n [providers],\n );\n const unverifiedProviders = React.useMemo(\n () => providers.filter((p) => !p.verified),\n [providers],\n );\n\n const verifiedModels = React.useMemo(\n () => providerModels.filter((m) => m.verified),\n [providerModels],\n );\n const unverifiedModels = React.useMemo(\n () => providerModels.filter((m) => !m.verified),\n [providerModels],\n );\n\n React.useEffect(() => {\n if (currentModel) {\n const { provider, model } = extractModelAndProvider(currentModel);\n\n setLitellmId(currentModel);\n setSelectedProvider(provider || null);\n setSelectedModel(model);\n onDefaultValuesChanged?.(provider || null, model);\n }\n }, [currentModel]);\n\n const handleChangeProvider = (provider: string) => {\n setSelectedProvider(provider);\n setSelectedModel(null);\n setLitellmId(`${provider}/`);\n onChange?.(provider, null);\n };\n\n const handleChangeModel = (model: string) => {\n let fullModel = `${selectedProvider}/${model}`;\n if (selectedProvider === \"openai\") {\n fullModel = model;\n }\n setLitellmId(fullModel);\n setSelectedModel(model);\n onChange?.(selectedProvider, model);\n };\n\n const clear = () => {\n setSelectedProvider(null);\n setLitellmId(null);\n };\n\n const { t } = useTranslation(\"openhands\");\n\n return (\n <div\n className={cn(\n \"flex flex-col md:flex-row w-full min-w-0 justify-between gap-4 md:gap-[46px]\",\n wrapperClassName,\n )}\n >\n <fieldset className=\"flex flex-col gap-2.5 w-full\">\n <label className={cn(\"text-sm\", labelClassName)}>\n {t(I18nKey.LLM$PROVIDER)}\n </label>\n <Autocomplete\n data-testid=\"llm-provider-input\"\n isRequired\n isVirtualized={false}\n name=\"llm-provider-input\"\n isDisabled={isDisabled}\n aria-label={t(I18nKey.LLM$PROVIDER)}\n isClearable={false}\n onSelectionChange={(e) => {\n if (e?.toString()) handleChangeProvider(e.toString());\n }}\n onInputChange={(value) => !value && clear()}\n defaultSelectedKey={selectedProvider ?? undefined}\n selectedKey={selectedProvider}\n classNames={{\n popoverContent:\n \"bg-content1 rounded-xl border border-[var(--oh-border)]\",\n selectorButton: heroUiAutocompleteSelectorButtonClassName,\n }}\n selectorButtonProps={{ disableRipple: true }}\n inputProps={{\n classNames: {\n inputWrapper: formControlSettingsFieldClassName,\n },\n }}\n >\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$VERIFIED)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {verifiedProviders.map((provider) => (\n <AutocompleteItem\n data-testid={`provider-item-${provider.name}`}\n key={provider.name}\n >\n {mapProvider(provider.name)}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n {unverifiedProviders.length > 0 ? (\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$OTHERS)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {unverifiedProviders.map((provider) => (\n <AutocompleteItem key={provider.name}>\n {mapProvider(provider.name)}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n ) : null}\n </Autocomplete>\n </fieldset>\n\n {selectedProvider === \"openhands\" && (\n <HelpLink\n testId=\"openhands-account-help\"\n text={t(I18nKey.SETTINGS$NEED_OPENHANDS_ACCOUNT)}\n linkText={t(I18nKey.SETTINGS$CLICK_HERE)}\n href={PRODUCT_URL.PRODUCTION}\n size=\"settings\"\n linkColor=\"white\"\n />\n )}\n\n <fieldset className=\"flex flex-col gap-2.5 w-full\">\n <label className={cn(\"text-sm\", labelClassName)}>\n {t(I18nKey.LLM$MODEL)}\n </label>\n <Autocomplete\n data-testid=\"llm-model-input\"\n isRequired\n isVirtualized={false}\n isLoading={isLoadingModels}\n name=\"llm-model-input\"\n aria-label={t(I18nKey.LLM$MODEL)}\n isClearable={false}\n onSelectionChange={(e) => {\n if (e?.toString()) handleChangeModel(e.toString());\n }}\n isDisabled={isDisabled || !selectedProvider}\n selectedKey={selectedModel}\n defaultSelectedKey={selectedModel ?? undefined}\n classNames={{\n popoverContent:\n \"bg-content1 rounded-xl border border-[var(--oh-border)]\",\n selectorButton: heroUiAutocompleteSelectorButtonClassName,\n }}\n selectorButtonProps={{ disableRipple: true }}\n inputProps={{\n classNames: {\n inputWrapper: formControlSettingsFieldClassName,\n },\n }}\n >\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$VERIFIED)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {verifiedModels.map((model) => (\n <AutocompleteItem key={model.name}>{model.name}</AutocompleteItem>\n ))}\n </AutocompleteSection>\n {unverifiedModels.length > 0 ? (\n <AutocompleteSection\n title={t(I18nKey.MODEL_SELECTOR$OTHERS)}\n classNames={{ heading: \"text-[var(--oh-muted)]\" }}\n >\n {unverifiedModels.map((model) => (\n <AutocompleteItem\n data-testid={`model-item-${model.name}`}\n key={model.name}\n >\n {model.name}\n </AutocompleteItem>\n ))}\n </AutocompleteSection>\n ) : null}\n </Autocomplete>\n {modelsError && (\n <p data-testid=\"models-error\" className=\"text-danger text-xs\">\n {t(I18nKey.CONFIGURATION$ERROR_FETCH_MODELS)}\n </p>\n )}\n </fieldset>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
interface ModelSelectorProps {
|
|
2
2
|
isDisabled?: boolean;
|
|
3
3
|
currentModel?: string;
|
|
4
|
-
currentBaseUrl?: string;
|
|
5
4
|
onChange?: (provider: string | null, model: string | null) => void;
|
|
6
5
|
onDefaultValuesChanged?: (provider: string | null, model: string | null) => void;
|
|
7
6
|
wrapperClassName?: string;
|
|
8
7
|
labelClassName?: string;
|
|
9
8
|
}
|
|
10
|
-
export declare function ModelSelector({ isDisabled, currentModel,
|
|
9
|
+
export declare function ModelSelector({ isDisabled, currentModel, onChange, onDefaultValuesChanged, wrapperClassName, labelClassName, }: ModelSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
11
10
|
export {};
|