@openhands/agent-canvas 1.5.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.windows.md +2 -2
- package/build/assets/{Trans-DqF_OEZB.js → Trans-52HCczKK.js} +1 -1
- package/build/assets/{acp-providers-DerAmTyY.js → acp-providers-xACMK9ZP.js} +1 -1
- package/build/assets/{active-backend-context-B8rMv0X9.js → active-backend-context-Cd1qcZsb.js} +1 -1
- package/build/assets/{add-backend-modal-CxC7BNEc.js → add-backend-modal-5chsfln3.js} +1 -1
- package/build/assets/{agent-profiles-settings-BJb8YXR1.js → agent-profiles-settings-BWK4H3kR.js} +1 -1
- package/build/assets/agent-server-compatibility-DMY0CihN.js +1 -0
- package/build/assets/agent-server-conversation-service.api-CI5-xmIX.js +41 -0
- package/build/assets/agent-settings-CMd8-O4f.js +2 -0
- package/build/assets/agent-settings-CdrhQJXX.js +1 -0
- package/build/assets/{alert-banner-Dh51WURQ.js → alert-banner-CLfWuIAX.js} +1 -1
- package/build/assets/api-key-entry-screen-Cc3aC7DZ.js +1 -0
- package/build/assets/app-settings-B-DQcBoB.js +1 -0
- package/build/assets/{automation-detail-CZsu2CoM.js → automation-detail-BgxBIpyK.js} +2 -2
- package/build/assets/automation-export-Dbur8OHa.js +2 -0
- package/build/assets/automations-list-BWfjizlp.js +1 -0
- package/build/assets/{back-nav-button-DVknCcSP.js → back-nav-button-CaKvsD1E.js} +1 -1
- package/build/assets/backend-form-modal-YcfpuBZo.js +1 -0
- package/build/assets/{backend-synced-settings-badge-BSfN0AZA.js → backend-synced-settings-badge-BellMmgC.js} +1 -1
- package/build/assets/{base-modal-CIF_785P.js → base-modal-Cw7enAHz.js} +1 -1
- package/build/assets/{brand-button-B1izLAdR.js → brand-button-BulEFHr3.js} +1 -1
- package/build/assets/{browser-DKaeq_sT.js → browser-DfVgUREb.js} +2 -2
- package/build/assets/browser-store-CBqI3tNR.js +1 -0
- package/build/assets/{browser-tab-qb_ftCxW.js → browser-tab-CmIKQB7S.js} +1 -1
- package/build/assets/chat-send-button-BchSSwuD.js +1 -0
- package/build/assets/circle-check-BXbQ5nEH.js +1 -0
- package/build/assets/{circle-plus-check-toggle-DoFIjVE0.js → circle-plus-check-toggle-BhpPjkh9.js} +1 -1
- package/build/assets/client-source-DAUgyJsi.js +1 -0
- package/build/assets/cloud-funnel-analytics-B5OeWh4y.js +1 -0
- package/build/assets/{color-themes-CHizm1xF.js → color-themes-QKMSVfDU.js} +1 -1
- package/build/assets/{combobox-caret-CxZpqoSR.js → combobox-caret-kNZtp53R.js} +1 -1
- package/build/assets/{command-menu-oTvKDU3Y.js → command-menu-tUsn23zy.js} +1 -1
- package/build/assets/{command-store-D8J5LMW1.js → command-store-B0hrIWMN.js} +1 -1
- package/build/assets/{condenser-settings-BGlWn93P.js → condenser-settings-BBizzfIH.js} +1 -1
- package/build/assets/{confirmation-modal-DGBWM2Ls.js → confirmation-modal-108xng7X.js} +1 -1
- package/build/assets/{context-menu-list-item-6psNyl7X.js → context-menu-list-item-BbKfFuN1.js} +1 -1
- package/build/assets/conversation-CTzSrLMq.js +1 -0
- package/build/assets/conversation-CgcXNb-Z.js +90 -0
- package/build/assets/conversation-panel-bscjGQda.js +1 -0
- package/build/assets/{conversation-service.api-_f9GlIEi.js → conversation-service.api-DbBvscJA.js} +1 -1
- package/build/assets/conversation-state-store-C5GagZHT.js +1 -0
- package/build/assets/{conversation-store-LptbOvKa.js → conversation-store-CyVqoa0d.js} +1 -1
- package/build/assets/{conversation-tab-empty-state-CNUmIms2.js → conversation-tab-empty-state-2KYlk5Bh.js} +1 -1
- package/build/assets/{copy-to-clipboard-button-CFzH_NOX.js → copy-to-clipboard-button-C54YRPMg.js} +1 -1
- package/build/assets/declaration-_yumYLEx.js +1 -0
- package/build/assets/{device-verify-WBSjJBLH.js → device-verify-D6FW_KZq.js} +1 -1
- package/build/assets/{dropdown-classes-D3wMJlXT.js → dropdown-classes-9uONlOg1.js} +1 -1
- package/build/assets/{ellipsis-button-CbNnHlIq.js → ellipsis-button-CoaUrKmQ.js} +1 -1
- package/build/assets/{entry.client-DNlPGxsu.js → entry.client-BJSVzw7V.js} +2 -2
- package/build/assets/{enum-filter-dropdown-JLYv1t8L.js → enum-filter-dropdown-qQzyjk_q.js} +1 -1
- package/build/assets/{environment-switch-overlay-B1PFO8P8.js → environment-switch-overlay-XRWCClLu.js} +1 -1
- package/build/assets/extensions-hub-DUp9sWQY.js +1 -0
- package/build/assets/extensions-navigation-DmkftjAx.js +1 -0
- package/build/assets/file-tUAzhmJ3.js +1 -0
- package/build/assets/files-tab-GV5hwiIM.js +1 -0
- package/build/assets/files-tab-store-DehyITNC.js +1 -0
- package/build/assets/{form-control-classes-CbdN5aO3.js → form-control-classes-BPUnoYyg.js} +1 -1
- package/build/assets/git-provider-icon-DDkru3b_.js +1 -0
- package/build/assets/highlighted-source-view-CYkPZUxr.js +1 -0
- package/build/assets/home-C53WekZ2.js +1 -0
- package/build/assets/home-EAwq8ah2.js +1 -0
- package/build/assets/index-home-kBdZGKtu.js +1 -0
- package/build/assets/install-server-modal-DYk4VP3-.js +1 -0
- package/build/assets/{launch-CAGavYl-.js → launch-CIecOy_y.js} +1 -1
- package/build/assets/lesson-plan-BSEUwflx.js +4 -0
- package/build/assets/llm-not-configured-banner-C8uv1PHT.js +27 -0
- package/build/assets/llm-settings-0Bb97NCk.js +1 -0
- package/build/assets/llm-settings-D4toJ90k.js +1 -0
- package/build/assets/{llm-subscription-service-Casyzgn1.js → llm-subscription-service-BPRw3u3H.js} +1 -1
- package/build/assets/{loading-spinner-BcdnT0mN.js → loading-spinner-BCInDEXB.js} +1 -1
- package/build/assets/manage-backends-modal-Bon32JYr.js +1 -0
- package/build/assets/manifest-ec000ae3.js +1 -0
- package/build/assets/markdown-renderer-BlaJOAI2.js +2 -0
- package/build/assets/mcp-CFIpOkn2.js +9 -0
- package/build/assets/messages-eRPeR4pW.js +40 -0
- package/build/assets/{modal-body-Cc2zp0xb.js → modal-body-Bg9UCeoV.js} +1 -1
- package/build/assets/{modal-classes-3qT9Ap7Q.js → modal-classes-H1KbJkeC.js} +1 -1
- package/build/assets/{modal-close-button-BcIBUdSq.js → modal-close-button-BMLYvo0C.js} +1 -1
- package/build/assets/{model-selector-DJrMrFAr.js → model-selector-BqX2RvEr.js} +1 -1
- package/build/assets/{navigation-link-D8hfwvxI.js → navigation-link-DoJzTCEz.js} +1 -1
- package/build/assets/onboarding-3KO4qE6R.js +1 -0
- package/build/assets/onboarding-modal-D4vqkJeT.js +1 -0
- package/build/assets/{organization-service.api-vrRNwOma.js → organization-service.api-CvfQugOt.js} +1 -1
- package/build/assets/{path-utils-PNfCKQDV.js → path-utils-DRgexxnX.js} +1 -1
- package/build/assets/{plan-components-BdZXPyZU.js → plan-components-qkMiGs_-.js} +1 -1
- package/build/assets/{planner-tab-ByOw1he8.js → planner-tab-ZrjiirRr.js} +1 -1
- package/build/assets/{plugins-management-service-B75jyC56.js → plugins-management-service-9qT-r_37.js} +1 -1
- package/build/assets/plus-CzE1b-wl.js +1 -0
- package/build/assets/{profiles-service.api-BQTklD5D.js → profiles-service.api-CRVlrQpT.js} +1 -1
- package/build/assets/{providers-DfTB2gPd.js → providers-C2DFGBrf.js} +1 -1
- package/build/assets/{proxy-B3tCGf0X.js → proxy-DnnDqkwn.js} +1 -1
- package/build/assets/puzzle-IHQnD54C.js +1 -0
- package/build/assets/recommended-automations-launcher-B97vgHuN.js +58 -0
- package/build/assets/refresh-cw-DxbAs3SK.js +1 -0
- package/build/assets/root-BbONavTg.css +1 -0
- package/build/assets/root-D01rpqZU.js +2 -0
- package/build/assets/root-layout-BiHbCIkS.js +2 -0
- package/build/assets/{runtime-waiting-state-CnyVhX4T.js → runtime-waiting-state-CbUV9txX.js} +1 -1
- package/build/assets/{schema-field-CUwk4wrQ.js → schema-field-B9-9Ta9u.js} +1 -1
- package/build/assets/sdk-section-page-DG1s25Pr.js +1 -0
- package/build/assets/{sdk-settings-schema-CLR01YIK.js → sdk-settings-schema-B42JFr5Y.js} +1 -1
- package/build/assets/{secrets-service-CvyPWJhg.js → secrets-service-DvyS6-mV.js} +1 -1
- package/build/assets/secrets-settings-CeSq6cQw.js +1 -0
- package/build/assets/{segmented-toggle-kzwZkLaj.js → segmented-toggle-DRVJBNy0.js} +1 -1
- package/build/assets/settings-Dzo0dJKM.js +1 -0
- package/build/assets/{settings-mQUckT0g.js → settings-HcwfqMjJ.js} +1 -1
- package/build/assets/{settings-dropdown-input-Dhx9ErGd.js → settings-dropdown-input-B6RL_mt0.js} +1 -1
- package/build/assets/settings-index-uAKHyijw.js +1 -0
- package/build/assets/{settings-input-BsgQWS5R.js → settings-input-ZoaAPNQh.js} +1 -1
- package/build/assets/{settings-list-classes-DSJJX99U.js → settings-list-classes-Dr8LgITi.js} +1 -1
- package/build/assets/settings-modal-BVX2G_IT.js +1 -0
- package/build/assets/{settings-service.api-DXk5TdeJ.js → settings-service.api-BY7ncxIz.js} +1 -1
- package/build/assets/{settings-switch-Bes8dIlV.js → settings-switch-DUlGnP0B.js} +1 -1
- package/build/assets/{settings-utils-DzCVfiR3.js → settings-utils-kWEEvcdv.js} +1 -1
- package/build/assets/shared-conversation-CV4Rtdz2.js +1 -0
- package/build/assets/{sidebar-layout-Bm7pa3Vk.js → sidebar-layout-BhGooCga.js} +1 -1
- package/build/assets/sidebar-mobile-menu-toggle-BntOJphE.js +1 -0
- package/build/assets/{sidebar-nav-link-CHqyFXwV.js → sidebar-nav-link-DkA1XWV8.js} +1 -1
- package/build/assets/{sidebar-store-uiUXBU1N.js → sidebar-store-CF3b12-m.js} +1 -1
- package/build/assets/{skill-card-pill-row-BPYKQ3IN.js → skill-card-pill-row-_gWe1Tws.js} +1 -1
- package/build/assets/skill-icon-badge-C-zbaXbD.js +1 -0
- package/build/assets/skills-plugins-BwoXKtrR.js +1 -0
- package/build/assets/skills-settings-Crq-fZSt.js +2 -0
- package/build/assets/{styled-tooltip-B14i_Uac.js → styled-tooltip-CdnCJ67u.js} +1 -1
- package/build/assets/syntax-highlighter-CZK2ab-O.js +1 -0
- package/build/assets/{task-list-tab-DyfgG4MC.js → task-list-tab-CONOO9iI.js} +1 -1
- package/build/assets/telemetry-CC32dJYW.js +2 -0
- package/build/assets/{terminal-DRXt2Lr4.js → terminal-CTkDpIU-.js} +1 -1
- package/build/assets/{toggle-switch-DX_k418f.js → toggle-switch-yVIzmJLM.js} +1 -1
- package/build/assets/{typography-CzfoD9DY.js → typography-BBVEW0un.js} +1 -1
- package/build/assets/{use-acp-credential-form-Bm8qXdlc.js → use-acp-credential-form-CIsp8hJe.js} +1 -1
- package/build/assets/use-activate-agent-profile-BfcTTJJG.js +1 -0
- package/build/assets/{use-active-agent-profile-hI-x-UBa.js → use-active-agent-profile-CCeFtmk9.js} +1 -1
- package/build/assets/{use-active-conversation-2qeez40F.js → use-active-conversation-Badxj8w4.js} +1 -1
- package/build/assets/{use-agent-profiles-0pr5bLS7.js → use-agent-profiles-BSWVN6hH.js} +1 -1
- package/build/assets/{use-agent-state-C6peDXUm.js → use-agent-state-BzRrhoPd.js} +1 -1
- package/build/assets/use-backends-health-BsZikyFW.js +1 -0
- package/build/assets/{use-can-manage-org-profiles-Ck_bsNbH.js → use-can-manage-org-profiles-Do6mYf6P.js} +1 -1
- package/build/assets/{use-cloud-current-user-id-DUCSxNjY.js → use-cloud-current-user-id-Cx3B_0-w.js} +1 -1
- package/build/assets/use-config-D9zUVw5b.js +1 -0
- package/build/assets/{use-create-conversation-r1JHfKO5.js → use-create-conversation-vvl0kvu7.js} +1 -1
- package/build/assets/{use-create-secret-Cf2N11d2.js → use-create-secret-CB7Dvd4s.js} +1 -1
- package/build/assets/use-event-store-BlpSUF7N.js +4 -0
- package/build/assets/{use-handle-plan-click-CsAW3FlH.js → use-handle-plan-click-DDZkew9p.js} +1 -1
- package/build/assets/use-is-creating-conversation-fxSzN778.js +1 -0
- package/build/assets/{use-launch-skill-in-chat-DJWEfVc5.js → use-launch-skill-in-chat-D6_n1fs3.js} +1 -1
- package/build/assets/use-llm-profiles-CNQm7HYS.js +1 -0
- package/build/assets/use-plugins-marketplace-CloojomS.js +1 -0
- package/build/assets/use-runtime-is-ready-Bx_4cfar.js +1 -0
- package/build/assets/{use-save-agent-profile-RqUGqTv6.js → use-save-agent-profile-Bj7N-1jS.js} +1 -1
- package/build/assets/{use-save-settings-Chvzeu2s.js → use-save-settings-BMsb2wk_.js} +1 -1
- package/build/assets/use-settings-B9XEmh7i.js +1 -0
- package/build/assets/use-settings-nav-items-BGfBS0yL.js +16 -0
- package/build/assets/{use-skills-xrVoKYrF.js → use-skills-CSRbvPle.js} +1 -1
- package/build/assets/{use-task-list-CfisapBW.js → use-task-list-CTIVLrQA.js} +1 -1
- package/build/assets/use-tracking-DjdCssvp.js +1 -0
- package/build/assets/{use-user-conversation-CnE4zhOA.js → use-user-conversation-BCpFn-Ei.js} +1 -1
- package/build/assets/{useTranslation-Cbf5AGg_.js → useTranslation-CHm_6BRr.js} +1 -1
- package/build/assets/{utils-DB9LsAzA.js → utils-CrRpzbM2.js} +1 -1
- package/build/assets/vendor-markdown-DzO4uO_0.js +37 -0
- package/build/assets/{vendor~browser-wXQ-WZEC.js → vendor~browser-Byfuq5J-.js} +1 -1
- package/build/assets/{vendor~browser-tab-CsMb-pta.js → vendor~browser-tab-BLk3qxhw.js} +1 -1
- package/build/assets/{vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-eGLBu60s.js → vendor~entry.client~root~root-layout~index-home~home~conversation-panel~conversation~launch~dhilvkxv-DTJ_cjR5.js} +2 -2
- package/build/assets/{vendor~files-tab-B-5fBohe.js → vendor~files-tab-XmnauIZI.js} +1 -1
- package/build/assets/{vendor~launch-_Km3J77E.js → vendor~launch-DeC8QhXQ.js} +1 -1
- package/build/assets/{vendor~root-layout~conversation-panel~conversation~shared-conversation-BrguKXCn.js → vendor~root-layout~conversation-panel~conversation~shared-conversation-DDmLzCzm.js} +1 -1
- package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-YrfJYTQw.js +1 -0
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-mC0v44WR.js → vendor~root-layout~index-home~home~conversation-panel~conversation~launch~skills-settings~a~j2jlu22h-DoaS51iW.js} +123 -3
- package/build/assets/{vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-BOKQkbc6.js → vendor~root-layout~index-home~home~conversation-panel~conversation~shared-conversation~aler~gfu7qdtz-DEYwoy8u.js} +1 -1
- package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-DZHLw5Sr.js +1 -0
- package/build/assets/{vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-cFNmfAE6.js → vendor~root~root-layout~index-home~home~conversation-panel~conversation~launch~extensions-h~ftka0fnu-UJ4BNDJP.js} +1 -1
- package/build/assets/{verification-settings-CfkrXoSa.js → verification-settings-uwOfc16F.js} +1 -1
- package/build/index.html +4 -4
- package/build/locales/ar/openhands.json +38 -4
- package/build/locales/ca/openhands.json +38 -4
- package/build/locales/de/openhands.json +38 -4
- package/build/locales/en/openhands.json +38 -4
- package/build/locales/es/openhands.json +38 -4
- package/build/locales/fr/openhands.json +38 -4
- package/build/locales/it/openhands.json +38 -4
- package/build/locales/ja/openhands.json +38 -4
- package/build/locales/ko-KR/openhands.json +38 -4
- package/build/locales/no/openhands.json +38 -4
- package/build/locales/pt/openhands.json +38 -4
- package/build/locales/tr/openhands.json +38 -4
- package/build/locales/uk/openhands.json +38 -4
- package/build/locales/zh-CN/openhands.json +38 -4
- package/build/locales/zh-TW/openhands.json +38 -4
- package/config/defaults.json +7 -3
- package/dist/api/agent-canvas-updates.cjs +2 -0
- package/dist/api/agent-canvas-updates.cjs.map +1 -0
- package/dist/api/agent-canvas-updates.d.ts +7 -0
- package/dist/api/agent-canvas-updates.js +19 -0
- package/dist/api/agent-canvas-updates.js.map +1 -0
- package/dist/api/agent-server-adapter.cjs +1 -1
- package/dist/api/agent-server-adapter.cjs.map +1 -1
- package/dist/api/agent-server-adapter.d.ts +3 -0
- package/dist/api/agent-server-adapter.js +1 -0
- 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 +5 -0
- package/dist/api/agent-server-compatibility.js +24 -15
- package/dist/api/agent-server-compatibility.js.map +1 -1
- package/dist/api/agent-server-config.cjs +1 -1
- package/dist/api/agent-server-config.cjs.map +1 -1
- package/dist/api/agent-server-config.js +11 -8
- package/dist/api/agent-server-config.js.map +1 -1
- package/dist/api/automation-service/automation-service.api.cjs +2 -0
- package/dist/api/automation-service/automation-service.api.cjs.map +1 -0
- package/dist/api/automation-service/automation-service.api.d.ts +3 -0
- package/dist/api/automation-service/automation-service.api.js +283 -0
- package/dist/api/automation-service/automation-service.api.js.map +1 -0
- package/dist/api/client-source.cjs +1 -1
- package/dist/api/client-source.cjs.map +1 -1
- package/dist/api/client-source.d.ts +3 -0
- package/dist/api/client-source.js +4 -4
- package/dist/api/client-source.js.map +1 -1
- package/dist/api/cloud/settings-service.api.cjs.map +1 -1
- package/dist/api/cloud/settings-service.api.js.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.cjs.map +1 -1
- package/dist/api/conversation-service/agent-server-conversation-service.api.js +111 -109
- package/dist/api/conversation-service/agent-server-conversation-service.api.js.map +1 -1
- package/dist/api/mcp-health/mcp-health-store.cjs +2 -0
- package/dist/api/mcp-health/mcp-health-store.cjs.map +1 -0
- package/dist/api/mcp-health/mcp-health-store.d.ts +22 -0
- package/dist/api/mcp-health/mcp-health-store.js +45 -0
- package/dist/api/mcp-health/mcp-health-store.js.map +1 -0
- package/dist/api/mcp-health/probe-mcp-server-health.cjs +2 -0
- package/dist/api/mcp-health/probe-mcp-server-health.cjs.map +1 -0
- package/dist/api/mcp-health/probe-mcp-server-health.d.ts +31 -0
- package/dist/api/mcp-health/probe-mcp-server-health.js +57 -0
- package/dist/api/mcp-health/probe-mcp-server-health.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.js +66 -46
- package/dist/api/mcp-service/mcp-service.api.js.map +1 -1
- package/dist/api/plugins-management-service.cjs.map +1 -1
- package/dist/api/plugins-management-service.d.ts +6 -1
- package/dist/api/plugins-management-service.js.map +1 -1
- package/dist/api/plugins-service.d.ts +30 -2
- package/dist/api/secrets-service.cjs +1 -1
- package/dist/api/secrets-service.cjs.map +1 -1
- package/dist/api/secrets-service.d.ts +6 -6
- package/dist/api/secrets-service.js +8 -3
- package/dist/api/secrets-service.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.d.ts +1 -1
- package/dist/api/settings-service/settings-service.api.js +1 -0
- package/dist/api/settings-service/settings-service.api.js.map +1 -1
- package/dist/components/conversation-events/chat/event-message-components/critic-result-display.cjs +1 -1
- package/dist/components/conversation-events/chat/event-message-components/critic-result-display.js +5 -5
- package/dist/components/features/backends/backend-form-modal.cjs +1 -1
- package/dist/components/features/backends/backend-form-modal.cjs.map +1 -1
- package/dist/components/features/backends/backend-form-modal.d.ts +4 -1
- package/dist/components/features/backends/backend-form-modal.js +15 -16
- 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 -102
- 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 +85 -73
- package/dist/components/features/backends/manage-backends-modal.js.map +1 -1
- package/dist/components/features/chat/chat-interface.cjs +2 -2
- package/dist/components/features/chat/chat-interface.cjs.map +1 -1
- package/dist/components/features/chat/chat-interface.js +131 -129
- package/dist/components/features/chat/chat-interface.js.map +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.cjs +1 -1
- package/dist/components/features/chat/confirmation-mode-enabled.js +4 -4
- package/dist/components/features/chat/skill-install-restart-banner.cjs +2 -0
- package/dist/components/features/chat/skill-install-restart-banner.cjs.map +1 -0
- package/dist/components/features/chat/skill-install-restart-banner.d.ts +11 -0
- package/dist/components/features/chat/skill-install-restart-banner.js +63 -0
- package/dist/components/features/chat/skill-install-restart-banner.js.map +1 -0
- package/dist/components/features/conversation/right-panel-toggle.cjs +1 -1
- package/dist/components/features/conversation/right-panel-toggle.cjs.map +1 -1
- package/dist/components/features/conversation/right-panel-toggle.js +1 -1
- package/dist/components/features/conversation/right-panel-toggle.js.map +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.cjs +1 -1
- package/dist/components/features/conversation-panel/conversation-panel.js +10 -10
- 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 +78 -77
- 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.d.ts +4 -1
- package/dist/components/features/mcp-page/install-server-modal.js +135 -136
- package/dist/components/features/mcp-page/install-server-modal.js.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs +1 -1
- package/dist/components/features/mcp-page/installed-server-card.cjs.map +1 -1
- package/dist/components/features/mcp-page/installed-server-card.js +40 -34
- package/dist/components/features/mcp-page/installed-server-card.js.map +1 -1
- package/dist/components/features/mcp-page/mcp-server-health.cjs +2 -0
- package/dist/components/features/mcp-page/mcp-server-health.cjs.map +1 -0
- package/dist/components/features/mcp-page/mcp-server-health.d.ts +18 -0
- package/dist/components/features/mcp-page/mcp-server-health.js +117 -0
- package/dist/components/features/mcp-page/mcp-server-health.js.map +1 -0
- package/dist/components/features/plugins/build-plugins-view-model.d.ts +10 -1
- package/dist/components/features/plugins/plugin-files-section.d.ts +13 -0
- package/dist/components/features/settings/agent-canvas-update-card.cjs +2 -0
- package/dist/components/features/settings/agent-canvas-update-card.cjs.map +1 -0
- package/dist/components/features/settings/agent-canvas-update-card.d.ts +7 -0
- package/dist/components/features/settings/agent-canvas-update-card.js +170 -0
- package/dist/components/features/settings/agent-canvas-update-card.js.map +1 -0
- package/dist/components/features/settings/integrations-settings-link.cjs +2 -0
- package/dist/components/features/settings/integrations-settings-link.cjs.map +1 -0
- package/dist/components/features/settings/integrations-settings-link.d.ts +5 -0
- package/dist/components/features/settings/integrations-settings-link.js +41 -0
- package/dist/components/features/settings/integrations-settings-link.js.map +1 -0
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.cjs +1 -1
- package/dist/components/features/settings/llm-profiles/llm-settings-local-view.js +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.cjs +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.cjs.map +1 -1
- package/dist/components/features/settings/settings-desktop-sidebar.js +31 -21
- package/dist/components/features/settings/settings-desktop-sidebar.js.map +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.cjs +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.cjs.map +1 -1
- package/dist/components/features/settings/settings-mobile-drawer.js +40 -30
- package/dist/components/features/settings/settings-mobile-drawer.js.map +1 -1
- package/dist/components/features/skills/extensions-navigation.cjs +1 -1
- package/dist/components/features/skills/extensions-navigation.cjs.map +1 -1
- package/dist/components/features/skills/extensions-navigation.js +54 -33
- package/dist/components/features/skills/extensions-navigation.js.map +1 -1
- package/dist/config/defaults.cjs +1 -1
- package/dist/config/defaults.cjs.map +1 -1
- package/dist/config/defaults.js +7 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants/acp-providers.cjs.map +1 -1
- package/dist/constants/acp-providers.js.map +1 -1
- package/dist/contexts/conversation-websocket-context.cjs +2 -2
- package/dist/contexts/conversation-websocket-context.cjs.map +1 -1
- package/dist/contexts/conversation-websocket-context.js +169 -166
- package/dist/contexts/conversation-websocket-context.js.map +1 -1
- package/dist/hooks/mutation/use-delete-llm-profile.cjs +1 -1
- package/dist/hooks/mutation/use-delete-llm-profile.js +1 -0
- package/dist/hooks/mutation/use-delete-mcp-server.cjs +1 -1
- package/dist/hooks/mutation/use-delete-mcp-server.cjs.map +1 -1
- package/dist/hooks/mutation/use-delete-mcp-server.js +8 -6
- package/dist/hooks/mutation/use-delete-mcp-server.js.map +1 -1
- package/dist/hooks/mutation/use-rename-llm-profile.cjs +1 -1
- package/dist/hooks/mutation/use-rename-llm-profile.js +1 -0
- package/dist/hooks/mutation/use-save-settings.cjs +1 -1
- package/dist/hooks/mutation/use-save-settings.js +3 -3
- package/dist/hooks/mutation/use-update-mcp-server.cjs +1 -1
- package/dist/hooks/mutation/use-update-mcp-server.cjs.map +1 -1
- package/dist/hooks/mutation/use-update-mcp-server.js +11 -9
- package/dist/hooks/mutation/use-update-mcp-server.js.map +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 +4 -0
- package/dist/hooks/query/query-keys.js +2 -2
- package/dist/hooks/query/query-keys.js.map +1 -1
- package/dist/hooks/query/use-automation-sdk-version.cjs +2 -0
- package/dist/hooks/query/use-automation-sdk-version.cjs.map +1 -0
- package/dist/hooks/query/use-automation-sdk-version.d.ts +3 -0
- package/dist/hooks/query/use-automation-sdk-version.js +63 -0
- package/dist/hooks/query/use-automation-sdk-version.js.map +1 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.cjs +2 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.cjs.map +1 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.d.ts +10 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.js +19 -0
- package/dist/hooks/query/use-latest-agent-canvas-version.js.map +1 -0
- package/dist/hooks/query/use-plugin-file-content.d.ts +7 -0
- package/dist/hooks/query/use-resolved-workspaces.cjs +1 -1
- package/dist/hooks/query/use-resolved-workspaces.cjs.map +1 -1
- package/dist/hooks/query/use-resolved-workspaces.js +25 -26
- package/dist/hooks/query/use-resolved-workspaces.js.map +1 -1
- package/dist/hooks/query/use-search-subdirs.cjs +1 -1
- package/dist/hooks/query/use-search-subdirs.cjs.map +1 -1
- package/dist/hooks/query/use-search-subdirs.d.ts +5 -0
- package/dist/hooks/query/use-search-subdirs.js +16 -4
- package/dist/hooks/query/use-search-subdirs.js.map +1 -1
- package/dist/hooks/query/use-task-polling.cjs +1 -1
- package/dist/hooks/query/use-task-polling.cjs.map +1 -1
- package/dist/hooks/query/use-task-polling.d.ts +19 -3
- package/dist/hooks/query/use-task-polling.js +36 -35
- package/dist/hooks/query/use-task-polling.js.map +1 -1
- package/dist/hooks/use-device-flow.cjs +1 -1
- package/dist/hooks/use-device-flow.js +6 -6
- package/dist/hooks/use-llm-configured.cjs +1 -1
- package/dist/hooks/use-llm-configured.js +3 -3
- package/dist/hooks/use-mcp-server-health.cjs +2 -0
- package/dist/hooks/use-mcp-server-health.cjs.map +1 -0
- package/dist/hooks/use-mcp-server-health.d.ts +11 -0
- package/dist/hooks/use-mcp-server-health.js +18 -0
- package/dist/hooks/use-mcp-server-health.js.map +1 -0
- package/dist/hooks/use-skill-installs.cjs +2 -0
- package/dist/hooks/use-skill-installs.cjs.map +1 -0
- package/dist/hooks/use-skill-installs.d.ts +10 -0
- package/dist/hooks/use-skill-installs.js +21 -0
- package/dist/hooks/use-skill-installs.js.map +1 -0
- package/dist/hooks/use-tracking.cjs +1 -1
- package/dist/hooks/use-tracking.cjs.map +1 -1
- package/dist/hooks/use-tracking.d.ts +3 -3
- package/dist/hooks/use-tracking.js +67 -52
- package/dist/hooks/use-tracking.js.map +1 -1
- package/dist/i18n/declaration.cjs +1 -1
- package/dist/i18n/declaration.cjs.map +1 -1
- package/dist/i18n/declaration.d.ts +35 -1
- package/dist/i18n/declaration.js +1 -1
- package/dist/i18n/declaration.js.map +1 -1
- package/dist/i18n/translation.cjs +3 -3
- package/dist/i18n/translation.cjs.map +1 -1
- package/dist/i18n/translation.js +623 -45
- package/dist/i18n/translation.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -2
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +0 -1
- package/dist/locales/ar/openhands.json +38 -4
- package/dist/locales/ca/openhands.json +38 -4
- package/dist/locales/de/openhands.json +38 -4
- package/dist/locales/en/openhands.json +38 -4
- package/dist/locales/es/openhands.json +38 -4
- package/dist/locales/fr/openhands.json +38 -4
- package/dist/locales/it/openhands.json +38 -4
- package/dist/locales/ja/openhands.json +38 -4
- package/dist/locales/ko-KR/openhands.json +38 -4
- package/dist/locales/no/openhands.json +38 -4
- package/dist/locales/pt/openhands.json +38 -4
- package/dist/locales/tr/openhands.json +38 -4
- package/dist/locales/uk/openhands.json +38 -4
- package/dist/locales/zh-CN/openhands.json +38 -4
- package/dist/locales/zh-TW/openhands.json +38 -4
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js +44 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian-rovo.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/atlassian.js.map +1 -1
- 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 +21 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/github.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/linear.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-outlook.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/microsoft-teams.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/notion.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/onedrive.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js +13 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/sharepoint.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js +16 -2
- package/dist/node_modules/@openhands/extensions/integrations/catalog/slack.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs +2 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.cjs.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js +46 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog/vanta.js.map +1 -0
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js +74 -70
- package/dist/node_modules/@openhands/extensions/integrations/catalog-index.js.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.cjs +123 -3
- package/dist/node_modules/@openhands/extensions/skills/index.cjs.map +1 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js +7 -1
- package/dist/node_modules/@openhands/extensions/skills/index.js.map +1 -1
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js +9 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/chevron-up.js.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs +2 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.cjs.map +1 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.js +21 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/info.js.map +1 -0
- package/dist/package.cjs +1 -1
- package/dist/package.cjs.map +1 -1
- package/dist/package.js +10 -3
- package/dist/package.js.map +1 -1
- package/dist/routes/app-settings.cjs +1 -1
- package/dist/routes/app-settings.cjs.map +1 -1
- package/dist/routes/app-settings.js +113 -67
- package/dist/routes/app-settings.js.map +1 -1
- package/dist/routes/conversation.cjs +1 -1
- package/dist/routes/conversation.cjs.map +1 -1
- package/dist/routes/conversation.js +1 -1
- package/dist/routes/conversation.js.map +1 -1
- package/dist/routes/mcp.cjs +1 -1
- package/dist/routes/mcp.cjs.map +1 -1
- package/dist/routes/mcp.js +1 -0
- package/dist/routes/mcp.js.map +1 -1
- package/dist/services/cloud-funnel-analytics.cjs +1 -1
- package/dist/services/cloud-funnel-analytics.cjs.map +1 -1
- package/dist/services/cloud-funnel-analytics.d.ts +2 -2
- package/dist/services/cloud-funnel-analytics.js +18 -16
- package/dist/services/cloud-funnel-analytics.js.map +1 -1
- package/dist/services/settings.cjs +1 -1
- package/dist/services/settings.cjs.map +1 -1
- package/dist/services/settings.js +1 -0
- package/dist/services/settings.js.map +1 -1
- package/dist/services/telemetry-context.cjs +2 -0
- package/dist/services/telemetry-context.cjs.map +1 -0
- package/dist/services/telemetry-context.d.ts +17 -0
- package/dist/services/telemetry-context.js +27 -0
- package/dist/services/telemetry-context.js.map +1 -0
- package/dist/services/telemetry.cjs +1 -1
- package/dist/services/telemetry.cjs.map +1 -1
- package/dist/services/telemetry.d.ts +7 -5
- package/dist/services/telemetry.js +132 -123
- package/dist/services/telemetry.js.map +1 -1
- package/dist/stores/skill-install-banner-store.cjs +2 -0
- package/dist/stores/skill-install-banner-store.cjs.map +1 -0
- package/dist/stores/skill-install-banner-store.d.ts +32 -0
- package/dist/stores/skill-install-banner-store.js +14 -0
- package/dist/stores/skill-install-banner-store.js.map +1 -0
- 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 +35 -35
- package/dist/stores/use-event-store.js.map +1 -1
- package/dist/types/mcp-health.cjs +2 -0
- package/dist/types/mcp-health.cjs.map +1 -0
- package/dist/types/mcp-health.d.ts +21 -0
- package/dist/types/mcp-health.js +6 -0
- package/dist/types/mcp-health.js.map +1 -0
- package/dist/types/settings.d.ts +1 -0
- 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 +5 -0
- package/dist/utils/handle-event-for-ui.js +71 -57
- package/dist/utils/handle-event-for-ui.js.map +1 -1
- package/dist/utils/mcp-credential-validation.cjs +1 -1
- package/dist/utils/mcp-credential-validation.cjs.map +1 -1
- package/dist/utils/mcp-credential-validation.js +32 -16
- package/dist/utils/mcp-credential-validation.js.map +1 -1
- package/dist/utils/mcp-server-health-key.cjs +2 -0
- package/dist/utils/mcp-server-health-key.cjs.map +1 -0
- package/dist/utils/mcp-server-health-key.d.ts +16 -0
- package/dist/utils/mcp-server-health-key.js +23 -0
- package/dist/utils/mcp-server-health-key.js.map +1 -0
- package/dist/utils/mcp-test-error-message.cjs +2 -0
- package/dist/utils/mcp-test-error-message.cjs.map +1 -0
- package/dist/utils/mcp-test-error-message.d.ts +8 -0
- package/dist/utils/mcp-test-error-message.js +14 -0
- package/dist/utils/mcp-test-error-message.js.map +1 -0
- package/dist/utils/redact-mcp-secrets.cjs +2 -0
- package/dist/utils/redact-mcp-secrets.cjs.map +1 -0
- package/dist/utils/redact-mcp-secrets.d.ts +13 -0
- package/dist/utils/redact-mcp-secrets.js +57 -0
- package/dist/utils/redact-mcp-secrets.js.map +1 -0
- package/dist/utils/settings-utils.cjs.map +1 -1
- package/dist/utils/settings-utils.js.map +1 -1
- package/dist/utils/skill-install-events.cjs +3 -0
- package/dist/utils/skill-install-events.cjs.map +1 -0
- package/dist/utils/skill-install-events.d.ts +16 -0
- package/dist/utils/skill-install-events.js +26 -0
- package/dist/utils/skill-install-events.js.map +1 -0
- package/dist/utils/title-llm-profile.cjs +2 -0
- package/dist/utils/title-llm-profile.cjs.map +1 -0
- package/dist/utils/title-llm-profile.d.ts +2 -0
- package/dist/utils/title-llm-profile.js +11 -0
- package/dist/utils/title-llm-profile.js.map +1 -0
- package/package.json +10 -3
- package/scripts/check-sdk-version-sync.mjs +6 -6
- package/scripts/check-translation-completeness.cjs +2 -0
- package/scripts/dev-process-utils.mjs +62 -1
- package/scripts/dev-safe.mjs +2 -2
- package/scripts/dev-static.mjs +5 -3
- package/scripts/dev-with-automation.mjs +98 -14
- package/scripts/download-node.mjs +382 -0
- package/scripts/download-uv.mjs +204 -0
- package/scripts/logger.mjs +64 -35
- package/build/assets/agent-server-compatibility-BWN-EIQn.js +0 -1
- package/build/assets/agent-server-conversation-service.api-DSPIkMwJ.js +0 -41
- package/build/assets/agent-settings-CgCnqaAA.js +0 -2
- package/build/assets/agent-settings-DDkSavD7.js +0 -1
- package/build/assets/api-key-entry-screen-iZc7n8AI.js +0 -1
- package/build/assets/app-settings-B5zyipxJ.js +0 -1
- package/build/assets/automation-export-BwRX6H32.js +0 -2
- package/build/assets/automations-list-lHAVzMoA.js +0 -1
- package/build/assets/backend-form-modal-RGcu909r.js +0 -1
- package/build/assets/browser-store-BI6uklCG.js +0 -1
- package/build/assets/chat-send-button-BZHG2hAW.js +0 -1
- package/build/assets/client-source-BZK8vRs2.js +0 -1
- package/build/assets/cloud-funnel-analytics-Zcv57hfT.js +0 -1
- package/build/assets/conversation-BoCYx8n2.js +0 -89
- package/build/assets/conversation-DgHqMjnY.js +0 -1
- package/build/assets/conversation-panel-78Rxh_-I.js +0 -1
- package/build/assets/conversation-state-store-B2Bp32XI.js +0 -1
- package/build/assets/declaration-BGsHjPEW.js +0 -1
- package/build/assets/extensions-hub-CCbLA7IM.js +0 -1
- package/build/assets/extensions-navigation-CPNjMNvR.js +0 -1
- package/build/assets/files-tab-store-DJsPxYdg.js +0 -1
- package/build/assets/files-tab-y4K7EXBO.js +0 -1
- package/build/assets/git-provider-icon-ITvsH4Ko.js +0 -1
- package/build/assets/home-BwbeOWwU.js +0 -1
- package/build/assets/home-DKPGQ5P3.js +0 -1
- package/build/assets/index-home-Bko2Itv5.js +0 -1
- package/build/assets/install-server-modal-Qk1gwyI8.js +0 -1
- package/build/assets/lesson-plan-DMCPdtrf.js +0 -4
- package/build/assets/llm-not-configured-banner-C1ktyb3C.js +0 -27
- package/build/assets/llm-settings-BBsZFi9l.js +0 -1
- package/build/assets/llm-settings-DFkJQr_w.js +0 -1
- package/build/assets/manage-backends-modal-CKQ46rvw.js +0 -1
- package/build/assets/manifest-03478bbf.js +0 -1
- package/build/assets/markdown-renderer-B4V2OMFP.js +0 -2
- package/build/assets/mcp-BapoJsDc.js +0 -9
- package/build/assets/messages-CUBFMY5o.js +0 -40
- package/build/assets/objectWithoutPropertiesLoose-BgYIAs2y.js +0 -1
- package/build/assets/onboarding-6NMkdNxV.js +0 -1
- package/build/assets/onboarding-modal-Q4AnpIdg.js +0 -1
- package/build/assets/recommended-automations-launcher-Bj7PuHY1.js +0 -58
- package/build/assets/refresh-cw-B9B7-vsy.js +0 -1
- package/build/assets/root-CDnuTToz.js +0 -2
- package/build/assets/root-CYWeTrWE.css +0 -1
- package/build/assets/root-layout-DfYVlcRG.js +0 -2
- package/build/assets/sdk-section-page-DLLNrYjI.js +0 -1
- package/build/assets/secrets-settings-CHy72A5C.js +0 -1
- package/build/assets/settings-B9S8UVQr.js +0 -1
- package/build/assets/settings-index-BKDl2CQ-.js +0 -1
- package/build/assets/settings-modal-DeK11CyT.js +0 -1
- package/build/assets/shared-conversation-9atDzTR4.js +0 -1
- package/build/assets/sidebar-mobile-menu-toggle-giMMZctn.js +0 -1
- package/build/assets/skills-plugins-Tropusio.js +0 -1
- package/build/assets/skills-settings-BvzBBCWk.js +0 -2
- package/build/assets/telemetry-C5JMEfqB.js +0 -2
- package/build/assets/use-activate-agent-profile-DlykqEfN.js +0 -1
- package/build/assets/use-backends-health-CLHPitJM.js +0 -1
- package/build/assets/use-config-B5r8erYt.js +0 -1
- package/build/assets/use-event-store-Bbaz51GR.js +0 -4
- package/build/assets/use-llm-profiles-Dr5__SlZ.js +0 -1
- package/build/assets/use-plugins-marketplace-BplU65ae.js +0 -1
- package/build/assets/use-runtime-is-ready-vCFOcLFa.js +0 -1
- package/build/assets/use-settings-CyxSlyTQ.js +0 -1
- package/build/assets/use-settings-nav-items-zEkSO_Bf.js +0 -16
- package/build/assets/use-tracking-D2Qg5Lpd.js +0 -1
- package/build/assets/useMutationState-OnAsCLA_.js +0 -1
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BD7v71DM.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-BT05Osu4.js +0 -28
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-COhHANvV.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DgzWSMRc.js +0 -2
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-DqZatR3B.js +0 -7
- package/build/assets/vendor~index-home~home~conversation-panel~conversation~shared-conversation~planner-tab~files-tab-FghQ3Z1a.js +0 -1
- package/build/assets/vendor~root-layout~index-home~home~conversation-panel~conversation-BTvhGHHG.js +0 -1
- package/build/assets/vendor~root-layout~index-home~home~mcp~automations-list~onboarding-modal-C4-GDgiF.js +0 -1
- package/dist/components/features/analytics/telemetry-consent-banner.cjs +0 -2
- package/dist/components/features/analytics/telemetry-consent-banner.cjs.map +0 -1
- package/dist/components/features/analytics/telemetry-consent-banner.d.ts +0 -29
- package/dist/components/features/analytics/telemetry-consent-banner.js +0 -59
- package/dist/components/features/analytics/telemetry-consent-banner.js.map +0 -1
- /package/build/assets/{__vite-browser-external-BQUj0sYu.js → __vite-browser-external-CKHVBTNC.js} +0 -0
- /package/build/assets/{agent-server-ui-style-scope-qhnhZHBV.js → agent-server-ui-style-scope-BvSa9on7.js} +0 -0
- /package/build/assets/{automation-LZB0MjdV.js → automation-BGiPmxFR.js} +0 -0
- /package/build/assets/{canvas-ui-COgjltGz.js → canvas-ui-CC4EJo-H.js} +0 -0
- /package/build/assets/{checkmark-h7udgXMM.js → checkmark-ygQB1AtV.js} +0 -0
- /package/build/assets/{close-DLFb5kfv.js → close-BjSA0HWT.js} +0 -0
- /package/build/assets/{code-tag-DYlAhEQY.js → code-tag-D9aPPbOe.js} +0 -0
- /package/build/assets/{common-CxbUL3nR.js → common-CCuqQy_S.js} +0 -0
- /package/build/assets/{conversation-local-storage-F6zVMM--.js → conversation-local-storage-BDjWPg0Z.js} +0 -0
- /package/build/assets/{copy-BLmGeJcd.js → copy-Dce7sOvS.js} +0 -0
- /package/build/assets/{copy-D1YGjP-C.js → copy-iPJAncAj.js} +0 -0
- /package/build/assets/{dist-CodhvuAP.js → dist-D9PhjOaq.js} +0 -0
- /package/build/assets/{environment-switch-store-DkjlKWzN.js → environment-switch-store-DHfcz4M4.js} +0 -0
- /package/build/assets/{extension-module-card-classes-9V3J9J_b.js → extension-module-card-classes-BpebKiN6.js} +0 -0
- /package/build/assets/{external-link-lhdITPqq.js → external-link-CpPMXxrV.js} +0 -0
- /package/build/assets/{folder-Bk311brm.js → folder-BabbYnbF.js} +0 -0
- /package/build/assets/{format-time-delta-DhDbkD7V.js → format-time-delta-BkAmJEPT.js} +0 -0
- /package/build/assets/{get-language-from-path-DBqBsCWH.js → get-language-from-path-CPNnuVhI.js} +0 -0
- /package/build/assets/{git-status-mapper-DnL9OC8_.js → git-status-mapper-BIXK0AAG.js} +0 -0
- /package/build/assets/{iconBase-Dz51Zn5x.js → iconBase-Ch-fOe8B.js} +0 -0
- /package/build/assets/{link-external-CaBmUEs_.js → link-external-DfKQroKX.js} +0 -0
- /package/build/assets/{list-todo-CAtvkzcy.js → list-todo-6J6zc8oS.js} +0 -0
- /package/build/assets/{llm-subscription-DtsX5Lhg.js → llm-subscription-Bvu8BLXc.js} +0 -0
- /package/build/assets/{loader-circle-CsAsfLIs.js → loader-circle-DGsqG5qw.js} +0 -0
- /package/build/assets/{map-provider-BbIb12oh.js → map-provider-BSvXvVR0.js} +0 -0
- /package/build/assets/{middleware-DYHYNAnP.js → middleware-_izt7V6U.js} +0 -0
- /package/build/assets/{modal-backdrop-zVwfOJZr.js → modal-backdrop-B7H42xHG.js} +0 -0
- /package/build/assets/{navigation-context-DPs2G0X8.js → navigation-context-cvyvI1WA.js} +0 -0
- /package/build/assets/{openhands-logo-bcNw5bkY.js → openhands-logo-pEw0nKFP.js} +0 -0
- /package/build/assets/{pencil-CWhApFIT.js → pencil-DmSqWUA3.js} +0 -0
- /package/build/assets/{react-DPDgL6du.js → react-MKQOkha9.js} +0 -0
- /package/build/assets/{search-BgOCR7_c.js → search-B5D5EuSn.js} +0 -0
- /package/build/assets/{search-dIQ09UY2.js → search-vnYL5jwV.js} +0 -0
- /package/build/assets/{settings-gear-MXCyZW0x.js → settings-gear-BOwF59Bs.js} +0 -0
- /package/build/assets/{settings-section-header-context-COMOIaxV.js → settings-section-header-context-CGgHZXrf.js} +0 -0
- /package/build/assets/{skills-EqzxYBvT.js → skills-arUOHLcS.js} +0 -0
- /package/build/assets/{square-chevron-right-DE-JN-2Z.js → square-chevron-right-EizCGtgq.js} +0 -0
- /package/build/assets/{switch-skeleton-DqQwalyu.js → switch-skeleton-BjPRx1QD.js} +0 -0
- /package/build/assets/{terminal-Cgf___rK.js → terminal-a57bHgZs.js} +0 -0
- /package/build/assets/{trash-2-BU6BlW4i.js → trash-2-CF3hilrY.js} +0 -0
- /package/build/assets/{u-check-circle-BqoIxNz_.js → u-check-circle-WGqHdtfO.js} +0 -0
- /package/build/assets/{u-check-circle-half-MsShT8Ec.js → u-check-circle-half-LiwZkuFe.js} +0 -0
- /package/build/assets/{u-edit-DL5LgKon.js → u-edit-BwHepAPi.js} +0 -0
- /package/build/assets/{use-breakpoint-BP3lqLMx.js → use-breakpoint-B-O0lQ84.js} +0 -0
- /package/build/assets/{use-click-outside-element-D9BYdANT.js → use-click-outside-element-DLQIMQrz.js} +0 -0
- /package/build/assets/{use-is-authed-BezEyfeh.js → use-is-authed-BSeo4coy.js} +0 -0
- /package/build/assets/{use-onboarding-completion-C_Swglzp.js → use-onboarding-completion-C0hPNGpw.js} +0 -0
- /package/build/assets/{v4-DbCkTSoU.js → v4-q4yWTlMz.js} +0 -0
- /package/build/assets/{vendor~browser-By2MVv_N.js → vendor~browser-UwB1jbAZ.js} +0 -0
- /package/build/assets/{vendor~conversation-panel~conversation~alert-banner-CxfzCmkN.js → vendor~conversation-panel~conversation~alert-banner-DHDkknt5.js} +0 -0
- /package/build/assets/{vendor~index-home~home~conversation-panel~conversation-ChmYLVgz.js → vendor~index-home~home~conversation-panel~conversation-Bff9cq5J.js} +0 -0
- /package/build/assets/{vendor~module-D5a_AClf.js → vendor~module-D4DeFV4J.js} +0 -0
- /package/build/assets/{vendor~terminal-CnKZILnC.js → vendor~terminal-B7Eiak0-.js} +0 -0
- /package/build/assets/{x-ZE4iplpF.js → x-DQB_00VJ.js} +0 -0
- /package/build/assets/{x-mark-Batp6gXa.js → x-mark-B32XuEwS.js} +0 -0
|
@@ -9,84 +9,83 @@ import { modalTitleLgClassName as c } from "../../../utils/modal-classes.js";
|
|
|
9
9
|
import { ModalCloseButton as l } from "../../shared/modals/modal-close-button.js";
|
|
10
10
|
import { ConfirmationModal as u } from "../../shared/modals/confirmation-modal.js";
|
|
11
11
|
import { useDeleteMcpServer as d } from "../../../hooks/mutation/use-delete-mcp-server.js";
|
|
12
|
-
import
|
|
13
|
-
import p from "../../../api/mcp-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import _ from "
|
|
18
|
-
import {
|
|
12
|
+
import f from "../../../api/mcp-service/mcp-service.api.js";
|
|
13
|
+
import { seedMcpServerHealth as p } from "../../../api/mcp-health/probe-mcp-server-health.js";
|
|
14
|
+
import { useUpdateMcpServer as m } from "../../../hooks/mutation/use-update-mcp-server.js";
|
|
15
|
+
import { makeMcpTestErrorMessage as h } from "../../../utils/mcp-test-error-message.js";
|
|
16
|
+
import { useAddMcpServer as g } from "../../../hooks/mutation/use-add-mcp-server.js";
|
|
17
|
+
import { useTestMcpServer as _ } from "../../../hooks/mutation/use-test-mcp-server.js";
|
|
18
|
+
import { MCPServerForm as v } from "../settings/mcp-settings/mcp-server-form.js";
|
|
19
|
+
import y from "react";
|
|
20
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
19
21
|
//#region src/components/features/mcp-page/custom-server-editor.tsx
|
|
20
|
-
function
|
|
21
|
-
let { t:
|
|
22
|
-
|
|
23
|
-
case "timeout": return w(t.MCP$TEST_ERROR_TIMEOUT);
|
|
24
|
-
case "connection": return w(t.MCP$TEST_ERROR_CONNECTION);
|
|
25
|
-
case "credentials": return w(t.MCP$TEST_ERROR_CREDENTIALS, { error: e.error });
|
|
26
|
-
default: return w(t.MCP$TEST_ERROR_UNKNOWN, { error: e.error });
|
|
27
|
-
}
|
|
28
|
-
}, q = _.useMemo(() => {
|
|
29
|
-
let e = L ?? N;
|
|
22
|
+
function C({ server: C, existingServers: w, onClose: T }) {
|
|
23
|
+
let { t: E } = e("openhands"), { mutate: D, isPending: O } = g(), { mutate: k, isPending: A } = m(), { mutate: j, isPending: M } = d(), { mutate: N, isPending: P, data: F, reset: I } = _(), [L, R] = y.useState(!1), [z, B] = y.useState(null), [V, H] = y.useState(!1), { backend: U } = o(), W = U.kind === "cloud", G = !!C.id, K = O || A || M, q = K || P || V || L, J = y.useMemo(() => {
|
|
24
|
+
let e = z ?? F;
|
|
30
25
|
return e ? e.ok ? {
|
|
31
26
|
ok: !0,
|
|
32
|
-
text:
|
|
27
|
+
text: E(t.MCP$TEST_SUCCESS, { count: e.tools.length })
|
|
33
28
|
} : {
|
|
34
29
|
ok: !1,
|
|
35
|
-
text:
|
|
30
|
+
text: h(E, e.error_kind, e.error)
|
|
36
31
|
} : null;
|
|
37
32
|
}, [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
]),
|
|
42
|
-
|
|
33
|
+
z,
|
|
34
|
+
F,
|
|
35
|
+
E
|
|
36
|
+
]), Y = (e, t) => {
|
|
37
|
+
W || p(e, t, G ? w.filter((e) => e.id !== C.id) : w);
|
|
38
|
+
}, X = (e) => {
|
|
39
|
+
i(r(e) || E(t.ERROR$GENERIC));
|
|
43
40
|
};
|
|
44
|
-
return /* @__PURE__ */ b
|
|
45
|
-
onClose:
|
|
46
|
-
closeOnEscape: !
|
|
47
|
-
"aria-label":
|
|
48
|
-
children: /* @__PURE__ */
|
|
41
|
+
return /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(s, {
|
|
42
|
+
onClose: q ? void 0 : T,
|
|
43
|
+
closeOnEscape: !q,
|
|
44
|
+
"aria-label": E(G ? t.MCP$EDIT_CUSTOM_TITLE : t.MCP$ADD_CUSTOM_TITLE),
|
|
45
|
+
children: /* @__PURE__ */ S("div", {
|
|
49
46
|
"data-testid": "mcp-custom-editor",
|
|
50
47
|
className: "relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar",
|
|
51
48
|
children: [
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
onClose:
|
|
49
|
+
/* @__PURE__ */ x(l, {
|
|
50
|
+
onClose: T,
|
|
54
51
|
testId: "mcp-custom-editor-close",
|
|
55
|
-
disabled:
|
|
52
|
+
disabled: q
|
|
56
53
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
54
|
+
/* @__PURE__ */ x("h2", {
|
|
58
55
|
className: n("mb-4 pr-6", c),
|
|
59
|
-
children:
|
|
56
|
+
children: E(G ? t.MCP$EDIT_CUSTOM_TITLE : t.MCP$ADD_CUSTOM_TITLE)
|
|
60
57
|
}),
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
mode:
|
|
63
|
-
server:
|
|
64
|
-
existingServers:
|
|
58
|
+
/* @__PURE__ */ x(v, {
|
|
59
|
+
mode: G ? "edit" : "add",
|
|
60
|
+
server: G ? C : void 0,
|
|
61
|
+
existingServers: w,
|
|
65
62
|
onSubmit: (e) => {
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
if (
|
|
63
|
+
if (I(), B(null), e.auth?.strategy === "oauth2") {
|
|
64
|
+
H(!0), f.authorizeOAuth(e).then((t) => {
|
|
65
|
+
if (B(t), !t.ok) return;
|
|
69
66
|
let n = t.oauth_state ? {
|
|
70
67
|
...e,
|
|
71
68
|
auth: {
|
|
72
69
|
...e.auth,
|
|
73
70
|
state: t.oauth_state
|
|
74
71
|
}
|
|
75
|
-
} : e
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
} : e, r = () => {
|
|
73
|
+
Y(n, t), T();
|
|
74
|
+
};
|
|
75
|
+
G ? k({
|
|
76
|
+
serverId: C.id,
|
|
78
77
|
server: n
|
|
79
78
|
}, {
|
|
80
|
-
onSuccess:
|
|
81
|
-
onError:
|
|
82
|
-
}) :
|
|
83
|
-
onSuccess:
|
|
84
|
-
onError:
|
|
79
|
+
onSuccess: r,
|
|
80
|
+
onError: X
|
|
81
|
+
}) : D(n, {
|
|
82
|
+
onSuccess: r,
|
|
83
|
+
onError: X
|
|
85
84
|
});
|
|
86
|
-
}).catch(
|
|
85
|
+
}).catch(X).finally(() => H(!1));
|
|
87
86
|
return;
|
|
88
87
|
}
|
|
89
|
-
|
|
88
|
+
N(e, {
|
|
90
89
|
onSuccess: (t) => {
|
|
91
90
|
if (!t.ok) return;
|
|
92
91
|
let n = t.oauth_state && e.auth?.strategy === "oauth2" ? {
|
|
@@ -95,53 +94,55 @@ function x({ server: x, existingServers: S, onClose: C }) {
|
|
|
95
94
|
...e.auth,
|
|
96
95
|
state: t.oauth_state
|
|
97
96
|
}
|
|
98
|
-
} : e
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
} : e, r = () => {
|
|
98
|
+
Y(n, t), T();
|
|
99
|
+
};
|
|
100
|
+
G ? k({
|
|
101
|
+
serverId: C.id,
|
|
101
102
|
server: n
|
|
102
103
|
}, {
|
|
103
|
-
onSuccess:
|
|
104
|
-
onError:
|
|
105
|
-
}) :
|
|
106
|
-
onSuccess:
|
|
107
|
-
onError:
|
|
104
|
+
onSuccess: r,
|
|
105
|
+
onError: X
|
|
106
|
+
}) : D(n, {
|
|
107
|
+
onSuccess: r,
|
|
108
|
+
onError: X
|
|
108
109
|
});
|
|
109
110
|
},
|
|
110
|
-
onError:
|
|
111
|
+
onError: X
|
|
111
112
|
});
|
|
112
113
|
},
|
|
113
|
-
onCancel:
|
|
114
|
-
onDelete:
|
|
115
|
-
isActionDisabled:
|
|
116
|
-
onTest:
|
|
117
|
-
if (
|
|
118
|
-
|
|
114
|
+
onCancel: T,
|
|
115
|
+
onDelete: G ? () => R(!0) : void 0,
|
|
116
|
+
isActionDisabled: K,
|
|
117
|
+
onTest: W ? void 0 : (e) => {
|
|
118
|
+
if (B(null), e.auth?.strategy === "oauth2" && !W) {
|
|
119
|
+
H(!0), f.authorizeOAuth(e).then(B).catch(X).finally(() => H(!1));
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
121
|
-
|
|
122
|
+
N(e);
|
|
122
123
|
},
|
|
123
|
-
isTestPending:
|
|
124
|
-
testMessage:
|
|
124
|
+
isTestPending: P || V,
|
|
125
|
+
testMessage: W ? null : J
|
|
125
126
|
})
|
|
126
127
|
]
|
|
127
128
|
})
|
|
128
|
-
}),
|
|
129
|
-
text:
|
|
130
|
-
onCancel: () =>
|
|
129
|
+
}), L ? /* @__PURE__ */ x(u, {
|
|
130
|
+
text: E(t.SETTINGS$MCP_CONFIRM_DELETE),
|
|
131
|
+
onCancel: () => R(!1),
|
|
131
132
|
onConfirm: () => {
|
|
132
|
-
|
|
133
|
+
j(C, {
|
|
133
134
|
onSuccess: () => {
|
|
134
|
-
a(
|
|
135
|
+
a(E(t.MCP$REMOVE_SUCCESS)), R(!1), T();
|
|
135
136
|
},
|
|
136
137
|
onError: (e) => {
|
|
137
|
-
|
|
138
|
+
X(e), R(!1);
|
|
138
139
|
}
|
|
139
140
|
});
|
|
140
141
|
},
|
|
141
|
-
isConfirming:
|
|
142
|
+
isConfirming: M
|
|
142
143
|
}) : null] });
|
|
143
144
|
}
|
|
144
145
|
//#endregion
|
|
145
|
-
export {
|
|
146
|
+
export { C as CustomServerEditor };
|
|
146
147
|
|
|
147
148
|
//# sourceMappingURL=custom-server-editor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-server-editor.js","names":[],"sources":["../../../../src/components/features/mcp-page/custom-server-editor.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport {\n MCPServerForm,\n type TestMessage,\n} from \"#/components/features/settings/mcp-settings/mcp-server-form\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport {\n ExtendedMCPTestFailure,\n ExtendedMCPTestResponse,\n MCPServerConfig,\n} from \"#/types/mcp-server\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { cn } from \"#/utils/utils\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\n\ninterface CustomServerEditorProps {\n server: MCPServerConfig;\n existingServers: MCPServerConfig[];\n onClose: () => void;\n}\n\n/**\n * Modal wrapper around `MCPServerForm` so users can hand-author\n * arbitrary stdio / SSE / SHTTP entries without reaching for raw JSON.\n * An empty `server.id` means \"Add new\".\n */\nexport function CustomServerEditor({\n server,\n existingServers,\n onClose,\n}: CustomServerEditorProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: updateMcpServer, isPending: isUpdating } =\n useUpdateMcpServer();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const {\n mutate: testServer,\n isPending: isTesting,\n data: testResult,\n reset: resetTest,\n } = useTestMcpServer();\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);\n const [oauthTestResult, setOauthTestResult] =\n React.useState<ExtendedMCPTestResponse | null>(null);\n const [isOauthTesting, setIsOauthTesting] = React.useState(false);\n\n // The MCP connectivity-test endpoint only exists on the local agent-server.\n // For cloud backends `McpService.testServer` short-circuits with a synthetic\n // success so the save still completes; we hide the manual \"Test connection\"\n // button here so cloud users aren't shown a misleading \"0 tools\" result.\n const { backend } = useActiveBackend();\n const isCloudBackend = backend.kind === \"cloud\";\n\n const isEditing = !!server.id;\n const isPending = isAdding || isUpdating || isDeleting;\n const isDismissBlocked =\n isPending || isTesting || isOauthTesting || showDeleteConfirm;\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 testMessage: TestMessage | null = React.useMemo(() => {\n const result = oauthTestResult ?? testResult;\n if (!result) return null;\n if (result.ok) {\n return {\n ok: true,\n text: t(I18nKey.MCP$TEST_SUCCESS, { count: result.tools.length }),\n };\n }\n return { ok: false, text: makeTestErrorMessage(result) };\n }, [oauthTestResult, testResult, t]);\n\n // Shared error handler so both add and update surface backend errors\n // as a toast instead of failing silently — previously these calls\n // had no `onError` and the modal closed even on a 4xx/5xx, leaving\n // the user to discover the failure on the next page load.\n const handleError = (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n };\n\n const handleSubmit = (payload: MCPServerConfig) => {\n resetTest();\n setOauthTestResult(null);\n if (payload.auth?.strategy === \"oauth2\") {\n setIsOauthTesting(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n setOauthTestResult(result);\n if (!result.ok) return;\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n { onSuccess: onClose, onError: handleError },\n );\n } else {\n addMcpServer(serverToSave, {\n onSuccess: onClose,\n onError: handleError,\n });\n }\n })\n .catch(handleError)\n .finally(() => setIsOauthTesting(false));\n return;\n }\n testServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n // Test failed — modal stays open, error shown via testMessage.\n return;\n }\n const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n { onSuccess: onClose, onError: handleError },\n );\n } else {\n addMcpServer(serverToSave, {\n onSuccess: onClose,\n onError: handleError,\n });\n }\n },\n onError: handleError,\n });\n };\n\n const handleTestClick = (payload: MCPServerConfig) => {\n setOauthTestResult(null);\n if (payload.auth?.strategy === \"oauth2\" && !isCloudBackend) {\n setIsOauthTesting(true);\n void McpService.authorizeOAuth(payload)\n .then(setOauthTestResult)\n .catch(handleError)\n .finally(() => setIsOauthTesting(false));\n return;\n }\n testServer(payload);\n };\n\n const handleConfirmDelete = () => {\n deleteMcpServer(server, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setShowDeleteConfirm(false);\n onClose();\n },\n onError: (err) => {\n handleError(err);\n setShowDeleteConfirm(false);\n },\n });\n };\n\n return (\n <>\n <ModalBackdrop\n // Block backdrop-click / Escape from dismissing the modal while\n // a mutation is in flight — closing mid-request would orphan\n // the request and leave the user with no error feedback.\n onClose={isDismissBlocked ? undefined : onClose}\n closeOnEscape={!isDismissBlocked}\n aria-label={\n isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)\n }\n >\n <div\n data-testid=\"mcp-custom-editor\"\n className=\"relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-custom-editor-close\"\n disabled={isDismissBlocked}\n />\n <h2 className={cn(\"mb-4 pr-6\", modalTitleLgClassName)}>\n {isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)}\n </h2>\n <MCPServerForm\n mode={isEditing ? \"edit\" : \"add\"}\n server={isEditing ? server : undefined}\n existingServers={existingServers}\n onSubmit={handleSubmit}\n onCancel={onClose}\n onDelete={isEditing ? () => setShowDeleteConfirm(true) : undefined}\n isActionDisabled={isPending}\n onTest={isCloudBackend ? undefined : handleTestClick}\n isTestPending={isTesting || isOauthTesting}\n testMessage={isCloudBackend ? null : testMessage}\n />\n </div>\n </ModalBackdrop>\n\n {showDeleteConfirm ? (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setShowDeleteConfirm(false)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"custom-server-editor.js","names":[],"sources":["../../../../src/components/features/mcp-page/custom-server-editor.tsx"],"sourcesContent":["import React from \"react\";\nimport { AxiosError } from \"axios\";\nimport { useTranslation } from \"react-i18next\";\nimport { I18nKey } from \"#/i18n/declaration\";\nimport { ModalBackdrop } from \"#/components/shared/modals/modal-backdrop\";\nimport { ModalCloseButton } from \"#/components/shared/modals/modal-close-button\";\nimport { ConfirmationModal } from \"#/components/shared/modals/confirmation-modal\";\nimport {\n MCPServerForm,\n type TestMessage,\n} from \"#/components/features/settings/mcp-settings/mcp-server-form\";\nimport { seedMcpServerHealth } from \"#/api/mcp-health/probe-mcp-server-health\";\nimport { useAddMcpServer } from \"#/hooks/mutation/use-add-mcp-server\";\nimport { useUpdateMcpServer } from \"#/hooks/mutation/use-update-mcp-server\";\nimport { useDeleteMcpServer } from \"#/hooks/mutation/use-delete-mcp-server\";\nimport { useTestMcpServer } from \"#/hooks/mutation/use-test-mcp-server\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\nimport { ExtendedMCPTestResponse, MCPServerConfig } from \"#/types/mcp-server\";\nimport {\n displayErrorToast,\n displaySuccessToast,\n} from \"#/utils/custom-toast-handlers\";\nimport { makeMcpTestErrorMessage } from \"#/utils/mcp-test-error-message\";\nimport { retrieveAxiosErrorMessage } from \"#/utils/retrieve-axios-error-message\";\nimport { cn } from \"#/utils/utils\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\n\ninterface CustomServerEditorProps {\n server: MCPServerConfig;\n existingServers: MCPServerConfig[];\n onClose: () => void;\n}\n\n/**\n * Modal wrapper around `MCPServerForm` so users can hand-author\n * arbitrary stdio / SSE / SHTTP entries without reaching for raw JSON.\n * An empty `server.id` means \"Add new\".\n */\nexport function CustomServerEditor({\n server,\n existingServers,\n onClose,\n}: CustomServerEditorProps) {\n const { t } = useTranslation(\"openhands\");\n const { mutate: addMcpServer, isPending: isAdding } = useAddMcpServer();\n const { mutate: updateMcpServer, isPending: isUpdating } =\n useUpdateMcpServer();\n const { mutate: deleteMcpServer, isPending: isDeleting } =\n useDeleteMcpServer();\n const {\n mutate: testServer,\n isPending: isTesting,\n data: testResult,\n reset: resetTest,\n } = useTestMcpServer();\n const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);\n const [oauthTestResult, setOauthTestResult] =\n React.useState<ExtendedMCPTestResponse | null>(null);\n const [isOauthTesting, setIsOauthTesting] = React.useState(false);\n\n // The MCP connectivity-test endpoint only exists on the local agent-server.\n // For cloud backends `McpService.testServer` short-circuits with a synthetic\n // success so the save still completes; we hide the manual \"Test connection\"\n // button here so cloud users aren't shown a misleading \"0 tools\" result.\n const { backend } = useActiveBackend();\n const isCloudBackend = backend.kind === \"cloud\";\n\n const isEditing = !!server.id;\n const isPending = isAdding || isUpdating || isDeleting;\n const isDismissBlocked =\n isPending || isTesting || isOauthTesting || showDeleteConfirm;\n\n const testMessage: TestMessage | null = React.useMemo(() => {\n const result = oauthTestResult ?? testResult;\n if (!result) return null;\n if (result.ok) {\n return {\n ok: true,\n text: t(I18nKey.MCP$TEST_SUCCESS, { count: result.tools.length }),\n };\n }\n return {\n ok: false,\n text: makeMcpTestErrorMessage(t, result.error_kind, result.error),\n };\n }, [oauthTestResult, testResult, t]);\n\n // A save always follows a fresh successful probe of the exact config being\n // saved, so publish that result to the card's health entry. On cloud\n // backends the probe is synthetic — never present it as a health verdict.\n const seedSavedServerHealth = (\n serverToSave: MCPServerConfig,\n result: ExtendedMCPTestResponse,\n ) => {\n if (isCloudBackend) return;\n // When editing, the server's own entry must be overwritten, so only the\n // OTHER servers guard against a same-key collision.\n const otherServers = isEditing\n ? existingServers.filter((existing) => existing.id !== server.id)\n : existingServers;\n seedMcpServerHealth(serverToSave, result, otherServers);\n };\n\n // Shared error handler so both add and update surface backend errors\n // as a toast instead of failing silently — previously these calls\n // had no `onError` and the modal closed even on a 4xx/5xx, leaving\n // the user to discover the failure on the next page load.\n const handleError = (err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n displayErrorToast(message || t(I18nKey.ERROR$GENERIC));\n };\n\n const handleSubmit = (payload: MCPServerConfig) => {\n resetTest();\n setOauthTestResult(null);\n if (payload.auth?.strategy === \"oauth2\") {\n setIsOauthTesting(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n setOauthTestResult(result);\n if (!result.ok) return;\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n const onSaved = () => {\n seedSavedServerHealth(serverToSave, result);\n onClose();\n };\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n { onSuccess: onSaved, onError: handleError },\n );\n } else {\n addMcpServer(serverToSave, {\n onSuccess: onSaved,\n onError: handleError,\n });\n }\n })\n .catch(handleError)\n .finally(() => setIsOauthTesting(false));\n return;\n }\n testServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n // Test failed — modal stays open, error shown via testMessage.\n return;\n }\n const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n const onSaved = () => {\n seedSavedServerHealth(serverToSave, result);\n onClose();\n };\n if (isEditing) {\n updateMcpServer(\n { serverId: server.id, server: serverToSave },\n { onSuccess: onSaved, onError: handleError },\n );\n } else {\n addMcpServer(serverToSave, {\n onSuccess: onSaved,\n onError: handleError,\n });\n }\n },\n onError: handleError,\n });\n };\n\n const handleTestClick = (payload: MCPServerConfig) => {\n setOauthTestResult(null);\n if (payload.auth?.strategy === \"oauth2\" && !isCloudBackend) {\n setIsOauthTesting(true);\n void McpService.authorizeOAuth(payload)\n .then(setOauthTestResult)\n .catch(handleError)\n .finally(() => setIsOauthTesting(false));\n return;\n }\n testServer(payload);\n };\n\n const handleConfirmDelete = () => {\n deleteMcpServer(server, {\n onSuccess: () => {\n displaySuccessToast(t(I18nKey.MCP$REMOVE_SUCCESS));\n setShowDeleteConfirm(false);\n onClose();\n },\n onError: (err) => {\n handleError(err);\n setShowDeleteConfirm(false);\n },\n });\n };\n\n return (\n <>\n <ModalBackdrop\n // Block backdrop-click / Escape from dismissing the modal while\n // a mutation is in flight — closing mid-request would orphan\n // the request and leave the user with no error feedback.\n onClose={isDismissBlocked ? undefined : onClose}\n closeOnEscape={!isDismissBlocked}\n aria-label={\n isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)\n }\n >\n <div\n data-testid=\"mcp-custom-editor\"\n className=\"relative bg-base-secondary p-6 rounded-xl border border-[var(--oh-border)] w-[520px] max-w-[90vw] max-h-[90vh] overflow-y-auto custom-scrollbar\"\n >\n <ModalCloseButton\n onClose={onClose}\n testId=\"mcp-custom-editor-close\"\n disabled={isDismissBlocked}\n />\n <h2 className={cn(\"mb-4 pr-6\", modalTitleLgClassName)}>\n {isEditing\n ? t(I18nKey.MCP$EDIT_CUSTOM_TITLE)\n : t(I18nKey.MCP$ADD_CUSTOM_TITLE)}\n </h2>\n <MCPServerForm\n mode={isEditing ? \"edit\" : \"add\"}\n server={isEditing ? server : undefined}\n existingServers={existingServers}\n onSubmit={handleSubmit}\n onCancel={onClose}\n onDelete={isEditing ? () => setShowDeleteConfirm(true) : undefined}\n isActionDisabled={isPending}\n onTest={isCloudBackend ? undefined : handleTestClick}\n isTestPending={isTesting || isOauthTesting}\n testMessage={isCloudBackend ? null : testMessage}\n />\n </div>\n </ModalBackdrop>\n\n {showDeleteConfirm ? (\n <ConfirmationModal\n text={t(I18nKey.SETTINGS$MCP_CONFIRM_DELETE)}\n onCancel={() => setShowDeleteConfirm(false)}\n onConfirm={handleConfirmDelete}\n isConfirming={isDeleting}\n />\n ) : null}\n </>\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/retrieve-axios-error-message.cjs`),i=require(`../../../utils/custom-toast-handlers.cjs`),a=require(`../../../node_modules/uuid/dist/v4.cjs`),o=require(`../../../utils/mcp-server-name.cjs`),s=require(`../../shared/modals/modal-backdrop.cjs`),c=require(`../../../utils/modal-classes.cjs`),l=require(`../../shared/modals/modal-close-button.cjs`),u=require(`../settings/brand-button.cjs`),d=require(`../settings/settings-input.cjs`),f=require(`../../../utils/mcp-marketplace-utils.cjs`),p=require(`../mcp-logo-badge.cjs`),m=require(`./save-as-secret-toggle.cjs`),h=require(`../../../hooks/mutation/use-add-mcp-server.cjs`),g=require(`../../../api/mcp-service/mcp-service.api.cjs`),_=require(`../../../hooks/mutation/use-test-mcp-server.cjs`),v=require(`../../../hooks/mutation/use-save-fields-as-secrets.cjs`);let y=require(`react`);y=e.__toESM(y,1);let b=require(`react/jsx-runtime`);function x(e){let t=/\[([^\]]+)\]\(([^)]+)\)/g,n=[],r=0;for(let i of e.matchAll(t))i.index>r&&n.push(e.slice(r,i.index)),n.push((0,b.jsx)(`a`,{href:/^https?:\/\//i.test(i[2])?i[2]:`#`,target:`_blank`,rel:`noreferrer`,className:`underline hover:text-white transition-colors`,children:i[1]},i.index)),r=i.index+i[0].length;return r<e.length&&n.push(e.slice(r)),n}function S(e){return e?.transport.kind!==`shttp`&&e?.transport.kind!==`sse`?!1:[`api_key`,`bearer`].includes(e.auth.strategy)}function C(e){return!!e&&e.auth.strategy===`oauth2`}function w(e){return e.transport.kind===`stdio`?e.auth.apiKeyOptional??!1:e.auth.apiKeyOptional??e.transport.apiKeyOptional??!1}function T(e){return e?.transport.kind!==`shttp`&&e?.transport.kind!==`sse`?[]:e.transport.headerFields??[]}function E(e){let t={},n={},r=f.getInstallableMcpConnectionOption(e),i=r?.transport;if(i?.kind===`stdio`){for(let e of i.envFields??[])t[e.key]=``,n[e.key]=e.type===`password`;for(let e of i.argFields??[])t[e.key]=``}else if(i?.kind===`shttp`||i?.kind===`sse`){t.url=i.url;for(let e of T(r))t[e.key]=``,n[e.key]=e.type===`password`;S(r)&&(t.api_key=``,r?.auth.credentialSecretName&&(n.api_key=r.auth.saveCredentialAsSecretByDefault??!1))}return{values:t,errors:{},savedAsSecret:n}}function D({entry:e,onClose:D,onSuccess:O}){let{t:k}=t.useTranslation(`openhands`),{mutate:A,isPending:j}=h.useAddMcpServer(),{mutate:M,isPending:N}=_.useTestMcpServer(),P=v.useSaveFieldsAsSecrets(),[F,I]=y.default.useState(()=>E(e)),L=y.default.useRef(F);L.current=F;let[R,z]=y.default.useState(null),[B,V]=y.default.useState(!1),[H,U]=y.default.useState(!1),W=f.getInstallableMcpConnectionOption(e),G=W?.transport,K=N||H||j||B,q=(e,t)=>{I(n=>({...n,values:{...n.values,[e]:t},errors:{...n.errors,[e]:null}})),z(null)},J=(e,t)=>{I(n=>({...n,savedAsSecret:{...n.savedAsSecret,[e]:t}}))},Y=()=>{let e=W?.auth.credentialSecretName,t=L.current.values.api_key?.trim();return!e||!t||!L.current.savedAsSecret.api_key?Promise.resolve():P([{key:e,label:W.auth.credentialLabel??e,type:`password`}],{[e]:t},{[e]:!0})},X=()=>G?.kind===`stdio`?P(G.envFields??[],L.current.values,L.current.savedAsSecret):G?.kind===`shttp`||G?.kind===`sse`?Promise.all([Y(),P(T(W),L.current.values,L.current.savedAsSecret)]).then(()=>void 0):Promise.resolve(),Z=e=>{switch(e.error_kind){case`timeout`:return k(n.I18nKey.MCP$TEST_ERROR_TIMEOUT);case`connection`:return k(n.I18nKey.MCP$TEST_ERROR_CONNECTION);case`credentials`:return k(n.I18nKey.MCP$TEST_ERROR_CREDENTIALS,{error:e.error});default:return k(n.I18nKey.MCP$TEST_ERROR_UNKNOWN,{error:e.error})}},Q=t=>{if(t.auth?.strategy===`oauth2`){U(!0),g.default.authorizeOAuth(t).then(a=>{if(!a.ok){z(Z(a));return}A(a.oauth_state?{...t,auth:{...t.auth,state:a.oauth_state}}:t,{onSuccess:()=>{i.displaySuccessToast(k(n.I18nKey.MCP$INSTALL_SUCCESS)),V(!0),(async()=>{try{await X()}finally{O?.(e),D()}})()},onError:e=>{z(r.retrieveAxiosErrorMessage(e)||k(n.I18nKey.ERROR$GENERIC))}})}).catch(e=>{z(r.retrieveAxiosErrorMessage(e)||k(n.I18nKey.ERROR$GENERIC))}).finally(()=>U(!1));return}M(t,{onSuccess:a=>{if(!a.ok){z(Z(a));return}A(a.oauth_state&&t.auth?.strategy===`oauth2`?{...t,auth:{...t.auth,state:a.oauth_state}}:t,{onSuccess:()=>{i.displaySuccessToast(k(n.I18nKey.MCP$INSTALL_SUCCESS)),V(!0),(async()=>{try{await X()}finally{O?.(e),D()}})()},onError:e=>{z(r.retrieveAxiosErrorMessage(e)||k(n.I18nKey.ERROR$GENERIC))}})},onError:e=>{z(r.retrieveAxiosErrorMessage(e)||k(n.I18nKey.ERROR$GENERIC))}})},$=()=>{if(G?.kind!==`shttp`&&G?.kind!==`sse`||!W)return;let t=F.values.api_key?.trim()??``,r=G.urlEditable?F.values.url?.trim()??``:G.url,i=C(W),s=S(W),c=T(W),l={};if(!r)l.url=k(n.I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);else try{let e=new URL(r);[`http:`,`https:`].includes(e.protocol)||(l.url=k(n.I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL))}catch{l.url=k(n.I18nKey.SETTINGS$MCP_ERROR_URL_INVALID)}for(let e of c)e.required&&!(F.values[e.key]??``).trim()&&(l[e.key]=k(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));if(!i&&s&&!w(W)&&!t&&(l.api_key=k(n.I18nKey.MCP$ERROR_FIELD_REQUIRED)),Object.values(l).some(Boolean)){I(e=>({...e,errors:l}));return}let u=i?f.getMcpOAuthAuthenticationConfig(W):void 0,d=Object.fromEntries(c.map(e=>[e.key,F.values[e.key]?.trim()??``]).filter(([,e])=>e)),p=Object.keys(d).length>0,m;i?m={strategy:`oauth2`,...u&&{authentication:u}}:s&&t?m=W.auth.strategy===`api_key`?{strategy:`api_key`,value:t,...W.auth.apiKeyHeaderName&&{header_name:W.auth.apiKeyHeaderName}}:{strategy:`bearer`,value:t}:p&&(m={strategy:`header`,headers:d}),Q({id:`${G.kind}-${a.default()}`,type:G.kind,name:o.toMcpServerName(e.id),url:r,...m&&{auth:m},...p&&m?.strategy!==`header`&&{headers:d}})},ee=()=>{if(G?.kind!==`stdio`)return;let e=G,t={};for(let r of e.envFields??[])r.required&&!(F.values[r.key]??``).trim()&&(t[r.key]=k(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));for(let r of e.argFields??[])r.required&&!(F.values[r.key]??``).trim()&&(t[r.key]=k(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));if(Object.values(t).some(Boolean)){I(e=>({...e,errors:t}));return}let r={};for(let t of e.envFields??[]){let e=F.values[t.key]?.trim();e&&(r[t.key]=e)}let i=[];for(let t of e.argFields??[]){let e=F.values[t.key]?.trim();if(e)for(let t of e.split(/\s+/))t&&i.push(t)}Q({id:`stdio-${a.default()}`,type:`stdio`,name:e.serverName,command:e.command,args:[...e.args,...i],...Object.keys(r).length>0&&{env:r}})};return(0,b.jsx)(s.ModalBackdrop,{onClose:D,"aria-label":e.name,children:(0,b.jsxs)(`form`,{"data-testid":`mcp-install-modal`,"data-marketplace-id":e.id,onSubmit:e=>(e.preventDefault(),z(null),G?.kind===`shttp`||G?.kind===`sse`?$():ee()),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`,children:[(0,b.jsx)(l.ModalCloseButton,{onClose:D,testId:`mcp-install-modal-close`,disabled:K}),(0,b.jsxs)(`div`,{className:`flex items-start gap-3 pr-6`,children:[(0,b.jsx)(p.McpLogoBadge,{entry:e}),(0,b.jsxs)(`div`,{className:`flex flex-col flex-1`,children:[(0,b.jsx)(`h2`,{className:c.modalTitleLgClassName,children:e.name}),(0,b.jsx)(`p`,{className:`text-xs text-tertiary-light`,children:e.description})]})]}),e.installHint&&(0,b.jsx)(`p`,{className:`text-xs text-tertiary-light`,children:e.installHint}),e.docsUrl&&(0,b.jsx)(`a`,{href:e.docsUrl,target:`_blank`,rel:`noreferrer`,className:`text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors`,children:k(n.I18nKey.MCP$VIEW_DOCS)}),(0,b.jsx)(`div`,{className:`flex flex-col gap-3`,children:(()=>{if(G?.kind===`shttp`||G?.kind===`sse`){let e=C(W),t=S(W),r=W?w(W):!1,i=W?.auth.credentialSecretName,a=T(W);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-url`,name:`url`,type:`url`,label:k(n.I18nKey.SETTINGS$MCP_URL),value:F.values.url??G.url,onChange:e=>q(`url`,e),isDisabled:!G.urlEditable,className:`w-full`}),F.errors.url&&(0,b.jsx)(`p`,{className:`text-xs text-red-500`,children:F.errors.url}),a.map(e=>(0,b.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:F.values[e.key]??``,onChange:t=>q(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,b.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:x(e.helperText)}),F.errors[e.key]&&(0,b.jsx)(`p`,{className:`text-xs text-red-500`,children:F.errors[e.key]}),e.key in F.savedAsSecret&&(0,b.jsx)(m.SaveAsSecretToggle,{fieldKey:e.key,checked:F.savedAsSecret[e.key]??!1,onToggle:t=>J(e.key,t)})]},e.key)),e?(0,b.jsxs)(`div`,{"data-testid":`mcp-install-oauth-info`,className:`flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary`,children:[(0,b.jsx)(`p`,{className:`text-sm text-secondary-light`,children:k(n.I18nKey.MCP$OAUTH_CONNECT_INFO)}),(0,b.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:k(n.I18nKey.MCP$OAUTH_CONNECT_HINT)})]}):t?(0,b.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-api_key`,name:`api_key`,type:`password`,label:W?.auth.credentialLabel??k(n.I18nKey.SETTINGS$MCP_API_KEY),value:F.values.api_key??``,onChange:e=>q(`api_key`,e),placeholder:W?.auth.credentialPlaceholder??k(n.I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER),showOptionalTag:r,required:!r,className:`w-full`}),W?.auth.credentialHelp&&(0,b.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:x(W.auth.credentialHelp)}),F.errors.api_key&&(0,b.jsx)(`p`,{className:`text-xs text-red-500`,children:F.errors.api_key}),i&&(0,b.jsx)(m.SaveAsSecretToggle,{fieldKey:i,checked:F.savedAsSecret.api_key??!1,onToggle:e=>J(`api_key`,e)})]}):null]})}if(G?.kind!==`stdio`)return null;let e=G;return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-command-readonly`,name:`command-readonly`,type:`text`,label:k(n.I18nKey.MCP$COMMAND_LABEL),value:`${e.command} ${e.args.join(` `)}`.trim(),onChange:()=>{},isDisabled:!0,className:`w-full`}),(e.envFields??[]).map(e=>(0,b.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:F.values[e.key]??``,onChange:t=>q(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,b.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:x(e.helperText)}),F.errors[e.key]&&(0,b.jsx)(`p`,{className:`text-xs text-red-500`,children:F.errors[e.key]}),e.key in F.savedAsSecret&&(0,b.jsx)(m.SaveAsSecretToggle,{fieldKey:e.key,checked:F.savedAsSecret[e.key],onToggle:t=>J(e.key,t)})]},e.key)),(e.argFields??[]).map(e=>(0,b.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,b.jsx)(d.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:F.values[e.key]??``,onChange:t=>q(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,b.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:x(e.helperText)}),F.errors[e.key]&&(0,b.jsx)(`p`,{className:`text-xs text-red-500`,children:F.errors[e.key]})]},e.key))]})})()}),R&&(0,b.jsx)(`p`,{"data-testid":`mcp-install-modal-error`,className:`text-sm text-red-500 whitespace-pre-wrap`,children:R}),(0,b.jsxs)(`div`,{className:`flex justify-end gap-2 mt-2`,children:[(0,b.jsx)(u.BrandButton,{type:`button`,variant:`secondary`,onClick:D,testId:`mcp-install-cancel`,isDisabled:K,children:k(n.I18nKey.BUTTON$CANCEL)}),(0,b.jsx)(u.BrandButton,{type:`submit`,variant:`primary`,isDisabled:K,testId:`mcp-install-submit`,children:k(N||H?n.I18nKey.MCP$VERIFYING:j||B?n.I18nKey.SETTINGS$SAVING:n.I18nKey.MCP$INSTALL_BUTTON)})]})]})})}exports.InstallServerModal=D;
|
|
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/retrieve-axios-error-message.cjs`),i=require(`../../../utils/custom-toast-handlers.cjs`),a=require(`../../../contexts/active-backend-context.cjs`),o=require(`../../../node_modules/uuid/dist/v4.cjs`),s=require(`../../../utils/mcp-server-name.cjs`),c=require(`../../shared/modals/modal-backdrop.cjs`),l=require(`../../../utils/modal-classes.cjs`),u=require(`../../shared/modals/modal-close-button.cjs`),d=require(`../settings/brand-button.cjs`),f=require(`../settings/settings-input.cjs`),p=require(`../../../utils/mcp-marketplace-utils.cjs`),m=require(`../mcp-logo-badge.cjs`),h=require(`../../../api/mcp-service/mcp-service.api.cjs`),g=require(`../../../api/mcp-health/probe-mcp-server-health.cjs`),_=require(`../../../utils/mcp-test-error-message.cjs`),v=require(`./save-as-secret-toggle.cjs`),y=require(`../../../hooks/mutation/use-add-mcp-server.cjs`),b=require(`../../../hooks/mutation/use-test-mcp-server.cjs`),x=require(`../../../hooks/mutation/use-save-fields-as-secrets.cjs`);let S=require(`react`);S=e.__toESM(S,1);let C=require(`react/jsx-runtime`);function w(e){let t=/\[([^\]]+)\]\(([^)]+)\)/g,n=[],r=0;for(let i of e.matchAll(t))i.index>r&&n.push(e.slice(r,i.index)),n.push((0,C.jsx)(`a`,{href:/^https?:\/\//i.test(i[2])?i[2]:`#`,target:`_blank`,rel:`noreferrer`,className:`underline hover:text-white transition-colors`,children:i[1]},i.index)),r=i.index+i[0].length;return r<e.length&&n.push(e.slice(r)),n}function T(e){return e?.transport.kind!==`shttp`&&e?.transport.kind!==`sse`?!1:[`api_key`,`bearer`].includes(e.auth.strategy)}function E(e){return!!e&&e.auth.strategy===`oauth2`}function D(e){return e.transport.kind===`stdio`?e.auth.apiKeyOptional??!1:e.auth.apiKeyOptional??e.transport.apiKeyOptional??!1}function O(e){return e?.transport.kind!==`shttp`&&e?.transport.kind!==`sse`?[]:e.transport.headerFields??[]}function ee(e){let t={},n={},r=p.getInstallableMcpConnectionOption(e),i=r?.transport;if(i?.kind===`stdio`){for(let e of i.envFields??[])t[e.key]=``,n[e.key]=e.type===`password`;for(let e of i.argFields??[])t[e.key]=``}else if(i?.kind===`shttp`||i?.kind===`sse`){t.url=i.url;for(let e of O(r))t[e.key]=``,n[e.key]=e.type===`password`;T(r)&&(t.api_key=``,r?.auth.credentialSecretName&&(n.api_key=r.auth.saveCredentialAsSecretByDefault??!1))}return{values:t,errors:{},savedAsSecret:n}}function k({entry:e,existingServers:k,onClose:A,onSuccess:j}){let{t:M}=t.useTranslation(`openhands`),{mutate:N,isPending:P}=y.useAddMcpServer(),{mutate:te,isPending:F}=b.useTestMcpServer(),I=x.useSaveFieldsAsSecrets(),{backend:ne}=a.useActiveBackend(),L=ne.kind===`cloud`,[R,z]=S.default.useState(()=>ee(e)),B=S.default.useRef(R);B.current=R;let[V,H]=S.default.useState(null),[U,W]=S.default.useState(!1),[G,K]=S.default.useState(!1),q=p.getInstallableMcpConnectionOption(e),J=q?.transport,Y=F||G||P||U,X=(e,t)=>{z(n=>({...n,values:{...n.values,[e]:t},errors:{...n.errors,[e]:null}})),H(null)},Z=(e,t)=>{z(n=>({...n,savedAsSecret:{...n.savedAsSecret,[e]:t}}))},re=()=>{let e=q?.auth.credentialSecretName,t=B.current.values.api_key?.trim();return!e||!t||!B.current.savedAsSecret.api_key?Promise.resolve():I([{key:e,label:q.auth.credentialLabel??e,type:`password`,required:!0}],{[e]:t},{[e]:!0})},Q=()=>J?.kind===`stdio`?I(J.envFields??[],B.current.values,B.current.savedAsSecret):J?.kind===`shttp`||J?.kind===`sse`?Promise.all([re(),I(O(q),B.current.values,B.current.savedAsSecret)]).then(()=>void 0):Promise.resolve(),$=t=>{if(t.auth?.strategy===`oauth2`){K(!0),h.default.authorizeOAuth(t).then(a=>{if(!a.ok){H(_.makeMcpTestErrorMessage(M,a.error_kind,a.error));return}let o=a.oauth_state?{...t,auth:{...t.auth,state:a.oauth_state}}:t;N(o,{onSuccess:()=>{L||g.seedMcpServerHealth(o,a,k),i.displaySuccessToast(M(n.I18nKey.MCP$INSTALL_SUCCESS)),W(!0),(async()=>{try{await Q()}finally{j?.(e),A()}})()},onError:e=>{H(r.retrieveAxiosErrorMessage(e)||M(n.I18nKey.ERROR$GENERIC))}})}).catch(e=>{H(r.retrieveAxiosErrorMessage(e)||M(n.I18nKey.ERROR$GENERIC))}).finally(()=>K(!1));return}te(t,{onSuccess:a=>{if(!a.ok){H(_.makeMcpTestErrorMessage(M,a.error_kind,a.error));return}let o=a.oauth_state&&t.auth?.strategy===`oauth2`?{...t,auth:{...t.auth,state:a.oauth_state}}:t;N(o,{onSuccess:()=>{L||g.seedMcpServerHealth(o,a,k),i.displaySuccessToast(M(n.I18nKey.MCP$INSTALL_SUCCESS)),W(!0),(async()=>{try{await Q()}finally{j?.(e),A()}})()},onError:e=>{H(r.retrieveAxiosErrorMessage(e)||M(n.I18nKey.ERROR$GENERIC))}})},onError:e=>{H(r.retrieveAxiosErrorMessage(e)||M(n.I18nKey.ERROR$GENERIC))}})},ie=()=>{if(J?.kind!==`shttp`&&J?.kind!==`sse`||!q)return;let t=R.values.api_key?.trim()??``,r=J.urlEditable?R.values.url?.trim()??``:J.url,i=E(q),a=T(q),c=O(q),l={};if(!r)l.url=M(n.I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);else try{let e=new URL(r);[`http:`,`https:`].includes(e.protocol)||(l.url=M(n.I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL))}catch{l.url=M(n.I18nKey.SETTINGS$MCP_ERROR_URL_INVALID)}for(let e of c)e.required&&!(R.values[e.key]??``).trim()&&(l[e.key]=M(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));if(!i&&a&&!D(q)&&!t&&(l.api_key=M(n.I18nKey.MCP$ERROR_FIELD_REQUIRED)),Object.values(l).some(Boolean)){z(e=>({...e,errors:l}));return}let u=i?p.getMcpOAuthAuthenticationConfig(q):void 0,d=Object.fromEntries(c.map(e=>[e.key,R.values[e.key]?.trim()??``]).filter(([,e])=>e)),f=Object.keys(d).length>0,m;i?m={strategy:`oauth2`,...u&&{authentication:u}}:a&&t?m=q.auth.strategy===`api_key`?{strategy:`api_key`,value:t,...q.auth.apiKeyHeaderName&&{header_name:q.auth.apiKeyHeaderName}}:{strategy:`bearer`,value:t}:f&&(m={strategy:`header`,headers:d}),$({id:`${J.kind}-${o.default()}`,type:J.kind,name:s.toMcpServerName(e.id),url:r,...m&&{auth:m},...f&&m?.strategy!==`header`&&{headers:d}})},ae=()=>{if(J?.kind!==`stdio`)return;let e=J,t={};for(let r of e.envFields??[])r.required&&!(R.values[r.key]??``).trim()&&(t[r.key]=M(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));for(let r of e.argFields??[])r.required&&!(R.values[r.key]??``).trim()&&(t[r.key]=M(n.I18nKey.MCP$ERROR_FIELD_REQUIRED));if(Object.values(t).some(Boolean)){z(e=>({...e,errors:t}));return}let r={};for(let t of e.envFields??[]){let e=R.values[t.key]?.trim();e&&(r[t.key]=e)}let i=[];for(let t of e.argFields??[]){let e=R.values[t.key]?.trim();if(e)for(let t of e.split(/\s+/))t&&i.push(t)}$({id:`stdio-${o.default()}`,type:`stdio`,name:e.serverName,command:e.command,args:[...e.args,...i],...Object.keys(r).length>0&&{env:r}})};return(0,C.jsx)(c.ModalBackdrop,{onClose:A,"aria-label":e.name,children:(0,C.jsxs)(`form`,{"data-testid":`mcp-install-modal`,"data-marketplace-id":e.id,onSubmit:e=>(e.preventDefault(),H(null),J?.kind===`shttp`||J?.kind===`sse`?ie():ae()),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`,children:[(0,C.jsx)(u.ModalCloseButton,{onClose:A,testId:`mcp-install-modal-close`,disabled:Y}),(0,C.jsxs)(`div`,{className:`flex items-start gap-3 pr-6`,children:[(0,C.jsx)(m.McpLogoBadge,{entry:e}),(0,C.jsxs)(`div`,{className:`flex flex-col flex-1`,children:[(0,C.jsx)(`h2`,{className:l.modalTitleLgClassName,children:e.name}),(0,C.jsx)(`p`,{className:`text-xs text-tertiary-light`,children:e.description})]})]}),e.installHint&&(0,C.jsx)(`p`,{className:`text-xs text-tertiary-light`,children:e.installHint}),e.docsUrl&&(0,C.jsx)(`a`,{href:e.docsUrl,target:`_blank`,rel:`noreferrer`,className:`text-xs text-[var(--oh-muted)] hover:text-white hover:underline self-start transition-colors`,children:M(n.I18nKey.MCP$VIEW_DOCS)}),(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:(()=>{if(J?.kind===`shttp`||J?.kind===`sse`){let e=E(q),t=T(q),r=q?D(q):!1,i=q?.auth.credentialSecretName,a=O(q);return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-url`,name:`url`,type:`url`,label:M(n.I18nKey.SETTINGS$MCP_URL),value:R.values.url??J.url,onChange:e=>X(`url`,e),isDisabled:!J.urlEditable,className:`w-full`}),R.errors.url&&(0,C.jsx)(`p`,{className:`text-xs text-red-500`,children:R.errors.url}),a.map(e=>(0,C.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:R.values[e.key]??``,onChange:t=>X(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,C.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:w(e.helperText)}),R.errors[e.key]&&(0,C.jsx)(`p`,{className:`text-xs text-red-500`,children:R.errors[e.key]}),e.key in R.savedAsSecret&&(0,C.jsx)(v.SaveAsSecretToggle,{fieldKey:e.key,checked:R.savedAsSecret[e.key]??!1,onToggle:t=>Z(e.key,t)})]},e.key)),e?(0,C.jsxs)(`div`,{"data-testid":`mcp-install-oauth-info`,className:`flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary`,children:[(0,C.jsx)(`p`,{className:`text-sm text-secondary-light`,children:M(n.I18nKey.MCP$OAUTH_CONNECT_INFO)}),(0,C.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:M(n.I18nKey.MCP$OAUTH_CONNECT_HINT)})]}):t?(0,C.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-api_key`,name:`api_key`,type:`password`,label:q?.auth.credentialLabel??M(n.I18nKey.SETTINGS$MCP_API_KEY),value:R.values.api_key??``,onChange:e=>X(`api_key`,e),placeholder:q?.auth.credentialPlaceholder??M(n.I18nKey.SETTINGS$MCP_API_KEY_PLACEHOLDER),showOptionalTag:r,required:!r,className:`w-full`}),q?.auth.credentialHelp&&(0,C.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:w(q.auth.credentialHelp)}),R.errors.api_key&&(0,C.jsx)(`p`,{className:`text-xs text-red-500`,children:R.errors.api_key}),i&&(0,C.jsx)(v.SaveAsSecretToggle,{fieldKey:i,checked:R.savedAsSecret.api_key??!1,onToggle:e=>Z(`api_key`,e)})]}):null]})}if(J?.kind!==`stdio`)return null;let e=J;return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-command-readonly`,name:`command-readonly`,type:`text`,label:M(n.I18nKey.MCP$COMMAND_LABEL),value:`${e.command} ${e.args.join(` `)}`.trim(),onChange:()=>{},isDisabled:!0,className:`w-full`}),(e.envFields??[]).map(e=>(0,C.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:R.values[e.key]??``,onChange:t=>X(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,C.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:w(e.helperText)}),R.errors[e.key]&&(0,C.jsx)(`p`,{className:`text-xs text-red-500`,children:R.errors[e.key]}),e.key in R.savedAsSecret&&(0,C.jsx)(v.SaveAsSecretToggle,{fieldKey:e.key,checked:R.savedAsSecret[e.key],onToggle:t=>Z(e.key,t)})]},e.key)),(e.argFields??[]).map(e=>(0,C.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,C.jsx)(f.SettingsInput,{testId:`mcp-install-field-${e.key}`,name:e.key,type:e.type===`password`?`password`:`text`,label:e.label,value:R.values[e.key]??``,onChange:t=>X(e.key,t),placeholder:e.placeholder,required:e.required,showOptionalTag:!e.required,className:`w-full`}),e.helperText&&(0,C.jsx)(`p`,{className:`text-xs text-tertiary-alt`,children:w(e.helperText)}),R.errors[e.key]&&(0,C.jsx)(`p`,{className:`text-xs text-red-500`,children:R.errors[e.key]})]},e.key))]})})()}),V&&(0,C.jsx)(`p`,{"data-testid":`mcp-install-modal-error`,className:`text-sm text-red-500 whitespace-pre-wrap`,children:V}),(0,C.jsxs)(`div`,{className:`flex justify-end gap-2 mt-2`,children:[(0,C.jsx)(d.BrandButton,{type:`button`,variant:`secondary`,onClick:A,testId:`mcp-install-cancel`,isDisabled:Y,children:M(n.I18nKey.BUTTON$CANCEL)}),(0,C.jsx)(d.BrandButton,{type:`submit`,variant:`primary`,isDisabled:Y,testId:`mcp-install-submit`,children:M(F||G?n.I18nKey.MCP$VERIFYING:P||U?n.I18nKey.SETTINGS$SAVING:n.I18nKey.MCP$INSTALL_BUTTON)})]})]})})}exports.InstallServerModal=k;
|
|
2
2
|
//# sourceMappingURL=install-server-modal.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-server-modal.cjs","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 type { MCPAuthCredential } from \"#/types/mcp-auth\";\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 getMcpOAuthAuthenticationConfig,\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\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\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\"].includes(option.auth.strategy);\n}\n\nfunction isOAuthOption(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n return !!option && option.auth.strategy === \"oauth2\";\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 getRemoteHeaderFields(\n option: McpMarketplaceConnectionOption | undefined,\n): MarketplaceField[] {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return [];\n }\n return option.transport.headerFields ?? [];\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 (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n values.url = template.url;\n for (const field of getRemoteHeaderFields(option)) {\n values[field.key] = \"\";\n savedAsSecret[field.key] = field.type === \"password\";\n }\n if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n if (option?.auth.credentialSecretName) {\n savedAsSecret.api_key =\n option.auth.saveCredentialAsSecretByDefault ?? false;\n }\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 [isAuthorizingOAuth, setIsAuthorizingOAuth] = React.useState(false);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending =\n isTesting || isAuthorizingOAuth || 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 Promise.all([\n saveHostedCredentialAsSecret(),\n saveFieldsAsSecrets(\n getRemoteHeaderFields(option),\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n ),\n ]).then(() => undefined);\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 if (payload.auth?.strategy === \"oauth2\") {\n setIsAuthorizingOAuth(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n if (!result.ok) {\n setGlobalError(makeTestErrorMessage(result));\n return;\n }\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\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 .catch((err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n })\n .finally(() => setIsAuthorizingOAuth(false));\n return;\n }\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 const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\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 url = template.urlEditable\n ? (state.values.url?.trim() ?? \"\")\n : template.url;\n const oauthMode = isOAuthOption(option);\n const needsCredential = optionNeedsCredentialField(option);\n const headerFields = getRemoteHeaderFields(option);\n const headerErrors: Record<string, string | null> = {};\n if (!url) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);\n } else {\n try {\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL);\n }\n } catch {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID);\n }\n }\n for (const field of headerFields) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n headerErrors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (\n !oauthMode &&\n needsCredential &&\n !isCredentialOptional(option) &&\n !apiKey\n ) {\n headerErrors.api_key = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n if (Object.values(headerErrors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors: headerErrors }));\n return;\n }\n const oauthAuthentication = oauthMode\n ? getMcpOAuthAuthenticationConfig(option)\n : undefined;\n const fieldHeaders = Object.fromEntries(\n headerFields\n .map((field) => [field.key, state.values[field.key]?.trim() ?? \"\"])\n .filter(([, value]) => value),\n );\n const hasFieldHeaders = Object.keys(fieldHeaders).length > 0;\n let auth: MCPAuthCredential | undefined;\n if (oauthMode) {\n auth = {\n strategy: \"oauth2\",\n ...(oauthAuthentication && { authentication: oauthAuthentication }),\n };\n } else if (needsCredential && apiKey) {\n auth =\n option.auth.strategy === \"api_key\"\n ? {\n strategy: \"api_key\",\n value: apiKey,\n ...(option.auth.apiKeyHeaderName && {\n header_name: option.auth.apiKeyHeaderName,\n }),\n }\n : { strategy: \"bearer\", value: apiKey };\n } else if (hasFieldHeaders) {\n auth = { strategy: \"header\", headers: fieldHeaders };\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n // Name remote servers after the catalog slug (e.g. \"github\") so they\n // get a referenceable, LLM-tool-safe mcp_config key instead of the\n // auto-generated \"sse\"/\"shttp\" fallback. Stdio installs already carry\n // serverName from the catalog.\n name: toMcpServerName(entry.id),\n url,\n ...(auth && { auth }),\n ...(hasFieldHeaders &&\n auth?.strategy !== \"header\" && { headers: fieldHeaders }),\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 oauthMode = isOAuthOption(option);\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n const credentialSecretName = option?.auth.credentialSecretName;\n const headerFields = getRemoteHeaderFields(option);\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={state.values.url ?? template.url}\n onChange={(value) => setValue(\"url\", value)}\n isDisabled={!template.urlEditable}\n className=\"w-full\"\n />\n {state.errors.url && (\n <p className=\"text-xs text-red-500\">{state.errors.url}</p>\n )}\n {headerFields.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\">\n {state.errors[field.key]}\n </p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key] ?? false}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {oauthMode ? (\n <div\n data-testid=\"mcp-install-oauth-info\"\n className=\"flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary\"\n >\n <p className=\"text-sm text-secondary-light\">\n {t(I18nKey.MCP$OAUTH_CONNECT_INFO)}\n </p>\n <p className=\"text-xs text-tertiary-alt\">\n {t(I18nKey.MCP$OAUTH_CONNECT_HINT)}\n </p>\n </div>\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 || isAuthorizingOAuth\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
|
+
{"version":3,"file":"install-server-modal.cjs","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 { MCPServerConfig } from \"#/types/mcp-server\";\nimport type { MCPAuthCredential } from \"#/types/mcp-auth\";\nimport { seedMcpServerHealth } from \"#/api/mcp-health/probe-mcp-server-health\";\nimport { useActiveBackend } from \"#/contexts/active-backend-context\";\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 getMcpOAuthAuthenticationConfig,\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 { makeMcpTestErrorMessage } from \"#/utils/mcp-test-error-message\";\nimport { modalTitleLgClassName } from \"#/utils/modal-classes\";\nimport McpService from \"#/api/mcp-service/mcp-service.api\";\nimport { toMcpServerName } from \"#/utils/mcp-server-name\";\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 /** Servers installed before this modal opened — guards health seeding. */\n existingServers: MCPServerConfig[];\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\"].includes(option.auth.strategy);\n}\n\nfunction isOAuthOption(\n option: McpMarketplaceConnectionOption | undefined,\n): boolean {\n return !!option && option.auth.strategy === \"oauth2\";\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 getRemoteHeaderFields(\n option: McpMarketplaceConnectionOption | undefined,\n): MarketplaceField[] {\n if (option?.transport.kind !== \"shttp\" && option?.transport.kind !== \"sse\") {\n return [];\n }\n return option.transport.headerFields ?? [];\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 (template?.kind === \"shttp\" || template?.kind === \"sse\") {\n values.url = template.url;\n for (const field of getRemoteHeaderFields(option)) {\n values[field.key] = \"\";\n savedAsSecret[field.key] = field.type === \"password\";\n }\n if (optionNeedsCredentialField(option)) {\n values.api_key = \"\";\n if (option?.auth.credentialSecretName) {\n savedAsSecret.api_key =\n option.auth.saveCredentialAsSecretByDefault ?? false;\n }\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 existingServers,\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 // Cloud backends get a synthetic test success (no local test endpoint);\n // never seed card health from it.\n const { backend } = useActiveBackend();\n const isCloudBackend = backend.kind === \"cloud\";\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 [isAuthorizingOAuth, setIsAuthorizingOAuth] = React.useState(false);\n const option = getInstallableMcpConnectionOption(entry);\n const template = option?.transport;\n\n const isPending =\n isTesting || isAuthorizingOAuth || 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 required: true,\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 Promise.all([\n saveHostedCredentialAsSecret(),\n saveFieldsAsSecrets(\n getRemoteHeaderFields(option),\n stateRef.current.values,\n stateRef.current.savedAsSecret,\n ),\n ]).then(() => undefined);\n }\n return Promise.resolve();\n };\n\n const submitServer = (payload: MCPServerConfig) => {\n if (payload.auth?.strategy === \"oauth2\") {\n setIsAuthorizingOAuth(true);\n void McpService.authorizeOAuth(payload)\n .then((result) => {\n if (!result.ok) {\n setGlobalError(\n makeMcpTestErrorMessage(t, result.error_kind, result.error),\n );\n return;\n }\n const serverToSave = result.oauth_state\n ? {\n ...payload,\n auth: { ...payload.auth!, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n if (!isCloudBackend) {\n seedMcpServerHealth(serverToSave, result, existingServers);\n }\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 .catch((err: unknown) => {\n const message = retrieveAxiosErrorMessage(err as AxiosError);\n setGlobalError(message || t(I18nKey.ERROR$GENERIC));\n })\n .finally(() => setIsAuthorizingOAuth(false));\n return;\n }\n testMcpServer(payload, {\n onSuccess: (result) => {\n if (!result.ok) {\n setGlobalError(\n makeMcpTestErrorMessage(t, result.error_kind, result.error),\n );\n // Modal stays open — do NOT call onClose.\n return;\n }\n const serverToSave =\n result.oauth_state && payload.auth?.strategy === \"oauth2\"\n ? {\n ...payload,\n auth: { ...payload.auth, state: result.oauth_state },\n }\n : payload;\n addMcpServer(serverToSave, {\n onSuccess: () => {\n if (!isCloudBackend) {\n seedMcpServerHealth(serverToSave, result, existingServers);\n }\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 url = template.urlEditable\n ? (state.values.url?.trim() ?? \"\")\n : template.url;\n const oauthMode = isOAuthOption(option);\n const needsCredential = optionNeedsCredentialField(option);\n const headerFields = getRemoteHeaderFields(option);\n const headerErrors: Record<string, string | null> = {};\n if (!url) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_REQUIRED);\n } else {\n try {\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID_PROTOCOL);\n }\n } catch {\n headerErrors.url = t(I18nKey.SETTINGS$MCP_ERROR_URL_INVALID);\n }\n }\n for (const field of headerFields) {\n if (field.required && !(state.values[field.key] ?? \"\").trim()) {\n headerErrors[field.key] = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n }\n if (\n !oauthMode &&\n needsCredential &&\n !isCredentialOptional(option) &&\n !apiKey\n ) {\n headerErrors.api_key = t(I18nKey.MCP$ERROR_FIELD_REQUIRED);\n }\n if (Object.values(headerErrors).some(Boolean)) {\n setState((prev) => ({ ...prev, errors: headerErrors }));\n return;\n }\n const oauthAuthentication = oauthMode\n ? getMcpOAuthAuthenticationConfig(option)\n : undefined;\n const fieldHeaders = Object.fromEntries(\n headerFields\n .map((field) => [field.key, state.values[field.key]?.trim() ?? \"\"])\n .filter(([, value]) => value),\n );\n const hasFieldHeaders = Object.keys(fieldHeaders).length > 0;\n let auth: MCPAuthCredential | undefined;\n if (oauthMode) {\n auth = {\n strategy: \"oauth2\",\n ...(oauthAuthentication && { authentication: oauthAuthentication }),\n };\n } else if (needsCredential && apiKey) {\n auth =\n option.auth.strategy === \"api_key\"\n ? {\n strategy: \"api_key\",\n value: apiKey,\n ...(option.auth.apiKeyHeaderName && {\n header_name: option.auth.apiKeyHeaderName,\n }),\n }\n : { strategy: \"bearer\", value: apiKey };\n } else if (hasFieldHeaders) {\n auth = { strategy: \"header\", headers: fieldHeaders };\n }\n const payload: MCPServerConfig = {\n id: `${template.kind}-${uuidv4()}`,\n type: template.kind,\n // Name remote servers after the catalog slug (e.g. \"github\") so they\n // get a referenceable, LLM-tool-safe mcp_config key instead of the\n // auto-generated \"sse\"/\"shttp\" fallback. Stdio installs already carry\n // serverName from the catalog.\n name: toMcpServerName(entry.id),\n url,\n ...(auth && { auth }),\n ...(hasFieldHeaders &&\n auth?.strategy !== \"header\" && { headers: fieldHeaders }),\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 oauthMode = isOAuthOption(option);\n const shouldRenderCredential = optionNeedsCredentialField(option);\n const apiKeyOptional = option ? isCredentialOptional(option) : false;\n const credentialSecretName = option?.auth.credentialSecretName;\n const headerFields = getRemoteHeaderFields(option);\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={state.values.url ?? template.url}\n onChange={(value) => setValue(\"url\", value)}\n isDisabled={!template.urlEditable}\n className=\"w-full\"\n />\n {state.errors.url && (\n <p className=\"text-xs text-red-500\">{state.errors.url}</p>\n )}\n {headerFields.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\">\n {state.errors[field.key]}\n </p>\n )}\n {field.key in state.savedAsSecret && (\n <SaveAsSecretToggle\n fieldKey={field.key}\n checked={state.savedAsSecret[field.key] ?? false}\n onToggle={(v) => toggleSecret(field.key, v)}\n />\n )}\n </div>\n ))}\n {oauthMode ? (\n <div\n data-testid=\"mcp-install-oauth-info\"\n className=\"flex flex-col gap-2 p-3 rounded-lg border border-[var(--oh-border)] bg-base-tertiary\"\n >\n <p className=\"text-sm text-secondary-light\">\n {t(I18nKey.MCP$OAUTH_CONNECT_INFO)}\n </p>\n <p className=\"text-xs text-tertiary-alt\">\n {t(I18nKey.MCP$OAUTH_CONNECT_HINT)}\n </p>\n </div>\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 || isAuthorizingOAuth\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,8 +1,11 @@
|
|
|
1
1
|
import type { IntegrationCatalogEntry as MarketplaceEntry } from "@openhands/extensions/integrations";
|
|
2
|
+
import { MCPServerConfig } from "#/types/mcp-server";
|
|
2
3
|
interface InstallServerModalProps {
|
|
3
4
|
entry: MarketplaceEntry;
|
|
5
|
+
/** Servers installed before this modal opened — guards health seeding. */
|
|
6
|
+
existingServers: MCPServerConfig[];
|
|
4
7
|
onClose: () => void;
|
|
5
8
|
onSuccess?: (entry: MarketplaceEntry) => void;
|
|
6
9
|
}
|
|
7
|
-
export declare function InstallServerModal({ entry, onClose, onSuccess, }: InstallServerModalProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function InstallServerModal({ entry, existingServers, onClose, onSuccess, }: InstallServerModalProps): import("react/jsx-runtime").JSX.Element;
|
|
8
11
|
export {};
|