@samanhappy/mcphub 1.0.43 → 1.0.44

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.
Files changed (57) hide show
  1. package/dist/controllers/oauthCallbackController.js +1 -1
  2. package/dist/controllers/oauthCallbackController.js.map +1 -1
  3. package/dist/services/mcpOAuthProvider.js +25 -0
  4. package/dist/services/mcpOAuthProvider.js.map +1 -1
  5. package/dist/services/mcpService.js +94 -10
  6. package/dist/services/mcpService.js.map +1 -1
  7. package/dist/services/oauthSettingsStore.js +5 -0
  8. package/dist/services/oauthSettingsStore.js.map +1 -1
  9. package/dist/services/requestContextService.js.map +1 -1
  10. package/dist/services/sseService.js +12 -1
  11. package/dist/services/sseService.js.map +1 -1
  12. package/frontend/dist/assets/{ActivityPage-Y8gIRxkd.js → ActivityPage-CW73GUD5.js} +2 -2
  13. package/frontend/dist/assets/{ActivityPage-Y8gIRxkd.js.map → ActivityPage-CW73GUD5.js.map} +1 -1
  14. package/frontend/dist/assets/{CopyClientConfigDialog-BHijFbyw.js → CopyClientConfigDialog-o6cE_gwR.js} +2 -2
  15. package/frontend/dist/assets/{CopyClientConfigDialog-BHijFbyw.js.map → CopyClientConfigDialog-o6cE_gwR.js.map} +1 -1
  16. package/frontend/dist/assets/{CredentialsPage-1UqVqEMQ.js → CredentialsPage-DtHT7dBz.js} +2 -2
  17. package/frontend/dist/assets/{CredentialsPage-1UqVqEMQ.js.map → CredentialsPage-DtHT7dBz.js.map} +1 -1
  18. package/frontend/dist/assets/{Dashboard-CswKNreX.js → Dashboard-BANagmEB.js} +2 -2
  19. package/frontend/dist/assets/{Dashboard-CswKNreX.js.map → Dashboard-BANagmEB.js.map} +1 -1
  20. package/frontend/dist/assets/{EndpointCopy-B0yIEBjO.js → EndpointCopy-DcF8AnZa.js} +2 -2
  21. package/frontend/dist/assets/{EndpointCopy-B0yIEBjO.js.map → EndpointCopy-DcF8AnZa.js.map} +1 -1
  22. package/frontend/dist/assets/{GroupsPage-KJJsAprG.js → GroupsPage-Dcsd8nze.js} +2 -2
  23. package/frontend/dist/assets/{GroupsPage-KJJsAprG.js.map → GroupsPage-Dcsd8nze.js.map} +1 -1
  24. package/frontend/dist/assets/{LoginPage-B1heSsJ6.js → LoginPage-DxvqW7Nv.js} +2 -2
  25. package/frontend/dist/assets/{LoginPage-B1heSsJ6.js.map → LoginPage-DxvqW7Nv.js.map} +1 -1
  26. package/frontend/dist/assets/{LogsPage-C4BOgOSW.js → LogsPage-DIAxm1E8.js} +2 -2
  27. package/frontend/dist/assets/{LogsPage-C4BOgOSW.js.map → LogsPage-DIAxm1E8.js.map} +1 -1
  28. package/frontend/dist/assets/{MarketPage-D0RXyf6g.js → MarketPage-JBz3na5T.js} +2 -2
  29. package/frontend/dist/assets/{MarketPage-D0RXyf6g.js.map → MarketPage-JBz3na5T.js.map} +1 -1
  30. package/frontend/dist/assets/{OAuthConsentPage-DLveAKh7.js → OAuthConsentPage-S5pynPb-.js} +2 -2
  31. package/frontend/dist/assets/{OAuthConsentPage-DLveAKh7.js.map → OAuthConsentPage-S5pynPb-.js.map} +1 -1
  32. package/frontend/dist/assets/{PromptsPage-cPHf4CM9.js → PromptsPage-D7CSJJ7D.js} +2 -2
  33. package/frontend/dist/assets/{PromptsPage-cPHf4CM9.js.map → PromptsPage-D7CSJJ7D.js.map} +1 -1
  34. package/frontend/dist/assets/{ResourcesPage-DcXEwXg9.js → ResourcesPage-Dha1wuaP.js} +2 -2
  35. package/frontend/dist/assets/{ResourcesPage-DcXEwXg9.js.map → ResourcesPage-Dha1wuaP.js.map} +1 -1
  36. package/frontend/dist/assets/{ServersPage-CIPZUbqT.js → ServersPage-DDyCg3F6.js} +4 -4
  37. package/frontend/dist/assets/{ServersPage-CIPZUbqT.js.map → ServersPage-DDyCg3F6.js.map} +1 -1
  38. package/frontend/dist/assets/{SettingsPage-vMxO3bOc.js → SettingsPage-i0qakyhB.js} +2 -2
  39. package/frontend/dist/assets/{SettingsPage-vMxO3bOc.js.map → SettingsPage-i0qakyhB.js.map} +1 -1
  40. package/frontend/dist/assets/{StatusDot-LGEKnAGN.js → StatusDot-D4PsbUse.js} +2 -2
  41. package/frontend/dist/assets/{StatusDot-LGEKnAGN.js.map → StatusDot-D4PsbUse.js.map} +1 -1
  42. package/frontend/dist/assets/{ToggleGroup-Ad_I2spO.js → ToggleGroup-DR2is5di.js} +2 -2
  43. package/frontend/dist/assets/{ToggleGroup-Ad_I2spO.js.map → ToggleGroup-DR2is5di.js.map} +1 -1
  44. package/frontend/dist/assets/{UsersPage-CbfajFCc.js → UsersPage-CfCbcfo8.js} +2 -2
  45. package/frontend/dist/assets/{UsersPage-CbfajFCc.js.map → UsersPage-CfCbcfo8.js.map} +1 -1
  46. package/frontend/dist/assets/{clipboard-CjtPOmJs.js → clipboard-D07Uwfz5.js} +2 -2
  47. package/frontend/dist/assets/{clipboard-CjtPOmJs.js.map → clipboard-D07Uwfz5.js.map} +1 -1
  48. package/frontend/dist/assets/{index-DJUr-vo3.js → index-DZZHe6u7.js} +3 -3
  49. package/frontend/dist/assets/{index-DJUr-vo3.js.map → index-DZZHe6u7.js.map} +1 -1
  50. package/frontend/dist/assets/{resourceService-D4dgqjzY.js → resourceService-bBf7W1JD.js} +2 -2
  51. package/frontend/dist/assets/{resourceService-D4dgqjzY.js.map → resourceService-bBf7W1JD.js.map} +1 -1
  52. package/frontend/dist/assets/{useCostData-CT2iwvzx.js → useCostData-CMKWXzc1.js} +2 -2
  53. package/frontend/dist/assets/{useCostData-CT2iwvzx.js.map → useCostData-CMKWXzc1.js.map} +1 -1
  54. package/frontend/dist/assets/{variableDetection-BHrhKDaj.js → variableDetection-R8Xv3uW7.js} +2 -2
  55. package/frontend/dist/assets/{variableDetection-BHrhKDaj.js.map → variableDetection-R8Xv3uW7.js.map} +1 -1
  56. package/frontend/dist/index.html +1 -1
  57. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CredentialsPage-1UqVqEMQ.js","sources":["../../src/pages/CredentialsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useSearchParams } from 'react-router-dom';\nimport type { MyCredentialBinding } from '../types';\nimport { apiDelete, apiGet, apiPut, type ApiResponse } from '../utils/fetchInterceptor';\n\nconst CredentialForm = ({\n binding,\n onChange,\n}: {\n binding: MyCredentialBinding;\n onChange: () => Promise<void>;\n}) => {\n const { t } = useTranslation();\n const [values, setValues] = useState<Record<string, string>>({});\n const [busy, setBusy] = useState(false);\n const [message, setMessage] = useState('');\n const save = async (remove: boolean) => {\n setBusy(true);\n setMessage('');\n try {\n const url = `/credentials/${encodeURIComponent(binding.serverName)}`;\n const result = remove\n ? await apiDelete<ApiResponse>(url)\n : await apiPut<ApiResponse>(url, { values });\n if (!result.success) throw new Error(result.message || t('credentials.failed'));\n setValues({});\n setMessage(t(remove ? 'credentials.deleted' : 'credentials.saved'));\n await onChange();\n } catch (error) {\n setMessage(error instanceof Error ? error.message : t('credentials.failed'));\n } finally {\n setBusy(false);\n }\n };\n return (\n <form\n className=\"hub-card p-5 space-y-4\"\n onSubmit={(event) => {\n event.preventDefault();\n void save(false);\n }}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"font-semibold\">{binding.serverName}</h2>\n <span className=\"hub-tag\">\n {t(binding.configured ? 'credentials.configured' : 'credentials.required')}\n </span>\n </div>\n <p className=\"text-sm text-[var(--hub-ink-3)]\">{t('credentials.writeOnly')}</p>\n {binding.credentialTemplate.map((slot) => {\n const id = `${slot.target}.${slot.name}`;\n return (\n <label key={id} className=\"block space-y-1 text-sm\">\n <span className=\"font-medium\">\n {slot.label || slot.name}{' '}\n <span className=\"hub-mono text-xs font-normal text-[var(--hub-ink-3)]\">({id})</span>\n </span>\n <input\n type=\"password\"\n required\n autoComplete=\"new-password\"\n maxLength={16384}\n value={values[id] || ''}\n placeholder={t(\n binding.configuredSlots.includes(id)\n ? 'credentials.replaceValue'\n : 'credentials.enterValue',\n )}\n className=\"hub-input\"\n onChange={(event) => setValues({ ...values, [id]: event.target.value })}\n />\n </label>\n );\n })}\n <div className=\"flex flex-wrap gap-2\">\n <button type=\"submit\" className=\"hub-btn primary\" disabled={busy}>\n {t('credentials.save')}\n </button>\n <button\n type=\"button\"\n className=\"hub-btn danger\"\n disabled={busy || !binding.updatedAt}\n onClick={() => void save(true)}\n >\n {t('credentials.delete')}\n </button>\n </div>\n {message && (\n <p role=\"status\" className=\"text-sm text-[var(--hub-ink-2)]\">\n {message}\n </p>\n )}\n </form>\n );\n};\n\nexport default function CredentialsPage() {\n const { t } = useTranslation();\n const [search, setSearch] = useSearchParams();\n const [bindings, setBindings] = useState<MyCredentialBinding[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const reload = useCallback(async () => {\n try {\n const result = await apiGet<ApiResponse<MyCredentialBinding[]>>('/credentials');\n if (!result.success) throw new Error(result.message || t('credentials.failed'));\n setBindings(result.data || []);\n setError('');\n } catch (error) {\n setError(error instanceof Error ? error.message : t('credentials.failed'));\n } finally {\n setLoading(false);\n }\n }, [t]);\n useEffect(() => {\n void reload();\n }, [reload]);\n const visible = bindings.filter(\n (binding) => !search.get('server') || binding.serverName === search.get('server'),\n );\n return (\n <div className=\"max-w-4xl mx-auto space-y-5\">\n <div>\n <h1 className=\"hub-h1\">{t('credentials.title')}</h1>\n <p className=\"hub-sub\">{t('credentials.description')}</p>\n </div>\n {search.has('server') && (\n <button className=\"hub-btn\" onClick={() => setSearch({})}>\n {t('credentials.showAll')}\n </button>\n )}\n {error && (\n <div className=\"hub-card px-4 py-3 text-sm\" style={{ color: 'var(--hub-err)' }} role=\"alert\">\n {error}\n </div>\n )}\n {loading ? (\n <div className=\"hub-card p-10 text-center text-sm\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('credentials.loading')}\n </div>\n ) : !visible.length && !error ? (\n <div className=\"hub-card p-10 text-center text-sm\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('credentials.empty')}\n </div>\n ) : null}\n {visible.map((binding) => (\n <CredentialForm key={binding.serverName} binding={binding} onChange={reload} />\n ))}\n </div>\n );\n}\n"],"names":["CredentialForm","binding","onChange","t","useTranslation","values","setValues","useState","busy","setBusy","message","setMessage","save","remove","url","result","apiDelete","apiPut","error","jsxs","event","jsx","slot","id","CredentialsPage","search","setSearch","useSearchParams","bindings","setBindings","loading","setLoading","setError","reload","useCallback","apiGet","useEffect","visible"],"mappings":"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"}
1
+ {"version":3,"file":"CredentialsPage-DtHT7dBz.js","sources":["../../src/pages/CredentialsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useSearchParams } from 'react-router-dom';\nimport type { MyCredentialBinding } from '../types';\nimport { apiDelete, apiGet, apiPut, type ApiResponse } from '../utils/fetchInterceptor';\n\nconst CredentialForm = ({\n binding,\n onChange,\n}: {\n binding: MyCredentialBinding;\n onChange: () => Promise<void>;\n}) => {\n const { t } = useTranslation();\n const [values, setValues] = useState<Record<string, string>>({});\n const [busy, setBusy] = useState(false);\n const [message, setMessage] = useState('');\n const save = async (remove: boolean) => {\n setBusy(true);\n setMessage('');\n try {\n const url = `/credentials/${encodeURIComponent(binding.serverName)}`;\n const result = remove\n ? await apiDelete<ApiResponse>(url)\n : await apiPut<ApiResponse>(url, { values });\n if (!result.success) throw new Error(result.message || t('credentials.failed'));\n setValues({});\n setMessage(t(remove ? 'credentials.deleted' : 'credentials.saved'));\n await onChange();\n } catch (error) {\n setMessage(error instanceof Error ? error.message : t('credentials.failed'));\n } finally {\n setBusy(false);\n }\n };\n return (\n <form\n className=\"hub-card p-5 space-y-4\"\n onSubmit={(event) => {\n event.preventDefault();\n void save(false);\n }}\n >\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"font-semibold\">{binding.serverName}</h2>\n <span className=\"hub-tag\">\n {t(binding.configured ? 'credentials.configured' : 'credentials.required')}\n </span>\n </div>\n <p className=\"text-sm text-[var(--hub-ink-3)]\">{t('credentials.writeOnly')}</p>\n {binding.credentialTemplate.map((slot) => {\n const id = `${slot.target}.${slot.name}`;\n return (\n <label key={id} className=\"block space-y-1 text-sm\">\n <span className=\"font-medium\">\n {slot.label || slot.name}{' '}\n <span className=\"hub-mono text-xs font-normal text-[var(--hub-ink-3)]\">({id})</span>\n </span>\n <input\n type=\"password\"\n required\n autoComplete=\"new-password\"\n maxLength={16384}\n value={values[id] || ''}\n placeholder={t(\n binding.configuredSlots.includes(id)\n ? 'credentials.replaceValue'\n : 'credentials.enterValue',\n )}\n className=\"hub-input\"\n onChange={(event) => setValues({ ...values, [id]: event.target.value })}\n />\n </label>\n );\n })}\n <div className=\"flex flex-wrap gap-2\">\n <button type=\"submit\" className=\"hub-btn primary\" disabled={busy}>\n {t('credentials.save')}\n </button>\n <button\n type=\"button\"\n className=\"hub-btn danger\"\n disabled={busy || !binding.updatedAt}\n onClick={() => void save(true)}\n >\n {t('credentials.delete')}\n </button>\n </div>\n {message && (\n <p role=\"status\" className=\"text-sm text-[var(--hub-ink-2)]\">\n {message}\n </p>\n )}\n </form>\n );\n};\n\nexport default function CredentialsPage() {\n const { t } = useTranslation();\n const [search, setSearch] = useSearchParams();\n const [bindings, setBindings] = useState<MyCredentialBinding[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const reload = useCallback(async () => {\n try {\n const result = await apiGet<ApiResponse<MyCredentialBinding[]>>('/credentials');\n if (!result.success) throw new Error(result.message || t('credentials.failed'));\n setBindings(result.data || []);\n setError('');\n } catch (error) {\n setError(error instanceof Error ? error.message : t('credentials.failed'));\n } finally {\n setLoading(false);\n }\n }, [t]);\n useEffect(() => {\n void reload();\n }, [reload]);\n const visible = bindings.filter(\n (binding) => !search.get('server') || binding.serverName === search.get('server'),\n );\n return (\n <div className=\"max-w-4xl mx-auto space-y-5\">\n <div>\n <h1 className=\"hub-h1\">{t('credentials.title')}</h1>\n <p className=\"hub-sub\">{t('credentials.description')}</p>\n </div>\n {search.has('server') && (\n <button className=\"hub-btn\" onClick={() => setSearch({})}>\n {t('credentials.showAll')}\n </button>\n )}\n {error && (\n <div className=\"hub-card px-4 py-3 text-sm\" style={{ color: 'var(--hub-err)' }} role=\"alert\">\n {error}\n </div>\n )}\n {loading ? (\n <div className=\"hub-card p-10 text-center text-sm\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('credentials.loading')}\n </div>\n ) : !visible.length && !error ? (\n <div className=\"hub-card p-10 text-center text-sm\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('credentials.empty')}\n </div>\n ) : null}\n {visible.map((binding) => (\n <CredentialForm key={binding.serverName} binding={binding} onChange={reload} />\n ))}\n </div>\n );\n}\n"],"names":["CredentialForm","binding","onChange","t","useTranslation","values","setValues","useState","busy","setBusy","message","setMessage","save","remove","url","result","apiDelete","apiPut","error","jsxs","event","jsx","slot","id","CredentialsPage","search","setSearch","useSearchParams","bindings","setBindings","loading","setLoading","setError","reload","useCallback","apiGet","useEffect","visible"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{d as $,R as u,r as p,j as e}from"./framework-vendor-_YL27Pfc.js";import{u as L,a as M}from"./useCostData-CT2iwvzx.js";import{d as P}from"./index-DJUr-vo3.js";import{u as A}from"./clipboard-CjtPOmJs.js";import{f as U}from"./contextCost-CilWqGWT.js";import{E as h}from"./EndpointCopy-B0yIEBjO.js";import{S as H}from"./StatusDot-LGEKnAGN.js";import{u as O}from"./i18n-vendor-BMaj5qV8.js";import{R as _,P as B,l as C,m as G}from"./icons-vendor-CvmEvkQ-.js";const i=({label:r,value:l,tone:a="default"})=>{const o=a==="ok"?"oklch(0.4 0.13 145)":a==="warn"?"oklch(0.45 0.13 80)":a==="err"?"oklch(0.45 0.18 25)":a==="muted"?"var(--hub-ink-3)":"var(--hub-ink)";return e.jsxs("div",{className:"hub-card",style:{padding:"14px 16px"},children:[e.jsx("div",{className:"text-[12px]",style:{color:"var(--hub-ink-3)"},children:r}),e.jsx("div",{className:"hub-num",style:{fontSize:26,fontWeight:500,letterSpacing:"-0.02em",lineHeight:1.1,marginTop:8,color:o},children:l})]})},w=(r,l)=>l?l==="stdio"?r("server.typeStdio")||"stdio":l==="sse"?r("server.typeSse")||"sse":l==="streamable-http"?r("server.typeStreamableHttp")||"http":l==="openapi"?r("server.typeOpenapi")||"openapi":l:null,Y=()=>{var k;const{t:r}=O(),l=$(),{allServers:a,error:o,setError:R,isLoading:b,triggerRefresh:z}=L({refreshOnMount:!0}),{groups:x}=P(),{installConfig:m}=A(),{serverCosts:v}=M(),[E,f]=u.useState(!1),g=u.useRef(!1);u.useEffect(()=>{if(b){g.current=!0;return}if(g.current){f(!0);return}(a.length>0||o)&&f(!0)},[b,a.length,o]);const t=p.useMemo(()=>({total:a.length,online:a.filter(s=>s.status==="connected").length,disabled:a.filter(s=>s.enabled===!1).length,offline:a.filter(s=>s.status==="disconnected"&&s.enabled!==!1).length,connecting:a.filter(s=>(s.status==="connecting"||s.status==="oauth_required")&&s.enabled!==!1).length,tools:a.reduce((s,n)=>{var c;return s+(((c=n.tools)==null?void 0:c.length)||0)},0)}),[a]),D=p.useMemo(()=>v.filter(s=>s.connected).reduce((s,n)=>s+n.exposed,0),[v]),T=p.useMemo(()=>a.slice(0,6),[a]),d=((k=m==null?void 0:m.baseUrl)==null?void 0:k.replace(/\/+$/,""))||"",j="minmax(220px,1.9fr) minmax(110px,0.95fr) minmax(120px,0.95fr) 80px 80px 90px 72px",N=!E;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:r("pages.dashboard.title")}),e.jsxs("p",{className:"hub-sub",children:[r("pages.dashboard.totalServers")," · ",e.jsx("span",{className:"hub-num",children:t.total})," · ",r("pages.dashboard.onlineServers")," · ",e.jsx("span",{className:"hub-num",children:t.online})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>z(),children:[e.jsx(_,{size:13})," ",r("common.refresh")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>l("/servers"),children:[e.jsx(B,{size:13})," ",r("server.add")]})]})]}),o&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-5",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(C,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:o})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>R(null),"aria-label":r("app.closeButton"),children:"✕"})]}),N?e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6",children:Array.from({length:6}).map((s,n)=>e.jsx("div",{className:"hub-card animate-pulse",style:{padding:"14px 16px",height:78}},n))}):e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6",children:[e.jsx(i,{label:r("pages.dashboard.totalServers"),value:t.total}),e.jsx(i,{label:r("pages.dashboard.onlineServers"),value:t.online,tone:"ok"}),e.jsx(i,{label:r("pages.dashboard.connectingServers"),value:t.connecting,tone:"warn"}),e.jsx(i,{label:r("pages.dashboard.offlineServers"),value:t.offline,tone:"err"}),e.jsx(i,{label:r("pages.dashboard.disabledServers"),value:t.disabled,tone:"muted"}),e.jsx(i,{label:r("cost.totalFootprint"),value:U(D)})]}),a.length>0&&!N&&e.jsxs("div",{className:"hub-card overflow-hidden mb-6",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",style:{borderBottom:"1px solid var(--hub-line-2)"},children:[e.jsx("h3",{className:"hub-card-title",children:r("pages.dashboard.recentServers")}),e.jsxs("button",{className:"hub-btn ghost sm",style:{color:"var(--hub-ink-3)"},onClick:()=>l("/servers"),children:[r("common.viewAll")||"View all",e.jsx(G,{size:12})]})]}),e.jsxs("div",{className:"hub-row head hub-mono",style:{gridTemplateColumns:j},children:[e.jsx("div",{children:r("server.name")}),e.jsx("div",{children:r("server.status")}),e.jsx("div",{children:r("common.type")||"Transport"}),e.jsx("div",{children:r("server.tools")}),e.jsx("div",{children:r("server.prompts")}),e.jsx("div",{children:r("nav.resources")}),e.jsx("div",{children:r("server.enabled")})]}),T.map(s=>{var n,c,S,y;return e.jsxs("div",{className:"hub-row hover cursor-pointer",style:{gridTemplateColumns:j},onClick:()=>l("/servers"),children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("span",{className:"hub-mono truncate",style:{fontSize:13,color:s.enabled===!1?"var(--hub-ink-3)":"var(--hub-ink)"},children:s.name}),s.error&&e.jsx(C,{size:13,className:"text-[var(--hub-err)] flex-shrink-0"})]}),e.jsx("div",{className:"min-w-0",children:e.jsx(H,{status:s.status,enabled:s.enabled})}),e.jsx("div",{className:"min-w-0",children:(n=s.config)!=null&&n.type?e.jsx("span",{className:"hub-tag",title:w(r,s.config.type)??void 0,children:w(r,s.config.type)}):e.jsx("span",{style:{color:"var(--hub-ink-3)",fontSize:12},children:"—"})}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5},children:((c=s.tools)==null?void 0:c.length)||0}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5,color:"var(--hub-ink-2)"},children:((S=s.prompts)==null?void 0:S.length)||0}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5,color:"var(--hub-ink-2)"},children:((y=s.resources)==null?void 0:y.length)||0}),e.jsx("div",{className:"text-[12px]",style:{color:s.enabled!==!1?"var(--hub-ok)":"var(--hub-ink-3)"},children:s.enabled!==!1?"✓":"—"})]},s.name)})]}),e.jsxs("div",{className:"hub-card mb-5",style:{padding:16},children:[e.jsxs("div",{className:"flex justify-between items-start gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"hub-card-title",children:r("pages.dashboard.endpoints")||"MCP Endpoints"}),e.jsx("p",{className:"hub-sub",style:{marginTop:2},children:r("pages.dashboard.endpointsHint")||"Use these URLs in Claude Desktop, Cursor, or any MCP client"})]}),e.jsxs("a",{className:"hub-btn ghost",href:"https://docs.mcphub.app",target:"_blank",rel:"noopener noreferrer",style:{color:"var(--hub-ink-3)"},children:[r("common.docs")||"Docs"," →"]})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-2.5",children:[e.jsx(h,{label:"ALL",url:`${d}/mcp`}),e.jsx(h,{label:"SMART",url:`${d}/mcp/$smart`}),x.slice(0,2).map(s=>e.jsx(h,{label:"GROUP",url:`${d}/mcp/${s.name}`},s.id)),x.length<2&&a[0]&&e.jsx(h,{label:"SERVER",url:`${d}/mcp/${a[0].name}`})]})]})]})};export{Y as default};
2
- //# sourceMappingURL=Dashboard-CswKNreX.js.map
1
+ import{d as $,R as u,r as p,j as e}from"./framework-vendor-_YL27Pfc.js";import{u as L,a as M}from"./useCostData-CMKWXzc1.js";import{d as P}from"./index-DZZHe6u7.js";import{u as A}from"./clipboard-D07Uwfz5.js";import{f as U}from"./contextCost-CilWqGWT.js";import{E as h}from"./EndpointCopy-DcF8AnZa.js";import{S as H}from"./StatusDot-D4PsbUse.js";import{u as O}from"./i18n-vendor-BMaj5qV8.js";import{R as _,P as B,l as C,m as G}from"./icons-vendor-CvmEvkQ-.js";const i=({label:r,value:l,tone:a="default"})=>{const o=a==="ok"?"oklch(0.4 0.13 145)":a==="warn"?"oklch(0.45 0.13 80)":a==="err"?"oklch(0.45 0.18 25)":a==="muted"?"var(--hub-ink-3)":"var(--hub-ink)";return e.jsxs("div",{className:"hub-card",style:{padding:"14px 16px"},children:[e.jsx("div",{className:"text-[12px]",style:{color:"var(--hub-ink-3)"},children:r}),e.jsx("div",{className:"hub-num",style:{fontSize:26,fontWeight:500,letterSpacing:"-0.02em",lineHeight:1.1,marginTop:8,color:o},children:l})]})},w=(r,l)=>l?l==="stdio"?r("server.typeStdio")||"stdio":l==="sse"?r("server.typeSse")||"sse":l==="streamable-http"?r("server.typeStreamableHttp")||"http":l==="openapi"?r("server.typeOpenapi")||"openapi":l:null,Y=()=>{var k;const{t:r}=O(),l=$(),{allServers:a,error:o,setError:R,isLoading:b,triggerRefresh:z}=L({refreshOnMount:!0}),{groups:x}=P(),{installConfig:m}=A(),{serverCosts:v}=M(),[E,f]=u.useState(!1),g=u.useRef(!1);u.useEffect(()=>{if(b){g.current=!0;return}if(g.current){f(!0);return}(a.length>0||o)&&f(!0)},[b,a.length,o]);const t=p.useMemo(()=>({total:a.length,online:a.filter(s=>s.status==="connected").length,disabled:a.filter(s=>s.enabled===!1).length,offline:a.filter(s=>s.status==="disconnected"&&s.enabled!==!1).length,connecting:a.filter(s=>(s.status==="connecting"||s.status==="oauth_required")&&s.enabled!==!1).length,tools:a.reduce((s,n)=>{var c;return s+(((c=n.tools)==null?void 0:c.length)||0)},0)}),[a]),D=p.useMemo(()=>v.filter(s=>s.connected).reduce((s,n)=>s+n.exposed,0),[v]),T=p.useMemo(()=>a.slice(0,6),[a]),d=((k=m==null?void 0:m.baseUrl)==null?void 0:k.replace(/\/+$/,""))||"",j="minmax(220px,1.9fr) minmax(110px,0.95fr) minmax(120px,0.95fr) 80px 80px 90px 72px",N=!E;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:r("pages.dashboard.title")}),e.jsxs("p",{className:"hub-sub",children:[r("pages.dashboard.totalServers")," · ",e.jsx("span",{className:"hub-num",children:t.total})," · ",r("pages.dashboard.onlineServers")," · ",e.jsx("span",{className:"hub-num",children:t.online})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>z(),children:[e.jsx(_,{size:13})," ",r("common.refresh")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>l("/servers"),children:[e.jsx(B,{size:13})," ",r("server.add")]})]})]}),o&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-5",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(C,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:o})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>R(null),"aria-label":r("app.closeButton"),children:"✕"})]}),N?e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6",children:Array.from({length:6}).map((s,n)=>e.jsx("div",{className:"hub-card animate-pulse",style:{padding:"14px 16px",height:78}},n))}):e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6",children:[e.jsx(i,{label:r("pages.dashboard.totalServers"),value:t.total}),e.jsx(i,{label:r("pages.dashboard.onlineServers"),value:t.online,tone:"ok"}),e.jsx(i,{label:r("pages.dashboard.connectingServers"),value:t.connecting,tone:"warn"}),e.jsx(i,{label:r("pages.dashboard.offlineServers"),value:t.offline,tone:"err"}),e.jsx(i,{label:r("pages.dashboard.disabledServers"),value:t.disabled,tone:"muted"}),e.jsx(i,{label:r("cost.totalFootprint"),value:U(D)})]}),a.length>0&&!N&&e.jsxs("div",{className:"hub-card overflow-hidden mb-6",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",style:{borderBottom:"1px solid var(--hub-line-2)"},children:[e.jsx("h3",{className:"hub-card-title",children:r("pages.dashboard.recentServers")}),e.jsxs("button",{className:"hub-btn ghost sm",style:{color:"var(--hub-ink-3)"},onClick:()=>l("/servers"),children:[r("common.viewAll")||"View all",e.jsx(G,{size:12})]})]}),e.jsxs("div",{className:"hub-row head hub-mono",style:{gridTemplateColumns:j},children:[e.jsx("div",{children:r("server.name")}),e.jsx("div",{children:r("server.status")}),e.jsx("div",{children:r("common.type")||"Transport"}),e.jsx("div",{children:r("server.tools")}),e.jsx("div",{children:r("server.prompts")}),e.jsx("div",{children:r("nav.resources")}),e.jsx("div",{children:r("server.enabled")})]}),T.map(s=>{var n,c,S,y;return e.jsxs("div",{className:"hub-row hover cursor-pointer",style:{gridTemplateColumns:j},onClick:()=>l("/servers"),children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("span",{className:"hub-mono truncate",style:{fontSize:13,color:s.enabled===!1?"var(--hub-ink-3)":"var(--hub-ink)"},children:s.name}),s.error&&e.jsx(C,{size:13,className:"text-[var(--hub-err)] flex-shrink-0"})]}),e.jsx("div",{className:"min-w-0",children:e.jsx(H,{status:s.status,enabled:s.enabled})}),e.jsx("div",{className:"min-w-0",children:(n=s.config)!=null&&n.type?e.jsx("span",{className:"hub-tag",title:w(r,s.config.type)??void 0,children:w(r,s.config.type)}):e.jsx("span",{style:{color:"var(--hub-ink-3)",fontSize:12},children:"—"})}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5},children:((c=s.tools)==null?void 0:c.length)||0}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5,color:"var(--hub-ink-2)"},children:((S=s.prompts)==null?void 0:S.length)||0}),e.jsx("div",{className:"hub-num hub-mono",style:{fontSize:12.5,color:"var(--hub-ink-2)"},children:((y=s.resources)==null?void 0:y.length)||0}),e.jsx("div",{className:"text-[12px]",style:{color:s.enabled!==!1?"var(--hub-ok)":"var(--hub-ink-3)"},children:s.enabled!==!1?"✓":"—"})]},s.name)})]}),e.jsxs("div",{className:"hub-card mb-5",style:{padding:16},children:[e.jsxs("div",{className:"flex justify-between items-start gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"hub-card-title",children:r("pages.dashboard.endpoints")||"MCP Endpoints"}),e.jsx("p",{className:"hub-sub",style:{marginTop:2},children:r("pages.dashboard.endpointsHint")||"Use these URLs in Claude Desktop, Cursor, or any MCP client"})]}),e.jsxs("a",{className:"hub-btn ghost",href:"https://docs.mcphub.app",target:"_blank",rel:"noopener noreferrer",style:{color:"var(--hub-ink-3)"},children:[r("common.docs")||"Docs"," →"]})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-2.5",children:[e.jsx(h,{label:"ALL",url:`${d}/mcp`}),e.jsx(h,{label:"SMART",url:`${d}/mcp/$smart`}),x.slice(0,2).map(s=>e.jsx(h,{label:"GROUP",url:`${d}/mcp/${s.name}`},s.id)),x.length<2&&a[0]&&e.jsx(h,{label:"SERVER",url:`${d}/mcp/${a[0].name}`})]})]})]})};export{Y as default};
2
+ //# sourceMappingURL=Dashboard-BANagmEB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dashboard-CswKNreX.js","sources":["../../src/pages/Dashboard.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router-dom';\nimport { RefreshCw, Plus, ChevronRight, AlertCircle } from 'lucide-react';\nimport { useServerData } from '@/hooks/useServerData';\nimport { useGroupData } from '@/hooks/useGroupData';\nimport { useSettingsData } from '@/hooks/useSettingsData';\nimport { useCostData } from '@/hooks/useCostData';\nimport { formatTokens } from '@/utils/contextCost';\nimport { Server } from '@/types';\nimport { EndpointCopy } from '@/components/ui/EndpointCopy';\nimport { ServerStatusDot } from '@/components/ui/StatusDot';\n\nconst Stat: React.FC<{ label: string; value: React.ReactNode; tone?: 'ok' | 'warn' | 'err' | 'muted' | 'default' }> = ({\n label,\n value,\n tone = 'default',\n}) => {\n const toneColor =\n tone === 'ok'\n ? 'oklch(0.4 0.13 145)'\n : tone === 'warn'\n ? 'oklch(0.45 0.13 80)'\n : tone === 'err'\n ? 'oklch(0.45 0.18 25)'\n : tone === 'muted'\n ? 'var(--hub-ink-3)'\n : 'var(--hub-ink)';\n return (\n <div className=\"hub-card\" style={{ padding: '14px 16px' }}>\n <div className=\"text-[12px]\" style={{ color: 'var(--hub-ink-3)' }}>\n {label}\n </div>\n <div\n className=\"hub-num\"\n style={{\n fontSize: 26,\n fontWeight: 500,\n letterSpacing: '-0.02em',\n lineHeight: 1.1,\n marginTop: 8,\n color: toneColor,\n }}\n >\n {value}\n </div>\n </div>\n );\n};\n\nconst transportLabel = (t: any, type?: string) => {\n if (!type) return null;\n if (type === 'stdio') return t('server.typeStdio') || 'stdio';\n if (type === 'sse') return t('server.typeSse') || 'sse';\n if (type === 'streamable-http') return t('server.typeStreamableHttp') || 'http';\n if (type === 'openapi') return t('server.typeOpenapi') || 'openapi';\n return type;\n};\n\nconst DashboardPage: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { allServers, error, setError, isLoading, triggerRefresh } = useServerData({\n refreshOnMount: true,\n });\n const { groups } = useGroupData();\n const { installConfig } = useSettingsData();\n const { serverCosts } = useCostData();\n\n const [hasLoaded, setHasLoaded] = React.useState(false);\n const loadingStartedRef = React.useRef(false);\n React.useEffect(() => {\n if (isLoading) {\n loadingStartedRef.current = true;\n return;\n }\n if (loadingStartedRef.current) {\n setHasLoaded(true);\n return;\n }\n if (allServers.length > 0 || error) setHasLoaded(true);\n }, [isLoading, allServers.length, error]);\n\n const stats = useMemo(\n () => ({\n total: allServers.length,\n online: allServers.filter((s: Server) => s.status === 'connected').length,\n disabled: allServers.filter((s: Server) => s.enabled === false).length,\n offline: allServers.filter(\n (s: Server) => s.status === 'disconnected' && s.enabled !== false,\n ).length,\n connecting: allServers.filter(\n (s: Server) =>\n (s.status === 'connecting' || s.status === 'oauth_required') && s.enabled !== false,\n ).length,\n tools: allServers.reduce((acc, s) => acc + (s.tools?.length || 0), 0),\n }),\n [allServers],\n );\n\n const footprint = useMemo(\n () => serverCosts.filter((c) => c.connected).reduce((acc, c) => acc + c.exposed, 0),\n [serverCosts],\n );\n\n const recentServers = useMemo(() => allServers.slice(0, 6), [allServers]);\n const baseUrl = installConfig?.baseUrl?.replace(/\\/+$/, '') || '';\n const recentServerColumns =\n 'minmax(220px,1.9fr) minmax(110px,0.95fr) minmax(120px,0.95fr) 80px 80px 90px 72px';\n\n const showSkeleton = !hasLoaded;\n\n return (\n <div>\n {/* Header */}\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.dashboard.title')}</h1>\n <p className=\"hub-sub\">\n {t('pages.dashboard.totalServers')} · <span className=\"hub-num\">{stats.total}</span>\n {' · '}\n {t('pages.dashboard.onlineServers')} · <span className=\"hub-num\">{stats.online}</span>\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button className=\"hub-btn\" onClick={() => triggerRefresh()}>\n <RefreshCw size={13} /> {t('common.refresh')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => navigate('/servers')}>\n <Plus size={13} /> {t('server.add')}\n </button>\n </div>\n </div>\n\n {error && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-5\"\n style={{\n padding: '10px 14px',\n borderColor: 'oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n }}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n <span className=\"truncate text-[13px]\">{error}</span>\n </div>\n <button\n className=\"hub-icon-btn sm\"\n onClick={() => setError(null)}\n aria-label={t('app.closeButton')}\n >\n ✕\n </button>\n </div>\n )}\n\n {/* Stat row */}\n {showSkeleton ? (\n <div className=\"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div\n key={i}\n className=\"hub-card animate-pulse\"\n style={{ padding: '14px 16px', height: 78 }}\n />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6\">\n <Stat label={t('pages.dashboard.totalServers')} value={stats.total} />\n <Stat label={t('pages.dashboard.onlineServers')} value={stats.online} tone=\"ok\" />\n <Stat label={t('pages.dashboard.connectingServers')} value={stats.connecting} tone=\"warn\" />\n <Stat label={t('pages.dashboard.offlineServers')} value={stats.offline} tone=\"err\" />\n <Stat label={t('pages.dashboard.disabledServers')} value={stats.disabled} tone=\"muted\" />\n <Stat label={t('cost.totalFootprint')} value={formatTokens(footprint)} />\n </div>\n )}\n\n {/* Recent servers */}\n {allServers.length > 0 && !showSkeleton && (\n <div className=\"hub-card overflow-hidden mb-6\">\n <div\n className=\"flex items-center justify-between px-4 py-3\"\n style={{ borderBottom: '1px solid var(--hub-line-2)' }}\n >\n <h3 className=\"hub-card-title\">{t('pages.dashboard.recentServers')}</h3>\n <button\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-ink-3)' }}\n onClick={() => navigate('/servers')}\n >\n {t('common.viewAll') || 'View all'}\n <ChevronRight size={12} />\n </button>\n </div>\n <div\n className=\"hub-row head hub-mono\"\n style={{ gridTemplateColumns: recentServerColumns }}\n >\n <div>{t('server.name')}</div>\n <div>{t('server.status')}</div>\n <div>{t('common.type') || 'Transport'}</div>\n <div>{t('server.tools')}</div>\n <div>{t('server.prompts')}</div>\n <div>{t('nav.resources')}</div>\n <div>{t('server.enabled')}</div>\n </div>\n {recentServers.map((s) => (\n <div\n key={s.name}\n className=\"hub-row hover cursor-pointer\"\n style={{ gridTemplateColumns: recentServerColumns }}\n onClick={() => navigate('/servers')}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span\n className=\"hub-mono truncate\"\n style={{ fontSize: 13, color: s.enabled === false ? 'var(--hub-ink-3)' : 'var(--hub-ink)' }}\n >\n {s.name}\n </span>\n {s.error && <AlertCircle size={13} className=\"text-[var(--hub-err)] flex-shrink-0\" />}\n </div>\n <div className=\"min-w-0\">\n <ServerStatusDot status={s.status} enabled={s.enabled} />\n </div>\n <div className=\"min-w-0\">\n {s.config?.type ? (\n <span className=\"hub-tag\" title={transportLabel(t, s.config.type) ?? undefined}>\n {transportLabel(t, s.config.type)}\n </span>\n ) : (\n <span style={{ color: 'var(--hub-ink-3)', fontSize: 12 }}>—</span>\n )}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5 }}>\n {s.tools?.length || 0}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5, color: 'var(--hub-ink-2)' }}>\n {s.prompts?.length || 0}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5, color: 'var(--hub-ink-2)' }}>\n {s.resources?.length || 0}\n </div>\n <div className=\"text-[12px]\" style={{ color: s.enabled !== false ? 'var(--hub-ok)' : 'var(--hub-ink-3)' }}>\n {s.enabled !== false ? '✓' : '—'}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Endpoint quick-access */}\n <div className=\"hub-card mb-5\" style={{ padding: 16 }}>\n <div className=\"flex justify-between items-start gap-3 mb-3\">\n <div>\n <h3 className=\"hub-card-title\">{t('pages.dashboard.endpoints') || 'MCP Endpoints'}</h3>\n <p className=\"hub-sub\" style={{ marginTop: 2 }}>\n {t('pages.dashboard.endpointsHint') ||\n 'Use these URLs in Claude Desktop, Cursor, or any MCP client'}\n </p>\n </div>\n <a\n className=\"hub-btn ghost\"\n href=\"https://docs.mcphub.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ color: 'var(--hub-ink-3)' }}\n >\n {t('common.docs') || 'Docs'} →\n </a>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-2.5\">\n <EndpointCopy label=\"ALL\" url={`${baseUrl}/mcp`} />\n <EndpointCopy label=\"SMART\" url={`${baseUrl}/mcp/$smart`} />\n {groups.slice(0, 2).map((g) => (\n <EndpointCopy key={g.id} label=\"GROUP\" url={`${baseUrl}/mcp/${g.name}`} />\n ))}\n {/* Pad with first server endpoint if there's space */}\n {groups.length < 2 && allServers[0] && (\n <EndpointCopy label=\"SERVER\" url={`${baseUrl}/mcp/${allServers[0].name}`} />\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default DashboardPage;\n"],"names":["Stat","label","value","tone","toneColor","jsxs","jsx","transportLabel","t","type","DashboardPage","useTranslation","navigate","useNavigate","allServers","error","setError","isLoading","triggerRefresh","useServerData","groups","useGroupData","installConfig","useSettingsData","serverCosts","useCostData","hasLoaded","setHasLoaded","React","loadingStartedRef","stats","useMemo","acc","s","_a","footprint","c","recentServers","baseUrl","recentServerColumns","showSkeleton","RefreshCw","Plus","AlertCircle","_","i","formatTokens","ChevronRight","ServerStatusDot","_b","_c","_d","EndpointCopy","g"],"mappings":"4cAaA,MAAMA,EAAgH,CAAC,CACrH,MAAAC,EACA,MAAAC,EACA,KAAAC,EAAO,SACT,IAAM,CACJ,MAAMC,EACJD,IAAS,KACL,sBACAA,IAAS,OACP,sBACAA,IAAS,MACP,sBACAA,IAAS,QACP,mBACA,iBACZ,OACEE,EAAAA,KAAC,OAAI,UAAU,WAAW,MAAO,CAAE,QAAS,aAC1C,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAI,UAAU,cAAc,MAAO,CAAE,MAAO,kBAAA,EAC1C,SAAAL,CAAA,CACH,EACAK,EAAAA,IAAC,MAAA,CACC,UAAU,UACV,MAAO,CACL,SAAU,GACV,WAAY,IACZ,cAAe,UACf,WAAY,IACZ,UAAW,EACX,MAAOF,CAAA,EAGR,SAAAF,CAAA,CAAA,CACH,EACF,CAEJ,EAEMK,EAAiB,CAACC,EAAQC,IACzBA,EACDA,IAAS,QAAgBD,EAAE,kBAAkB,GAAK,QAClDC,IAAS,MAAcD,EAAE,gBAAgB,GAAK,MAC9CC,IAAS,kBAA0BD,EAAE,2BAA2B,GAAK,OACrEC,IAAS,UAAkBD,EAAE,oBAAoB,GAAK,UACnDC,EALW,KAQdC,EAA0B,IAAM,OACpC,KAAM,CAAE,EAAAF,CAAA,EAAMG,EAAA,EACRC,EAAWC,EAAA,EACX,CAAE,WAAAC,EAAY,MAAAC,EAAO,SAAAC,EAAU,UAAAC,EAAW,eAAAC,CAAA,EAAmBC,EAAc,CAC/E,eAAgB,EAAA,CACjB,EACK,CAAE,OAAAC,CAAA,EAAWC,EAAA,EACb,CAAE,cAAAC,CAAA,EAAkBC,EAAA,EACpB,CAAE,YAAAC,CAAA,EAAgBC,EAAA,EAElB,CAACC,EAAWC,CAAY,EAAIC,EAAM,SAAS,EAAK,EAChDC,EAAoBD,EAAM,OAAO,EAAK,EAC5CA,EAAM,UAAU,IAAM,CACpB,GAAIX,EAAW,CACbY,EAAkB,QAAU,GAC5B,MACF,CACA,GAAIA,EAAkB,QAAS,CAC7BF,EAAa,EAAI,EACjB,MACF,EACIb,EAAW,OAAS,GAAKC,MAAoB,EAAI,CACvD,EAAG,CAACE,EAAWH,EAAW,OAAQC,CAAK,CAAC,EAExC,MAAMe,EAAQC,EAAAA,QACZ,KAAO,CACL,MAAOjB,EAAW,OAClB,OAAQA,EAAW,OAAQ,GAAc,EAAE,SAAW,WAAW,EAAE,OACnE,SAAUA,EAAW,OAAQ,GAAc,EAAE,UAAY,EAAK,EAAE,OAChE,QAASA,EAAW,OACjB,GAAc,EAAE,SAAW,gBAAkB,EAAE,UAAY,EAAA,EAC5D,OACF,WAAYA,EAAW,OACpB,IACE,EAAE,SAAW,cAAgB,EAAE,SAAW,mBAAqB,EAAE,UAAY,EAAA,EAChF,OACF,MAAOA,EAAW,OAAO,CAACkB,EAAKC,IAAA,OAAM,OAAAD,KAAOE,EAAAD,EAAE,QAAF,YAAAC,EAAS,SAAU,IAAI,CAAC,CAAA,GAEtE,CAACpB,CAAU,CAAA,EAGPqB,EAAYJ,EAAAA,QAChB,IAAMP,EAAY,OAAQY,GAAMA,EAAE,SAAS,EAAE,OAAO,CAACJ,EAAKI,IAAMJ,EAAMI,EAAE,QAAS,CAAC,EAClF,CAACZ,CAAW,CAAA,EAGRa,EAAgBN,UAAQ,IAAMjB,EAAW,MAAM,EAAG,CAAC,EAAG,CAACA,CAAU,CAAC,EAClEwB,IAAUJ,EAAAZ,GAAA,YAAAA,EAAe,UAAf,YAAAY,EAAwB,QAAQ,OAAQ,MAAO,GACzDK,EACJ,oFAEIC,EAAe,CAACd,EAEtB,cACG,MAAA,CAEC,SAAA,CAAArB,EAAAA,KAAC,MAAA,CAAI,UAAU,4CACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,MAAC,KAAA,CAAG,UAAU,SAAU,SAAAE,EAAE,uBAAuB,EAAE,EACnDH,EAAAA,KAAC,IAAA,CAAE,UAAU,UACV,SAAA,CAAAG,EAAE,8BAA8B,EAAE,MAAGF,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAW,WAAM,MAAM,EAC5E,QACAE,EAAE,+BAA+B,EAAE,MAAGF,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAW,WAAM,MAAA,CAAO,CAAA,CAAA,CACjF,CAAA,EACF,EACAD,EAAAA,KAAC,MAAA,CAAI,UAAU,aACb,SAAA,CAAAA,OAAC,UAAO,UAAU,UAAU,QAAS,IAAMa,IACzC,SAAA,CAAAZ,EAAAA,IAACmC,EAAA,CAAU,KAAM,EAAA,CAAI,EAAE,IAAEjC,EAAE,gBAAgB,CAAA,EAC7C,EACAH,OAAC,UAAO,UAAU,kBAAkB,QAAS,IAAMO,EAAS,UAAU,EACpE,SAAA,CAAAN,EAAAA,IAACoC,EAAA,CAAK,KAAM,EAAA,CAAI,EAAE,IAAElC,EAAE,YAAY,CAAA,CAAA,CACpC,CAAA,CAAA,CACF,CAAA,EACF,EAECO,GACCV,EAAAA,KAAC,MAAA,CACC,UAAU,wDACV,MAAO,CACL,QAAS,YACT,YAAa,qBACb,WAAY,sBACZ,MAAO,oBAAA,EAGT,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAC,EAAAA,IAACqC,EAAA,CAAY,KAAM,GAAI,UAAU,gBAAgB,EACjDrC,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAwB,SAAAS,CAAA,CAAM,CAAA,EAChD,EACAT,EAAAA,IAAC,SAAA,CACC,UAAU,kBACV,QAAS,IAAMU,EAAS,IAAI,EAC5B,aAAYR,EAAE,iBAAiB,EAChC,SAAA,GAAA,CAAA,CAED,CAAA,CAAA,EAKHgC,EACClC,EAAAA,IAAC,MAAA,CAAI,UAAU,6CACZ,SAAA,MAAM,KAAK,CAAE,OAAQ,EAAG,EAAE,IAAI,CAACsC,EAAGC,IACjCvC,EAAAA,IAAC,MAAA,CAEC,UAAU,yBACV,MAAO,CAAE,QAAS,YAAa,OAAQ,EAAA,CAAG,EAFrCuC,CAAA,CAIR,CAAA,CACH,EAEAxC,OAAC,MAAA,CAAI,UAAU,6CACb,SAAA,CAAAC,MAACN,GAAK,MAAOQ,EAAE,8BAA8B,EAAG,MAAOsB,EAAM,MAAO,EACpExB,EAAAA,IAACN,EAAA,CAAK,MAAOQ,EAAE,+BAA+B,EAAG,MAAOsB,EAAM,OAAQ,KAAK,IAAA,CAAK,EAChFxB,EAAAA,IAACN,EAAA,CAAK,MAAOQ,EAAE,mCAAmC,EAAG,MAAOsB,EAAM,WAAY,KAAK,MAAA,CAAO,EAC1FxB,EAAAA,IAACN,EAAA,CAAK,MAAOQ,EAAE,gCAAgC,EAAG,MAAOsB,EAAM,QAAS,KAAK,KAAA,CAAM,EACnFxB,EAAAA,IAACN,EAAA,CAAK,MAAOQ,EAAE,iCAAiC,EAAG,MAAOsB,EAAM,SAAU,KAAK,OAAA,CAAQ,EACvFxB,MAACN,GAAK,MAAOQ,EAAE,qBAAqB,EAAG,MAAOsC,EAAaX,CAAS,CAAA,CAAG,CAAA,EACzE,EAIDrB,EAAW,OAAS,GAAK,CAAC0B,GACzBnC,OAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CACC,UAAU,8CACV,MAAO,CAAE,aAAc,6BAAA,EAEvB,SAAA,CAAAC,MAAC,KAAA,CAAG,UAAU,iBAAkB,SAAAE,EAAE,+BAA+B,EAAE,EACnEH,EAAAA,KAAC,SAAA,CACC,UAAU,mBACV,MAAO,CAAE,MAAO,kBAAA,EAChB,QAAS,IAAMO,EAAS,UAAU,EAEjC,SAAA,CAAAJ,EAAE,gBAAgB,GAAK,WACxBF,EAAAA,IAACyC,EAAA,CAAa,KAAM,EAAA,CAAI,CAAA,CAAA,CAAA,CAC1B,CAAA,CAAA,EAEF1C,EAAAA,KAAC,MAAA,CACC,UAAU,wBACV,MAAO,CAAE,oBAAqBkC,CAAA,EAE9B,SAAA,CAAAjC,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,aAAa,CAAA,CAAE,EACvBF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,eAAe,CAAA,CAAE,EACzBF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,aAAa,GAAK,YAAY,EACtCF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,cAAc,CAAA,CAAE,EACxBF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,gBAAgB,CAAA,CAAE,EAC1BF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,eAAe,CAAA,CAAE,EACzBF,EAAAA,IAAC,MAAA,CAAK,SAAAE,EAAE,gBAAgB,CAAA,CAAE,CAAA,CAAA,CAAA,EAE3B6B,EAAc,IAAK,gBAClBhC,OAAAA,EAAAA,KAAC,MAAA,CAEC,UAAU,+BACV,MAAO,CAAE,oBAAqBkC,CAAA,EAC9B,QAAS,IAAM3B,EAAS,UAAU,EAElC,SAAA,CAAAP,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAC,EAAAA,IAAC,OAAA,CACC,UAAU,oBACV,MAAO,CAAE,SAAU,GAAI,MAAO,EAAE,UAAY,GAAQ,mBAAqB,gBAAA,EAExE,SAAA,EAAE,IAAA,CAAA,EAEJ,EAAE,OAASA,EAAAA,IAACqC,GAAY,KAAM,GAAI,UAAU,qCAAA,CAAsC,CAAA,EACrF,EACArC,EAAAA,IAAC,MAAA,CAAI,UAAU,UACb,SAAAA,EAAAA,IAAC0C,EAAA,CAAgB,OAAQ,EAAE,OAAQ,QAAS,EAAE,OAAA,CAAS,EACzD,QACC,MAAA,CAAI,UAAU,UACZ,UAAAd,EAAA,EAAE,SAAF,MAAAA,EAAU,KACT5B,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAU,MAAOC,EAAeC,EAAG,EAAE,OAAO,IAAI,GAAK,OAClE,SAAAD,EAAeC,EAAG,EAAE,OAAO,IAAI,CAAA,CAClC,EAEAF,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,MAAO,mBAAoB,SAAU,EAAA,EAAM,aAAC,EAE/D,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,mBAAmB,MAAO,CAAE,SAAU,IAAA,EAClD,WAAA2C,EAAA,EAAE,QAAF,YAAAA,EAAS,SAAU,CAAA,CACtB,EACA3C,EAAAA,IAAC,MAAA,CAAI,UAAU,mBAAmB,MAAO,CAAE,SAAU,KAAM,MAAO,kBAAA,EAC/D,WAAA4C,EAAA,EAAE,UAAF,YAAAA,EAAW,SAAU,EACxB,EACA5C,EAAAA,IAAC,MAAA,CAAI,UAAU,mBAAmB,MAAO,CAAE,SAAU,KAAM,MAAO,kBAAA,EAC/D,WAAA6C,EAAA,EAAE,YAAF,YAAAA,EAAa,SAAU,EAC1B,QACC,MAAA,CAAI,UAAU,cAAc,MAAO,CAAE,MAAO,EAAE,UAAY,GAAQ,gBAAkB,kBAAA,EAClF,WAAE,UAAY,GAAQ,IAAM,GAAA,CAC/B,CAAA,CAAA,EArCK,EAAE,IAAA,EAuCV,CAAA,EACH,EAIF9C,OAAC,OAAI,UAAU,gBAAgB,MAAO,CAAE,QAAS,IAC/C,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,8CACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAC,MAAC,MAAG,UAAU,iBAAkB,SAAAE,EAAE,2BAA2B,GAAK,gBAAgB,EAClFF,EAAAA,IAAC,IAAA,CAAE,UAAU,UAAU,MAAO,CAAE,UAAW,CAAA,EACxC,SAAAE,EAAE,+BAA+B,GAChC,6DAAA,CACJ,CAAA,EACF,EACAH,EAAAA,KAAC,IAAA,CACC,UAAU,gBACV,KAAK,0BACL,OAAO,SACP,IAAI,sBACJ,MAAO,CAAE,MAAO,kBAAA,EAEf,SAAA,CAAAG,EAAE,aAAa,GAAK,OAAO,IAAA,CAAA,CAAA,CAC9B,EACF,EACAH,EAAAA,KAAC,MAAA,CAAI,UAAU,0CACb,SAAA,CAAAC,MAAC8C,GAAa,MAAM,MAAM,IAAK,GAAGd,CAAO,OAAQ,QAChDc,EAAA,CAAa,MAAM,QAAQ,IAAK,GAAGd,CAAO,cAAe,EACzDlB,EAAO,MAAM,EAAG,CAAC,EAAE,IAAKiC,GACvB/C,EAAAA,IAAC8C,EAAA,CAAwB,MAAM,QAAQ,IAAK,GAAGd,CAAO,QAAQe,EAAE,IAAI,EAAA,EAAjDA,EAAE,EAAmD,CACzE,EAEAjC,EAAO,OAAS,GAAKN,EAAW,CAAC,SAC/BsC,EAAA,CAAa,MAAM,SAAS,IAAK,GAAGd,CAAO,QAAQxB,EAAW,CAAC,EAAE,IAAI,EAAA,CAAI,CAAA,CAAA,CAE9E,CAAA,CAAA,CACF,CAAA,EACF,CAEJ"}
1
+ {"version":3,"file":"Dashboard-BANagmEB.js","sources":["../../src/pages/Dashboard.tsx"],"sourcesContent":["import React, { useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router-dom';\nimport { RefreshCw, Plus, ChevronRight, AlertCircle } from 'lucide-react';\nimport { useServerData } from '@/hooks/useServerData';\nimport { useGroupData } from '@/hooks/useGroupData';\nimport { useSettingsData } from '@/hooks/useSettingsData';\nimport { useCostData } from '@/hooks/useCostData';\nimport { formatTokens } from '@/utils/contextCost';\nimport { Server } from '@/types';\nimport { EndpointCopy } from '@/components/ui/EndpointCopy';\nimport { ServerStatusDot } from '@/components/ui/StatusDot';\n\nconst Stat: React.FC<{ label: string; value: React.ReactNode; tone?: 'ok' | 'warn' | 'err' | 'muted' | 'default' }> = ({\n label,\n value,\n tone = 'default',\n}) => {\n const toneColor =\n tone === 'ok'\n ? 'oklch(0.4 0.13 145)'\n : tone === 'warn'\n ? 'oklch(0.45 0.13 80)'\n : tone === 'err'\n ? 'oklch(0.45 0.18 25)'\n : tone === 'muted'\n ? 'var(--hub-ink-3)'\n : 'var(--hub-ink)';\n return (\n <div className=\"hub-card\" style={{ padding: '14px 16px' }}>\n <div className=\"text-[12px]\" style={{ color: 'var(--hub-ink-3)' }}>\n {label}\n </div>\n <div\n className=\"hub-num\"\n style={{\n fontSize: 26,\n fontWeight: 500,\n letterSpacing: '-0.02em',\n lineHeight: 1.1,\n marginTop: 8,\n color: toneColor,\n }}\n >\n {value}\n </div>\n </div>\n );\n};\n\nconst transportLabel = (t: any, type?: string) => {\n if (!type) return null;\n if (type === 'stdio') return t('server.typeStdio') || 'stdio';\n if (type === 'sse') return t('server.typeSse') || 'sse';\n if (type === 'streamable-http') return t('server.typeStreamableHttp') || 'http';\n if (type === 'openapi') return t('server.typeOpenapi') || 'openapi';\n return type;\n};\n\nconst DashboardPage: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { allServers, error, setError, isLoading, triggerRefresh } = useServerData({\n refreshOnMount: true,\n });\n const { groups } = useGroupData();\n const { installConfig } = useSettingsData();\n const { serverCosts } = useCostData();\n\n const [hasLoaded, setHasLoaded] = React.useState(false);\n const loadingStartedRef = React.useRef(false);\n React.useEffect(() => {\n if (isLoading) {\n loadingStartedRef.current = true;\n return;\n }\n if (loadingStartedRef.current) {\n setHasLoaded(true);\n return;\n }\n if (allServers.length > 0 || error) setHasLoaded(true);\n }, [isLoading, allServers.length, error]);\n\n const stats = useMemo(\n () => ({\n total: allServers.length,\n online: allServers.filter((s: Server) => s.status === 'connected').length,\n disabled: allServers.filter((s: Server) => s.enabled === false).length,\n offline: allServers.filter(\n (s: Server) => s.status === 'disconnected' && s.enabled !== false,\n ).length,\n connecting: allServers.filter(\n (s: Server) =>\n (s.status === 'connecting' || s.status === 'oauth_required') && s.enabled !== false,\n ).length,\n tools: allServers.reduce((acc, s) => acc + (s.tools?.length || 0), 0),\n }),\n [allServers],\n );\n\n const footprint = useMemo(\n () => serverCosts.filter((c) => c.connected).reduce((acc, c) => acc + c.exposed, 0),\n [serverCosts],\n );\n\n const recentServers = useMemo(() => allServers.slice(0, 6), [allServers]);\n const baseUrl = installConfig?.baseUrl?.replace(/\\/+$/, '') || '';\n const recentServerColumns =\n 'minmax(220px,1.9fr) minmax(110px,0.95fr) minmax(120px,0.95fr) 80px 80px 90px 72px';\n\n const showSkeleton = !hasLoaded;\n\n return (\n <div>\n {/* Header */}\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.dashboard.title')}</h1>\n <p className=\"hub-sub\">\n {t('pages.dashboard.totalServers')} · <span className=\"hub-num\">{stats.total}</span>\n {' · '}\n {t('pages.dashboard.onlineServers')} · <span className=\"hub-num\">{stats.online}</span>\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button className=\"hub-btn\" onClick={() => triggerRefresh()}>\n <RefreshCw size={13} /> {t('common.refresh')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => navigate('/servers')}>\n <Plus size={13} /> {t('server.add')}\n </button>\n </div>\n </div>\n\n {error && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-5\"\n style={{\n padding: '10px 14px',\n borderColor: 'oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n }}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n <span className=\"truncate text-[13px]\">{error}</span>\n </div>\n <button\n className=\"hub-icon-btn sm\"\n onClick={() => setError(null)}\n aria-label={t('app.closeButton')}\n >\n ✕\n </button>\n </div>\n )}\n\n {/* Stat row */}\n {showSkeleton ? (\n <div className=\"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div\n key={i}\n className=\"hub-card animate-pulse\"\n style={{ padding: '14px 16px', height: 78 }}\n />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-2 md:grid-cols-6 gap-3 mb-6\">\n <Stat label={t('pages.dashboard.totalServers')} value={stats.total} />\n <Stat label={t('pages.dashboard.onlineServers')} value={stats.online} tone=\"ok\" />\n <Stat label={t('pages.dashboard.connectingServers')} value={stats.connecting} tone=\"warn\" />\n <Stat label={t('pages.dashboard.offlineServers')} value={stats.offline} tone=\"err\" />\n <Stat label={t('pages.dashboard.disabledServers')} value={stats.disabled} tone=\"muted\" />\n <Stat label={t('cost.totalFootprint')} value={formatTokens(footprint)} />\n </div>\n )}\n\n {/* Recent servers */}\n {allServers.length > 0 && !showSkeleton && (\n <div className=\"hub-card overflow-hidden mb-6\">\n <div\n className=\"flex items-center justify-between px-4 py-3\"\n style={{ borderBottom: '1px solid var(--hub-line-2)' }}\n >\n <h3 className=\"hub-card-title\">{t('pages.dashboard.recentServers')}</h3>\n <button\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-ink-3)' }}\n onClick={() => navigate('/servers')}\n >\n {t('common.viewAll') || 'View all'}\n <ChevronRight size={12} />\n </button>\n </div>\n <div\n className=\"hub-row head hub-mono\"\n style={{ gridTemplateColumns: recentServerColumns }}\n >\n <div>{t('server.name')}</div>\n <div>{t('server.status')}</div>\n <div>{t('common.type') || 'Transport'}</div>\n <div>{t('server.tools')}</div>\n <div>{t('server.prompts')}</div>\n <div>{t('nav.resources')}</div>\n <div>{t('server.enabled')}</div>\n </div>\n {recentServers.map((s) => (\n <div\n key={s.name}\n className=\"hub-row hover cursor-pointer\"\n style={{ gridTemplateColumns: recentServerColumns }}\n onClick={() => navigate('/servers')}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span\n className=\"hub-mono truncate\"\n style={{ fontSize: 13, color: s.enabled === false ? 'var(--hub-ink-3)' : 'var(--hub-ink)' }}\n >\n {s.name}\n </span>\n {s.error && <AlertCircle size={13} className=\"text-[var(--hub-err)] flex-shrink-0\" />}\n </div>\n <div className=\"min-w-0\">\n <ServerStatusDot status={s.status} enabled={s.enabled} />\n </div>\n <div className=\"min-w-0\">\n {s.config?.type ? (\n <span className=\"hub-tag\" title={transportLabel(t, s.config.type) ?? undefined}>\n {transportLabel(t, s.config.type)}\n </span>\n ) : (\n <span style={{ color: 'var(--hub-ink-3)', fontSize: 12 }}>—</span>\n )}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5 }}>\n {s.tools?.length || 0}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5, color: 'var(--hub-ink-2)' }}>\n {s.prompts?.length || 0}\n </div>\n <div className=\"hub-num hub-mono\" style={{ fontSize: 12.5, color: 'var(--hub-ink-2)' }}>\n {s.resources?.length || 0}\n </div>\n <div className=\"text-[12px]\" style={{ color: s.enabled !== false ? 'var(--hub-ok)' : 'var(--hub-ink-3)' }}>\n {s.enabled !== false ? '✓' : '—'}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Endpoint quick-access */}\n <div className=\"hub-card mb-5\" style={{ padding: 16 }}>\n <div className=\"flex justify-between items-start gap-3 mb-3\">\n <div>\n <h3 className=\"hub-card-title\">{t('pages.dashboard.endpoints') || 'MCP Endpoints'}</h3>\n <p className=\"hub-sub\" style={{ marginTop: 2 }}>\n {t('pages.dashboard.endpointsHint') ||\n 'Use these URLs in Claude Desktop, Cursor, or any MCP client'}\n </p>\n </div>\n <a\n className=\"hub-btn ghost\"\n href=\"https://docs.mcphub.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ color: 'var(--hub-ink-3)' }}\n >\n {t('common.docs') || 'Docs'} →\n </a>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-2.5\">\n <EndpointCopy label=\"ALL\" url={`${baseUrl}/mcp`} />\n <EndpointCopy label=\"SMART\" url={`${baseUrl}/mcp/$smart`} />\n {groups.slice(0, 2).map((g) => (\n <EndpointCopy key={g.id} label=\"GROUP\" url={`${baseUrl}/mcp/${g.name}`} />\n ))}\n {/* Pad with first server endpoint if there's space */}\n {groups.length < 2 && allServers[0] && (\n <EndpointCopy label=\"SERVER\" url={`${baseUrl}/mcp/${allServers[0].name}`} />\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default DashboardPage;\n"],"names":["Stat","label","value","tone","toneColor","jsxs","jsx","transportLabel","t","type","DashboardPage","useTranslation","navigate","useNavigate","allServers","error","setError","isLoading","triggerRefresh","useServerData","groups","useGroupData","installConfig","useSettingsData","serverCosts","useCostData","hasLoaded","setHasLoaded","React","loadingStartedRef","stats","useMemo","acc","s","_a","footprint","c","recentServers","baseUrl","recentServerColumns","showSkeleton","RefreshCw","Plus","AlertCircle","_","i","formatTokens","ChevronRight","ServerStatusDot","_b","_c","_d","EndpointCopy","g"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{r as y,j as o}from"./framework-vendor-_YL27Pfc.js";import{j as h,m as p}from"./index-DJUr-vo3.js";import{c as x}from"./clipboard-CjtPOmJs.js";import{u as C}from"./i18n-vendor-BMaj5qV8.js";import{C as b,q as j}from"./icons-vendor-CvmEvkQ-.js";const g=({url:s,label:e,prefix:a,className:r,copyValue:m,ariaLabel:l})=>{const{t}=C(),{showToast:c}=h(),[n,i]=y.useState(!1),d=async u=>{if(u.stopPropagation(),!await x(m??s)){c(t("common.copyFailed")||"Copy failed","error");return}i(!0),c(t("common.copySuccess")||"Copied to clipboard","success"),setTimeout(()=>i(!1),1200)};return o.jsxs("div",{className:p("hub-endpoint",r),role:"group","aria-label":l||s,children:[e&&o.jsx("div",{className:"hub-endpoint-label",children:e}),o.jsxs("div",{className:"hub-endpoint-url",title:s,children:[a&&o.jsx("span",{style:{color:"var(--hub-ink-3)"},children:a}),s]}),o.jsx("button",{type:"button",onClick:d,className:p("hub-endpoint-copy",n?"copied":""),title:t("common.copy")||"Copy","aria-label":t("common.copy")||"Copy",children:n?o.jsx(b,{size:13}):o.jsx(j,{size:13})})]})};export{g as E};
2
- //# sourceMappingURL=EndpointCopy-B0yIEBjO.js.map
1
+ import{r as y,j as o}from"./framework-vendor-_YL27Pfc.js";import{j as h,m as p}from"./index-DZZHe6u7.js";import{c as x}from"./clipboard-D07Uwfz5.js";import{u as C}from"./i18n-vendor-BMaj5qV8.js";import{C as b,q as j}from"./icons-vendor-CvmEvkQ-.js";const g=({url:s,label:e,prefix:a,className:r,copyValue:m,ariaLabel:l})=>{const{t}=C(),{showToast:c}=h(),[n,i]=y.useState(!1),d=async u=>{if(u.stopPropagation(),!await x(m??s)){c(t("common.copyFailed")||"Copy failed","error");return}i(!0),c(t("common.copySuccess")||"Copied to clipboard","success"),setTimeout(()=>i(!1),1200)};return o.jsxs("div",{className:p("hub-endpoint",r),role:"group","aria-label":l||s,children:[e&&o.jsx("div",{className:"hub-endpoint-label",children:e}),o.jsxs("div",{className:"hub-endpoint-url",title:s,children:[a&&o.jsx("span",{style:{color:"var(--hub-ink-3)"},children:a}),s]}),o.jsx("button",{type:"button",onClick:d,className:p("hub-endpoint-copy",n?"copied":""),title:t("common.copy")||"Copy","aria-label":t("common.copy")||"Copy",children:n?o.jsx(b,{size:13}):o.jsx(j,{size:13})})]})};export{g as E};
2
+ //# sourceMappingURL=EndpointCopy-DcF8AnZa.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EndpointCopy-B0yIEBjO.js","sources":["../../src/components/ui/EndpointCopy.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Copy, Check } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useToast } from '@/contexts/ToastContext';\nimport { copyText } from '@/utils/clipboard';\nimport { cn } from '@/utils/cn';\n\ninterface EndpointCopyProps {\n url: string;\n label?: string;\n prefix?: string;\n className?: string;\n /** Optionally override the value placed on the clipboard. */\n copyValue?: string;\n ariaLabel?: string;\n}\n\nexport const EndpointCopy: React.FC<EndpointCopyProps> = ({\n url,\n label,\n prefix,\n className,\n copyValue,\n ariaLabel,\n}) => {\n const { t } = useTranslation();\n const { showToast } = useToast();\n const [copied, setCopied] = useState(false);\n\n const onCopy = async (e: React.MouseEvent) => {\n e.stopPropagation();\n const ok = await copyText(copyValue ?? url);\n if (!ok) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n return;\n }\n setCopied(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopied(false), 1200);\n };\n\n return (\n <div className={cn('hub-endpoint', className)} role=\"group\" aria-label={ariaLabel || url}>\n {label && <div className=\"hub-endpoint-label\">{label}</div>}\n <div className=\"hub-endpoint-url\" title={url}>\n {prefix && <span style={{ color: 'var(--hub-ink-3)' }}>{prefix}</span>}\n {url}\n </div>\n <button\n type=\"button\"\n onClick={onCopy}\n className={cn('hub-endpoint-copy', copied ? 'copied' : '')}\n title={t('common.copy') || 'Copy'}\n aria-label={t('common.copy') || 'Copy'}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n </div>\n );\n};\n\ninterface MonoCopyProps {\n text: string;\n className?: string;\n copyValue?: string;\n title?: string;\n}\n\n/** Inline monospace value with hover-to-copy icon. */\nexport const MonoCopy: React.FC<MonoCopyProps> = ({ text, className, copyValue, title }) => {\n const { t } = useTranslation();\n const { showToast } = useToast();\n const [copied, setCopied] = useState(false);\n\n const onCopy = async (e: React.MouseEvent) => {\n e.stopPropagation();\n const ok = await copyText(copyValue ?? text);\n if (!ok) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n return;\n }\n setCopied(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopied(false), 1200);\n };\n\n return (\n <span\n className={cn(\n 'hub-mono inline-flex items-center gap-1.5 group cursor-pointer text-[12.5px]',\n className,\n )}\n onClick={onCopy}\n title={title || text}\n role=\"button\"\n >\n <span className=\"truncate\">{text}</span>\n {copied ? (\n <Check size={12} className=\"text-[var(--hub-ok)] flex-shrink-0\" />\n ) : (\n <Copy\n size={12}\n className=\"text-[var(--hub-ink-3)] opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\"\n />\n )}\n </span>\n );\n};\n"],"names":["EndpointCopy","url","label","prefix","className","copyValue","ariaLabel","useTranslation","showToast","useToast","copied","setCopied","useState","onCopy","e","copyText","jsxs","cn","jsx","Check","Copy"],"mappings":"yPAiBO,MAAMA,EAA4C,CAAC,CACxD,IAAAC,EACA,MAAAC,EACA,OAAAC,EACA,UAAAC,EACA,UAAAC,EACA,UAAAC,CACF,IAAM,CACJ,KAAM,CAAE,CAAA,EAAMC,EAAA,EACR,CAAE,UAAAC,CAAA,EAAcC,EAAA,EAChB,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAS,EAAK,EAEpCC,EAAS,MAAOC,GAAwB,CAG5C,GAFAA,EAAE,gBAAA,EAEE,CADO,MAAMC,EAASV,GAAaJ,CAAG,EACjC,CACPO,EAAU,EAAE,mBAAmB,GAAK,cAAe,OAAO,EAC1D,MACF,CACAG,EAAU,EAAI,EACdH,EAAU,EAAE,oBAAoB,GAAK,sBAAuB,SAAS,EACrE,WAAW,IAAMG,EAAU,EAAK,EAAG,IAAI,CACzC,EAEA,OACEK,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAG,eAAgBb,CAAS,EAAG,KAAK,QAAQ,aAAYE,GAAaL,EAClF,SAAA,CAAAC,GAASgB,EAAAA,IAAC,MAAA,CAAI,UAAU,qBAAsB,SAAAhB,EAAM,EACrDc,EAAAA,KAAC,MAAA,CAAI,UAAU,mBAAmB,MAAOf,EACtC,SAAA,CAAAE,SAAW,OAAA,CAAK,MAAO,CAAE,MAAO,kBAAA,EAAuB,SAAAA,EAAO,EAC9DF,CAAA,EACH,EACAiB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASL,EACT,UAAWI,EAAG,oBAAqBP,EAAS,SAAW,EAAE,EACzD,MAAO,EAAE,aAAa,GAAK,OAC3B,aAAY,EAAE,aAAa,GAAK,OAE/B,SAAAA,QAAUS,EAAA,CAAM,KAAM,GAAI,EAAKD,EAAAA,IAACE,EAAA,CAAK,KAAM,EAAA,CAAI,CAAA,CAAA,CAClD,EACF,CAEJ"}
1
+ {"version":3,"file":"EndpointCopy-DcF8AnZa.js","sources":["../../src/components/ui/EndpointCopy.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Copy, Check } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { useToast } from '@/contexts/ToastContext';\nimport { copyText } from '@/utils/clipboard';\nimport { cn } from '@/utils/cn';\n\ninterface EndpointCopyProps {\n url: string;\n label?: string;\n prefix?: string;\n className?: string;\n /** Optionally override the value placed on the clipboard. */\n copyValue?: string;\n ariaLabel?: string;\n}\n\nexport const EndpointCopy: React.FC<EndpointCopyProps> = ({\n url,\n label,\n prefix,\n className,\n copyValue,\n ariaLabel,\n}) => {\n const { t } = useTranslation();\n const { showToast } = useToast();\n const [copied, setCopied] = useState(false);\n\n const onCopy = async (e: React.MouseEvent) => {\n e.stopPropagation();\n const ok = await copyText(copyValue ?? url);\n if (!ok) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n return;\n }\n setCopied(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopied(false), 1200);\n };\n\n return (\n <div className={cn('hub-endpoint', className)} role=\"group\" aria-label={ariaLabel || url}>\n {label && <div className=\"hub-endpoint-label\">{label}</div>}\n <div className=\"hub-endpoint-url\" title={url}>\n {prefix && <span style={{ color: 'var(--hub-ink-3)' }}>{prefix}</span>}\n {url}\n </div>\n <button\n type=\"button\"\n onClick={onCopy}\n className={cn('hub-endpoint-copy', copied ? 'copied' : '')}\n title={t('common.copy') || 'Copy'}\n aria-label={t('common.copy') || 'Copy'}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n </div>\n );\n};\n\ninterface MonoCopyProps {\n text: string;\n className?: string;\n copyValue?: string;\n title?: string;\n}\n\n/** Inline monospace value with hover-to-copy icon. */\nexport const MonoCopy: React.FC<MonoCopyProps> = ({ text, className, copyValue, title }) => {\n const { t } = useTranslation();\n const { showToast } = useToast();\n const [copied, setCopied] = useState(false);\n\n const onCopy = async (e: React.MouseEvent) => {\n e.stopPropagation();\n const ok = await copyText(copyValue ?? text);\n if (!ok) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n return;\n }\n setCopied(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopied(false), 1200);\n };\n\n return (\n <span\n className={cn(\n 'hub-mono inline-flex items-center gap-1.5 group cursor-pointer text-[12.5px]',\n className,\n )}\n onClick={onCopy}\n title={title || text}\n role=\"button\"\n >\n <span className=\"truncate\">{text}</span>\n {copied ? (\n <Check size={12} className=\"text-[var(--hub-ok)] flex-shrink-0\" />\n ) : (\n <Copy\n size={12}\n className=\"text-[var(--hub-ink-3)] opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\"\n />\n )}\n </span>\n );\n};\n"],"names":["EndpointCopy","url","label","prefix","className","copyValue","ariaLabel","useTranslation","showToast","useToast","copied","setCopied","useState","onCopy","e","copyText","jsxs","cn","jsx","Check","Copy"],"mappings":"yPAiBO,MAAMA,EAA4C,CAAC,CACxD,IAAAC,EACA,MAAAC,EACA,OAAAC,EACA,UAAAC,EACA,UAAAC,EACA,UAAAC,CACF,IAAM,CACJ,KAAM,CAAE,CAAA,EAAMC,EAAA,EACR,CAAE,UAAAC,CAAA,EAAcC,EAAA,EAChB,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAS,EAAK,EAEpCC,EAAS,MAAOC,GAAwB,CAG5C,GAFAA,EAAE,gBAAA,EAEE,CADO,MAAMC,EAASV,GAAaJ,CAAG,EACjC,CACPO,EAAU,EAAE,mBAAmB,GAAK,cAAe,OAAO,EAC1D,MACF,CACAG,EAAU,EAAI,EACdH,EAAU,EAAE,oBAAoB,GAAK,sBAAuB,SAAS,EACrE,WAAW,IAAMG,EAAU,EAAK,EAAG,IAAI,CACzC,EAEA,OACEK,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAG,eAAgBb,CAAS,EAAG,KAAK,QAAQ,aAAYE,GAAaL,EAClF,SAAA,CAAAC,GAASgB,EAAAA,IAAC,MAAA,CAAI,UAAU,qBAAsB,SAAAhB,EAAM,EACrDc,EAAAA,KAAC,MAAA,CAAI,UAAU,mBAAmB,MAAOf,EACtC,SAAA,CAAAE,SAAW,OAAA,CAAK,MAAO,CAAE,MAAO,kBAAA,EAAuB,SAAAA,EAAO,EAC9DF,CAAA,EACH,EACAiB,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASL,EACT,UAAWI,EAAG,oBAAqBP,EAAS,SAAW,EAAE,EACzD,MAAO,EAAE,aAAa,GAAK,OAC3B,aAAY,EAAE,aAAa,GAAK,OAE/B,SAAAA,QAAUS,EAAA,CAAM,KAAM,GAAI,EAAKD,EAAAA,IAACE,EAAA,CAAK,KAAM,EAAA,CAAI,CAAA,CAAA,CAClD,EACF,CAEJ"}
@@ -1,4 +1,4 @@
1
- import{r as h,R as _,j as e}from"./framework-vendor-_YL27Pfc.js";import{m as Z,e as ge,d as Q,u as fe,j as ye,i as ee}from"./index-DJUr-vo3.js";import{u as se,a as te}from"./useCostData-CT2iwvzx.js";import{u as me,c as ve}from"./clipboard-CjtPOmJs.js";import{f as W,p as je}from"./contextCost-CilWqGWT.js";import{g as Ne,A as ke,C as Se}from"./CopyClientConfigDialog-BHijFbyw.js";import{u as G}from"./i18n-vendor-BMaj5qV8.js";import{W as we,g as Ce,F as Ae,H as Ee,C as Te,q as J,J as ie,z as De,w as Ie,T as ze,u as Fe,D as oe,N as Pe,P as ce,l as Re,X as Ue}from"./icons-vendor-CvmEvkQ-.js";import{D as Le}from"./DeleteDialog-BYhrMGZo.js";const Oe={tools:[],prompts:[],resources:[]},de={tools:"all",prompts:"all",resources:"all"},ue=({servers:l,value:b,onChange:t,className:n,serverCosts:N=[]})=>{const{t:d}=G(),{nameSeparator:v,smartRoutingConfig:E}=me(),[D,f]=h.useState(new Set),p=_.useMemo(()=>b.map(s=>typeof s=="string"?{name:s,...de}:{...s,tools:s.tools||"all",prompts:s.prompts||"all",resources:s.resources||"all"}),[b]),k=_.useMemo(()=>l.filter(s=>s.enabled!==!1),[l]);_.useEffect(()=>{const s=new Set(p.map(r=>r.name)),i=new Set(k.map(r=>r.name));f(r=>{const y=new Set;return r.forEach(x=>{(s.has(x)||i.has(x))&&y.add(x)}),y})},[p,k]);const C=s=>{if(p.findIndex(r=>r.name===s)>=0){const r=p.filter(y=>y.name!==s);t(r)}else{const r=[...p,{name:s,...de}];t(r)}},w=s=>{f(i=>{const r=new Set(i);return r.has(s)?r.delete(s):r.add(s),r})},A=s=>["tools","prompts","resources"].some(i=>{const r=s[i];return r==="all"||Array.isArray(r)&&r.length>0}),o=(s,i,r,y=!1)=>{const x=p.find(z=>z.name===s),I={...x?{...x}:{name:s,...Oe},[i]:r};if(i==="tools"&&Array.isArray(r)&&I.pinnedTools&&(I.pinnedTools=I.pinnedTools.filter(z=>r.includes(z)),I.pinnedTools.length===0&&delete I.pinnedTools),!A(I)){const z=p.filter(u=>u.name!==s);t(z),y||f(u=>{const L=new Set(u);return L.delete(s),L});return}if(x){t(p.map(z=>z.name===s?I:z));return}t([...p,I])},j=(s,i)=>{const r=p.find(x=>x.name===s);if(!r)return;const y={...r};i?y.alias=i:delete y.alias,t(p.map(x=>x.name===s?y:x))},g=(s,i)=>{const r=p.find(P=>P.name===s);if(!r)return;const y=r.pinnedTools??[],x={...r,pinnedTools:y.includes(i)?y.filter(P=>P!==i):[...y,i]};x.pinnedTools.length===0&&delete x.pinnedTools,t(p.map(P=>P.name===s?x:P))},a=(s,i)=>{const r=`${s}${v}`;return i.startsWith(r)?i.slice(r.length):i},c=(s,i)=>i==="tools"?(s.tools||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.name,value:a(s.name,r.name),description:r.description,defaultDescription:r.defaultDescription,hasDescriptionOverride:r.hasDescriptionOverride})):i==="prompts"?(s.prompts||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.name,value:a(s.name,r.name),description:r.description})):(s.resources||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.uri,value:r.uri,description:r.description})),m=_.useMemo(()=>{const s=new Map;return N.forEach(i=>{const r=new Map;i.items.forEach(y=>r.set(y.name,y.cost)),s.set(i.name,r)}),s},[N]),S=s=>m.get(s)??new Map,F=(s,i)=>{const r=S(s.name);return c(s,i).filter(y=>M(s.name,i,y.value)).reduce((y,x)=>y+(r.get(x.key)??0),0)},O=s=>["tools","prompts","resources"].reduce((i,r)=>i+F(s,r),0),H=(s,i,r)=>{const y=k.find(z=>z.name===s);if(!y)return;const x=c(y,i).map(z=>z.value),P=p.find(z=>z.name===s);if(!P){o(s,i,[r]);return}const I=P[i];if(I==="all"){const z=x.filter(u=>u!==r);o(s,i,z);return}if(Array.isArray(I)){if(I.includes(r)){o(s,i,I.filter(u=>u!==r));return}const z=[...I,r];o(s,i,z.length===x.length?"all":z);return}o(s,i,[r])},X=s=>{const i=p.find(r=>r.name===s);return!!(i&&A(i))},$=s=>{const i=p.find(r=>r.name===s);return i?["tools","prompts","resources"].some(r=>{const y=i[r];return Array.isArray(y)&&y.length>0}):!1},M=(s,i,r)=>{const y=p.find(P=>P.name===s);if(!y)return!1;const x=y[i];return x==="all"?!0:Array.isArray(x)?x.includes(r):!1},K=(s,i)=>{const r=p.find(P=>P.name===s.name);if(!r)return 0;const y=c(s,i),x=r[i];if(x==="all")return y.length;if(Array.isArray(x)){const P=new Set(y.map(I=>I.value));return x.filter(I=>P.has(I)).length}return 0},B=[{key:"tools",titleKey:"groups.toolSelection",countKey:"groups.toolsSelected",allKey:"groups.allTools"},{key:"prompts",titleKey:"groups.promptSelection",countKey:"groups.promptsSelected",allKey:"groups.allPrompts"},{key:"resources",titleKey:"groups.resourceSelection",countKey:"groups.resourcesSelected",allKey:"groups.allResources"}],T=s=>B.map(({key:i})=>({key:i,count:K(s,i)})).filter(i=>i.count>0);return e.jsxs("div",{className:Z("space-y-4",n),children:[e.jsx("div",{className:"space-y-3",children:k.map(s=>{const i=X(s.name),r=$(s.name),y=D.has(s.name),x=p.find(u=>u.name===s.name),P=T(s),I=B.filter(({key:u})=>c(s,u).length>0),z=S(s.name);return e.jsxs("div",{className:"border border-gray-200 dark:border-gray-700 rounded-lg hover:border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between p-3 cursor-pointer rounded-lg transition-colors",onClick:()=>w(s.name),children:[e.jsxs("div",{className:"flex items-center space-x-3",onClick:u=>{u.stopPropagation(),C(s.name)},children:[e.jsx("input",{type:"checkbox",checked:i||r,onChange:()=>C(s.name),className:"w-4 h-4 text-blue-600 bg-gray-100 dark:bg-gray-800 border-gray-300 rounded focus:ring-blue-500"}),e.jsx("span",{className:"font-medium text-gray-900 cursor-pointer select-none",children:s.name})]}),e.jsxs("div",{className:"flex items-center space-x-3",children:[O(s)>0&&e.jsxs("span",{className:"text-sm text-gray-400 hub-mono",title:d("cost.estimate"),children:["Σ ",W(O(s))]}),P.map(({key:u,count:L})=>e.jsxs("span",{className:"text-sm text-green-600 flex items-center gap-1",children:[u==="tools"?e.jsx(we,{size:14}):u==="prompts"?e.jsx(Ce,{size:14}):e.jsx(Ae,{size:14})," ",L]},u)),I.length>0&&e.jsx("button",{type:"button",className:"p-1 text-gray-400 hover:text-gray-600 transition-colors",children:e.jsx("svg",{className:Z("w-5 h-5 transition-transform",y&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})})]})]}),y&&I.length>0&&e.jsx("div",{className:"border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 p-3",children:e.jsxs("div",{className:"space-y-4",children:[x&&e.jsxs("div",{className:"space-y-1",onClick:u=>u.stopPropagation(),children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600",children:d("groups.alias")}),e.jsx("input",{type:"text",value:x.alias||"",placeholder:s.name,onChange:u=>j(s.name,u.target.value),className:"w-full rounded-md border border-gray-300 bg-white px-2.5 py-1.5 text-sm text-gray-800 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100"})]}),I.map(({key:u,titleKey:L,countKey:he,allKey:be})=>{const V=c(s,u),re=K(s,u),Y=(x==null?void 0:x[u])==="all"||re===V.length;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("span",{className:"text-sm font-medium text-gray-700",children:d(L)}),e.jsxs("div",{className:"flex items-center gap-3",children:[x&&e.jsx("span",{className:"text-xs text-green-600",children:Y?`(${d(be)} ${V.length}/${V.length})`:`(${d(he)} ${re}/${V.length})`}),x&&F(s,u)>0&&e.jsxs("span",{className:"text-xs text-gray-400 hub-mono",title:d("cost.estimate"),children:["Σ ",W(F(s,u))]}),e.jsx("button",{type:"button",onClick:()=>{o(s.name,u,Y?[]:"all",!0)},className:"text-sm text-blue-600 hover:text-blue-800 transition-colors",children:d(Y?"groups.selectNone":"groups.selectAll")})]})]}),e.jsx("div",{className:"grid grid-cols-1 gap-2 max-h-32 overflow-y-auto",children:V.map(R=>{var le;const ae=M(s.name,u,R.value),q=!!((le=x==null?void 0:x.pinnedTools)!=null&&le.includes(R.value)),U=u==="tools"?Ne({description:R.description,defaultDescription:R.defaultDescription,hasDescriptionOverride:R.hasDescriptionOverride},d("tool.noDescription")):null,ne=U!=null&&U.hasDescriptionOverride?d("tool.defaultDescriptionTooltip",{description:U.defaultDescription}):R.description;return e.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[e.jsxs("label",{className:"flex min-w-0 flex-1 items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:ae,onChange:()=>H(s.name,u,R.value),className:"w-3 h-3 text-blue-600 bg-gray-100 dark:bg-gray-800 border-gray-300 rounded focus:ring-blue-500"}),e.jsx("span",{className:"text-gray-700 break-all whitespace-nowrap flex-shrink-0",children:R.value}),(R.description||(U==null?void 0:U.hasDescriptionOverride))&&e.jsxs("span",{className:"min-w-0 flex items-center gap-1 text-gray-400 text-xs truncate",children:[e.jsx("span",{className:"truncate",title:ne||void 0,children:U?U.currentDescription:R.description}),(U==null?void 0:U.hasDescriptionOverride)&&e.jsx("span",{className:"inline-flex flex-shrink-0 items-center rounded-full border border-amber-200 bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 dark:border-amber-700/60 dark:bg-amber-900/20 dark:text-amber-300",title:ne||void 0,children:d("tool.descriptionModifiedBadge")})]}),z.get(R.key)!=null&&e.jsxs("span",{className:"text-xs text-gray-400 hub-mono whitespace-nowrap ml-auto flex-shrink-0",title:d("cost.estimate"),children:["Σ ",W(z.get(R.key))]})]}),u==="tools"&&ae&&(E.enabled||q)&&e.jsx("button",{type:"button",onClick:()=>g(s.name,R.value),title:d(q?"groups.unpinTool":"groups.pinTool"),"aria-label":d("groups.pinToolLabel"),"aria-pressed":q,className:Z("flex-shrink-0 transition-colors",q?"text-blue-600":"text-gray-300 hover:text-gray-500 dark:text-gray-600 dark:hover:text-gray-400"),children:e.jsx(Ee,{size:12,fill:q?"currentColor":"none"})})]},R.key)})})]},u)})]})})]},s.name)})}),k.length===0&&e.jsx("p",{className:"text-gray-500 text-sm",children:d("groups.noServerOptions")})]})};function pe({groupId:l,value:b,onChange:t}){const{t:n}=G(),[N,d]=h.useState([]),[v,E]=h.useState(""),[D,f]=h.useState(!1),[p,k]=h.useState(!1),[C,w]=h.useState(!1);h.useEffect(()=>{if(!l||b.visibility!=="group")return;let m=!1;return f(!0),k(!1),ge(`/groups/${encodeURIComponent(l)}/share-candidates`).then(S=>{m||(S.success&&Array.isArray(S.data)?d(S.data):k(!0))}).catch(()=>{m||k(!0)}).finally(()=>{m||f(!1)}),()=>{m=!0}},[l,b.visibility]);const A=b.sharedWithUsers||[],o=[...new Set([...N,...A])].sort().filter(m=>m.toLowerCase().includes(v.toLowerCase())),j=new Set(A),g=o.length>0&&o.every(m=>j.has(m)),a=o.length===0||o.every(m=>!j.has(m)),c=m=>{const S=new Set(A);S.has(m)?S.delete(m):S.add(m),t({sharedWithUsers:Array.from(S)})};return e.jsxs("div",{className:"mb-4",children:[e.jsxs("div",{className:"flex items-center justify-between cursor-pointer bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 p-3 rounded border border-gray-200 dark:border-gray-700",onClick:()=>w(!C),children:[e.jsx("h3",{className:"text-sm font-semibold text-[var(--hub-ink)]",children:n("server.sectionAdvanced","Advanced Options")}),e.jsx("span",{className:"text-gray-500 text-sm",children:C?"▼":"▶"})]}),C&&e.jsxs("div",{className:"border border-gray-200 dark:border-gray-700 rounded-b p-4 bg-white dark:bg-gray-900 border-t-0",children:[e.jsx("label",{htmlFor:"group-visibility",className:"block text-sm font-medium mb-1.5 text-[var(--hub-ink-2)]",children:n("server.visibility")}),e.jsxs("select",{id:"group-visibility",className:"w-full py-2 px-3 form-input",value:b.visibility||"",onChange:m=>t({visibility:m.target.value}),children:[!b.visibility&&e.jsx("option",{value:"",disabled:!0,children:n("groups.legacyVisibility")}),e.jsx("option",{value:"private",children:n("server.visibilityPrivate")}),e.jsx("option",{value:"group",children:n("server.visibilityGroup")}),e.jsx("option",{value:"public",children:n("server.visibilityPublic")})]}),e.jsx("p",{className:"text-xs text-gray-500 mt-1",children:n("groups.visibilityDescription")}),!b.visibility&&e.jsx("p",{className:"text-sm text-amber-600",children:n("groups.legacyVisibilityHint")}),b.visibility==="group"&&e.jsxs("div",{className:"mt-4 rounded border border-gray-200 dark:border-gray-700 p-3",children:[e.jsx("div",{className:"text-sm font-medium text-[var(--hub-ink-2)]",children:n("server.shareWithUsers")}),e.jsx("p",{className:"text-xs text-gray-500 mt-1 mb-3",children:n("server.shareWithUsersDescription")}),l?e.jsxs(e.Fragment,{children:[D&&e.jsx("p",{className:"text-sm text-gray-500",children:n("server.shareCandidatesLoading")}),p&&e.jsx("p",{role:"alert",className:"text-sm text-red-600 dark:text-red-400",children:n("server.shareCandidatesError")}),!D&&!p&&o.length===0&&e.jsx("p",{className:"text-sm text-gray-500",children:n(v?"server.noMatchingShareUsers":"server.noShareCandidates")}),o.length>0&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 space-y-2",children:[e.jsx("label",{htmlFor:"group-share-search",className:"block text-xs font-medium text-[var(--hub-ink-2)]",children:n("server.shareUserSearchLabel")}),e.jsx("input",{id:"group-share-search",type:"search",value:v,onChange:m=>E(m.target.value),placeholder:n("server.shareUserSearchPlaceholder"),className:"w-full py-2 px-3 form-input text-sm"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:()=>t({sharedWithUsers:[...new Set([...A,...o])]}),disabled:g,className:"hub-btn text-sm",children:n("server.selectAllShareUsers")}),e.jsx("button",{type:"button",onClick:()=>t({sharedWithUsers:A.filter(m=>!o.includes(m))}),disabled:a,className:"hub-btn text-sm",children:n("server.deselectAllShareUsers")})]})]}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:o.map(m=>e.jsxs("label",{className:"flex items-center gap-2 rounded border border-gray-200 dark:border-gray-700 px-3 py-2 text-sm text-[var(--hub-ink-2)]",children:[e.jsx("input",{type:"checkbox",checked:j.has(m),onChange:()=>c(m)}),e.jsx("span",{children:m})]},m))})]})]}):e.jsx("p",{className:"text-sm text-gray-500",children:n("groups.shareAfterCreate")})]})]})]})}const $e=({onAdd:l,onCancel:b})=>{const{t}=G(),{createGroup:n}=Q(),{allServers:N}=se(),{serverCosts:d}=te(),[v,E]=h.useState([]),[D,f]=h.useState(null),[p,k]=h.useState(!1),[C,w]=h.useState({visibility:"private",sharedWithUsers:[],name:"",description:"",servers:[]});h.useEffect(()=>{E(N.filter(j=>j.enabled!==!1))},[N]);const A=j=>{const{name:g,value:a}=j.target;w(c=>({...c,[g]:a}))},o=async j=>{j.preventDefault(),k(!0),f(null);try{if(!C.name.trim()){f(t("groups.nameRequired")),k(!1);return}const g=await n(C.name,C.description,C.servers,{visibility:C.visibility,sharedWithUsers:C.sharedWithUsers});if(!g||!g.success){f((g==null?void 0:g.message)||t("groups.createError")),k(!1);return}l()}catch(g){f(g instanceof Error?g.message:String(g)),k(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col",children:[e.jsxs("div",{className:"p-6 flex-shrink-0",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 mb-4",children:t("groups.addNew")}),D&&e.jsx("div",{className:"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-gray-200 dark:border-gray-700",children:D})]}),e.jsxs("form",{onSubmit:o,className:"flex flex-col flex-1 min-h-0",children:[e.jsx("div",{className:"flex-1 overflow-y-auto px-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-gray-700 text-sm font-bold mb-2",htmlFor:"name",children:[t("groups.name")," *"]}),e.jsx("input",{type:"text",id:"name",name:"name",value:C.name,onChange:A,className:"w-full border border-gray-300 rounded-md px-3 py-2 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",placeholder:t("groups.namePlaceholder"),required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-gray-700 text-sm font-bold mb-2",children:t("groups.configureCapabilities")}),e.jsx(ue,{servers:v,value:C.servers,onChange:j=>w(g=>({...g,servers:j})),className:"border border-gray-200 dark:border-gray-700 rounded-lg p-4 bg-gray-50 dark:bg-gray-800",serverCosts:d})]}),e.jsx(pe,{value:C,onChange:j=>w(g=>({...g,...j}))})]})}),e.jsxs("div",{className:"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0",children:[e.jsx("button",{type:"button",onClick:b,className:"hub-btn",disabled:p,children:t("common.cancel")}),e.jsx("button",{type:"submit",className:"hub-btn primary",disabled:p,children:t(p?"common.submitting":"common.create")})]})]})]})})},Ge=({group:l,onEdit:b,onCancel:t})=>{const{t:n}=G(),{updateGroup:N}=Q(),{allServers:d}=se(),{serverCosts:v}=te(),[E,D]=h.useState([]),[f,p]=h.useState(null),[k,C]=h.useState(!1),[w,A]=h.useState({visibility:l.visibility,sharedWithUsers:l.sharedWithUsers||[],name:l.name,description:l.description||"",servers:l.servers||[]});h.useEffect(()=>{D(d.filter(g=>g.enabled!==!1))},[d]);const o=g=>{const{name:a,value:c}=g.target;A(m=>({...m,[a]:c}))},j=async g=>{g.preventDefault(),C(!0),p(null);try{if(!w.name.trim()){p(n("groups.nameRequired")),C(!1);return}const a=await N(l.id,{visibility:w.visibility,sharedWithUsers:w.sharedWithUsers,name:w.name,description:w.description,servers:w.servers});if(!a||!a.success){p((a==null?void 0:a.message)||n("groups.updateError")),C(!1);return}b()}catch(a){p(a instanceof Error?a.message:String(a)),C(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col",children:[e.jsxs("div",{className:"p-6 flex-shrink-0",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 mb-4",children:n("groups.edit")}),f&&e.jsx("div",{className:"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-gray-200 dark:border-gray-700",children:f})]}),e.jsxs("form",{onSubmit:j,className:"flex flex-col flex-1 min-h-0",children:[e.jsx("div",{className:"flex-1 overflow-y-auto px-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-gray-700 text-sm font-bold mb-2",htmlFor:"name",children:[n("groups.name")," *"]}),e.jsx("input",{type:"text",id:"name",name:"name",value:w.name,onChange:o,className:"w-full border border-gray-300 rounded-md px-3 py-2 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",placeholder:n("groups.namePlaceholder"),required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-gray-700 text-sm font-bold mb-2",children:n("groups.configureCapabilities")}),e.jsx(ue,{servers:E,value:w.servers,onChange:g=>A(a=>({...a,servers:g})),className:"border border-gray-200 dark:border-gray-700 rounded-lg p-4 bg-gray-50 dark:bg-gray-800",serverCosts:v})]}),e.jsx(pe,{groupId:l.id,value:w,onChange:g=>A(a=>({...a,...g}))})]})}),e.jsxs("div",{className:"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0",children:[e.jsx("button",{type:"button",onClick:t,className:"hub-btn",disabled:k,children:n("common.cancel")}),e.jsx("button",{type:"submit",className:"hub-btn primary",disabled:k,children:n(k?"common.submitting":"common.save")})]})]})]})})},We=l=>l.map(b=>typeof b=="string"?b:b.name),xe=(l,b)=>{const t=l.servers.find(n=>typeof n=="string"?n===b:n.name===b);return t?typeof t=="string"?{name:t,tools:"all",prompts:"all",resources:"all"}:t:{name:b,tools:"all",prompts:"all",resources:"all"}},Me=(l,b)=>{var n;return((n=xe(l,b).alias)==null?void 0:n.trim())||b},Be=({group:l,servers:b,onEdit:t,onDelete:n,cost:N})=>{var B;const{t:d}=G(),{auth:v}=fe(),E=!!v.user&&(v.user.isAdmin||v.user.username===l.owner),{showToast:D}=ye(),{installConfig:f,nameSeparator:p}=me(),k=((B=f==null?void 0:f.baseUrl)==null?void 0:B.replace(/\/+$/,""))||"",[C,w]=h.useState(!1),[A,o]=h.useState(null),[j,g]=h.useState(!1),[a,c]=h.useState(!1),m=h.useRef(null);h.useEffect(()=>{const T=s=>{m.current&&!m.current.contains(s.target)&&c(!1)};return document.addEventListener("mousedown",T),()=>document.removeEventListener("mousedown",T)},[]);const S=async T=>{await ve(T)?(g(!0),c(!1),D(d("common.copySuccess")||"Copied","success"),setTimeout(()=>g(!1),1500)):D(d("common.copyFailed")||"Copy failed","error")},F=`${k}/mcp/${l.name}`,O=`${k}/mcp/${encodeURIComponent(l.name)}`,H=`${k}/api/${l.name}`,X=We(l.servers),$=b.filter(T=>X.includes(T.name)),M=T=>{const s=xe(l,T.name),i=`${T.name}${p}`,r=T.tools||[],y=T.prompts||[],x=T.resources||[],P=Array.isArray(s.tools)?r.filter(u=>{if(u.enabled===!1)return!1;const L=u.name.startsWith(i)?u.name.slice(i.length):u.name;return s.tools.includes(L)}).length:r.filter(u=>u.enabled!==!1).length,I=Array.isArray(s.prompts)?y.filter(u=>{if(u.enabled===!1)return!1;const L=u.name.startsWith(i)?u.name.slice(i.length):u.name;return s.prompts.includes(L)}).length:y.filter(u=>u.enabled!==!1).length,z=Array.isArray(s.resources)?x.filter(u=>u.enabled!==!1&&s.resources.includes(u.uri)).length:x.filter(u=>u.enabled!==!1).length;return{visibleTools:P,totalTools:r.length,visiblePrompts:I,totalPrompts:y.length,visibleResources:z,totalResources:x.length}},K=$.reduce((T,s)=>T+M(s).visibleTools,0);return e.jsxs("div",{className:"hub-card flex h-full flex-col overflow-visible",children:[e.jsxs("div",{className:"flex items-start gap-3 px-4 py-3",style:{borderBottom:"1px solid var(--hub-line-2)"},children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{style:{fontSize:15,fontWeight:600,letterSpacing:"-0.015em"},children:l.name}),e.jsx("span",{className:"hub-mono",style:{fontSize:11,color:"var(--hub-ink-3)",padding:"0 6px",border:"1px solid var(--hub-line)",borderRadius:4,height:18,display:"inline-flex",alignItems:"center"},title:l.id,children:l.id})]}),e.jsx("div",{className:"mt-1 text-xs text-[var(--hub-ink-3)]",children:l.visibility?d(`server.visibility${l.visibility==="group"?"Group":l.visibility==="public"?"Public":"Private"}`):d("groups.legacyVisibility")}),l.description&&e.jsx("div",{style:{fontSize:12.5,color:"var(--hub-ink-3)",marginTop:2},children:l.description})]}),e.jsxs("div",{className:"flex items-center gap-1",ref:m,children:[e.jsxs("div",{className:"relative",children:[e.jsx("button",{onClick:()=>c(T=>!T),className:"hub-icon-btn sm",title:d("common.copy"),children:j?e.jsx(Te,{size:13,className:"text-[var(--hub-ok)]"}):e.jsx(J,{size:13})}),a&&e.jsxs("div",{className:"absolute top-full right-0 mt-1 z-20 hub-card",style:{minWidth:160,padding:4},children:[e.jsxs("button",{onClick:()=>S(l.id),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(J,{size:12})," ",d("common.copyId")]}),e.jsxs("button",{onClick:()=>S(F),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(ie,{size:12})," ",d("common.copyUrl")]}),e.jsxs("button",{onClick:()=>S(H),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(ie,{size:12})," ",d("common.copyOpenApiUrl")]}),e.jsxs("button",{onClick:()=>{c(!1),o({name:l.name,url:O,headers:{Authorization:`Bearer ${ke}`}})},className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(De,{size:12})," ",d("clientConfig.menuItem")]})]})]}),E&&e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>t(l),className:"hub-icon-btn sm",title:d("groups.edit"),children:e.jsx(Ie,{size:13})}),e.jsx("button",{onClick:()=>w(!0),className:"hub-icon-btn sm",title:d("groups.delete"),style:{color:"var(--hub-ink-3)"},children:e.jsx(ze,{size:13})})]})]})]}),e.jsxs("div",{className:"grid flex-1 items-center gap-3 px-4 py-3",style:{gridTemplateColumns:"1fr 80px 1fr",minHeight:180},children:[e.jsx("div",{className:"flex flex-col gap-1.5",children:$.length===0?e.jsx("div",{style:{fontSize:12,color:"var(--hub-ink-3)"},children:d("groups.noServers")}):$.map(T=>{const s=M(T);return e.jsxs("div",{className:"flex items-center gap-2.5 px-2.5 py-1.5 rounded-md",style:{background:"var(--hub-bg-2)",border:"1px solid var(--hub-line-2)"},children:[e.jsx("span",{className:"inline-block flex-shrink-0",style:{width:6,height:6,borderRadius:50,background:T.status==="connected"?"var(--hub-ok)":T.status==="connecting"?"var(--hub-warn)":"var(--hub-err)"}}),e.jsx("span",{className:"hub-mono truncate flex-1",style:{fontSize:12.5},children:e.jsx("span",{title:T.name,children:Me(l,T.name)})}),e.jsxs("span",{className:"hub-mono hub-num flex-shrink-0",style:{fontSize:11,color:"var(--hub-ink-3)"},children:[s.visibleTools,"/",s.totalTools," tools"]})]},T.name)})}),e.jsxs("svg",{width:"80",height:"80",viewBox:"0 0 80 80",className:"self-center",children:[$.length===0?e.jsx("path",{d:"M0,40 C30,40 50,40 80,40",stroke:"var(--hub-line)",strokeWidth:"1",fill:"none",strokeDasharray:"3 3"}):$.map((T,s)=>{const i=12+60/Math.max($.length,1)*(s+.5);return e.jsx("path",{d:`M0,${i} C 30,${i} 50,40 80,40`,stroke:"var(--hub-line)",strokeWidth:"1",fill:"none",strokeDasharray:"3 3"},s)}),e.jsx("circle",{cx:"80",cy:"40",r:"4",fill:"var(--hub-ink)"})]}),e.jsxs("div",{className:"px-3 py-2.5 rounded-md",style:{border:"1px solid var(--hub-line)",background:"var(--hub-bg-2)"},children:[e.jsx("div",{className:"hub-sect",style:{marginBottom:4},children:"endpoint"}),e.jsxs("div",{className:"hub-mono break-all",style:{fontSize:12,color:"var(--hub-ink-2)",lineHeight:1.4},children:[e.jsx("span",{style:{color:"var(--hub-ink-3)"},children:"/mcp/"}),e.jsx("b",{style:{color:"var(--hub-ink)",fontWeight:600},children:l.name})]}),e.jsxs("div",{className:"hub-mono break-all",style:{fontSize:12,color:"var(--hub-ink-2)",lineHeight:1.4},children:[e.jsx("span",{style:{color:"var(--hub-ink-3)"},children:"/api/"}),e.jsx("b",{style:{color:"var(--hub-ink)",fontWeight:600},children:l.name})]}),e.jsxs("div",{className:"flex gap-1.5 mt-2",children:[e.jsxs("button",{className:"hub-btn sm flex-1 justify-center",onClick:()=>S(F),title:d("common.copyUrl"),children:[e.jsx(J,{size:11})," MCP"]}),e.jsxs("button",{className:"hub-btn sm flex-1 justify-center",onClick:()=>S(H),title:d("common.copyOpenApiUrl"),children:[e.jsx(J,{size:11})," OpenAPI"]})]})]})]}),e.jsxs("div",{className:"flex justify-between items-center px-4 py-2",style:{borderTop:"1px solid var(--hub-line-2)",background:"var(--hub-bg-2)",fontSize:12,color:"var(--hub-ink-3)"},children:[e.jsxs("div",{children:[e.jsxs("div",{className:"hub-mono",children:[e.jsx("span",{style:{color:"var(--hub-ink-2)"},children:$.length})," ",d("nav.servers").toLowerCase()," ·"," ",e.jsx("span",{style:{color:"var(--hub-ink-2)"},children:K})," ",d("server.tools").toLowerCase()]}),N&&e.jsxs("div",{className:"hub-mono mt-1",style:{fontSize:11.5,color:"var(--hub-ink-3)"},children:[e.jsxs("div",{title:d("cost.estimate"),children:[d("cost.totalFootprint"),": ",W(N.direct.exposed),"/",W(N.direct.gross)]}),N.smartRouting&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{children:[d("cost.smartRouting"),": ",W(N.smartRouting.base)," (",d("cost.saved",{percent:je(N.direct.exposed,N.smartRouting.base)}),")"]}),e.jsxs("div",{title:d("cost.smartRoutingPdHint"),children:[d("cost.smartRoutingPd"),":"," ",W(N.smartRouting.progressiveDisclosure)]})]}),N.connectedCount<N.totalCount&&e.jsx("div",{children:d("cost.connectedOf",{connected:N.connectedCount,total:N.totalCount})})]})]}),E&&e.jsxs("button",{className:"hub-btn ghost sm",style:{color:"var(--hub-ink-3)"},onClick:()=>t(l),children:[d("groups.configureTools")||d("groups.edit"),e.jsx(Fe,{size:11,style:{transform:"rotate(-90deg)"}})]})]}),e.jsx(Se,{isOpen:A!==null,target:A,onClose:()=>o(null)}),e.jsx(Le,{isOpen:C,onClose:()=>w(!1),onConfirm:()=>{n(l.id),w(!1)},serverName:l.name,isGroup:!0})]})},Ve=({onSuccess:l,onCancel:b})=>{const{t}=G(),[n,N]=h.useState(""),[d,v]=h.useState(null),[E,D]=h.useState(!1),[f,p]=h.useState(null),k=`{
1
+ import{r as h,R as _,j as e}from"./framework-vendor-_YL27Pfc.js";import{m as Z,e as ge,d as Q,u as fe,j as ye,i as ee}from"./index-DZZHe6u7.js";import{u as se,a as te}from"./useCostData-CMKWXzc1.js";import{u as me,c as ve}from"./clipboard-D07Uwfz5.js";import{f as W,p as je}from"./contextCost-CilWqGWT.js";import{g as Ne,A as ke,C as Se}from"./CopyClientConfigDialog-o6cE_gwR.js";import{u as G}from"./i18n-vendor-BMaj5qV8.js";import{W as we,g as Ce,F as Ae,H as Ee,C as Te,q as J,J as ie,z as De,w as Ie,T as ze,u as Fe,D as oe,N as Pe,P as ce,l as Re,X as Ue}from"./icons-vendor-CvmEvkQ-.js";import{D as Le}from"./DeleteDialog-BYhrMGZo.js";const Oe={tools:[],prompts:[],resources:[]},de={tools:"all",prompts:"all",resources:"all"},ue=({servers:l,value:b,onChange:t,className:n,serverCosts:N=[]})=>{const{t:d}=G(),{nameSeparator:v,smartRoutingConfig:E}=me(),[D,f]=h.useState(new Set),p=_.useMemo(()=>b.map(s=>typeof s=="string"?{name:s,...de}:{...s,tools:s.tools||"all",prompts:s.prompts||"all",resources:s.resources||"all"}),[b]),k=_.useMemo(()=>l.filter(s=>s.enabled!==!1),[l]);_.useEffect(()=>{const s=new Set(p.map(r=>r.name)),i=new Set(k.map(r=>r.name));f(r=>{const y=new Set;return r.forEach(x=>{(s.has(x)||i.has(x))&&y.add(x)}),y})},[p,k]);const C=s=>{if(p.findIndex(r=>r.name===s)>=0){const r=p.filter(y=>y.name!==s);t(r)}else{const r=[...p,{name:s,...de}];t(r)}},w=s=>{f(i=>{const r=new Set(i);return r.has(s)?r.delete(s):r.add(s),r})},A=s=>["tools","prompts","resources"].some(i=>{const r=s[i];return r==="all"||Array.isArray(r)&&r.length>0}),o=(s,i,r,y=!1)=>{const x=p.find(z=>z.name===s),I={...x?{...x}:{name:s,...Oe},[i]:r};if(i==="tools"&&Array.isArray(r)&&I.pinnedTools&&(I.pinnedTools=I.pinnedTools.filter(z=>r.includes(z)),I.pinnedTools.length===0&&delete I.pinnedTools),!A(I)){const z=p.filter(u=>u.name!==s);t(z),y||f(u=>{const L=new Set(u);return L.delete(s),L});return}if(x){t(p.map(z=>z.name===s?I:z));return}t([...p,I])},j=(s,i)=>{const r=p.find(x=>x.name===s);if(!r)return;const y={...r};i?y.alias=i:delete y.alias,t(p.map(x=>x.name===s?y:x))},g=(s,i)=>{const r=p.find(P=>P.name===s);if(!r)return;const y=r.pinnedTools??[],x={...r,pinnedTools:y.includes(i)?y.filter(P=>P!==i):[...y,i]};x.pinnedTools.length===0&&delete x.pinnedTools,t(p.map(P=>P.name===s?x:P))},a=(s,i)=>{const r=`${s}${v}`;return i.startsWith(r)?i.slice(r.length):i},c=(s,i)=>i==="tools"?(s.tools||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.name,value:a(s.name,r.name),description:r.description,defaultDescription:r.defaultDescription,hasDescriptionOverride:r.hasDescriptionOverride})):i==="prompts"?(s.prompts||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.name,value:a(s.name,r.name),description:r.description})):(s.resources||[]).filter(r=>r.enabled!==!1).map(r=>({key:r.uri,value:r.uri,description:r.description})),m=_.useMemo(()=>{const s=new Map;return N.forEach(i=>{const r=new Map;i.items.forEach(y=>r.set(y.name,y.cost)),s.set(i.name,r)}),s},[N]),S=s=>m.get(s)??new Map,F=(s,i)=>{const r=S(s.name);return c(s,i).filter(y=>M(s.name,i,y.value)).reduce((y,x)=>y+(r.get(x.key)??0),0)},O=s=>["tools","prompts","resources"].reduce((i,r)=>i+F(s,r),0),H=(s,i,r)=>{const y=k.find(z=>z.name===s);if(!y)return;const x=c(y,i).map(z=>z.value),P=p.find(z=>z.name===s);if(!P){o(s,i,[r]);return}const I=P[i];if(I==="all"){const z=x.filter(u=>u!==r);o(s,i,z);return}if(Array.isArray(I)){if(I.includes(r)){o(s,i,I.filter(u=>u!==r));return}const z=[...I,r];o(s,i,z.length===x.length?"all":z);return}o(s,i,[r])},X=s=>{const i=p.find(r=>r.name===s);return!!(i&&A(i))},$=s=>{const i=p.find(r=>r.name===s);return i?["tools","prompts","resources"].some(r=>{const y=i[r];return Array.isArray(y)&&y.length>0}):!1},M=(s,i,r)=>{const y=p.find(P=>P.name===s);if(!y)return!1;const x=y[i];return x==="all"?!0:Array.isArray(x)?x.includes(r):!1},K=(s,i)=>{const r=p.find(P=>P.name===s.name);if(!r)return 0;const y=c(s,i),x=r[i];if(x==="all")return y.length;if(Array.isArray(x)){const P=new Set(y.map(I=>I.value));return x.filter(I=>P.has(I)).length}return 0},B=[{key:"tools",titleKey:"groups.toolSelection",countKey:"groups.toolsSelected",allKey:"groups.allTools"},{key:"prompts",titleKey:"groups.promptSelection",countKey:"groups.promptsSelected",allKey:"groups.allPrompts"},{key:"resources",titleKey:"groups.resourceSelection",countKey:"groups.resourcesSelected",allKey:"groups.allResources"}],T=s=>B.map(({key:i})=>({key:i,count:K(s,i)})).filter(i=>i.count>0);return e.jsxs("div",{className:Z("space-y-4",n),children:[e.jsx("div",{className:"space-y-3",children:k.map(s=>{const i=X(s.name),r=$(s.name),y=D.has(s.name),x=p.find(u=>u.name===s.name),P=T(s),I=B.filter(({key:u})=>c(s,u).length>0),z=S(s.name);return e.jsxs("div",{className:"border border-gray-200 dark:border-gray-700 rounded-lg hover:border-gray-300 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 transition-colors",children:[e.jsxs("div",{className:"flex items-center justify-between p-3 cursor-pointer rounded-lg transition-colors",onClick:()=>w(s.name),children:[e.jsxs("div",{className:"flex items-center space-x-3",onClick:u=>{u.stopPropagation(),C(s.name)},children:[e.jsx("input",{type:"checkbox",checked:i||r,onChange:()=>C(s.name),className:"w-4 h-4 text-blue-600 bg-gray-100 dark:bg-gray-800 border-gray-300 rounded focus:ring-blue-500"}),e.jsx("span",{className:"font-medium text-gray-900 cursor-pointer select-none",children:s.name})]}),e.jsxs("div",{className:"flex items-center space-x-3",children:[O(s)>0&&e.jsxs("span",{className:"text-sm text-gray-400 hub-mono",title:d("cost.estimate"),children:["Σ ",W(O(s))]}),P.map(({key:u,count:L})=>e.jsxs("span",{className:"text-sm text-green-600 flex items-center gap-1",children:[u==="tools"?e.jsx(we,{size:14}):u==="prompts"?e.jsx(Ce,{size:14}):e.jsx(Ae,{size:14})," ",L]},u)),I.length>0&&e.jsx("button",{type:"button",className:"p-1 text-gray-400 hover:text-gray-600 transition-colors",children:e.jsx("svg",{className:Z("w-5 h-5 transition-transform",y&&"rotate-180"),fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})})]})]}),y&&I.length>0&&e.jsx("div",{className:"border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 p-3",children:e.jsxs("div",{className:"space-y-4",children:[x&&e.jsxs("div",{className:"space-y-1",onClick:u=>u.stopPropagation(),children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600",children:d("groups.alias")}),e.jsx("input",{type:"text",value:x.alias||"",placeholder:s.name,onChange:u=>j(s.name,u.target.value),className:"w-full rounded-md border border-gray-300 bg-white px-2.5 py-1.5 text-sm text-gray-800 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100"})]}),I.map(({key:u,titleKey:L,countKey:he,allKey:be})=>{const V=c(s,u),re=K(s,u),Y=(x==null?void 0:x[u])==="all"||re===V.length;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("span",{className:"text-sm font-medium text-gray-700",children:d(L)}),e.jsxs("div",{className:"flex items-center gap-3",children:[x&&e.jsx("span",{className:"text-xs text-green-600",children:Y?`(${d(be)} ${V.length}/${V.length})`:`(${d(he)} ${re}/${V.length})`}),x&&F(s,u)>0&&e.jsxs("span",{className:"text-xs text-gray-400 hub-mono",title:d("cost.estimate"),children:["Σ ",W(F(s,u))]}),e.jsx("button",{type:"button",onClick:()=>{o(s.name,u,Y?[]:"all",!0)},className:"text-sm text-blue-600 hover:text-blue-800 transition-colors",children:d(Y?"groups.selectNone":"groups.selectAll")})]})]}),e.jsx("div",{className:"grid grid-cols-1 gap-2 max-h-32 overflow-y-auto",children:V.map(R=>{var le;const ae=M(s.name,u,R.value),q=!!((le=x==null?void 0:x.pinnedTools)!=null&&le.includes(R.value)),U=u==="tools"?Ne({description:R.description,defaultDescription:R.defaultDescription,hasDescriptionOverride:R.hasDescriptionOverride},d("tool.noDescription")):null,ne=U!=null&&U.hasDescriptionOverride?d("tool.defaultDescriptionTooltip",{description:U.defaultDescription}):R.description;return e.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[e.jsxs("label",{className:"flex min-w-0 flex-1 items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:ae,onChange:()=>H(s.name,u,R.value),className:"w-3 h-3 text-blue-600 bg-gray-100 dark:bg-gray-800 border-gray-300 rounded focus:ring-blue-500"}),e.jsx("span",{className:"text-gray-700 break-all whitespace-nowrap flex-shrink-0",children:R.value}),(R.description||(U==null?void 0:U.hasDescriptionOverride))&&e.jsxs("span",{className:"min-w-0 flex items-center gap-1 text-gray-400 text-xs truncate",children:[e.jsx("span",{className:"truncate",title:ne||void 0,children:U?U.currentDescription:R.description}),(U==null?void 0:U.hasDescriptionOverride)&&e.jsx("span",{className:"inline-flex flex-shrink-0 items-center rounded-full border border-amber-200 bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 dark:border-amber-700/60 dark:bg-amber-900/20 dark:text-amber-300",title:ne||void 0,children:d("tool.descriptionModifiedBadge")})]}),z.get(R.key)!=null&&e.jsxs("span",{className:"text-xs text-gray-400 hub-mono whitespace-nowrap ml-auto flex-shrink-0",title:d("cost.estimate"),children:["Σ ",W(z.get(R.key))]})]}),u==="tools"&&ae&&(E.enabled||q)&&e.jsx("button",{type:"button",onClick:()=>g(s.name,R.value),title:d(q?"groups.unpinTool":"groups.pinTool"),"aria-label":d("groups.pinToolLabel"),"aria-pressed":q,className:Z("flex-shrink-0 transition-colors",q?"text-blue-600":"text-gray-300 hover:text-gray-500 dark:text-gray-600 dark:hover:text-gray-400"),children:e.jsx(Ee,{size:12,fill:q?"currentColor":"none"})})]},R.key)})})]},u)})]})})]},s.name)})}),k.length===0&&e.jsx("p",{className:"text-gray-500 text-sm",children:d("groups.noServerOptions")})]})};function pe({groupId:l,value:b,onChange:t}){const{t:n}=G(),[N,d]=h.useState([]),[v,E]=h.useState(""),[D,f]=h.useState(!1),[p,k]=h.useState(!1),[C,w]=h.useState(!1);h.useEffect(()=>{if(!l||b.visibility!=="group")return;let m=!1;return f(!0),k(!1),ge(`/groups/${encodeURIComponent(l)}/share-candidates`).then(S=>{m||(S.success&&Array.isArray(S.data)?d(S.data):k(!0))}).catch(()=>{m||k(!0)}).finally(()=>{m||f(!1)}),()=>{m=!0}},[l,b.visibility]);const A=b.sharedWithUsers||[],o=[...new Set([...N,...A])].sort().filter(m=>m.toLowerCase().includes(v.toLowerCase())),j=new Set(A),g=o.length>0&&o.every(m=>j.has(m)),a=o.length===0||o.every(m=>!j.has(m)),c=m=>{const S=new Set(A);S.has(m)?S.delete(m):S.add(m),t({sharedWithUsers:Array.from(S)})};return e.jsxs("div",{className:"mb-4",children:[e.jsxs("div",{className:"flex items-center justify-between cursor-pointer bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 p-3 rounded border border-gray-200 dark:border-gray-700",onClick:()=>w(!C),children:[e.jsx("h3",{className:"text-sm font-semibold text-[var(--hub-ink)]",children:n("server.sectionAdvanced","Advanced Options")}),e.jsx("span",{className:"text-gray-500 text-sm",children:C?"▼":"▶"})]}),C&&e.jsxs("div",{className:"border border-gray-200 dark:border-gray-700 rounded-b p-4 bg-white dark:bg-gray-900 border-t-0",children:[e.jsx("label",{htmlFor:"group-visibility",className:"block text-sm font-medium mb-1.5 text-[var(--hub-ink-2)]",children:n("server.visibility")}),e.jsxs("select",{id:"group-visibility",className:"w-full py-2 px-3 form-input",value:b.visibility||"",onChange:m=>t({visibility:m.target.value}),children:[!b.visibility&&e.jsx("option",{value:"",disabled:!0,children:n("groups.legacyVisibility")}),e.jsx("option",{value:"private",children:n("server.visibilityPrivate")}),e.jsx("option",{value:"group",children:n("server.visibilityGroup")}),e.jsx("option",{value:"public",children:n("server.visibilityPublic")})]}),e.jsx("p",{className:"text-xs text-gray-500 mt-1",children:n("groups.visibilityDescription")}),!b.visibility&&e.jsx("p",{className:"text-sm text-amber-600",children:n("groups.legacyVisibilityHint")}),b.visibility==="group"&&e.jsxs("div",{className:"mt-4 rounded border border-gray-200 dark:border-gray-700 p-3",children:[e.jsx("div",{className:"text-sm font-medium text-[var(--hub-ink-2)]",children:n("server.shareWithUsers")}),e.jsx("p",{className:"text-xs text-gray-500 mt-1 mb-3",children:n("server.shareWithUsersDescription")}),l?e.jsxs(e.Fragment,{children:[D&&e.jsx("p",{className:"text-sm text-gray-500",children:n("server.shareCandidatesLoading")}),p&&e.jsx("p",{role:"alert",className:"text-sm text-red-600 dark:text-red-400",children:n("server.shareCandidatesError")}),!D&&!p&&o.length===0&&e.jsx("p",{className:"text-sm text-gray-500",children:n(v?"server.noMatchingShareUsers":"server.noShareCandidates")}),o.length>0&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 space-y-2",children:[e.jsx("label",{htmlFor:"group-share-search",className:"block text-xs font-medium text-[var(--hub-ink-2)]",children:n("server.shareUserSearchLabel")}),e.jsx("input",{id:"group-share-search",type:"search",value:v,onChange:m=>E(m.target.value),placeholder:n("server.shareUserSearchPlaceholder"),className:"w-full py-2 px-3 form-input text-sm"}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:()=>t({sharedWithUsers:[...new Set([...A,...o])]}),disabled:g,className:"hub-btn text-sm",children:n("server.selectAllShareUsers")}),e.jsx("button",{type:"button",onClick:()=>t({sharedWithUsers:A.filter(m=>!o.includes(m))}),disabled:a,className:"hub-btn text-sm",children:n("server.deselectAllShareUsers")})]})]}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2",children:o.map(m=>e.jsxs("label",{className:"flex items-center gap-2 rounded border border-gray-200 dark:border-gray-700 px-3 py-2 text-sm text-[var(--hub-ink-2)]",children:[e.jsx("input",{type:"checkbox",checked:j.has(m),onChange:()=>c(m)}),e.jsx("span",{children:m})]},m))})]})]}):e.jsx("p",{className:"text-sm text-gray-500",children:n("groups.shareAfterCreate")})]})]})]})}const $e=({onAdd:l,onCancel:b})=>{const{t}=G(),{createGroup:n}=Q(),{allServers:N}=se(),{serverCosts:d}=te(),[v,E]=h.useState([]),[D,f]=h.useState(null),[p,k]=h.useState(!1),[C,w]=h.useState({visibility:"private",sharedWithUsers:[],name:"",description:"",servers:[]});h.useEffect(()=>{E(N.filter(j=>j.enabled!==!1))},[N]);const A=j=>{const{name:g,value:a}=j.target;w(c=>({...c,[g]:a}))},o=async j=>{j.preventDefault(),k(!0),f(null);try{if(!C.name.trim()){f(t("groups.nameRequired")),k(!1);return}const g=await n(C.name,C.description,C.servers,{visibility:C.visibility,sharedWithUsers:C.sharedWithUsers});if(!g||!g.success){f((g==null?void 0:g.message)||t("groups.createError")),k(!1);return}l()}catch(g){f(g instanceof Error?g.message:String(g)),k(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col",children:[e.jsxs("div",{className:"p-6 flex-shrink-0",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 mb-4",children:t("groups.addNew")}),D&&e.jsx("div",{className:"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-gray-200 dark:border-gray-700",children:D})]}),e.jsxs("form",{onSubmit:o,className:"flex flex-col flex-1 min-h-0",children:[e.jsx("div",{className:"flex-1 overflow-y-auto px-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-gray-700 text-sm font-bold mb-2",htmlFor:"name",children:[t("groups.name")," *"]}),e.jsx("input",{type:"text",id:"name",name:"name",value:C.name,onChange:A,className:"w-full border border-gray-300 rounded-md px-3 py-2 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",placeholder:t("groups.namePlaceholder"),required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-gray-700 text-sm font-bold mb-2",children:t("groups.configureCapabilities")}),e.jsx(ue,{servers:v,value:C.servers,onChange:j=>w(g=>({...g,servers:j})),className:"border border-gray-200 dark:border-gray-700 rounded-lg p-4 bg-gray-50 dark:bg-gray-800",serverCosts:d})]}),e.jsx(pe,{value:C,onChange:j=>w(g=>({...g,...j}))})]})}),e.jsxs("div",{className:"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0",children:[e.jsx("button",{type:"button",onClick:b,className:"hub-btn",disabled:p,children:t("common.cancel")}),e.jsx("button",{type:"submit",className:"hub-btn primary",disabled:p,children:t(p?"common.submitting":"common.create")})]})]})]})})},Ge=({group:l,onEdit:b,onCancel:t})=>{const{t:n}=G(),{updateGroup:N}=Q(),{allServers:d}=se(),{serverCosts:v}=te(),[E,D]=h.useState([]),[f,p]=h.useState(null),[k,C]=h.useState(!1),[w,A]=h.useState({visibility:l.visibility,sharedWithUsers:l.sharedWithUsers||[],name:l.name,description:l.description||"",servers:l.servers||[]});h.useEffect(()=>{D(d.filter(g=>g.enabled!==!1))},[d]);const o=g=>{const{name:a,value:c}=g.target;A(m=>({...m,[a]:c}))},j=async g=>{g.preventDefault(),C(!0),p(null);try{if(!w.name.trim()){p(n("groups.nameRequired")),C(!1);return}const a=await N(l.id,{visibility:w.visibility,sharedWithUsers:w.sharedWithUsers,name:w.name,description:w.description,servers:w.servers});if(!a||!a.success){p((a==null?void 0:a.message)||n("groups.updateError")),C(!1);return}b()}catch(a){p(a instanceof Error?a.message:String(a)),C(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col",children:[e.jsxs("div",{className:"p-6 flex-shrink-0",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-800 mb-4",children:n("groups.edit")}),f&&e.jsx("div",{className:"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-gray-200 dark:border-gray-700",children:f})]}),e.jsxs("form",{onSubmit:j,className:"flex flex-col flex-1 min-h-0",children:[e.jsx("div",{className:"flex-1 overflow-y-auto px-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-gray-700 text-sm font-bold mb-2",htmlFor:"name",children:[n("groups.name")," *"]}),e.jsx("input",{type:"text",id:"name",name:"name",value:w.name,onChange:o,className:"w-full border border-gray-300 rounded-md px-3 py-2 text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",placeholder:n("groups.namePlaceholder"),required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-gray-700 text-sm font-bold mb-2",children:n("groups.configureCapabilities")}),e.jsx(ue,{servers:E,value:w.servers,onChange:g=>A(a=>({...a,servers:g})),className:"border border-gray-200 dark:border-gray-700 rounded-lg p-4 bg-gray-50 dark:bg-gray-800",serverCosts:v})]}),e.jsx(pe,{groupId:l.id,value:w,onChange:g=>A(a=>({...a,...g}))})]})}),e.jsxs("div",{className:"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0",children:[e.jsx("button",{type:"button",onClick:t,className:"hub-btn",disabled:k,children:n("common.cancel")}),e.jsx("button",{type:"submit",className:"hub-btn primary",disabled:k,children:n(k?"common.submitting":"common.save")})]})]})]})})},We=l=>l.map(b=>typeof b=="string"?b:b.name),xe=(l,b)=>{const t=l.servers.find(n=>typeof n=="string"?n===b:n.name===b);return t?typeof t=="string"?{name:t,tools:"all",prompts:"all",resources:"all"}:t:{name:b,tools:"all",prompts:"all",resources:"all"}},Me=(l,b)=>{var n;return((n=xe(l,b).alias)==null?void 0:n.trim())||b},Be=({group:l,servers:b,onEdit:t,onDelete:n,cost:N})=>{var B;const{t:d}=G(),{auth:v}=fe(),E=!!v.user&&(v.user.isAdmin||v.user.username===l.owner),{showToast:D}=ye(),{installConfig:f,nameSeparator:p}=me(),k=((B=f==null?void 0:f.baseUrl)==null?void 0:B.replace(/\/+$/,""))||"",[C,w]=h.useState(!1),[A,o]=h.useState(null),[j,g]=h.useState(!1),[a,c]=h.useState(!1),m=h.useRef(null);h.useEffect(()=>{const T=s=>{m.current&&!m.current.contains(s.target)&&c(!1)};return document.addEventListener("mousedown",T),()=>document.removeEventListener("mousedown",T)},[]);const S=async T=>{await ve(T)?(g(!0),c(!1),D(d("common.copySuccess")||"Copied","success"),setTimeout(()=>g(!1),1500)):D(d("common.copyFailed")||"Copy failed","error")},F=`${k}/mcp/${l.name}`,O=`${k}/mcp/${encodeURIComponent(l.name)}`,H=`${k}/api/${l.name}`,X=We(l.servers),$=b.filter(T=>X.includes(T.name)),M=T=>{const s=xe(l,T.name),i=`${T.name}${p}`,r=T.tools||[],y=T.prompts||[],x=T.resources||[],P=Array.isArray(s.tools)?r.filter(u=>{if(u.enabled===!1)return!1;const L=u.name.startsWith(i)?u.name.slice(i.length):u.name;return s.tools.includes(L)}).length:r.filter(u=>u.enabled!==!1).length,I=Array.isArray(s.prompts)?y.filter(u=>{if(u.enabled===!1)return!1;const L=u.name.startsWith(i)?u.name.slice(i.length):u.name;return s.prompts.includes(L)}).length:y.filter(u=>u.enabled!==!1).length,z=Array.isArray(s.resources)?x.filter(u=>u.enabled!==!1&&s.resources.includes(u.uri)).length:x.filter(u=>u.enabled!==!1).length;return{visibleTools:P,totalTools:r.length,visiblePrompts:I,totalPrompts:y.length,visibleResources:z,totalResources:x.length}},K=$.reduce((T,s)=>T+M(s).visibleTools,0);return e.jsxs("div",{className:"hub-card flex h-full flex-col overflow-visible",children:[e.jsxs("div",{className:"flex items-start gap-3 px-4 py-3",style:{borderBottom:"1px solid var(--hub-line-2)"},children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{style:{fontSize:15,fontWeight:600,letterSpacing:"-0.015em"},children:l.name}),e.jsx("span",{className:"hub-mono",style:{fontSize:11,color:"var(--hub-ink-3)",padding:"0 6px",border:"1px solid var(--hub-line)",borderRadius:4,height:18,display:"inline-flex",alignItems:"center"},title:l.id,children:l.id})]}),e.jsx("div",{className:"mt-1 text-xs text-[var(--hub-ink-3)]",children:l.visibility?d(`server.visibility${l.visibility==="group"?"Group":l.visibility==="public"?"Public":"Private"}`):d("groups.legacyVisibility")}),l.description&&e.jsx("div",{style:{fontSize:12.5,color:"var(--hub-ink-3)",marginTop:2},children:l.description})]}),e.jsxs("div",{className:"flex items-center gap-1",ref:m,children:[e.jsxs("div",{className:"relative",children:[e.jsx("button",{onClick:()=>c(T=>!T),className:"hub-icon-btn sm",title:d("common.copy"),children:j?e.jsx(Te,{size:13,className:"text-[var(--hub-ok)]"}):e.jsx(J,{size:13})}),a&&e.jsxs("div",{className:"absolute top-full right-0 mt-1 z-20 hub-card",style:{minWidth:160,padding:4},children:[e.jsxs("button",{onClick:()=>S(l.id),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(J,{size:12})," ",d("common.copyId")]}),e.jsxs("button",{onClick:()=>S(F),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(ie,{size:12})," ",d("common.copyUrl")]}),e.jsxs("button",{onClick:()=>S(H),className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(ie,{size:12})," ",d("common.copyOpenApiUrl")]}),e.jsxs("button",{onClick:()=>{c(!1),o({name:l.name,url:O,headers:{Authorization:`Bearer ${ke}`}})},className:"flex items-center gap-2 w-full px-2.5 py-1.5 text-[13px] rounded-md hover:bg-[var(--hub-surface-hover)] text-left",children:[e.jsx(De,{size:12})," ",d("clientConfig.menuItem")]})]})]}),E&&e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>t(l),className:"hub-icon-btn sm",title:d("groups.edit"),children:e.jsx(Ie,{size:13})}),e.jsx("button",{onClick:()=>w(!0),className:"hub-icon-btn sm",title:d("groups.delete"),style:{color:"var(--hub-ink-3)"},children:e.jsx(ze,{size:13})})]})]})]}),e.jsxs("div",{className:"grid flex-1 items-center gap-3 px-4 py-3",style:{gridTemplateColumns:"1fr 80px 1fr",minHeight:180},children:[e.jsx("div",{className:"flex flex-col gap-1.5",children:$.length===0?e.jsx("div",{style:{fontSize:12,color:"var(--hub-ink-3)"},children:d("groups.noServers")}):$.map(T=>{const s=M(T);return e.jsxs("div",{className:"flex items-center gap-2.5 px-2.5 py-1.5 rounded-md",style:{background:"var(--hub-bg-2)",border:"1px solid var(--hub-line-2)"},children:[e.jsx("span",{className:"inline-block flex-shrink-0",style:{width:6,height:6,borderRadius:50,background:T.status==="connected"?"var(--hub-ok)":T.status==="connecting"?"var(--hub-warn)":"var(--hub-err)"}}),e.jsx("span",{className:"hub-mono truncate flex-1",style:{fontSize:12.5},children:e.jsx("span",{title:T.name,children:Me(l,T.name)})}),e.jsxs("span",{className:"hub-mono hub-num flex-shrink-0",style:{fontSize:11,color:"var(--hub-ink-3)"},children:[s.visibleTools,"/",s.totalTools," tools"]})]},T.name)})}),e.jsxs("svg",{width:"80",height:"80",viewBox:"0 0 80 80",className:"self-center",children:[$.length===0?e.jsx("path",{d:"M0,40 C30,40 50,40 80,40",stroke:"var(--hub-line)",strokeWidth:"1",fill:"none",strokeDasharray:"3 3"}):$.map((T,s)=>{const i=12+60/Math.max($.length,1)*(s+.5);return e.jsx("path",{d:`M0,${i} C 30,${i} 50,40 80,40`,stroke:"var(--hub-line)",strokeWidth:"1",fill:"none",strokeDasharray:"3 3"},s)}),e.jsx("circle",{cx:"80",cy:"40",r:"4",fill:"var(--hub-ink)"})]}),e.jsxs("div",{className:"px-3 py-2.5 rounded-md",style:{border:"1px solid var(--hub-line)",background:"var(--hub-bg-2)"},children:[e.jsx("div",{className:"hub-sect",style:{marginBottom:4},children:"endpoint"}),e.jsxs("div",{className:"hub-mono break-all",style:{fontSize:12,color:"var(--hub-ink-2)",lineHeight:1.4},children:[e.jsx("span",{style:{color:"var(--hub-ink-3)"},children:"/mcp/"}),e.jsx("b",{style:{color:"var(--hub-ink)",fontWeight:600},children:l.name})]}),e.jsxs("div",{className:"hub-mono break-all",style:{fontSize:12,color:"var(--hub-ink-2)",lineHeight:1.4},children:[e.jsx("span",{style:{color:"var(--hub-ink-3)"},children:"/api/"}),e.jsx("b",{style:{color:"var(--hub-ink)",fontWeight:600},children:l.name})]}),e.jsxs("div",{className:"flex gap-1.5 mt-2",children:[e.jsxs("button",{className:"hub-btn sm flex-1 justify-center",onClick:()=>S(F),title:d("common.copyUrl"),children:[e.jsx(J,{size:11})," MCP"]}),e.jsxs("button",{className:"hub-btn sm flex-1 justify-center",onClick:()=>S(H),title:d("common.copyOpenApiUrl"),children:[e.jsx(J,{size:11})," OpenAPI"]})]})]})]}),e.jsxs("div",{className:"flex justify-between items-center px-4 py-2",style:{borderTop:"1px solid var(--hub-line-2)",background:"var(--hub-bg-2)",fontSize:12,color:"var(--hub-ink-3)"},children:[e.jsxs("div",{children:[e.jsxs("div",{className:"hub-mono",children:[e.jsx("span",{style:{color:"var(--hub-ink-2)"},children:$.length})," ",d("nav.servers").toLowerCase()," ·"," ",e.jsx("span",{style:{color:"var(--hub-ink-2)"},children:K})," ",d("server.tools").toLowerCase()]}),N&&e.jsxs("div",{className:"hub-mono mt-1",style:{fontSize:11.5,color:"var(--hub-ink-3)"},children:[e.jsxs("div",{title:d("cost.estimate"),children:[d("cost.totalFootprint"),": ",W(N.direct.exposed),"/",W(N.direct.gross)]}),N.smartRouting&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{children:[d("cost.smartRouting"),": ",W(N.smartRouting.base)," (",d("cost.saved",{percent:je(N.direct.exposed,N.smartRouting.base)}),")"]}),e.jsxs("div",{title:d("cost.smartRoutingPdHint"),children:[d("cost.smartRoutingPd"),":"," ",W(N.smartRouting.progressiveDisclosure)]})]}),N.connectedCount<N.totalCount&&e.jsx("div",{children:d("cost.connectedOf",{connected:N.connectedCount,total:N.totalCount})})]})]}),E&&e.jsxs("button",{className:"hub-btn ghost sm",style:{color:"var(--hub-ink-3)"},onClick:()=>t(l),children:[d("groups.configureTools")||d("groups.edit"),e.jsx(Fe,{size:11,style:{transform:"rotate(-90deg)"}})]})]}),e.jsx(Se,{isOpen:A!==null,target:A,onClose:()=>o(null)}),e.jsx(Le,{isOpen:C,onClose:()=>w(!1),onConfirm:()=>{n(l.id),w(!1)},serverName:l.name,isGroup:!0})]})},Ve=({onSuccess:l,onCancel:b})=>{const{t}=G(),[n,N]=h.useState(""),[d,v]=h.useState(null),[E,D]=h.useState(!1),[f,p]=h.useState(null),k=`{
2
2
  "groups": [
3
3
  {
4
4
  "name": "AI Assistants",
@@ -30,4 +30,4 @@ Supports:
30
30
  - All groups will be imported in a single efficient batch operation.`,C=a=>{try{const c=JSON.parse(a.trim());if(!c.groups||!Array.isArray(c.groups))return v(t("groupImport.invalidFormat")),null;for(const m of c.groups)if(!m.name||typeof m.name!="string")return v(t("groupImport.missingName")),null;return c}catch{return v(t("groupImport.parseError")),null}},w=()=>{v(null);const a=C(n);a&&p(a.groups)},A=async()=>{if(f){D(!0),v(null);try{const a=await ee("/groups/batch",{groups:f});if(a.success){const{successCount:c,failureCount:m,results:S}=a;if(m>0){const F=S.filter(O=>!O.success).map(O=>`${O.name}: ${O.message||t("groupImport.addFailed")}`);v(t("groupImport.partialSuccess",{count:c,total:f.length})+`
31
31
  `+F.join(`
32
32
  `))}c>0&&l()}else v(a.message||t("groupImport.importFailed"))}catch(a){console.error("Import error:",a),v(t("groupImport.importFailed"))}finally{D(!1)}}},o=a=>e.jsx("span",{className:"text-gray-500 ml-2",children:t(`groups.${a}`)}),j=(a,c)=>{if(!c||c==="all")return null;const m=Array.isArray(c)?c.join(", "):c;return e.jsx("span",{className:"text-gray-500 ml-2",children:t(`groups.${a}`,{items:m})})},g=a=>!a||a.length===0?e.jsx("span",{className:"text-gray-500",children:t("groups.noServers")}):e.jsx("div",{className:"space-y-1",children:a.map((c,m)=>typeof c=="string"?e.jsxs("div",{className:"text-sm",children:["• ",c]},m):e.jsxs("div",{className:"text-sm",children:["• ",c.name,c.tools&&c.tools!=="all"&&e.jsxs("span",{className:"text-gray-500 ml-2",children:["(",Array.isArray(c.tools)?c.tools.join(", "):c.tools,")"]}),c.tools==="all"&&o("previewAllTools"),j("previewPrompts",c.prompts),c.prompts==="all"&&o("previewAllPrompts"),j("previewResources",c.resources),c.resources==="all"&&o("previewAllResources")]},m))});return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto",children:[e.jsxs("div",{className:"flex justify-between items-center mb-6",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-900",children:t("groupImport.title")}),e.jsx("button",{onClick:b,className:"text-gray-500 hover:text-gray-700",children:"✕"})]}),d&&e.jsx("div",{className:"mb-4 bg-red-50 border-l-4 border-red-500 p-4 rounded",children:e.jsx("p",{className:"text-red-700 whitespace-pre-wrap",children:d})}),f?e.jsxs("div",{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("h3",{className:"text-lg font-medium text-gray-900 mb-3",children:t("groupImport.previewTitle")}),e.jsx("div",{className:"space-y-3",children:f.map((a,c)=>e.jsx("div",{className:"bg-gray-50 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700",children:e.jsx("div",{className:"flex items-start justify-between",children:e.jsxs("div",{className:"flex-1",children:[e.jsx("h4",{className:"font-medium text-gray-900",children:a.name}),a.description&&e.jsx("p",{className:"text-sm text-gray-600 mt-1",children:a.description}),e.jsxs("div",{className:"mt-2 text-sm text-gray-600",children:[e.jsxs("strong",{children:[t("groups.servers"),":"]}),e.jsx("div",{className:"mt-1",children:g(a.servers)})]})]})})},c))})]}),e.jsxs("div",{className:"flex justify-end space-x-4",children:[e.jsx("button",{onClick:()=>p(null),disabled:E,className:"hub-btn",children:t("common.back")}),e.jsx("button",{onClick:A,disabled:E,className:"hub-btn primary",children:E?e.jsxs(e.Fragment,{children:[e.jsxs("svg",{className:"animate-spin h-4 w-4 mr-2",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),t("groupImport.importing")]}):t("groupImport.import")})]})]}):e.jsxs("div",{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:t("groupImport.inputLabel")}),e.jsx("textarea",{value:n,onChange:a=>N(a.target.value),className:"w-full h-96 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 font-mono text-sm",placeholder:k}),e.jsx("p",{className:"text-xs text-gray-500 mt-2",children:t("groupImport.inputHelp")})]}),e.jsxs("div",{className:"flex justify-end space-x-4",children:[e.jsx("button",{onClick:b,className:"hub-btn",children:t("common.cancel")}),e.jsx("button",{onClick:w,disabled:!n.trim(),className:"hub-btn primary",children:t("groupImport.preview")})]})]})]})})},qe=({groups:l,onCancel:b})=>{const{t}=G(),[n,N]=h.useState(""),[d,v]=h.useState(""),[E,D]=h.useState([]),[f,p]=h.useState(!1),[k,C]=h.useState(!1),[w,A]=h.useState(null),o=a=>{D(c=>c.includes(a)?c.filter(m=>m!==a):[...c,a])},j=()=>{E.length===l.length?D([]):D(l.map(a=>a.id))},g=async()=>{if(!n.trim()){A(t("template.nameRequired"));return}C(!0),A(null);try{const a=await ee("/templates/export",{name:n.trim(),description:d.trim()||void 0,groupIds:E.length>0?E:void 0,includeDisabledServers:f});if(a.success&&a.data){const c=a.data,m=new Blob([JSON.stringify(c,null,2)],{type:"application/json"}),S=URL.createObjectURL(m),F=document.createElement("a");F.href=S,F.download=`${c.name.replace(/[^a-zA-Z0-9-_]/g,"_")}.mcphub-template.json`,document.body.appendChild(F),F.click(),document.body.removeChild(F),URL.revokeObjectURL(S),b()}else A(a.message||t("template.exportFailed"))}catch(a){console.error("Export error:",a),A(t("template.exportFailed"))}finally{C(!1)}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-3xl max-h-[90vh] overflow-y-auto",children:[e.jsxs("div",{className:"flex justify-between items-center mb-6",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-900",children:t("template.exportTitle")}),e.jsx("button",{onClick:b,className:"text-gray-500 hover:text-gray-700",children:"✕"})]}),w&&e.jsx("div",{className:"mb-4 bg-red-50 border-l-4 border-red-500 p-4 rounded",children:e.jsx("p",{className:"text-red-700",children:w})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:[t("template.name")," *"]}),e.jsx("input",{type:"text",value:n,onChange:a=>N(a.target.value),className:"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:t("template.namePlaceholder")})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:t("template.description")}),e.jsx("input",{type:"text",value:d,onChange:a=>v(a.target.value),className:"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:t("template.descriptionPlaceholder")})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex justify-between items-center mb-2",children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700",children:t("template.selectGroups")}),e.jsx("button",{onClick:j,className:"text-sm text-blue-600 hover:text-blue-800",children:E.length===l.length?t("template.deselectAll"):t("template.selectAll")})]}),e.jsx("p",{className:"text-xs text-gray-500 mb-2",children:t("template.selectGroupsHelp")}),e.jsx("div",{className:"border border-gray-200 dark:border-gray-700 rounded-md max-h-48 overflow-y-auto",children:l.map(a=>e.jsxs("label",{className:"flex items-center px-3 py-2 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:E.includes(a.id),onChange:()=>o(a.id),className:"mr-3 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"}),e.jsxs("div",{children:[e.jsx("span",{className:"text-sm font-medium text-gray-900",children:a.name}),a.description&&e.jsx("span",{className:"text-xs text-gray-500 ml-2",children:a.description})]})]},a.id))})]}),e.jsxs("label",{className:"flex items-center space-x-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:f,onChange:a=>p(a.target.checked),className:"h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"}),e.jsx("span",{className:"text-sm text-gray-700",children:t("template.includeDisabled")})]})]}),e.jsx("div",{className:"mt-4 p-3 bg-blue-50 border border-blue-200 rounded-md",children:e.jsx("p",{className:"text-sm text-blue-700",children:t("template.exportNote")})}),e.jsxs("div",{className:"flex justify-end space-x-4 mt-6",children:[e.jsx("button",{onClick:b,className:"hub-btn",children:t("common.cancel")}),e.jsx("button",{onClick:g,disabled:k||!n.trim(),className:"hub-btn primary",children:t(k?"template.exporting":"template.export")})]})]})})},He=({onSuccess:l,onCancel:b})=>{const{t}=G(),[n,N]=h.useState(null),[d,v]=h.useState(null),[E,D]=h.useState(!1),[f,p]=h.useState(null),k=h.useRef(null),C=o=>{var a;v(null),N(null),p(null);const j=(a=o.target.files)==null?void 0:a[0];if(!j)return;const g=new FileReader;g.onload=c=>{var m;try{const S=JSON.parse((m=c.target)==null?void 0:m.result);if(!S.version||!S.name||!S.servers||!S.groups){v(t("template.invalidFormat"));return}N(S)}catch{v(t("template.parseError"))}},g.readAsText(j)},w=o=>{if(v(null),N(null),p(null),!!o.trim())try{const j=JSON.parse(o.trim());if(!j.version||!j.name||!j.servers||!j.groups){v(t("template.invalidFormat"));return}N(j)}catch{v(t("template.parseError"))}},A=async()=>{if(n){D(!0),v(null);try{const o=await ee("/templates/import",n);o.data?(p(o.data),o.data.success&&l()):v(o.message||t("template.importFailed"))}catch(o){console.error("Import error:",o),v(t("template.importFailed"))}finally{D(!1)}}};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsxs("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto",children:[e.jsxs("div",{className:"flex justify-between items-center mb-6",children:[e.jsx("h2",{className:"text-xl font-semibold text-gray-900",children:t("template.importTitle")}),e.jsx("button",{onClick:b,className:"text-gray-500 hover:text-gray-700",children:"✕"})]}),d&&e.jsx("div",{className:"mb-4 bg-red-50 border-l-4 border-red-500 p-4 rounded",children:e.jsx("p",{className:"text-red-700",children:d})}),f&&e.jsxs("div",{className:`mb-4 p-4 rounded border-l-4 ${f.success?"bg-green-50 border-green-500":"bg-yellow-50 border-yellow-500"}`,children:[e.jsx("p",{className:f.success?"text-green-700":"text-yellow-700",children:t("template.importResult",{serversCreated:f.serversCreated,serversSkipped:f.serversSkipped,groupsCreated:f.groupsCreated,groupsSkipped:f.groupsSkipped})}),f.requiredEnvVars.length>0&&e.jsxs("div",{className:"mt-2 p-2 bg-orange-50 border border-orange-200 rounded",children:[e.jsx("p",{className:"text-sm font-medium text-orange-800",children:t("template.envVarsNeeded")}),e.jsx("ul",{className:"mt-1 text-sm text-orange-700",children:f.requiredEnvVars.map(o=>e.jsx("li",{className:"font-mono",children:o},o))})]})]}),n?e.jsxs("div",{children:[e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"p-3 bg-gray-50 dark:bg-gray-800 rounded-md",children:[e.jsx("h3",{className:"font-medium text-gray-900",children:n.name}),n.description&&e.jsx("p",{className:"text-sm text-gray-600 mt-1",children:n.description}),e.jsxs("p",{className:"text-xs text-gray-500 mt-1",children:[t("template.version"),": ",n.version," | ",t("template.createdAt"),":"," ",new Date(n.createdAt).toLocaleDateString()]})]}),e.jsxs("div",{children:[e.jsxs("h4",{className:"text-sm font-medium text-gray-700 mb-2",children:[t("template.servers")," (",Object.keys(n.servers).length,")"]}),e.jsx("div",{className:"border border-gray-200 dark:border-gray-700 rounded-md divide-y divide-gray-200 dark:divide-gray-700 max-h-40 overflow-y-auto",children:Object.entries(n.servers).map(([o,j])=>e.jsxs("div",{className:"px-3 py-2",children:[e.jsx("span",{className:"text-sm font-medium text-gray-900",children:o}),e.jsx("span",{className:"text-xs text-gray-500 ml-2",children:j.type||"stdio"})]},o))})]}),e.jsxs("div",{children:[e.jsxs("h4",{className:"text-sm font-medium text-gray-700 mb-2",children:[t("template.groups")," (",n.groups.length,")"]}),e.jsx("div",{className:"border border-gray-200 dark:border-gray-700 rounded-md divide-y divide-gray-200 dark:divide-gray-700 max-h-40 overflow-y-auto",children:n.groups.map((o,j)=>e.jsxs("div",{className:"px-3 py-2",children:[e.jsx("span",{className:"text-sm font-medium text-gray-900",children:o.name}),o.description&&e.jsx("span",{className:"text-xs text-gray-500 ml-2",children:o.description}),e.jsxs("div",{className:"text-xs text-gray-500 mt-1",children:[o.servers.length," ",t("template.serversInGroup")]})]},j))})]}),n.requiredEnvVars.length>0&&e.jsxs("div",{className:"p-3 bg-orange-50 border border-orange-200 rounded-md",children:[e.jsx("h4",{className:"text-sm font-medium text-orange-800",children:t("template.envVarsNeeded")}),e.jsx("ul",{className:"mt-1 text-sm text-orange-700 font-mono",children:n.requiredEnvVars.map(o=>e.jsx("li",{children:o},o))})]})]}),e.jsxs("div",{className:"flex justify-end space-x-4 mt-6",children:[e.jsx("button",{onClick:()=>{N(null),p(null),k.current&&(k.current.value="")},className:"hub-btn",children:t("common.back")}),e.jsx("button",{onClick:A,disabled:E,className:"hub-btn primary",children:t(E?"template.importing":"template.import")})]})]}):e.jsxs("div",{children:[e.jsxs("div",{className:"mb-4",children:[e.jsx("div",{className:"flex items-center justify-between mb-2",children:e.jsx("label",{className:"block text-sm font-medium text-gray-700",children:t("template.uploadFile")})}),e.jsx("div",{className:"flex items-center space-x-4",children:e.jsx("input",{ref:k,type:"file",accept:".json",onChange:C,className:"block text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"})})]}),e.jsxs("div",{className:"relative my-4",children:[e.jsx("div",{className:"absolute inset-0 flex items-center",children:e.jsx("div",{className:"w-full border-t border-gray-300"})}),e.jsx("div",{className:"relative flex justify-center text-sm",children:e.jsx("span",{className:"bg-white dark:bg-gray-800 px-2 text-gray-500",children:t("template.or")})})]}),e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-2",children:t("template.pasteJson")}),e.jsx("textarea",{className:"w-full h-64 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 font-mono text-sm",placeholder:t("template.pastePlaceholder"),onChange:o=>w(o.target.value)})]}),e.jsx("div",{className:"flex justify-end space-x-4",children:e.jsx("button",{onClick:b,className:"hub-btn",children:t("common.cancel")})})]})]})})},ts=()=>{const{t:l}=G(),{groups:b,loading:t,error:n,setError:N,deleteGroup:d,triggerRefresh:v}=Q(),{allServers:E}=se({refreshOnMount:!0}),{groupCosts:D,refetch:f}=te();h.useEffect(()=>{f()},[b,E,f]);const[p,k]=h.useState(null),[C,w]=h.useState(!1),[A,o]=h.useState(!1),[j,g]=h.useState(!1),[a,c]=h.useState(!1),m=async S=>{const F=await d(S);(!F||!F.success)&&N((F==null?void 0:F.message)||l("groups.deleteError"))};return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:l("pages.groups.title")}),e.jsxs("p",{className:"hub-sub",children:[e.jsx("span",{className:"hub-num",children:b.length})," ",l("nav.groups").toLowerCase()]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>o(!0),children:[e.jsx(oe,{size:13})," ",l("groupImport.button")]}),e.jsxs("button",{className:"hub-btn",onClick:()=>g(!0),children:[e.jsx(Pe,{size:13})," ",l("template.exportButton")]}),e.jsxs("button",{className:"hub-btn",onClick:()=>c(!0),children:[e.jsx(oe,{size:13})," ",l("template.importButton")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>w(!0),children:[e.jsx(ce,{size:13})," ",l("groups.add")]})]})]}),n&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-4",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(Re,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:n})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>N(null),children:e.jsx(Ue,{size:13})})]}),t?e.jsx("div",{className:"hub-card p-6 text-center",style:{color:"var(--hub-ink-3)"},children:l("app.loading")}):b.length===0?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:l("groups.noGroups")}):e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-3.5",children:[b.map(S=>e.jsx(Be,{group:S,servers:E,onEdit:k,onDelete:m,cost:D.find(F=>F.id===S.id)},S.id)),e.jsx("button",{onClick:()=>w(!0),className:"flex items-center justify-center text-[var(--hub-ink-3)] hover:text-[var(--hub-ink-2)] transition-colors",style:{border:"1px dashed var(--hub-line)",borderRadius:10,minHeight:200,background:"transparent",cursor:"pointer"},children:e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"grid place-items-center mx-auto mb-2",style:{width:36,height:36,borderRadius:10,border:"1px solid var(--hub-line)"},children:e.jsx(ce,{size:16})}),e.jsx("div",{style:{fontSize:13,fontWeight:500,color:"var(--hub-ink-2)"},children:l("groups.add")}),e.jsx("div",{style:{fontSize:12,marginTop:2},children:l("groups.addNew")})]})})]}),C&&e.jsx($e,{onAdd:()=>{w(!1),v()},onCancel:()=>w(!1)}),A&&e.jsx(Ve,{onSuccess:()=>{o(!1),v()},onCancel:()=>o(!1)}),p&&e.jsx(Ge,{group:p,onEdit:()=>{k(null),v()},onCancel:()=>k(null)}),j&&e.jsx(qe,{groups:b,onCancel:()=>g(!1)}),a&&e.jsx(He,{onSuccess:()=>{c(!1),v()},onCancel:()=>c(!1)})]})};export{ts as default};
33
- //# sourceMappingURL=GroupsPage-KJJsAprG.js.map
33
+ //# sourceMappingURL=GroupsPage-Dcsd8nze.js.map