@samanhappy/mcphub 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clients/openapi.js +2 -1
- package/dist/clients/openapi.js.map +1 -1
- package/dist/controllers/authController.js +27 -1
- package/dist/controllers/authController.js.map +1 -1
- package/dist/controllers/configController.js +4 -1
- package/dist/controllers/configController.js.map +1 -1
- package/dist/controllers/oauthServerController.js +12 -14
- package/dist/controllers/oauthServerController.js.map +1 -1
- package/dist/controllers/promptController.js +2 -2
- package/dist/controllers/promptController.js.map +1 -1
- package/dist/controllers/serverController.js +201 -12
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/OAuthTokenDaoDbImpl.js +2 -0
- package/dist/dao/OAuthTokenDaoDbImpl.js.map +1 -1
- package/dist/dao/ServerDao.js.map +1 -1
- package/dist/dao/ServerDaoDbImpl.js.map +1 -1
- package/dist/db/entities/OAuthToken.js +4 -0
- package/dist/db/entities/OAuthToken.js.map +1 -1
- package/dist/db/entities/Server.js.map +1 -1
- package/dist/middlewares/auth.js +7 -25
- package/dist/middlewares/auth.js.map +1 -1
- package/dist/middlewares/userContext.js +6 -34
- package/dist/middlewares/userContext.js.map +1 -1
- package/dist/models/OAuth.js +14 -93
- package/dist/models/OAuth.js.map +1 -1
- package/dist/routes/index.js +3 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/services/betterAuthConfig.js +1 -0
- package/dist/services/betterAuthConfig.js.map +1 -1
- package/dist/services/contextCostService.js +3 -1
- package/dist/services/contextCostService.js.map +1 -1
- package/dist/services/credentialBindingService.js +8 -3
- package/dist/services/credentialBindingService.js.map +1 -1
- package/dist/services/elicitationService.js +93 -0
- package/dist/services/elicitationService.js.map +1 -0
- package/dist/services/mcpService.js +167 -95
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/oauthServerService.js +15 -1
- package/dist/services/oauthServerService.js.map +1 -1
- package/dist/services/openApiGeneratorService.js +3 -1
- package/dist/services/openApiGeneratorService.js.map +1 -1
- package/dist/services/personalOAuthService.js +70 -8
- package/dist/services/personalOAuthService.js.map +1 -1
- package/dist/services/registrationService.js +28 -0
- package/dist/services/registrationService.js.map +1 -0
- package/dist/services/serverConfigPresenter.js +6 -1
- package/dist/services/serverConfigPresenter.js.map +1 -1
- package/dist/services/smartRoutingService.js +7 -6
- package/dist/services/smartRoutingService.js.map +1 -1
- package/dist/services/sseService.js +1 -2
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/templateService.js +5 -4
- package/dist/services/templateService.js.map +1 -1
- package/dist/services/userService.js +22 -4
- package/dist/services/userService.js.map +1 -1
- package/dist/utils/credentialTemplate.js +76 -6
- package/dist/utils/credentialTemplate.js.map +1 -1
- package/dist/utils/migration.js +1 -0
- package/dist/utils/migration.js.map +1 -1
- package/dist/utils/namePattern.js +28 -0
- package/dist/utils/namePattern.js.map +1 -0
- package/dist/utils/oauthBearer.js +4 -2
- package/dist/utils/oauthBearer.js.map +1 -1
- package/dist/utils/passthroughHeaders.js +17 -0
- package/dist/utils/passthroughHeaders.js.map +1 -0
- package/dist/utils/rateLimit.js +1 -1
- package/dist/utils/rateLimit.js.map +1 -1
- package/dist/utils/serverConfigPersistence.js +1 -3
- package/dist/utils/serverConfigPersistence.js.map +1 -1
- package/dist/utils/serverConfigValidation.js +2 -1
- package/dist/utils/serverConfigValidation.js.map +1 -1
- package/dist/utils/settingsSync.js +5 -1
- package/dist/utils/settingsSync.js.map +1 -1
- package/dist/utils/toolConfig.js +93 -0
- package/dist/utils/toolConfig.js.map +1 -0
- package/dist/utils/upstreamError.js +9 -2
- package/dist/utils/upstreamError.js.map +1 -1
- package/dist/utils/userSession.js +29 -0
- package/dist/utils/userSession.js.map +1 -0
- package/frontend/dist/assets/{ActivityPage-BEpHoGLB.js → ActivityPage-CFRX20v4.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-BEpHoGLB.js.map → ActivityPage-CFRX20v4.js.map} +1 -1
- package/frontend/dist/assets/{CopyClientConfigDialog-B4RDMLQ7.js → CopyClientConfigDialog-CDEiSInj.js} +2 -2
- package/frontend/dist/assets/{CopyClientConfigDialog-B4RDMLQ7.js.map → CopyClientConfigDialog-CDEiSInj.js.map} +1 -1
- package/frontend/dist/assets/CredentialsPage-BCLHY_fN.js +2 -0
- package/frontend/dist/assets/CredentialsPage-BCLHY_fN.js.map +1 -0
- package/frontend/dist/assets/{Dashboard-Bp8ZGDp5.js → Dashboard-B3Y6nAFL.js} +2 -2
- package/frontend/dist/assets/{Dashboard-Bp8ZGDp5.js.map → Dashboard-B3Y6nAFL.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-CH7rfwDL.js → EndpointCopy-BMxT99Ne.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-CH7rfwDL.js.map → EndpointCopy-BMxT99Ne.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-5iCk1LKT.js +33 -0
- package/frontend/dist/assets/GroupsPage-5iCk1LKT.js.map +1 -0
- package/frontend/dist/assets/LoginPage-BjYzY6RH.js +2 -0
- package/frontend/dist/assets/LoginPage-BjYzY6RH.js.map +1 -0
- package/frontend/dist/assets/{LogsPage-B4RyT3TS.js → LogsPage-CGcFNKJn.js} +2 -2
- package/frontend/dist/assets/{LogsPage-B4RyT3TS.js.map → LogsPage-CGcFNKJn.js.map} +1 -1
- package/frontend/dist/assets/{MarketPage-DV7Bs6bj.js → MarketPage-B7JPqFw3.js} +2 -2
- package/frontend/dist/assets/{MarketPage-DV7Bs6bj.js.map → MarketPage-B7JPqFw3.js.map} +1 -1
- package/frontend/dist/assets/{OAuthConsentPage-DdxMIqDO.js → OAuthConsentPage-BYi_kgNj.js} +2 -2
- package/frontend/dist/assets/{OAuthConsentPage-DdxMIqDO.js.map → OAuthConsentPage-BYi_kgNj.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-61Uj8gCp.js → PromptsPage-x6X5trLX.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-61Uj8gCp.js.map → PromptsPage-x6X5trLX.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-BSgOwVld.js → ResourcesPage-BJZCPBs8.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-BSgOwVld.js.map → ResourcesPage-BJZCPBs8.js.map} +1 -1
- package/frontend/dist/assets/ServersPage-CsyGLden.js +39 -0
- package/frontend/dist/assets/ServersPage-CsyGLden.js.map +1 -0
- package/frontend/dist/assets/{SettingsPage-C8zYH_jq.js → SettingsPage-C53DI0Sz.js} +6 -6
- package/frontend/dist/assets/SettingsPage-C53DI0Sz.js.map +1 -0
- package/frontend/dist/assets/{StatusDot-R86yLB-f.js → StatusDot-BDJd3Iix.js} +2 -2
- package/frontend/dist/assets/{StatusDot-R86yLB-f.js.map → StatusDot-BDJd3Iix.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-DN1ttokb.js → ToggleGroup-BbmRhILg.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-DN1ttokb.js.map → ToggleGroup-BbmRhILg.js.map} +1 -1
- package/frontend/dist/assets/{UsersPage-BCMjm9JG.js → UsersPage-NUG6vF8C.js} +2 -2
- package/frontend/dist/assets/{UsersPage-BCMjm9JG.js.map → UsersPage-NUG6vF8C.js.map} +1 -1
- package/frontend/dist/assets/{clipboard-DjzVWhkB.js → clipboard-7BggsilD.js} +2 -2
- package/frontend/dist/assets/{clipboard-DjzVWhkB.js.map → clipboard-7BggsilD.js.map} +1 -1
- package/frontend/dist/assets/index-B_IITM9e.js +3 -0
- package/frontend/dist/assets/index-B_IITM9e.js.map +1 -0
- package/frontend/dist/assets/index-CnqLKewL.css +1 -0
- package/frontend/dist/assets/{resourceService-DRZl8_Vm.js → resourceService-B674Fopr.js} +2 -2
- package/frontend/dist/assets/{resourceService-DRZl8_Vm.js.map → resourceService-B674Fopr.js.map} +1 -1
- package/frontend/dist/assets/{useCostData-DVLGVcuy.js → useCostData-8Z1HjAL5.js} +2 -2
- package/frontend/dist/assets/{useCostData-DVLGVcuy.js.map → useCostData-8Z1HjAL5.js.map} +1 -1
- package/frontend/dist/assets/variableDetection-C0nP3Jj2.js +18 -0
- package/frontend/dist/assets/variableDetection-C0nP3Jj2.js.map +1 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +2 -2
- package/frontend/dist/assets/CredentialsPage-46Z8Qv7O.js +0 -2
- package/frontend/dist/assets/CredentialsPage-46Z8Qv7O.js.map +0 -1
- package/frontend/dist/assets/GroupsPage-DTjOja6T.js +0 -33
- package/frontend/dist/assets/GroupsPage-DTjOja6T.js.map +0 -1
- package/frontend/dist/assets/LoginPage-o6ibb_j3.js +0 -2
- package/frontend/dist/assets/LoginPage-o6ibb_j3.js.map +0 -1
- package/frontend/dist/assets/ServersPage-DYumMhzV.js +0 -39
- package/frontend/dist/assets/ServersPage-DYumMhzV.js.map +0 -1
- package/frontend/dist/assets/SettingsPage-C8zYH_jq.js.map +0 -1
- package/frontend/dist/assets/index--NhF_yyy.css +0 -1
- package/frontend/dist/assets/index-P_O2kAcB.js +0 -3
- package/frontend/dist/assets/index-P_O2kAcB.js.map +0 -1
- package/frontend/dist/assets/variableDetection-DiE4h0o7.js +0 -16
- package/frontend/dist/assets/variableDetection-DiE4h0o7.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupsPage-5iCk1LKT.js","sources":["../../src/utils/capabilitySelection.ts","../../src/components/CapabilitySelection.tsx","../../src/components/ServerToolConfig.tsx","../../src/components/GroupVisibilityFields.tsx","../../src/components/AddGroupForm.tsx","../../src/components/EditGroupForm.tsx","../../src/components/GroupCard.tsx","../../src/components/GroupImportForm.tsx","../../src/components/TemplateExportForm.tsx","../../src/components/TemplateImportForm.tsx","../../src/pages/GroupsPage.tsx"],"sourcesContent":["export interface SelectableCapability {\n value: string;\n description?: string;\n annotations?: Record<string, unknown>;\n}\nexport type SelectionAction = 'select' | 'deselect' | 'invert';\nexport type AnnotationFilter = 'all' | 'readOnlyHint' | 'destructiveHint' | 'idempotentHint';\nexport type RiskGroup = 'read' | 'create' | 'update' | 'delete' | 'other';\nexport const RISK_GROUPS: RiskGroup[] = ['read', 'create', 'update', 'delete', 'other'];\nexport const classifyTool = (item: SelectableCapability): RiskGroup => {\n if (item.annotations?.readOnlyHint === true) return 'read';\n const name = item.value.toLowerCase();\n if (/^(delete|remove)[_-]/.test(name)) return 'delete';\n // A destructive hint does not distinguish create/update/delete.\n if (item.annotations?.destructiveHint === true) return 'other';\n if (/^(create|add)[_-]/.test(name)) return 'create';\n if (/^(update|set)[_-]/.test(name)) return 'update';\n if (item.annotations?.readOnlyHint !== false && /^(get|list|read|search)[_-]/.test(name))\n return 'read';\n return 'other';\n};\n\nexport const filterCapabilities = <T extends SelectableCapability>(\n items: T[],\n query: string,\n annotation: AnnotationFilter,\n): T[] => {\n const search = query.trim().toLowerCase();\n return items.filter(\n (item) =>\n (item.value.toLowerCase().includes(search) ||\n item.description?.toLowerCase().includes(search)) &&\n (annotation === 'all' || item.annotations?.[annotation] === true),\n );\n};\n\nexport const applyVisibleSelection = (\n selection: string[] | 'all',\n all: string[],\n visible: string[],\n action: SelectionAction,\n): string[] | 'all' => {\n if (visible.length === 0 || (selection === 'all' && action === 'select')) return selection;\n const selected = new Set(selection === 'all' ? all : selection);\n for (const name of visible) {\n if (action === 'deselect' || (action === 'invert' && selected.has(name))) selected.delete(name);\n else selected.add(name);\n }\n // An explicit snapshot stays explicit, including when every current item is selected.\n return [...selected];\n};\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n AnnotationFilter,\n applyVisibleSelection,\n classifyTool,\n filterCapabilities,\n RISK_GROUPS,\n SelectableCapability,\n SelectionAction,\n} from '@/utils/capabilitySelection';\n\ninterface Props<T extends SelectableCapability> {\n items: T[];\n selection: string[] | 'all';\n tools: boolean;\n label: string;\n onChange: (selection: string[] | 'all') => void;\n children: (item: T) => React.ReactNode;\n}\n\nexport const CapabilitySelection = <T extends SelectableCapability>({\n items,\n selection,\n tools,\n label,\n onChange,\n children,\n}: Props<T>) => {\n const { t } = useTranslation();\n const [query, setQuery] = useState('');\n const [annotation, setAnnotation] = useState<AnnotationFilter>('all');\n const [grouped, setGrouped] = useState(false);\n const visible = filterCapabilities(items, query, annotation);\n const selected = new Set(selection === 'all' ? items.map((item) => item.value) : selection);\n const apply = (target: T[], action: SelectionAction) =>\n onChange(\n applyVisibleSelection(\n selection,\n items.map((item) => item.value),\n target.map((item) => item.value),\n action,\n ),\n );\n const sections =\n tools && grouped\n ? RISK_GROUPS.map((risk) => ({\n risk,\n items: visible.filter((item) => classifyTool(item) === risk),\n }))\n : [{ risk: null, items: visible }];\n const buttonClass =\n 'text-xs text-blue-600 hover:text-blue-800 disabled:opacity-40 disabled:cursor-not-allowed';\n\n return (\n <section aria-label={label}>\n <div className=\"flex flex-wrap items-center gap-2 mb-2\">\n <input\n type=\"search\"\n aria-label={t('groups.bulkSearchLabel', { capability: label })}\n placeholder={t('groups.bulkSearch')}\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n className=\"min-w-0 flex-1 basis-48 rounded border border-gray-300 bg-white dark:bg-gray-800 px-2 py-1 text-sm\"\n />\n {tools && (\n <>\n <select\n aria-label={t('groups.annotationFilter')}\n value={annotation}\n onChange={(event) => setAnnotation(event.target.value as AnnotationFilter)}\n className=\"max-w-full rounded border border-gray-300 bg-white dark:bg-gray-800 px-2 py-1 text-sm\"\n >\n <option value=\"all\">{t('groups.allAnnotations')}</option>\n {(['readOnlyHint', 'destructiveHint', 'idempotentHint'] as const).map((hint) => (\n <option key={hint} value={hint}>\n {t(`groups.${hint}`)}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n aria-pressed={grouped}\n onClick={() => setGrouped(!grouped)}\n className={buttonClass}\n >\n {t(grouped ? 'groups.flatList' : 'groups.riskGroups')}\n </button>\n </>\n )}\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 mb-2\">\n <span className=\"text-xs text-gray-500\" role=\"status\">\n {t('groups.visibleCount', { count: visible.length, total: items.length })}\n </span>\n {(['select', 'deselect', 'invert'] as const).map((action) => (\n <button\n key={action}\n type=\"button\"\n disabled={!visible.length}\n onClick={() => apply(visible, action)}\n className={buttonClass}\n >\n {t(`groups.${action}Visible`)}\n </button>\n ))}\n </div>\n {tools && grouped && <p className=\"text-xs text-gray-500 mb-2\">{t('groups.riskHint')}</p>}\n <div className=\"grid grid-cols-1 gap-2 max-h-96 overflow-y-auto\">\n {visible.length === 0 && (\n <p className=\"text-sm text-gray-500\">{t('groups.noMatchingItems')}</p>\n )}\n {sections\n .filter((section) => section.items.length > 0)\n .map((section) => {\n const count = section.items.filter((item) => selected.has(item.value)).length;\n return (\n <React.Fragment key={section.risk ?? 'flat'}>\n {section.risk && (\n <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-gray-200 py-1\">\n <span className=\"text-xs font-medium\">\n {t(`groups.risk_${section.risk}`)} ({count}/{section.items.length})\n </span>\n <button\n type=\"button\"\n className={buttonClass}\n onClick={() =>\n apply(section.items, count === section.items.length ? 'deselect' : 'select')\n }\n >\n {t(count === section.items.length ? 'groups.selectNone' : 'groups.selectAll')}\n </button>\n </div>\n )}\n {section.items.map((item) => (\n <React.Fragment key={item.value}>{children(item)}</React.Fragment>\n ))}\n </React.Fragment>\n );\n })}\n </div>\n </section>\n );\n};\n","import { CapabilitySelection } from './CapabilitySelection.js';\nimport React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { IGroupServerConfig, Prompt, Resource, Server, ServerCost, Tool } from '@/types';\nimport { Wrench, MessageSquare, FileText, Pin } from 'lucide-react';\nimport { cn } from '@/utils/cn';\nimport { useSettingsData } from '@/hooks/useSettingsData';\nimport { formatTokens } from '@/utils/contextCost';\nimport { getToolDescriptionInfo } from '@/utils/toolDescription';\n\ntype CapabilityKey = 'tools' | 'prompts' | 'resources';\n\nconst EMPTY_SELECTIONS: Pick<IGroupServerConfig, CapabilityKey> = {\n tools: [],\n prompts: [],\n resources: [],\n};\n\nconst FULL_SELECTIONS: Pick<IGroupServerConfig, CapabilityKey> = {\n tools: 'all',\n prompts: 'all',\n resources: 'all',\n};\n\ninterface ServerToolConfigProps {\n servers: Server[];\n value: string[] | IGroupServerConfig[];\n onChange: (value: IGroupServerConfig[]) => void;\n className?: string;\n serverCosts?: ServerCost[];\n}\n\ninterface CapabilityItem {\n annotations?: Record<string, unknown>;\n key: string;\n value: string;\n description?: string;\n defaultDescription?: string;\n hasDescriptionOverride?: boolean;\n}\n\nexport const ServerToolConfig: React.FC<ServerToolConfigProps> = ({\n servers,\n value,\n onChange,\n className,\n serverCosts = [],\n}) => {\n const { t } = useTranslation();\n const { nameSeparator, smartRoutingConfig } = useSettingsData();\n const [expandedServers, setExpandedServers] = useState<Set<string>>(new Set());\n\n // Normalize current value to IGroupServerConfig[] format\n const normalizedValue: IGroupServerConfig[] = React.useMemo(() => {\n return value.map((item) => {\n if (typeof item === 'string') {\n return { name: item, ...FULL_SELECTIONS };\n }\n return {\n ...item,\n tools: item.tools || 'all',\n prompts: item.prompts || 'all',\n resources: item.resources || 'all',\n };\n });\n }, [value]);\n\n // Get available servers (enabled only)\n const availableServers = React.useMemo(\n () => servers.filter((server) => server.enabled !== false),\n [servers],\n );\n\n // Clean up expanded servers when servers are removed from configuration\n // But keep servers that were explicitly expanded even if they have no configuration\n React.useEffect(() => {\n const configuredServerNames = new Set(normalizedValue.map((config) => config.name));\n const availableServerNames = new Set(availableServers.map((server) => server.name));\n\n setExpandedServers((prev) => {\n const newSet = new Set<string>();\n prev.forEach((serverName) => {\n // Keep expanded if server is configured OR if server exists and user manually expanded it\n if (configuredServerNames.has(serverName) || availableServerNames.has(serverName)) {\n newSet.add(serverName);\n }\n });\n return newSet;\n });\n }, [normalizedValue, availableServers]);\n\n const toggleServer = (serverName: string) => {\n const existingIndex = normalizedValue.findIndex((config) => config.name === serverName);\n\n if (existingIndex >= 0) {\n // Remove server - this also removes all capability selections\n const newValue = normalizedValue.filter((config) => config.name !== serverName);\n onChange(newValue);\n } else {\n // Add server with all capabilities by default\n const newValue = [...normalizedValue, { name: serverName, ...FULL_SELECTIONS }];\n onChange(newValue);\n }\n };\n\n const toggleServerExpanded = (serverName: string) => {\n setExpandedServers((prev) => {\n const newSet = new Set(prev);\n if (newSet.has(serverName)) {\n newSet.delete(serverName);\n } else {\n newSet.add(serverName);\n }\n return newSet;\n });\n };\n\n const hasAnyCapabilitySelection = (config: IGroupServerConfig) => {\n return (['tools', 'prompts', 'resources'] as CapabilityKey[]).some((capability) => {\n const selection = config[capability];\n return selection === 'all' || (Array.isArray(selection) && selection.length > 0);\n });\n };\n\n const updateServerCapability = (\n serverName: string,\n capability: CapabilityKey,\n selection: string[] | 'all',\n keepExpanded = false,\n ) => {\n const existingServer = normalizedValue.find((config) => config.name === serverName);\n const baseConfig: IGroupServerConfig = existingServer\n ? { ...existingServer }\n : { name: serverName, ...EMPTY_SELECTIONS };\n const nextConfig: IGroupServerConfig = {\n ...baseConfig,\n [capability]: selection,\n };\n // A deselected tool drops its pin, so selecting it again does not silently re-pin it\n if (capability === 'tools' && Array.isArray(selection) && nextConfig.pinnedTools) {\n nextConfig.pinnedTools = nextConfig.pinnedTools.filter((name) => selection.includes(name));\n if (nextConfig.pinnedTools.length === 0) delete nextConfig.pinnedTools;\n }\n\n if (!hasAnyCapabilitySelection(nextConfig)) {\n const newValue = normalizedValue.filter((config) => config.name !== serverName);\n onChange(newValue);\n if (!keepExpanded) {\n setExpandedServers((prev) => {\n const newSet = new Set(prev);\n newSet.delete(serverName);\n return newSet;\n });\n }\n return;\n }\n\n if (existingServer) {\n onChange(normalizedValue.map((config) => (config.name === serverName ? nextConfig : config)));\n return;\n }\n\n onChange([...normalizedValue, nextConfig]);\n };\n\n const updateServerAlias = (serverName: string, alias: string) => {\n const existingServer = normalizedValue.find((config) => config.name === serverName);\n if (!existingServer) return;\n\n const nextConfig: IGroupServerConfig = { ...existingServer };\n if (alias) {\n nextConfig.alias = alias;\n } else {\n delete nextConfig.alias;\n }\n\n onChange(normalizedValue.map((config) => (config.name === serverName ? nextConfig : config)));\n };\n\n const togglePinnedTool = (serverName: string, toolName: string) => {\n const existingServer = normalizedValue.find((config) => config.name === serverName);\n if (!existingServer) return;\n\n const pinnedTools = existingServer.pinnedTools ?? [];\n const nextConfig: IGroupServerConfig = {\n ...existingServer,\n pinnedTools: pinnedTools.includes(toolName)\n ? pinnedTools.filter((name) => name !== toolName)\n : [...pinnedTools, toolName],\n };\n if (nextConfig.pinnedTools!.length === 0) delete nextConfig.pinnedTools;\n\n onChange(normalizedValue.map((config) => (config.name === serverName ? nextConfig : config)));\n };\n\n const normalizeNamedCapability = (serverName: string, name: string) => {\n const prefix = `${serverName}${nameSeparator}`;\n return name.startsWith(prefix) ? name.slice(prefix.length) : name;\n };\n\n const getCapabilityItems = (server: Server, capability: CapabilityKey): CapabilityItem[] => {\n if (capability === 'tools') {\n return (server.tools || [])\n .filter((tool) => tool.enabled !== false)\n .map((tool: Tool) => ({\n key: tool.name,\n value: normalizeNamedCapability(server.name, tool.name),\n description: tool.description,\n annotations: tool.annotations,\n defaultDescription: tool.defaultDescription,\n hasDescriptionOverride: tool.hasDescriptionOverride,\n }));\n }\n\n if (capability === 'prompts') {\n return (server.prompts || [])\n .filter((prompt) => prompt.enabled !== false)\n .map((prompt: Prompt) => ({\n key: prompt.name,\n value: normalizeNamedCapability(server.name, prompt.name),\n description: prompt.description,\n }));\n }\n\n return (server.resources || [])\n .filter((resource) => resource.enabled !== false)\n .map((resource: Resource) => ({\n key: resource.uri,\n value: resource.uri,\n description: resource.description,\n }));\n };\n\n // Build one nested map (server -> item name -> cost) once per serverCosts change,\n // so per-render lookups don't rebuild a Map on every call (avoids O(N^2) churn).\n const serverCostsMap = React.useMemo(() => {\n const outerMap = new Map<string, Map<string, number>>();\n serverCosts.forEach((sc) => {\n const innerMap = new Map<string, number>();\n sc.items.forEach((i) => innerMap.set(i.name, i.cost));\n outerMap.set(sc.name, innerMap);\n });\n return outerMap;\n }, [serverCosts]);\n\n const costMapForServer = (serverName: string): Map<string, number> =>\n serverCostsMap.get(serverName) ?? new Map<string, number>();\n\n const getSelectedCapabilityCost = (server: Server, capability: CapabilityKey): number => {\n const costMap = costMapForServer(server.name);\n return getCapabilityItems(server, capability)\n .filter((item) => isCapabilityItemSelected(server.name, capability, item.value))\n .reduce((sum, item) => sum + (costMap.get(item.key) ?? 0), 0);\n };\n\n const getServerSelectedCost = (server: Server): number =>\n (['tools', 'prompts', 'resources'] as CapabilityKey[]).reduce(\n (sum, cap) => sum + getSelectedCapabilityCost(server, cap),\n 0,\n );\n\n const toggleCapabilityItem = (\n serverName: string,\n capability: CapabilityKey,\n itemValue: string,\n ) => {\n const server = availableServers.find((s) => s.name === serverName);\n if (!server) return;\n\n const allItems = getCapabilityItems(server, capability).map((item) => item.value);\n const serverConfig = normalizedValue.find((config) => config.name === serverName);\n\n if (!serverConfig) {\n updateServerCapability(serverName, capability, [itemValue]);\n return;\n }\n\n const currentSelection = serverConfig[capability];\n if (currentSelection === 'all') {\n const nextSelection = allItems.filter((value) => value !== itemValue);\n updateServerCapability(serverName, capability, nextSelection);\n return;\n }\n\n if (Array.isArray(currentSelection)) {\n if (currentSelection.includes(itemValue)) {\n updateServerCapability(\n serverName,\n capability,\n currentSelection.filter((value) => value !== itemValue),\n );\n return;\n }\n\n const nextSelection = [...currentSelection, itemValue];\n updateServerCapability(\n serverName,\n capability,\n nextSelection.length === allItems.length ? 'all' : nextSelection,\n );\n return;\n }\n\n updateServerCapability(serverName, capability, [itemValue]);\n };\n\n const isServerSelected = (serverName: string) => {\n const serverConfig = normalizedValue.find((config) => config.name === serverName);\n return Boolean(serverConfig && hasAnyCapabilitySelection(serverConfig));\n };\n\n const isServerPartiallySelected = (serverName: string) => {\n const serverConfig = normalizedValue.find((config) => config.name === serverName);\n if (!serverConfig) return false;\n\n return (['tools', 'prompts', 'resources'] as CapabilityKey[]).some((capability) => {\n const selection = serverConfig[capability];\n return Array.isArray(selection) && selection.length > 0;\n });\n };\n\n const isCapabilityItemSelected = (\n serverName: string,\n capability: CapabilityKey,\n itemValue: string,\n ) => {\n const serverConfig = normalizedValue.find((config) => config.name === serverName);\n if (!serverConfig) return false;\n\n const selection = serverConfig[capability];\n if (selection === 'all') return true;\n return Array.isArray(selection) ? selection.includes(itemValue) : false;\n };\n\n const getSelectedCapabilityCount = (server: Server, capability: CapabilityKey) => {\n const serverConfig = normalizedValue.find((config) => config.name === server.name);\n if (!serverConfig) return 0;\n\n const items = getCapabilityItems(server, capability);\n const selection = serverConfig[capability];\n if (selection === 'all') return items.length;\n if (Array.isArray(selection)) {\n const itemSet = new Set(items.map((item) => item.value));\n return selection.filter((item) => itemSet.has(item)).length;\n }\n return 0;\n };\n\n const capabilityConfigs: Array<{\n key: CapabilityKey;\n titleKey: string;\n countKey: string;\n allKey: string;\n }> = [\n {\n key: 'tools',\n titleKey: 'groups.toolSelection',\n countKey: 'groups.toolsSelected',\n allKey: 'groups.allTools',\n },\n {\n key: 'prompts',\n titleKey: 'groups.promptSelection',\n countKey: 'groups.promptsSelected',\n allKey: 'groups.allPrompts',\n },\n {\n key: 'resources',\n titleKey: 'groups.resourceSelection',\n countKey: 'groups.resourcesSelected',\n allKey: 'groups.allResources',\n },\n ];\n\n const getServerSummaryBadges = (server: Server) => {\n return capabilityConfigs\n .map(({ key }) => ({ key, count: getSelectedCapabilityCount(server, key) }))\n .filter((entry) => entry.count > 0);\n };\n\n return (\n <div className={cn('space-y-4', className)}>\n <div className=\"space-y-3\">\n {availableServers.map((server) => {\n const isSelected = isServerSelected(server.name);\n const isPartiallySelected = isServerPartiallySelected(server.name);\n const isExpanded = expandedServers.has(server.name);\n const serverConfig = normalizedValue.find((config) => config.name === server.name);\n const summaryBadges = getServerSummaryBadges(server);\n const serverCapabilities = capabilityConfigs.filter(\n ({ key }) => getCapabilityItems(server, key).length > 0,\n );\n const costMap = costMapForServer(server.name);\n\n return (\n <div\n key={server.name}\n className=\"border border-[var(--hub-line)] rounded-lg bg-[var(--hub-surface)] hover:border-[var(--hub-ink-3)] hover:bg-[var(--hub-surface-hover)] transition-colors\"\n >\n <div\n className=\"flex items-center justify-between p-3 cursor-pointer rounded-lg transition-colors\"\n onClick={() => toggleServerExpanded(server.name)}\n >\n <div\n className=\"flex items-center space-x-3\"\n onClick={(e) => {\n e.stopPropagation();\n toggleServer(server.name);\n }}\n >\n <input\n type=\"checkbox\"\n checked={isSelected || isPartiallySelected}\n onChange={() => toggleServer(server.name)}\n className=\"w-4 h-4 text-blue-600 accent-[var(--hub-accent)] rounded focus:ring-blue-500\"\n />\n <span className=\"font-medium text-[var(--hub-ink)] cursor-pointer select-none\">\n {server.name}\n </span>\n </div>\n\n <div className=\"flex items-center space-x-3\">\n {getServerSelectedCost(server) > 0 && (\n <span className=\"text-sm text-[var(--hub-ink-3)] hub-mono\" title={t('cost.estimate')}>\n Σ {formatTokens(getServerSelectedCost(server))}\n </span>\n )}\n {summaryBadges.map(({ key, count }) => (\n <span key={key} className=\"text-sm text-green-600 flex items-center gap-1\">\n {key === 'tools' ? (\n <Wrench size={14} />\n ) : key === 'prompts' ? (\n <MessageSquare size={14} />\n ) : (\n <FileText size={14} />\n )}{' '}\n {count}\n </span>\n ))}\n\n {serverCapabilities.length > 0 && (\n <button\n type=\"button\"\n className=\"p-1 text-[var(--hub-ink-3)] hover:text-[var(--hub-ink-2)] transition-colors\"\n >\n <svg\n className={cn('w-5 h-5 transition-transform', isExpanded && 'rotate-180')}\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {isExpanded && serverCapabilities.length > 0 && (\n <div className=\"border-t border-[var(--hub-line)] bg-[var(--hub-bg-2)] p-3\">\n <div className=\"space-y-4\">\n {serverConfig && (\n <div className=\"space-y-1\" onClick={(e) => e.stopPropagation()}>\n <label className=\"block text-xs font-medium text-[var(--hub-ink-2)]\">\n {t('groups.alias')}\n </label>\n <input\n type=\"text\"\n value={serverConfig.alias || ''}\n placeholder={server.name}\n onChange={(event) => updateServerAlias(server.name, event.target.value)}\n className=\"hub-input\"\n />\n </div>\n )}\n {serverCapabilities.map(({ key, titleKey, countKey, allKey }) => {\n const items = getCapabilityItems(server, key);\n const selectedCount = getSelectedCapabilityCount(server, key);\n const allSelected =\n serverConfig?.[key] === 'all' || selectedCount === items.length;\n\n return (\n <div key={key}>\n <div className=\"flex items-center justify-between mb-3\">\n <span className=\"text-sm font-medium text-[var(--hub-ink-2)]\">{t(titleKey)}</span>\n <div className=\"flex items-center gap-3\">\n {serverConfig && (\n <span className=\"text-xs text-green-600\">\n {allSelected\n ? `(${t(allKey)} ${items.length}/${items.length})`\n : `(${t(countKey)} ${selectedCount}/${items.length})`}\n </span>\n )}\n {serverConfig && getSelectedCapabilityCost(server, key) > 0 && (\n <span\n className=\"text-xs text-[var(--hub-ink-3)] hub-mono\"\n title={t('cost.estimate')}\n >\n Σ {formatTokens(getSelectedCapabilityCost(server, key))}\n </span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n updateServerCapability(\n server.name,\n key,\n allSelected ? [] : 'all',\n true,\n );\n }}\n className=\"text-sm text-blue-600 hover:text-blue-800 transition-colors\"\n >\n {allSelected ? t('groups.selectNone') : t('groups.selectAll')}\n </button>\n </div>\n </div>\n\n <CapabilitySelection\n items={items}\n selection={serverConfig?.[key] ?? []}\n tools={key === 'tools'}\n label={t(titleKey)}\n onChange={(selection) =>\n updateServerCapability(server.name, key, selection, true)\n }\n >\n {(item) => {\n const isChecked = isCapabilityItemSelected(\n server.name,\n key,\n item.value,\n );\n const isPinned = Boolean(\n serverConfig?.pinnedTools?.includes(item.value),\n );\n const descriptionInfo =\n key === 'tools'\n ? getToolDescriptionInfo(\n {\n description: item.description,\n defaultDescription: item.defaultDescription,\n hasDescriptionOverride: item.hasDescriptionOverride,\n },\n t('tool.noDescription'),\n )\n : null;\n const descriptionTitle = descriptionInfo?.hasDescriptionOverride\n ? t('tool.defaultDescriptionTooltip', {\n description: descriptionInfo.defaultDescription,\n })\n : item.description;\n\n return (\n <div key={item.key} className=\"flex min-w-0 items-center gap-2\">\n <label className=\"flex min-w-0 flex-1 items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={isChecked}\n onChange={() =>\n toggleCapabilityItem(server.name, key, item.value)\n }\n className=\"w-3 h-3 text-blue-600 accent-[var(--hub-accent)] rounded focus:ring-blue-500\"\n />\n <span className=\"text-[var(--hub-ink-2)] break-all whitespace-nowrap flex-shrink-0\">\n {item.value}\n </span>\n {(item.description ||\n descriptionInfo?.hasDescriptionOverride) && (\n <span className=\"min-w-0 flex items-center gap-1 text-[var(--hub-ink-3)] text-xs truncate\">\n <span\n className=\"truncate\"\n title={descriptionTitle || undefined}\n >\n {descriptionInfo\n ? descriptionInfo.currentDescription\n : item.description}\n </span>\n {descriptionInfo?.hasDescriptionOverride && (\n <span\n 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\"\n title={descriptionTitle || undefined}\n >\n {t('tool.descriptionModifiedBadge')}\n </span>\n )}\n </span>\n )}\n {costMap.get(item.key) != null && (\n <span\n className=\"text-xs text-[var(--hub-ink-3)] hub-mono whitespace-nowrap ml-auto flex-shrink-0\"\n title={t('cost.estimate')}\n >\n Σ {formatTokens(costMap.get(item.key)!)}\n </span>\n )}\n </label>\n {/* Shown while Smart Routing is on, and for an existing pin even\n when it is off, so a pin is never left invisible */}\n {key === 'tools' &&\n isChecked &&\n (smartRoutingConfig.enabled || isPinned) && (\n <button\n type=\"button\"\n onClick={() => togglePinnedTool(server.name, item.value)}\n title={t(isPinned ? 'groups.unpinTool' : 'groups.pinTool')}\n aria-label={t('groups.pinToolLabel')}\n aria-pressed={isPinned}\n className={cn(\n 'flex-shrink-0 transition-colors',\n isPinned\n ? 'text-blue-600'\n : 'text-[var(--hub-ink-3)] hover:text-[var(--hub-ink-2)]',\n )}\n >\n <Pin size={12} fill={isPinned ? 'currentColor' : 'none'} />\n </button>\n )}\n </div>\n );\n }}\n </CapabilitySelection>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </div>\n );\n })}\n </div>\n\n {availableServers.length === 0 && (\n <p className=\"text-[var(--hub-ink-3)] text-sm\">{t('groups.noServerOptions')}</p>\n )}\n </div>\n );\n};\n","import { useEffect, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { Group } from '@/types';\nimport { apiGet } from '@/utils/fetchInterceptor';\n\ntype Access = Pick<Group, 'visibility' | 'sharedWithUsers'>;\n\nexport default function GroupVisibilityFields({\n groupId,\n value,\n onChange,\n}: {\n groupId?: string;\n value: Access;\n onChange: (access: Access) => void;\n}) {\n const { t } = useTranslation();\n const [users, setUsers] = useState<string[]>([]);\n const [search, setSearch] = useState('');\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(false);\n const [isAdvancedExpanded, setIsAdvancedExpanded] = useState(false);\n useEffect(() => {\n if (!groupId || value.visibility !== 'group') return;\n let cancelled = false;\n setLoading(true);\n setError(false);\n apiGet<{ success: boolean; data?: string[] }>(\n `/groups/${encodeURIComponent(groupId)}/share-candidates`,\n )\n .then((result) => {\n if (cancelled) return;\n if (result.success && Array.isArray(result.data)) setUsers(result.data);\n else setError(true);\n })\n .catch(() => {\n if (!cancelled) setError(true);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [groupId, value.visibility]);\n const selected = value.sharedWithUsers || [];\n const candidates = [...new Set([...users, ...selected])]\n .sort()\n .filter((username) => username.toLowerCase().includes(search.toLowerCase()));\n const selectedUsers = new Set(selected);\n const allCandidatesSelected =\n candidates.length > 0 && candidates.every((username) => selectedUsers.has(username));\n const noCandidatesSelected =\n candidates.length === 0 || candidates.every((username) => !selectedUsers.has(username));\n\n const toggleSharedUser = (username: string) => {\n const nextSelected = new Set(selected);\n if (nextSelected.has(username)) {\n nextSelected.delete(username);\n } else {\n nextSelected.add(username);\n }\n onChange({ sharedWithUsers: Array.from(nextSelected) });\n };\n\n return (\n <div className=\"mb-4\">\n <div\n className=\"flex items-center justify-between cursor-pointer bg-[var(--hub-bg-2)] hover:bg-[var(--hub-surface-hover)] p-3 rounded border border-[var(--hub-line)]\"\n onClick={() => setIsAdvancedExpanded(!isAdvancedExpanded)}\n >\n <h3 className=\"text-sm font-semibold text-[var(--hub-ink)]\">\n {t('server.sectionAdvanced', 'Advanced Options')}\n </h3>\n <span className=\"text-[var(--hub-ink-3)] text-sm\">{isAdvancedExpanded ? '▼' : '▶'}</span>\n </div>\n\n {isAdvancedExpanded && (\n <div className=\"border border-[var(--hub-line)] rounded-b p-4 bg-[var(--hub-surface)] border-t-0\">\n <label\n htmlFor=\"group-visibility\"\n className=\"block text-sm font-medium mb-1.5 text-[var(--hub-ink-2)]\"\n >\n {t('server.visibility')}\n </label>\n <select\n id=\"group-visibility\"\n className=\"hub-input\"\n value={value.visibility || ''}\n onChange={(event) =>\n onChange({ visibility: event.target.value as Group['visibility'] })\n }\n >\n {!value.visibility && (\n <option value=\"\" disabled>\n {t('groups.legacyVisibility')}\n </option>\n )}\n <option value=\"private\">{t('server.visibilityPrivate')}</option>\n <option value=\"group\">{t('server.visibilityGroup')}</option>\n <option value=\"public\">{t('server.visibilityPublic')}</option>\n </select>\n <p className=\"text-xs text-[var(--hub-ink-3)] mt-1\">{t('groups.visibilityDescription')}</p>\n {!value.visibility && (\n <p className=\"text-sm text-amber-600\">{t('groups.legacyVisibilityHint')}</p>\n )}\n {value.visibility === 'group' && (\n <div className=\"mt-4 rounded border border-[var(--hub-line)] p-3\">\n <div className=\"text-sm font-medium text-[var(--hub-ink-2)]\">\n {t('server.shareWithUsers')}\n </div>\n <p className=\"text-xs text-[var(--hub-ink-3)] mt-1 mb-3\">\n {t('server.shareWithUsersDescription')}\n </p>\n {!groupId ? (\n <p className=\"text-sm text-[var(--hub-ink-3)]\">{t('groups.shareAfterCreate')}</p>\n ) : (\n <>\n {loading && (\n <p className=\"text-sm text-[var(--hub-ink-3)]\">{t('server.shareCandidatesLoading')}</p>\n )}\n {error && (\n <p role=\"alert\" className=\"text-sm text-red-600 dark:text-red-400\">\n {t('server.shareCandidatesError')}\n </p>\n )}\n {!loading && !error && candidates.length === 0 && (\n <p className=\"text-sm text-[var(--hub-ink-3)]\">\n {search ? t('server.noMatchingShareUsers') : t('server.noShareCandidates')}\n </p>\n )}\n {candidates.length > 0 && (\n <>\n <div className=\"mb-3 space-y-2\">\n <label\n htmlFor=\"group-share-search\"\n className=\"block text-xs font-medium text-[var(--hub-ink-2)]\"\n >\n {t('server.shareUserSearchLabel')}\n </label>\n <input\n id=\"group-share-search\"\n type=\"search\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n placeholder={t('server.shareUserSearchPlaceholder')}\n className=\"hub-input text-sm\"\n />\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() =>\n onChange({\n sharedWithUsers: [...new Set([...selected, ...candidates])],\n })\n }\n disabled={allCandidatesSelected}\n className=\"hub-btn text-sm\"\n >\n {t('server.selectAllShareUsers')}\n </button>\n <button\n type=\"button\"\n onClick={() =>\n onChange({\n sharedWithUsers: selected.filter(\n (name) => !candidates.includes(name),\n ),\n })\n }\n disabled={noCandidatesSelected}\n className=\"hub-btn text-sm\"\n >\n {t('server.deselectAllShareUsers')}\n </button>\n </div>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-2\">\n {candidates.map((username) => (\n <label\n key={username}\n className=\"flex items-center gap-2 rounded border border-[var(--hub-line)] px-3 py-2 text-sm text-[var(--hub-ink-2)]\"\n >\n <input\n type=\"checkbox\"\n checked={selectedUsers.has(username)}\n onChange={() => toggleSharedUser(username)}\n />\n <span>{username}</span>\n </label>\n ))}\n </div>\n </>\n )}\n </>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useGroupData } from '@/hooks/useGroupData';\nimport { useServerData } from '@/hooks/useServerData';\nimport { useCostData } from '@/hooks/useCostData';\nimport { GroupFormData, Server, IGroupServerConfig } from '@/types';\nimport { ServerToolConfig } from './ServerToolConfig';\nimport GroupVisibilityFields from './GroupVisibilityFields';\n\ninterface AddGroupFormProps {\n onAdd: () => void;\n onCancel: () => void;\n}\n\nconst AddGroupForm = ({ onAdd, onCancel }: AddGroupFormProps) => {\n const { t } = useTranslation();\n const { createGroup } = useGroupData();\n const { allServers } = useServerData();\n const { serverCosts } = useCostData();\n const [availableServers, setAvailableServers] = useState<Server[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState<GroupFormData>({\n visibility: 'private',\n sharedWithUsers: [],\n name: '',\n description: '',\n instructions: '',\n servers: [] as IGroupServerConfig[],\n });\n\n useEffect(() => {\n // Filter available servers (enabled only)\n setAvailableServers(allServers.filter((server) => server.enabled !== false));\n }, [allServers]);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: value,\n }));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setError(null);\n\n try {\n if (!formData.name.trim()) {\n setError(t('groups.nameRequired'));\n setIsSubmitting(false);\n return;\n }\n\n const result = await createGroup(formData.name, formData.description, formData.servers, {\n visibility: formData.visibility,\n sharedWithUsers: formData.sharedWithUsers,\n instructions: formData.instructions,\n });\n if (!result || !result.success) {\n setError(result?.message || t('groups.createError'));\n setIsSubmitting(false);\n return;\n }\n\n onAdd();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setIsSubmitting(false);\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"hub-card shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col\">\n <div className=\"p-6 flex-shrink-0\">\n <h2 className=\"text-xl font-semibold text-[var(--hub-ink)] mb-4\">{t('groups.addNew')}</h2>\n\n {error && (\n <div className=\"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-[var(--hub-line)]\">\n {error}\n </div>\n )}\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex flex-col flex-1 min-h-0\">\n <div className=\"flex-1 overflow-y-auto px-6\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\" htmlFor=\"name\">\n {t('groups.name')} *\n </label>\n <input\n type=\"text\"\n id=\"name\"\n name=\"name\"\n value={formData.name}\n onChange={handleChange}\n className=\"w-full border border-[var(--hub-line)] bg-[var(--hub-surface)] rounded-md px-3 py-2 text-[var(--hub-ink)] placeholder:text-[var(--hub-ink-3)] focus:outline-none focus:border-[var(--hub-ink-2)]\"\n placeholder={t('groups.namePlaceholder')}\n required\n />\n </div>\n\n <div>\n <label\n className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\"\n htmlFor=\"instructions\"\n >\n {t('groups.instructions')}\n </label>\n <textarea\n id=\"instructions\"\n name=\"instructions\"\n value={formData.instructions}\n onChange={handleChange}\n rows={3}\n className=\"w-full border border-[var(--hub-line)] bg-[var(--hub-surface)] rounded-md px-3 py-2 text-[var(--hub-ink)] placeholder:text-[var(--hub-ink-3)] focus:outline-none focus:border-[var(--hub-ink-2)]\"\n placeholder={t('groups.instructionsPlaceholder')}\n />\n <p className=\"text-xs text-[var(--hub-ink-3)] mt-1\">{t('groups.instructionsHelp')}</p>\n </div>\n\n <div>\n <label className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\">\n {t('groups.configureCapabilities')}\n </label>\n <ServerToolConfig\n servers={availableServers}\n value={formData.servers as IGroupServerConfig[]}\n onChange={(servers) => setFormData((prev) => ({ ...prev, servers }))}\n className=\"border border-[var(--hub-line)] rounded-lg p-4 bg-[var(--hub-bg-2)]\"\n serverCosts={serverCosts}\n />\n </div>\n\n <GroupVisibilityFields\n value={formData}\n onChange={(access) => setFormData((previous) => ({ ...previous, ...access }))}\n />\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0\">\n <button type=\"button\" onClick={onCancel} className=\"hub-btn\" disabled={isSubmitting}>\n {t('common.cancel')}\n </button>\n <button type=\"submit\" className=\"hub-btn primary\" disabled={isSubmitting}>\n {isSubmitting ? t('common.submitting') : t('common.create')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default AddGroupForm;\n","import { useState, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Group, GroupFormData, Server, IGroupServerConfig } from '@/types';\nimport { useGroupData } from '@/hooks/useGroupData';\nimport { useServerData } from '@/hooks/useServerData';\nimport { useCostData } from '@/hooks/useCostData';\nimport { ServerToolConfig } from './ServerToolConfig';\nimport GroupVisibilityFields from './GroupVisibilityFields';\n\ninterface EditGroupFormProps {\n group: Group;\n onEdit: () => void;\n onCancel: () => void;\n}\n\nconst EditGroupForm = ({ group, onEdit, onCancel }: EditGroupFormProps) => {\n const { t } = useTranslation();\n const { updateGroup } = useGroupData();\n const { allServers } = useServerData();\n const { serverCosts } = useCostData();\n const [availableServers, setAvailableServers] = useState<Server[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState<GroupFormData>({\n visibility: group.visibility,\n sharedWithUsers: group.sharedWithUsers || [],\n name: group.name,\n description: group.description || '',\n instructions: group.instructions || '',\n servers: group.servers || [],\n });\n\n useEffect(() => {\n // Filter available servers (enabled only)\n setAvailableServers(allServers.filter((server) => server.enabled !== false));\n }, [allServers]);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: value,\n }));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setError(null);\n\n try {\n if (!formData.name.trim()) {\n setError(t('groups.nameRequired'));\n setIsSubmitting(false);\n return;\n }\n\n const result = await updateGroup(group.id, {\n visibility: formData.visibility,\n sharedWithUsers: formData.sharedWithUsers,\n name: formData.name,\n description: formData.description,\n instructions: formData.instructions,\n servers: formData.servers,\n });\n\n if (!result || !result.success) {\n setError(result?.message || t('groups.updateError'));\n setIsSubmitting(false);\n return;\n }\n\n onEdit();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n setIsSubmitting(false);\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"hub-card shadow-lg max-w-3xl w-full max-h-[90vh] flex flex-col\">\n <div className=\"p-6 flex-shrink-0\">\n <h2 className=\"text-xl font-semibold text-[var(--hub-ink)] mb-4\">{t('groups.edit')}</h2>\n\n {error && (\n <div className=\"mb-4 p-3 bg-red-100 text-red-700 rounded-md border border-[var(--hub-line)]\">\n {error}\n </div>\n )}\n </div>\n\n <form onSubmit={handleSubmit} className=\"flex flex-col flex-1 min-h-0\">\n <div className=\"flex-1 overflow-y-auto px-6\">\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\" htmlFor=\"name\">\n {t('groups.name')} *\n </label>\n <input\n type=\"text\"\n id=\"name\"\n name=\"name\"\n value={formData.name}\n onChange={handleChange}\n className=\"w-full border border-[var(--hub-line)] bg-[var(--hub-surface)] rounded-md px-3 py-2 text-[var(--hub-ink)] placeholder:text-[var(--hub-ink-3)] focus:outline-none focus:border-[var(--hub-ink-2)]\"\n placeholder={t('groups.namePlaceholder')}\n required\n />\n </div>\n\n <div>\n <label\n className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\"\n htmlFor=\"instructions\"\n >\n {t('groups.instructions')}\n </label>\n <textarea\n id=\"instructions\"\n name=\"instructions\"\n value={formData.instructions}\n onChange={handleChange}\n rows={3}\n className=\"w-full border border-[var(--hub-line)] bg-[var(--hub-surface)] rounded-md px-3 py-2 text-[var(--hub-ink)] placeholder:text-[var(--hub-ink-3)] focus:outline-none focus:border-[var(--hub-ink-2)]\"\n placeholder={t('groups.instructionsPlaceholder')}\n />\n <p className=\"text-xs text-[var(--hub-ink-3)] mt-1\">{t('groups.instructionsHelp')}</p>\n </div>\n\n <div>\n <label className=\"block text-[var(--hub-ink-2)] text-sm font-bold mb-2\">\n {t('groups.configureCapabilities')}\n </label>\n <ServerToolConfig\n servers={availableServers}\n value={formData.servers as IGroupServerConfig[]}\n onChange={(servers) => setFormData((prev) => ({ ...prev, servers }))}\n className=\"border border-[var(--hub-line)] rounded-lg p-4 bg-[var(--hub-bg-2)]\"\n serverCosts={serverCosts}\n />\n </div>\n\n <GroupVisibilityFields\n groupId={group.id}\n value={formData}\n onChange={(access) => setFormData((previous) => ({ ...previous, ...access }))}\n />\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 p-5 pt-3 border-t border-[var(--hub-line-2)] flex-shrink-0\">\n <button type=\"button\" onClick={onCancel} className=\"hub-btn\" disabled={isSubmitting}>\n {t('common.cancel')}\n </button>\n <button type=\"submit\" className=\"hub-btn primary\" disabled={isSubmitting}>\n {isSubmitting ? t('common.submitting') : t('common.save')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default EditGroupForm;\n","import { useAuth } from '@/contexts/AuthContext';\nimport { useState, useRef, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Edit3, Trash2, Copy, Check, Link as LinkIcon, FileCode, ChevronDown } from 'lucide-react';\nimport { Group, Server, IGroupServerConfig, GroupCost } from '@/types';\nimport DeleteDialog from '@/components/ui/DeleteDialog';\nimport CopyClientConfigDialog from '@/components/ui/CopyClientConfigDialog';\nimport {\n ACCESS_TOKEN_PLACEHOLDER,\n type ClientSnippetTarget,\n} from '@/utils/mcpClientSnippets';\nimport { copyText } from '@/utils/clipboard';\nimport { useToast } from '@/contexts/ToastContext';\nimport { useSettingsData } from '@/hooks/useSettingsData';\nimport { formatTokens, percentSaved } from '@/utils/contextCost';\n\ninterface GroupCardProps {\n group: Group;\n servers: Server[];\n onEdit: (group: Group) => void;\n onDelete: (groupId: string) => void;\n cost?: GroupCost;\n}\n\nconst getServerNames = (servers: string[] | IGroupServerConfig[]): string[] =>\n servers.map((server) => (typeof server === 'string' ? server : server.name));\n\nconst getServerConfig = (group: Group, serverName: string): IGroupServerConfig => {\n const server = group.servers.find((s) =>\n typeof s === 'string' ? s === serverName : s.name === serverName,\n );\n if (!server) return { name: serverName, tools: 'all', prompts: 'all', resources: 'all' };\n if (typeof server === 'string') {\n return { name: server, tools: 'all', prompts: 'all', resources: 'all' };\n }\n return server;\n};\n\nconst getServerDisplayName = (group: Group, serverName: string): string => {\n const config = getServerConfig(group, serverName);\n return config.alias?.trim() || serverName;\n};\n\nconst GroupCard = ({ group, servers, onEdit, onDelete, cost }: GroupCardProps) => {\n const { t } = useTranslation();\n const { auth } = useAuth();\n const canManage = !!auth.user && (auth.user.isAdmin || auth.user.username === group.owner);\n const { showToast } = useToast();\n const { installConfig, nameSeparator } = useSettingsData();\n const baseUrl = installConfig?.baseUrl?.replace(/\\/+$/, '') || '';\n\n const [showDeleteDialog, setShowDeleteDialog] = useState(false);\n const [clientConfigTarget, setClientConfigTarget] = useState<ClientSnippetTarget | null>(null);\n const [copied, setCopied] = useState(false);\n const [showCopyDropdown, setShowCopyDropdown] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handle = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setShowCopyDropdown(false);\n }\n };\n document.addEventListener('mousedown', handle);\n return () => document.removeEventListener('mousedown', handle);\n }, []);\n\n const doCopy = async (text: string) => {\n const ok = await copyText(text);\n if (ok) {\n setCopied(true);\n setShowCopyDropdown(false);\n showToast(t('common.copySuccess') || 'Copied', 'success');\n setTimeout(() => setCopied(false), 1500);\n } else {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n }\n };\n\n const groupEndpoint = `${baseUrl}/mcp/${group.name}`;\n // Only the client-config dialog needs a URL-encoded path segment: group names\n // may contain spaces/CJK, and the generated client snippets must be valid URLs.\n // The raw groupEndpoint above is intentionally left as-is for the legacy\n // \"Copy URL\" actions.\n const clientConfigEndpoint = `${baseUrl}/mcp/${encodeURIComponent(group.name)}`;\n const groupOpenApiEndpoint = `${baseUrl}/api/${group.name}`;\n\n const serverNames = getServerNames(group.servers);\n const groupServers = servers.filter((s) => serverNames.includes(s.name));\n\n const tally = (server: Server) => {\n const cfg = getServerConfig(group, server.name);\n const prefix = `${server.name}${nameSeparator}`;\n const allTools = server.tools || [];\n const allPrompts = server.prompts || [];\n const allResources = server.resources || [];\n\n const visibleTools = Array.isArray(cfg.tools)\n ? allTools.filter((t) => {\n if (t.enabled === false) return false;\n const short = t.name.startsWith(prefix) ? t.name.slice(prefix.length) : t.name;\n return cfg.tools!.includes(short);\n }).length\n : allTools.filter((t) => t.enabled !== false).length;\n const visiblePrompts = Array.isArray(cfg.prompts)\n ? allPrompts.filter((p) => {\n if (p.enabled === false) return false;\n const short = p.name.startsWith(prefix) ? p.name.slice(prefix.length) : p.name;\n return cfg.prompts!.includes(short);\n }).length\n : allPrompts.filter((p) => p.enabled !== false).length;\n const visibleResources = Array.isArray(cfg.resources)\n ? allResources.filter((r) => r.enabled !== false && cfg.resources!.includes(r.uri)).length\n : allResources.filter((r) => r.enabled !== false).length;\n\n return {\n visibleTools,\n totalTools: allTools.length,\n visiblePrompts,\n totalPrompts: allPrompts.length,\n visibleResources,\n totalResources: allResources.length,\n };\n };\n\n const totalVisibleTools = groupServers.reduce((acc, s) => acc + tally(s).visibleTools, 0);\n\n return (\n <div className=\"hub-card flex h-full flex-col overflow-visible\">\n {/* Header */}\n <div\n className=\"flex items-start gap-3 px-4 py-3\"\n style={{ borderBottom: '1px solid var(--hub-line-2)' }}\n >\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-0.015em' }}>\n {group.name}\n </span>\n <span\n className=\"hub-mono\"\n style={{\n fontSize: 11,\n color: 'var(--hub-ink-3)',\n padding: '0 6px',\n border: '1px solid var(--hub-line)',\n borderRadius: 4,\n height: 18,\n display: 'inline-flex',\n alignItems: 'center',\n }}\n title={group.id}\n >\n {group.id}\n </span>\n </div>\n <div className=\"mt-1 text-xs text-[var(--hub-ink-3)]\">\n {group.visibility\n ? t(\n `server.visibility${group.visibility === 'group' ? 'Group' : group.visibility === 'public' ? 'Public' : 'Private'}`,\n )\n : t('groups.legacyVisibility')}\n </div>\n {group.description && (\n <div style={{ fontSize: 12.5, color: 'var(--hub-ink-3)', marginTop: 2 }}>\n {group.description}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-1\" ref={dropdownRef}>\n <div className=\"relative\">\n <button\n onClick={() => setShowCopyDropdown((v) => !v)}\n className=\"hub-icon-btn sm\"\n title={t('common.copy')}\n >\n {copied ? <Check size={13} className=\"text-[var(--hub-ok)]\" /> : <Copy size={13} />}\n </button>\n {showCopyDropdown && (\n <div\n className=\"absolute top-full right-0 mt-1 z-20 hub-card\"\n style={{ minWidth: 160, padding: 4 }}\n >\n <button\n onClick={() => doCopy(group.id)}\n 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\"\n >\n <Copy size={12} /> {t('common.copyId')}\n </button>\n <button\n onClick={() => doCopy(groupEndpoint)}\n 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\"\n >\n <LinkIcon size={12} /> {t('common.copyUrl')}\n </button>\n <button\n onClick={() => doCopy(groupOpenApiEndpoint)}\n 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\"\n >\n <LinkIcon size={12} /> {t('common.copyOpenApiUrl')}\n </button>\n <button\n onClick={() => {\n setShowCopyDropdown(false);\n setClientConfigTarget({\n name: group.name,\n url: clientConfigEndpoint,\n headers: { Authorization: `Bearer ${ACCESS_TOKEN_PLACEHOLDER}` },\n });\n }}\n 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\"\n >\n <FileCode size={12} /> {t('clientConfig.menuItem')}\n </button>\n </div>\n )}\n </div>\n {canManage && (\n <>\n <button\n onClick={() => onEdit(group)}\n className=\"hub-icon-btn sm\"\n title={t('groups.edit')}\n >\n <Edit3 size={13} />\n </button>\n <button\n onClick={() => setShowDeleteDialog(true)}\n className=\"hub-icon-btn sm\"\n title={t('groups.delete')}\n style={{ color: 'var(--hub-ink-3)' }}\n >\n <Trash2 size={13} />\n </button>\n </>\n )}\n </div>\n </div>\n\n {/* Routing diagram */}\n <div\n className=\"grid flex-1 items-center gap-3 px-4 py-3\"\n style={{ gridTemplateColumns: '1fr 80px 1fr', minHeight: 180 }}\n >\n {/* Servers */}\n <div className=\"flex flex-col gap-1.5\">\n {groupServers.length === 0 ? (\n <div style={{ fontSize: 12, color: 'var(--hub-ink-3)' }}>{t('groups.noServers')}</div>\n ) : (\n groupServers.map((s) => {\n const tn = tally(s);\n return (\n <div\n key={s.name}\n className=\"flex items-center gap-2.5 px-2.5 py-1.5 rounded-md\"\n style={{\n background: 'var(--hub-bg-2)',\n border: '1px solid var(--hub-line-2)',\n }}\n >\n <span\n className=\"inline-block flex-shrink-0\"\n style={{\n width: 6,\n height: 6,\n borderRadius: 50,\n background:\n s.status === 'connected'\n ? 'var(--hub-ok)'\n : s.status === 'connecting'\n ? 'var(--hub-warn)'\n : 'var(--hub-err)',\n }}\n />\n <span className=\"hub-mono truncate flex-1\" style={{ fontSize: 12.5 }}>\n <span title={s.name}>{getServerDisplayName(group, s.name)}</span>\n </span>\n <span\n className=\"hub-mono hub-num flex-shrink-0\"\n style={{ fontSize: 11, color: 'var(--hub-ink-3)' }}\n >\n {tn.visibleTools}/{tn.totalTools} tools\n </span>\n </div>\n );\n })\n )}\n </div>\n\n {/* Flow */}\n <svg width=\"80\" height=\"80\" viewBox=\"0 0 80 80\" className=\"self-center\">\n {groupServers.length === 0 ? (\n <path\n d=\"M0,40 C30,40 50,40 80,40\"\n stroke=\"var(--hub-line)\"\n strokeWidth=\"1\"\n fill=\"none\"\n strokeDasharray=\"3 3\"\n />\n ) : (\n groupServers.map((_, i) => {\n const y1 = 12 + (60 / Math.max(groupServers.length, 1)) * (i + 0.5);\n return (\n <path\n key={i}\n d={`M0,${y1} C 30,${y1} 50,40 80,40`}\n stroke=\"var(--hub-line)\"\n strokeWidth=\"1\"\n fill=\"none\"\n strokeDasharray=\"3 3\"\n />\n );\n })\n )}\n <circle cx=\"80\" cy=\"40\" r=\"4\" fill=\"var(--hub-ink)\" />\n </svg>\n\n {/* Endpoint */}\n <div\n className=\"px-3 py-2.5 rounded-md\"\n style={{\n border: '1px solid var(--hub-line)',\n background: 'var(--hub-bg-2)',\n }}\n >\n <div className=\"hub-sect\" style={{ marginBottom: 4 }}>\n endpoint\n </div>\n <div\n className=\"hub-mono break-all\"\n style={{ fontSize: 12, color: 'var(--hub-ink-2)', lineHeight: 1.4 }}\n >\n <span style={{ color: 'var(--hub-ink-3)' }}>/mcp/</span>\n <b style={{ color: 'var(--hub-ink)', fontWeight: 600 }}>{group.name}</b>\n </div>\n <div\n className=\"hub-mono break-all\"\n style={{ fontSize: 12, color: 'var(--hub-ink-2)', lineHeight: 1.4 }}\n >\n <span style={{ color: 'var(--hub-ink-3)' }}>/api/</span>\n <b style={{ color: 'var(--hub-ink)', fontWeight: 600 }}>{group.name}</b>\n </div>\n <div className=\"flex gap-1.5 mt-2\">\n <button\n className=\"hub-btn sm flex-1 justify-center\"\n onClick={() => doCopy(groupEndpoint)}\n title={t('common.copyUrl')}\n >\n <Copy size={11} /> MCP\n </button>\n <button\n className=\"hub-btn sm flex-1 justify-center\"\n onClick={() => doCopy(groupOpenApiEndpoint)}\n title={t('common.copyOpenApiUrl')}\n >\n <Copy size={11} /> OpenAPI\n </button>\n </div>\n </div>\n </div>\n\n {/* Footer */}\n <div\n className=\"flex justify-between items-center px-4 py-2\"\n style={{\n borderTop: '1px solid var(--hub-line-2)',\n background: 'var(--hub-bg-2)',\n fontSize: 12,\n color: 'var(--hub-ink-3)',\n }}\n >\n <div>\n <div className=\"hub-mono\">\n <span style={{ color: 'var(--hub-ink-2)' }}>{groupServers.length}</span>{' '}\n {t('nav.servers').toLowerCase()} ·{' '}\n <span style={{ color: 'var(--hub-ink-2)' }}>{totalVisibleTools}</span>{' '}\n {t('server.tools').toLowerCase()}\n </div>\n {cost && (\n <div className=\"hub-mono mt-1\" style={{ fontSize: 11.5, color: 'var(--hub-ink-3)' }}>\n <div title={t('cost.estimate')}>\n {t('cost.totalFootprint')}: {formatTokens(cost.direct.exposed)}/\n {formatTokens(cost.direct.gross)}\n </div>\n {cost.smartRouting && (\n <>\n <div>\n {t('cost.smartRouting')}: {formatTokens(cost.smartRouting.base)} (\n {t('cost.saved', {\n percent: percentSaved(cost.direct.exposed, cost.smartRouting.base),\n })}\n )\n </div>\n <div title={t('cost.smartRoutingPdHint')}>\n {t('cost.smartRoutingPd')}:{' '}\n {formatTokens(cost.smartRouting.progressiveDisclosure)}\n </div>\n </>\n )}\n {cost.connectedCount < cost.totalCount && (\n <div>\n {t('cost.connectedOf', {\n connected: cost.connectedCount,\n total: cost.totalCount,\n })}\n </div>\n )}\n </div>\n )}\n </div>\n {canManage && (\n <button\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-ink-3)' }}\n onClick={() => onEdit(group)}\n >\n {t('groups.configureTools') || t('groups.edit')}\n <ChevronDown size={11} style={{ transform: 'rotate(-90deg)' }} />\n </button>\n )}\n </div>\n\n <CopyClientConfigDialog\n isOpen={clientConfigTarget !== null}\n target={clientConfigTarget}\n onClose={() => setClientConfigTarget(null)}\n />\n\n <DeleteDialog\n isOpen={showDeleteDialog}\n onClose={() => setShowDeleteDialog(false)}\n onConfirm={() => {\n onDelete(group.id);\n setShowDeleteDialog(false);\n }}\n serverName={group.name}\n isGroup={true}\n />\n </div>\n );\n};\n\nexport default GroupCard;\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { apiPost } from '@/utils/fetchInterceptor';\n\ninterface GroupImportFormProps {\n onSuccess: () => void;\n onCancel: () => void;\n}\n\ninterface ImportGroupConfig {\n name: string;\n description?: string;\n servers?: string[] | Array<{\n name: string;\n tools?: string[] | 'all';\n prompts?: string[] | 'all';\n resources?: string[] | 'all';\n }>;\n}\n\ninterface ImportJsonFormat {\n groups: ImportGroupConfig[];\n}\n\nconst GroupImportForm: React.FC<GroupImportFormProps> = ({ onSuccess, onCancel }) => {\n const { t } = useTranslation();\n const [jsonInput, setJsonInput] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isImporting, setIsImporting] = useState(false);\n const [previewGroups, setPreviewGroups] = useState<ImportGroupConfig[] | null>(null);\n\n const examplePlaceholder = `{\n \"groups\": [\n {\n \"name\": \"AI Assistants\",\n \"servers\": [\"openai-server\", \"anthropic-server\"]\n },\n {\n \"name\": \"Development Tools\",\n \"servers\": [\n {\n \"name\": \"github-server\",\n \"tools\": [\"create_issue\", \"list_repos\"],\n \"prompts\": [\"triage_prompt\"],\n \"resources\": [\"resource://docs/repo-guide\"]\n },\n {\n \"name\": \"gitlab-server\",\n \"tools\": \"all\",\n \"prompts\": \"all\",\n \"resources\": \"all\"\n }\n ]\n }\n ]\n}\n\nSupports:\n- Simple server list: [\"server1\", \"server2\"]\n- Advanced server config: [{\"name\": \"server1\", \"tools\": [\"tool1\"], \"prompts\": [\"prompt1\"], \"resources\": [\"resource://docs/guide\"]}]\n- All groups will be imported in a single efficient batch operation.`;\n\n const parseAndValidateJson = (input: string): ImportJsonFormat | null => {\n try {\n const parsed = JSON.parse(input.trim());\n\n // Validate structure\n if (!parsed.groups || !Array.isArray(parsed.groups)) {\n setError(t('groupImport.invalidFormat'));\n return null;\n }\n\n // Validate each group\n for (const group of parsed.groups) {\n if (!group.name || typeof group.name !== 'string') {\n setError(t('groupImport.missingName'));\n return null;\n }\n }\n\n return parsed as ImportJsonFormat;\n } catch (e) {\n setError(t('groupImport.parseError'));\n return null;\n }\n };\n\n const handlePreview = () => {\n setError(null);\n const parsed = parseAndValidateJson(jsonInput);\n if (!parsed) return;\n\n setPreviewGroups(parsed.groups);\n };\n\n const handleImport = async () => {\n if (!previewGroups) return;\n\n setIsImporting(true);\n setError(null);\n\n try {\n // Use batch import API for better performance\n const result = await apiPost('/groups/batch', {\n groups: previewGroups,\n });\n\n if (result.success) {\n const { successCount, failureCount, results } = result;\n\n if (failureCount > 0) {\n const errors = results\n .filter((r: any) => !r.success)\n .map((r: any) => `${r.name}: ${r.message || t('groupImport.addFailed')}`);\n\n setError(\n t('groupImport.partialSuccess', { count: successCount, total: previewGroups.length }) +\n '\\n' +\n errors.join('\\n'),\n );\n }\n\n if (successCount > 0) {\n onSuccess();\n }\n } else {\n setError(result.message || t('groupImport.importFailed'));\n }\n } catch (err) {\n console.error('Import error:', err);\n setError(t('groupImport.importFailed'));\n } finally {\n setIsImporting(false);\n }\n };\n\n const renderAllCapabilitiesLabel = (\n key: 'previewAllTools' | 'previewAllPrompts' | 'previewAllResources',\n ) => <span className=\"text-gray-500 ml-2\">{t(`groups.${key}`)}</span>;\n\n const renderCapabilityPreview = (\n key: 'previewPrompts' | 'previewResources',\n value: string[] | 'all' | undefined,\n ) => {\n if (!value || value === 'all') {\n return null;\n }\n\n const items = Array.isArray(value) ? value.join(', ') : value;\n return <span className=\"text-gray-500 ml-2\">{t(`groups.${key}`, { items })}</span>;\n };\n\n const renderServerList = (\n servers?: string[] | Array<{\n name: string;\n tools?: string[] | 'all';\n prompts?: string[] | 'all';\n resources?: string[] | 'all';\n }>,\n ) => {\n if (!servers || servers.length === 0) {\n return <span className=\"text-gray-500\">{t('groups.noServers')}</span>;\n }\n\n return (\n <div className=\"space-y-1\">\n {servers.map((server, idx) => {\n if (typeof server === 'string') {\n return (\n <div key={idx} className=\"text-sm\">\n • {server}\n </div>\n );\n } else {\n return (\n <div key={idx} className=\"text-sm\">\n • {server.name}\n {server.tools && server.tools !== 'all' && (\n <span className=\"text-gray-500 ml-2\">\n ({Array.isArray(server.tools) ? server.tools.join(', ') : server.tools})\n </span>\n )}\n {server.tools === 'all' && renderAllCapabilitiesLabel('previewAllTools')}\n {renderCapabilityPreview('previewPrompts', server.prompts)}\n {server.prompts === 'all' && renderAllCapabilitiesLabel('previewAllPrompts')}\n {renderCapabilityPreview('previewResources', server.resources)}\n {server.resources === 'all' && renderAllCapabilitiesLabel('previewAllResources')}\n </div>\n );\n }\n })}\n </div>\n );\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto\">\n <div className=\"flex justify-between items-center mb-6\">\n <h2 className=\"text-xl font-semibold text-gray-900\">{t('groupImport.title')}</h2>\n <button onClick={onCancel} className=\"text-gray-500 hover:text-gray-700\">\n ✕\n </button>\n </div>\n\n {error && (\n <div className=\"mb-4 bg-red-50 border-l-4 border-red-500 p-4 rounded\">\n <p className=\"text-red-700 whitespace-pre-wrap\">{error}</p>\n </div>\n )}\n\n {!previewGroups ? (\n <div>\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {t('groupImport.inputLabel')}\n </label>\n <textarea\n value={jsonInput}\n onChange={(e) => setJsonInput(e.target.value)}\n 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\"\n placeholder={examplePlaceholder}\n />\n <p className=\"text-xs text-gray-500 mt-2\">{t('groupImport.inputHelp')}</p>\n </div>\n\n <div className=\"flex justify-end space-x-4\">\n <button\n onClick={onCancel}\n className=\"hub-btn\"\n >\n {t('common.cancel')}\n </button>\n <button\n onClick={handlePreview}\n disabled={!jsonInput.trim()}\n className=\"hub-btn primary\"\n >\n {t('groupImport.preview')}\n </button>\n </div>\n </div>\n ) : (\n <div>\n <div className=\"mb-4\">\n <h3 className=\"text-lg font-medium text-gray-900 mb-3\">\n {t('groupImport.previewTitle')}\n </h3>\n <div className=\"space-y-3\">\n {previewGroups.map((group, index) => (\n <div key={index} className=\"bg-gray-50 dark:bg-gray-800 p-4 rounded-lg border border-gray-200 dark:border-gray-700\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h4 className=\"font-medium text-gray-900\">{group.name}</h4>\n {group.description && (\n <p className=\"text-sm text-gray-600 mt-1\">{group.description}</p>\n )}\n <div className=\"mt-2 text-sm text-gray-600\">\n <strong>{t('groups.servers')}:</strong>\n <div className=\"mt-1\">{renderServerList(group.servers)}</div>\n </div>\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-4\">\n <button\n onClick={() => setPreviewGroups(null)}\n disabled={isImporting}\n className=\"hub-btn\"\n >\n {t('common.back')}\n </button>\n <button\n onClick={handleImport}\n disabled={isImporting}\n className=\"hub-btn primary\"\n >\n {isImporting ? (\n <>\n <svg\n className=\"animate-spin h-4 w-4 mr-2\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n 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\"\n ></path>\n </svg>\n {t('groupImport.importing')}\n </>\n ) : (\n t('groupImport.import')\n )}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default GroupImportForm;\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { apiPost } from '@/utils/fetchInterceptor';\nimport { Group, ConfigTemplate } from '@/types';\n\ninterface TemplateExportFormProps {\n groups: Group[];\n onCancel: () => void;\n}\n\nconst TemplateExportForm: React.FC<TemplateExportFormProps> = ({ groups, onCancel }) => {\n const { t } = useTranslation();\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [selectedGroupIds, setSelectedGroupIds] = useState<string[]>([]);\n const [includeDisabled, setIncludeDisabled] = useState(false);\n const [isExporting, setIsExporting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleToggleGroup = (groupId: string) => {\n setSelectedGroupIds((prev) =>\n prev.includes(groupId) ? prev.filter((id) => id !== groupId) : [...prev, groupId],\n );\n };\n\n const handleSelectAll = () => {\n if (selectedGroupIds.length === groups.length) {\n setSelectedGroupIds([]);\n } else {\n setSelectedGroupIds(groups.map((g) => g.id));\n }\n };\n\n const handleExport = async () => {\n if (!name.trim()) {\n setError(t('template.nameRequired'));\n return;\n }\n\n setIsExporting(true);\n setError(null);\n\n try {\n const result = await apiPost('/templates/export', {\n name: name.trim(),\n description: description.trim() || undefined,\n groupIds: selectedGroupIds.length > 0 ? selectedGroupIds : undefined,\n includeDisabledServers: includeDisabled,\n });\n\n if (result.success && result.data) {\n const template: ConfigTemplate = result.data;\n const blob = new Blob([JSON.stringify(template, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `${template.name.replace(/[^a-zA-Z0-9-_]/g, '_')}.mcphub-template.json`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n onCancel();\n } else {\n setError(result.message || t('template.exportFailed'));\n }\n } catch (err) {\n console.error('Export error:', err);\n setError(t('template.exportFailed'));\n } finally {\n setIsExporting(false);\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-3xl max-h-[90vh] overflow-y-auto\">\n <div className=\"flex justify-between items-center mb-6\">\n <h2 className=\"text-xl font-semibold text-gray-900\">{t('template.exportTitle')}</h2>\n <button onClick={onCancel} className=\"text-gray-500 hover:text-gray-700\">\n ✕\n </button>\n </div>\n\n {error && (\n <div className=\"mb-4 bg-red-50 dark:bg-red-900/20 border-l-4 border-red-500 p-4 rounded\">\n <p className=\"text-red-700 dark:text-red-300\">{error}</p>\n </div>\n )}\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('template.name')} *\n </label>\n <input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder={t('template.namePlaceholder')}\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('template.description')}\n </label>\n <input\n type=\"text\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500\"\n placeholder={t('template.descriptionPlaceholder')}\n />\n </div>\n\n <div>\n <div className=\"flex justify-between items-center mb-2\">\n <label className=\"block text-sm font-medium text-gray-700\">\n {t('template.selectGroups')}\n </label>\n <button\n onClick={handleSelectAll}\n className=\"text-sm text-blue-600 hover:text-blue-800 dark:text-blue-300\"\n >\n {selectedGroupIds.length === groups.length\n ? t('template.deselectAll')\n : t('template.selectAll')}\n </button>\n </div>\n <p className=\"text-xs text-gray-500 mb-2\">{t('template.selectGroupsHelp')}</p>\n <div className=\"border border-gray-200 dark:border-gray-700 rounded-md max-h-48 overflow-y-auto\">\n {groups.map((group) => (\n <label\n key={group.id}\n className=\"flex items-center px-3 py-2 hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 cursor-pointer\"\n >\n <input\n type=\"checkbox\"\n checked={selectedGroupIds.includes(group.id)}\n onChange={() => handleToggleGroup(group.id)}\n className=\"mr-3 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <div>\n <span className=\"text-sm font-medium text-gray-900\">{group.name}</span>\n {group.description && (\n <span className=\"text-xs text-gray-500 ml-2\">{group.description}</span>\n )}\n </div>\n </label>\n ))}\n </div>\n </div>\n\n <label className=\"flex items-center space-x-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={includeDisabled}\n onChange={(e) => setIncludeDisabled(e.target.checked)}\n className=\"h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500\"\n />\n <span className=\"text-sm text-gray-700\">{t('template.includeDisabled')}</span>\n </label>\n </div>\n\n <div className=\"mt-4 p-3 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-700/60 rounded-md\">\n <p className=\"text-sm text-blue-700 dark:text-blue-300\">{t('template.exportNote')}</p>\n </div>\n\n <div className=\"flex justify-end space-x-4 mt-6\">\n <button\n onClick={onCancel}\n className=\"hub-btn\"\n >\n {t('common.cancel')}\n </button>\n <button\n onClick={handleExport}\n disabled={isExporting || !name.trim()}\n className=\"hub-btn primary\"\n >\n {isExporting ? t('template.exporting') : t('template.export')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default TemplateExportForm;\n","import React, { useState, useRef } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { apiPost } from '@/utils/fetchInterceptor';\nimport { ConfigTemplate, TemplateImportResult } from '@/types';\n\ninterface TemplateImportFormProps {\n onSuccess: () => void;\n onCancel: () => void;\n}\n\nconst TemplateImportForm: React.FC<TemplateImportFormProps> = ({ onSuccess, onCancel }) => {\n const { t } = useTranslation();\n const [template, setTemplate] = useState<ConfigTemplate | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isImporting, setIsImporting] = useState(false);\n const [result, setResult] = useState<TemplateImportResult | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {\n setError(null);\n setTemplate(null);\n setResult(null);\n\n const file = e.target.files?.[0];\n if (!file) return;\n\n const reader = new FileReader();\n reader.onload = (event) => {\n try {\n const parsed = JSON.parse(event.target?.result as string);\n if (!parsed.version || !parsed.name || !parsed.servers || !parsed.groups) {\n setError(t('template.invalidFormat'));\n return;\n }\n setTemplate(parsed as ConfigTemplate);\n } catch {\n setError(t('template.parseError'));\n }\n };\n reader.readAsText(file);\n };\n\n const handlePaste = (input: string) => {\n setError(null);\n setTemplate(null);\n setResult(null);\n\n if (!input.trim()) return;\n\n try {\n const parsed = JSON.parse(input.trim());\n if (!parsed.version || !parsed.name || !parsed.servers || !parsed.groups) {\n setError(t('template.invalidFormat'));\n return;\n }\n setTemplate(parsed as ConfigTemplate);\n } catch {\n setError(t('template.parseError'));\n }\n };\n\n const handleImport = async () => {\n if (!template) return;\n\n setIsImporting(true);\n setError(null);\n\n try {\n const response = await apiPost('/templates/import', template);\n\n if (response.data) {\n setResult(response.data as TemplateImportResult);\n if (response.data.success) {\n onSuccess();\n }\n } else {\n setError(response.message || t('template.importFailed'));\n }\n } catch (err) {\n console.error('Import error:', err);\n setError(t('template.importFailed'));\n } finally {\n setIsImporting(false);\n }\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto\">\n <div className=\"flex justify-between items-center mb-6\">\n <h2 className=\"text-xl font-semibold text-gray-900\">{t('template.importTitle')}</h2>\n <button onClick={onCancel} className=\"text-gray-500 hover:text-gray-700\">\n ✕\n </button>\n </div>\n\n {error && (\n <div className=\"mb-4 bg-red-50 dark:bg-red-900/20 border-l-4 border-red-500 p-4 rounded\">\n <p className=\"text-red-700 dark:text-red-300\">{error}</p>\n </div>\n )}\n\n {result && (\n <div\n className={`mb-4 p-4 rounded border-l-4 ${result.success ? 'bg-green-50 dark:bg-green-900/20 border-green-500' : 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-500'}`}\n >\n <p className={result.success ? 'text-green-700 dark:text-green-300' : 'text-yellow-700 dark:text-yellow-300'}>\n {t('template.importResult', {\n serversCreated: result.serversCreated,\n serversSkipped: result.serversSkipped,\n groupsCreated: result.groupsCreated,\n groupsSkipped: result.groupsSkipped,\n })}\n </p>\n {result.requiredEnvVars.length > 0 && (\n <div className=\"mt-2 p-2 bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-700/60 rounded\">\n <p className=\"text-sm font-medium text-orange-800 dark:text-orange-300\">\n {t('template.envVarsNeeded')}\n </p>\n <ul className=\"mt-1 text-sm text-orange-700 dark:text-orange-300\">\n {result.requiredEnvVars.map((v) => (\n <li key={v} className=\"font-mono\">\n {v}\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )}\n\n {!template ? (\n <div>\n <div className=\"mb-4\">\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"block text-sm font-medium text-gray-700\">\n {t('template.uploadFile')}\n </label>\n </div>\n <div className=\"flex items-center space-x-4\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".json\"\n onChange={handleFileSelect}\n 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\"\n />\n </div>\n </div>\n\n <div className=\"relative my-4\">\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full border-t border-gray-300\" />\n </div>\n <div className=\"relative flex justify-center text-sm\">\n <span className=\"bg-white dark:bg-gray-800 px-2 text-gray-500\">{t('template.or')}</span>\n </div>\n </div>\n\n <div className=\"mb-4\">\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n {t('template.pasteJson')}\n </label>\n <textarea\n 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\"\n placeholder={t('template.pastePlaceholder')}\n onChange={(e) => handlePaste(e.target.value)}\n />\n </div>\n\n <div className=\"flex justify-end space-x-4\">\n <button\n onClick={onCancel}\n className=\"hub-btn\"\n >\n {t('common.cancel')}\n </button>\n </div>\n </div>\n ) : (\n <div>\n {/* Template preview */}\n <div className=\"space-y-4\">\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <h3 className=\"font-medium text-gray-900\">{template.name}</h3>\n {template.description && (\n <p className=\"text-sm text-gray-600 mt-1\">{template.description}</p>\n )}\n <p className=\"text-xs text-gray-500 mt-1\">\n {t('template.version')}: {template.version} | {t('template.createdAt')}:{' '}\n {new Date(template.createdAt).toLocaleDateString()}\n </p>\n </div>\n\n <div>\n <h4 className=\"text-sm font-medium text-gray-700 mb-2\">\n {t('template.servers')} ({Object.keys(template.servers).length})\n </h4>\n <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\">\n {Object.entries(template.servers).map(([name, config]) => (\n <div key={name} className=\"px-3 py-2\">\n <span className=\"text-sm font-medium text-gray-900\">{name}</span>\n <span className=\"text-xs text-gray-500 ml-2\">\n {config.type || 'stdio'}\n </span>\n </div>\n ))}\n </div>\n </div>\n\n <div>\n <h4 className=\"text-sm font-medium text-gray-700 mb-2\">\n {t('template.groups')} ({template.groups.length})\n </h4>\n <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\">\n {template.groups.map((group, idx) => (\n <div key={idx} className=\"px-3 py-2\">\n <span className=\"text-sm font-medium text-gray-900\">{group.name}</span>\n {group.description && (\n <span className=\"text-xs text-gray-500 ml-2\">{group.description}</span>\n )}\n <div className=\"text-xs text-gray-500 mt-1\">\n {group.servers.length} {t('template.serversInGroup')}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {template.requiredEnvVars.length > 0 && (\n <div className=\"p-3 bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-700/60 rounded-md\">\n <h4 className=\"text-sm font-medium text-orange-800 dark:text-orange-300\">\n {t('template.envVarsNeeded')}\n </h4>\n <ul className=\"mt-1 text-sm text-orange-700 dark:text-orange-300 font-mono\">\n {template.requiredEnvVars.map((v) => (\n <li key={v}>{v}</li>\n ))}\n </ul>\n </div>\n )}\n </div>\n\n <div className=\"flex justify-end space-x-4 mt-6\">\n <button\n onClick={() => {\n setTemplate(null);\n setResult(null);\n if (fileInputRef.current) fileInputRef.current.value = '';\n }}\n className=\"hub-btn\"\n >\n {t('common.back')}\n </button>\n <button\n onClick={handleImport}\n disabled={isImporting}\n className=\"hub-btn primary\"\n >\n {isImporting ? t('template.importing') : t('template.import')}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default TemplateImportForm;\n","import React, { useState, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Plus, Download, Upload, AlertCircle, X } from 'lucide-react';\nimport { Group } from '@/types';\nimport { useGroupData } from '@/hooks/useGroupData';\nimport { useServerData } from '@/hooks/useServerData';\nimport AddGroupForm from '@/components/AddGroupForm';\nimport EditGroupForm from '@/components/EditGroupForm';\nimport GroupCard from '@/components/GroupCard';\nimport GroupImportForm from '@/components/GroupImportForm';\nimport TemplateExportForm from '@/components/TemplateExportForm';\nimport TemplateImportForm from '@/components/TemplateImportForm';\nimport { useCostData } from '@/hooks/useCostData';\n\nconst GroupsPage: React.FC = () => {\n const { t } = useTranslation();\n const {\n groups,\n loading: groupsLoading,\n error: groupError,\n setError: setGroupError,\n deleteGroup,\n triggerRefresh,\n } = useGroupData();\n const { allServers } = useServerData({ refreshOnMount: true });\n const { groupCosts, refetch: refetchCost } = useCostData();\n\n // Re-fetch context footprint whenever group definitions or server connection state change.\n useEffect(() => {\n refetchCost();\n }, [groups, allServers, refetchCost]);\n\n const [editingGroup, setEditingGroup] = useState<Group | null>(null);\n const [showAddForm, setShowAddForm] = useState(false);\n const [showImportForm, setShowImportForm] = useState(false);\n const [showTemplateExport, setShowTemplateExport] = useState(false);\n const [showTemplateImport, setShowTemplateImport] = useState(false);\n\n const handleDeleteGroup = async (groupId: string) => {\n const result = await deleteGroup(groupId);\n if (!result || !result.success) {\n setGroupError(result?.message || t('groups.deleteError'));\n }\n };\n\n return (\n <div>\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.groups.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{groups.length}</span> {t('nav.groups').toLowerCase()}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button className=\"hub-btn\" onClick={() => setShowImportForm(true)}>\n <Upload size={13} /> {t('groupImport.button')}\n </button>\n <button className=\"hub-btn\" onClick={() => setShowTemplateExport(true)}>\n <Download size={13} /> {t('template.exportButton')}\n </button>\n <button className=\"hub-btn\" onClick={() => setShowTemplateImport(true)}>\n <Upload size={13} /> {t('template.importButton')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => setShowAddForm(true)}>\n <Plus size={13} /> {t('groups.add')}\n </button>\n </div>\n </div>\n\n {groupError && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-4\"\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]\">{groupError}</span>\n </div>\n <button className=\"hub-icon-btn sm\" onClick={() => setGroupError(null)}>\n <X size={13} />\n </button>\n </div>\n )}\n\n {groupsLoading ? (\n <div className=\"hub-card p-6 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('app.loading')}\n </div>\n ) : groups.length === 0 ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('groups.noGroups')}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-3.5\">\n {groups.map((group) => (\n <GroupCard\n key={group.id}\n group={group}\n servers={allServers}\n onEdit={setEditingGroup}\n onDelete={handleDeleteGroup}\n cost={groupCosts.find((c) => c.id === group.id)}\n />\n ))}\n <button\n onClick={() => setShowAddForm(true)}\n className=\"flex items-center justify-center text-[var(--hub-ink-3)] hover:text-[var(--hub-ink-2)] transition-colors\"\n style={{\n border: '1px dashed var(--hub-line)',\n borderRadius: 10,\n minHeight: 200,\n background: 'transparent',\n cursor: 'pointer',\n }}\n >\n <div className=\"text-center\">\n <div\n className=\"grid place-items-center mx-auto mb-2\"\n style={{\n width: 36,\n height: 36,\n borderRadius: 10,\n border: '1px solid var(--hub-line)',\n }}\n >\n <Plus size={16} />\n </div>\n <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--hub-ink-2)' }}>\n {t('groups.add')}\n </div>\n <div style={{ fontSize: 12, marginTop: 2 }}>{t('groups.addNew')}</div>\n </div>\n </button>\n </div>\n )}\n\n {showAddForm && (\n <AddGroupForm\n onAdd={() => {\n setShowAddForm(false);\n triggerRefresh();\n }}\n onCancel={() => setShowAddForm(false)}\n />\n )}\n\n {showImportForm && (\n <GroupImportForm\n onSuccess={() => {\n setShowImportForm(false);\n triggerRefresh();\n }}\n onCancel={() => setShowImportForm(false)}\n />\n )}\n\n {editingGroup && (\n <EditGroupForm\n group={editingGroup}\n onEdit={() => {\n setEditingGroup(null);\n triggerRefresh();\n }}\n onCancel={() => setEditingGroup(null)}\n />\n )}\n\n {showTemplateExport && (\n <TemplateExportForm groups={groups} onCancel={() => setShowTemplateExport(false)} />\n )}\n\n {showTemplateImport && (\n <TemplateImportForm\n onSuccess={() => {\n setShowTemplateImport(false);\n triggerRefresh();\n }}\n onCancel={() => setShowTemplateImport(false)}\n />\n )}\n </div>\n );\n};\n\nexport default GroupsPage;\n"],"names":["RISK_GROUPS","classifyTool","item","_a","name","_b","_c","filterCapabilities","items","query","annotation","search","applyVisibleSelection","selection","all","visible","action","selected","CapabilitySelection","tools","label","onChange","children","t","useTranslation","setQuery","useState","setAnnotation","grouped","setGrouped","apply","target","sections","risk","buttonClass","jsxs","jsx","event","Fragment","hint","section","count","React","EMPTY_SELECTIONS","FULL_SELECTIONS","ServerToolConfig","servers","value","className","serverCosts","nameSeparator","smartRoutingConfig","useSettingsData","expandedServers","setExpandedServers","normalizedValue","availableServers","server","configuredServerNames","config","availableServerNames","prev","newSet","serverName","toggleServer","newValue","toggleServerExpanded","hasAnyCapabilitySelection","capability","updateServerCapability","keepExpanded","existingServer","nextConfig","updateServerAlias","alias","togglePinnedTool","toolName","pinnedTools","normalizeNamedCapability","prefix","getCapabilityItems","tool","prompt","resource","serverCostsMap","outerMap","sc","innerMap","i","costMapForServer","getSelectedCapabilityCost","costMap","isCapabilityItemSelected","sum","getServerSelectedCost","cap","toggleCapabilityItem","itemValue","s","allItems","serverConfig","currentSelection","nextSelection","isServerSelected","isServerPartiallySelected","getSelectedCapabilityCount","itemSet","capabilityConfigs","getServerSummaryBadges","key","entry","cn","isSelected","isPartiallySelected","isExpanded","summaryBadges","serverCapabilities","e","formatTokens","Wrench","MessageSquare","FileText","titleKey","countKey","allKey","selectedCount","allSelected","isChecked","isPinned","descriptionInfo","getToolDescriptionInfo","descriptionTitle","Pin","GroupVisibilityFields","groupId","users","setUsers","setSearch","loading","setLoading","error","setError","isAdvancedExpanded","setIsAdvancedExpanded","useEffect","cancelled","apiGet","result","candidates","username","selectedUsers","allCandidatesSelected","noCandidatesSelected","toggleSharedUser","nextSelected","AddGroupForm","onAdd","onCancel","createGroup","useGroupData","allServers","useServerData","useCostData","setAvailableServers","isSubmitting","setIsSubmitting","formData","setFormData","handleChange","handleSubmit","err","access","previous","EditGroupForm","group","onEdit","updateGroup","getServerNames","getServerConfig","getServerDisplayName","GroupCard","onDelete","cost","auth","useAuth","canManage","showToast","useToast","installConfig","baseUrl","showDeleteDialog","setShowDeleteDialog","clientConfigTarget","setClientConfigTarget","copied","setCopied","showCopyDropdown","setShowCopyDropdown","dropdownRef","useRef","handle","doCopy","text","copyText","groupEndpoint","clientConfigEndpoint","groupOpenApiEndpoint","serverNames","groupServers","tally","cfg","allTools","allPrompts","allResources","visibleTools","short","visiblePrompts","p","visibleResources","r","totalVisibleTools","acc","v","Check","Copy","LinkIcon","ACCESS_TOKEN_PLACEHOLDER","FileCode","Edit3","Trash2","tn","_","y1","percentSaved","ChevronDown","CopyClientConfigDialog","DeleteDialog","GroupImportForm","onSuccess","jsonInput","setJsonInput","isImporting","setIsImporting","previewGroups","setPreviewGroups","examplePlaceholder","parseAndValidateJson","input","parsed","handlePreview","handleImport","apiPost","successCount","failureCount","results","errors","renderAllCapabilitiesLabel","renderCapabilityPreview","renderServerList","idx","index","TemplateExportForm","groups","setName","description","setDescription","selectedGroupIds","setSelectedGroupIds","includeDisabled","setIncludeDisabled","isExporting","setIsExporting","handleToggleGroup","id","handleSelectAll","g","handleExport","template","blob","url","a","TemplateImportForm","setTemplate","setResult","fileInputRef","handleFileSelect","file","reader","handlePaste","response","GroupsPage","groupsLoading","groupError","setGroupError","deleteGroup","triggerRefresh","groupCosts","refetchCost","editingGroup","setEditingGroup","showAddForm","setShowAddForm","showImportForm","setShowImportForm","showTemplateExport","setShowTemplateExport","showTemplateImport","setShowTemplateImport","handleDeleteGroup","Upload","Download","Plus","AlertCircle","X","c"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{d as V,j as e,r as n,u as oe}from"./framework-vendor-CQFm9vKd.js";import{u as le,g as ie,G as H,T as ce,L as de,a as ue,s as he,b as K,c as ge}from"./index-B_IITM9e.js";import{u as J}from"./i18n-vendor-DVmjrzgW.js";import{B as me,l as _}from"./icons-vendor-CkcU1LMA.js";const be=({isOpen:s,onClose:d})=>{const{t:i}=J(),c=V();if(!s)return null;const k=()=>{d(),c("/settings"),setTimeout(()=>{const o=document.querySelector('[data-section="password"]');if(o){o.scrollIntoView({behavior:"smooth",block:"start"});const v=o.querySelector('[role="button"]');v&&!o.querySelector(".mt-4")&&v.click()}},100)},x=o=>{o.target===o.currentTarget&&d()},w=o=>{o.key==="Escape"&&d()};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-[100] flex items-center justify-center p-4",onClick:x,onKeyDown:w,tabIndex:-1,children:e.jsx("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full transform transition-all duration-200 ease-out",role:"dialog","aria-modal":"true","aria-labelledby":"password-warning-title","aria-describedby":"password-warning-message",children:e.jsxs("div",{className:"p-6",children:[e.jsxs("div",{className:"flex items-start space-x-3",children:[e.jsx("div",{className:"flex-shrink-0",children:e.jsx("svg",{className:"w-6 h-6 text-yellow-600 dark:text-yellow-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"})})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h3",{id:"password-warning-title",className:"text-lg font-medium text-gray-900 dark:text-white mb-2",children:i("auth.defaultPasswordWarning")}),e.jsx("p",{id:"password-warning-message",className:"text-gray-600 dark:text-gray-300 leading-relaxed",children:i("auth.defaultPasswordMessage")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-3 mt-6",children:[e.jsx("button",{onClick:d,className:"hub-btn",children:i("common.cancel")}),e.jsx("button",{onClick:k,className:"hub-btn primary",autoFocus:!0,children:i("auth.goToSettings")})]})]})})})},pe=s=>{if(!s)return null;try{const d=typeof window<"u"?window.location.origin:"http://localhost",i=new URL(s,d);return i.origin!==d?null:`${i.pathname}${i.search}${i.hash}`||"/"}catch{return s.startsWith("/")&&!s.startsWith("//")?s:null}},je=()=>{const{t:s}=J(),[d,i]=n.useState(!1),[c,k]=n.useState(!1),[x,w]=n.useState(""),[o,v]=n.useState(""),[m,C]=n.useState(""),[Q,u]=n.useState(null),[N,S]=n.useState(!1),[h,R]=n.useState(null),[U,j]=n.useState(null),[z,X]=n.useState(void 0),[P,Y]=n.useState(!1),[g,W]=n.useState({google:!1,github:!1,oidc:!1}),[Z,ee]=n.useState("oidc"),[se,A]=n.useState(!1),{login:te,register:ae,auth:b}=le(),y=oe(),E=V(),l=n.useMemo(()=>{const a=new URLSearchParams(y.search);return pe(a.get("returnUrl"))},[y.search]),I=n.useCallback(a=>{if(!a)return!1;const t=a.toLowerCase();return t.includes("failed to fetch")||t.includes("networkerror")||t.includes("network error")||t.includes("connection refused")||t.includes("unable to connect")||t.includes("fetch error")||t.includes("econnrefused")||t.includes("http 500")||t.includes("internal server error")||t.includes("proxy error")},[]),T=n.useCallback(()=>{if(!l)return"/";if(!l.startsWith("/oauth/authorize"))return l;const a=ie();if(!a)return l;try{const t=window.location.origin,r=new URL(l,t);return r.searchParams.set("token",a),`${r.pathname}${r.search}${r.hash}`}catch{const t=l.includes("?")?"&":"?";return`${l}${t}token=${encodeURIComponent(a)}`}},[l]),p=n.useCallback(()=>{l?window.location.assign(T()):E("/")},[T,E,l]);n.useEffect(()=>{!b.loading&&b.isAuthenticated&&p()},[b.isAuthenticated,b.loading,p]),n.useEffect(()=>{const t=new URLSearchParams(y.search).get("error");if(t){const r=`auth.error.${t}`,f=s(r);j(f!==r?f:s("auth.socialLoginFailed"))}},[y.search,s]),n.useEffect(()=>{(async()=>{var f,B,D,F,M,O,q,G;const t=await ue();i(t.allowRegistration===!0);const r=t.betterAuth;if(!(r!=null&&r.enabled)){W({google:!1,github:!1,oidc:!1});return}X(r.basePath),Y(r.disablePasswordLogin===!0),ee(((B=(f=r.providers)==null?void 0:f.oidc)==null?void 0:B.providerId)||"oidc"),W({google:((F=(D=r.providers)==null?void 0:D.google)==null?void 0:F.enabled)===!0,github:((O=(M=r.providers)==null?void 0:M.github)==null?void 0:O.enabled)===!0,oidc:((G=(q=r.providers)==null?void 0:q.oidc)==null?void 0:G.enabled)===!0})})()},[]);const re=async a=>{a.preventDefault(),u(null),j(null),S(!0);try{if(!o||!m){u(s("auth.emptyFields")),S(!1);return}if(c){if(m!==x){u(s("auth.passwordsNotMatch"));return}await ae(o,m)&&p();return}const t=await te(o,m);if(t.success)t.isUsingDefaultPassword?A(!0):p();else{const r=t.message;u(I(r)?s("auth.serverUnavailable"):s("auth.loginFailed"))}}catch(t){const r=t instanceof Error?t.message:void 0;u(I(r)?s("auth.serverUnavailable"):s("auth.loginError"))}finally{S(!1)}},L=async a=>{j(null),R(a);try{if(a==="oidc"){await he({providerId:Z,callbackURL:l||"/",errorCallbackURL:`${K()}/login`,basePathOverride:z});return}await ge(z).signIn.social({provider:a,callbackURL:l||"/",errorCallbackURL:`${K()}/login`})}catch(t){console.error("Social login error:",t),j(s("auth.socialLoginFailed")),R(null)}},$=Q||(c?b.error:null),ne=()=>{A(!1),p()};return e.jsxs("div",{className:"relative min-h-screen w-full overflow-hidden",style:{background:"var(--hub-bg)",color:"var(--hub-ink)"},children:[e.jsxs("div",{className:"absolute top-3 right-4 z-20 flex items-center gap-1",children:[e.jsx("a",{href:"https://github.com/samanhappy/mcphub",target:"_blank",rel:"noopener noreferrer",className:"hub-icon-btn","aria-label":"GitHub Repository",children:e.jsx(H,{className:"h-4 w-4"})}),e.jsx("a",{href:"https://docs.mcphub.app",target:"_blank",rel:"noopener noreferrer",className:"hub-icon-btn","aria-label":"Documentation",children:e.jsx(me,{className:"h-4 w-4"})}),e.jsx(ce,{}),e.jsx(de,{})]}),e.jsx("div",{className:"pointer-events-none absolute inset-0 -z-10",children:e.jsxs("svg",{className:"h-full w-full",style:{opacity:.5},xmlns:"http://www.w3.org/2000/svg",children:[e.jsx("defs",{children:e.jsx("pattern",{id:"grid",width:"32",height:"32",patternUnits:"userSpaceOnUse",children:e.jsx("path",{d:"M 32 0 L 0 0 0 32",fill:"none",stroke:"var(--hub-line-2)",strokeWidth:"0.5"})})}),e.jsx("rect",{width:"100%",height:"100%",fill:"url(#grid)"})]})}),e.jsx("div",{className:"relative mx-auto flex min-h-screen w-full max-w-md items-center justify-center px-6",children:e.jsxs("div",{className:"w-full space-y-8",children:[e.jsxs("div",{className:"flex flex-col items-center gap-3",children:[e.jsxs("div",{className:"relative grid place-items-center",style:{width:44,height:44,borderRadius:10,background:"var(--hub-ink)",color:"var(--hub-bg)"},children:[e.jsx("span",{className:"hub-mono font-semibold",style:{fontSize:18},children:"M"}),e.jsx("span",{className:"absolute",style:{right:-2,bottom:-2,width:8,height:8,borderRadius:50,background:"var(--hub-ok)",boxShadow:"0 0 0 3px var(--hub-bg)"}})]}),e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{style:{fontSize:20,fontWeight:600,letterSpacing:"-0.02em",color:"var(--hub-ink)"},children:s("app.title")}),e.jsx("p",{className:"hub-sub",style:{marginTop:4},children:s("auth.slogan")})]})]}),e.jsxs("div",{className:"hub-card",style:{padding:"22px 22px 20px",boxShadow:"0 1px 2px rgba(0,0,0,0.02)"},children:[!P&&e.jsxs("form",{className:"space-y-3",onSubmit:re,children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"username",className:"hub-sect block",style:{marginBottom:6},children:s("auth.username")}),e.jsx("input",{id:"username",name:"username",type:"text",autoComplete:"username",required:!0,className:"hub-input",placeholder:s("auth.username"),value:o,onChange:a=>v(a.target.value)})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"password",className:"hub-sect block",style:{marginBottom:6},children:s("auth.password")}),e.jsx("input",{id:"password",name:"password",type:"password",autoComplete:c?"new-password":"current-password",minLength:c?8:void 0,required:!0,className:"hub-input",placeholder:s("auth.password"),value:m,onChange:a=>C(a.target.value)})]}),c&&e.jsxs("div",{children:[e.jsx("p",{className:"hub-sub mb-3",children:s("auth.passwordStrengthHint")}),e.jsx("label",{htmlFor:"confirmPassword",className:"hub-sect block mb-1.5",children:s("auth.confirmPassword")}),e.jsx("input",{id:"confirmPassword",name:"confirmPassword",type:"password",autoComplete:"new-password",required:!0,className:"hub-input",value:x,onChange:a=>w(a.target.value)})]}),$&&e.jsxs("div",{role:"alert",className:"flex items-center gap-2",style:{padding:"8px 10px",borderRadius:7,border:"1px solid oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)",fontSize:12.5},children:[e.jsx(_,{size:13,className:"flex-shrink-0"}),e.jsx("span",{children:$})]}),e.jsx("button",{type:"submit",disabled:N,className:"hub-btn primary w-full justify-center",style:{height:34},children:s(N?"common.loading":c?"auth.createAccount":"auth.login")}),d&&e.jsx("button",{type:"button",disabled:N,className:"hub-btn w-full justify-center",onClick:()=>{k(!c),u(null),C(""),w("")},children:s(c?"auth.backToLogin":"auth.createAccount")})]}),(g.google||g.github||g.oidc)&&e.jsxs("div",{className:P?"space-y-3":"mt-5 space-y-3",children:[!P&&e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"h-px flex-1",style:{background:"var(--hub-line)"}}),e.jsx("span",{className:"hub-sect",style:{textTransform:"uppercase",letterSpacing:"0.08em"},children:s("auth.orContinue")}),e.jsx("div",{className:"h-px flex-1",style:{background:"var(--hub-line)"}})]}),U&&e.jsxs("div",{className:"flex items-center gap-2",style:{padding:"8px 10px",borderRadius:7,border:"1px solid oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)",fontSize:12.5},children:[e.jsx(_,{size:13,className:"flex-shrink-0"}),e.jsx("span",{children:U})]}),e.jsxs("div",{className:"space-y-2",children:[g.google&&e.jsx("button",{type:"button",onClick:()=>L("google"),disabled:h!==null,className:"hub-btn w-full justify-center",style:{height:34},children:s(h==="google"?"auth.loggingIn":"auth.loginWithGoogle")}),g.github&&e.jsxs("button",{type:"button",onClick:()=>L("github"),disabled:h!==null,className:"hub-btn w-full justify-center",style:{height:34,background:"var(--hub-ink)",color:"var(--hub-bg)",borderColor:"var(--hub-ink)"},children:[e.jsx(H,{className:"h-3.5 w-3.5"}),s(h==="github"?"auth.loggingIn":"auth.loginWithGithub")]}),g.oidc&&e.jsx("button",{type:"button",onClick:()=>L("oidc"),disabled:h!==null,className:"hub-btn w-full justify-center",style:{height:34},children:s(h==="oidc"?"auth.loggingIn":"auth.loginWithOIDC")})]})]})]}),e.jsxs("p",{className:"text-center hub-mono",style:{fontSize:11,color:"var(--hub-ink-3)"},children:["v","1.1.9"]})]})}),e.jsx(be,{isOpen:se,onClose:ne})]})};export{je as default};
|
|
2
|
+
//# sourceMappingURL=LoginPage-BjYzY6RH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginPage-BjYzY6RH.js","sources":["../../src/components/ui/DefaultPasswordWarningModal.tsx","../../src/pages/LoginPage.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router-dom';\n\ninterface DefaultPasswordWarningModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nconst DefaultPasswordWarningModal: React.FC<DefaultPasswordWarningModalProps> = ({\n isOpen,\n onClose,\n}) => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n\n if (!isOpen) return null;\n\n const handleGoToSettings = () => {\n onClose();\n navigate('/settings');\n // Auto-scroll to password section after a small delay to ensure page is loaded\n setTimeout(() => {\n const passwordSection = document.querySelector('[data-section=\"password\"]');\n if (passwordSection) {\n passwordSection.scrollIntoView({ behavior: 'smooth', block: 'start' });\n // If the section is collapsed, expand it\n const clickTarget = passwordSection.querySelector('[role=\"button\"]');\n if (clickTarget && !passwordSection.querySelector('.mt-4')) {\n (clickTarget as HTMLElement).click();\n }\n }\n }, 100);\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 bg-black/50 z-[100] flex items-center justify-center p-4\"\n onClick={handleBackdropClick}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n <div\n className=\"bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full transform transition-all duration-200 ease-out\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"password-warning-title\"\n aria-describedby=\"password-warning-message\"\n >\n <div className=\"p-6\">\n <div className=\"flex items-start space-x-3\">\n <div className=\"flex-shrink-0\">\n <svg\n className=\"w-6 h-6 text-yellow-600 dark:text-yellow-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\"\n />\n </svg>\n </div>\n <div className=\"flex-1\">\n <h3\n id=\"password-warning-title\"\n className=\"text-lg font-medium text-gray-900 dark:text-white mb-2\"\n >\n {t('auth.defaultPasswordWarning')}\n </h3>\n <p\n id=\"password-warning-message\"\n className=\"text-gray-600 dark:text-gray-300 leading-relaxed\"\n >\n {t('auth.defaultPasswordMessage')}\n </p>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-3 mt-6\">\n <button\n onClick={onClose}\n className=\"hub-btn\"\n >\n {t('common.cancel')}\n </button>\n <button\n onClick={handleGoToSettings}\n className=\"hub-btn primary\"\n autoFocus\n >\n {t('auth.goToSettings')}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default DefaultPasswordWarningModal;\n","import React, { useState, useMemo, useCallback, useEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useTranslation } from 'react-i18next';\nimport { BookOpen, AlertCircle } from 'lucide-react';\nimport { useAuth } from '../contexts/AuthContext';\nimport { getToken } from '../services/authService';\nimport { getPublicConfig } from '../services/configService';\nimport { createBetterAuthClient, startOidcLogin } from '../services/betterAuthClient';\nimport { getBasePath } from '../utils/runtime';\nimport ThemeSwitch from '@/components/ui/ThemeSwitch';\nimport LanguageSwitch from '@/components/ui/LanguageSwitch';\nimport GitHubIcon from '@/components/icons/GitHubIcon';\nimport DefaultPasswordWarningModal from '@/components/ui/DefaultPasswordWarningModal';\n\ntype SocialProvider = 'google' | 'github' | 'oidc';\n\nconst sanitizeReturnUrl = (value: string | null): string | null => {\n if (!value) return null;\n try {\n const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost';\n const url = new URL(value, origin);\n if (url.origin !== origin) return null;\n const relativePath = `${url.pathname}${url.search}${url.hash}`;\n return relativePath || '/';\n } catch {\n if (value.startsWith('/') && !value.startsWith('//')) return value;\n return null;\n }\n};\n\nconst LoginPage: React.FC = () => {\n const { t } = useTranslation();\n const [allowRegistration, setAllowRegistration] = useState(false);\n const [registering, setRegistering] = useState(false);\n const [confirmPassword, setConfirmPassword] = useState('');\n const [username, setUsername] = useState('');\n const [password, setPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [socialLoading, setSocialLoading] = useState<SocialProvider | null>(null);\n const [socialError, setSocialError] = useState<string | null>(null);\n const [betterAuthBasePath, setBetterAuthBasePath] = useState<string | undefined>(undefined);\n // Set from the public config: only SSO sign-in is offered\n const [passwordLoginDisabled, setPasswordLoginDisabled] = useState(false);\n const [socialProviders, setSocialProviders] = useState({\n google: false,\n github: false,\n oidc: false,\n });\n const [oidcProviderId, setOidcProviderId] = useState<string>('oidc');\n const [showDefaultPasswordWarning, setShowDefaultPasswordWarning] = useState(false);\n const { login, register, auth } = useAuth();\n const location = useLocation();\n const navigate = useNavigate();\n const returnUrl = useMemo(() => {\n const params = new URLSearchParams(location.search);\n return sanitizeReturnUrl(params.get('returnUrl'));\n }, [location.search]);\n\n const isServerUnavailableError = useCallback((message?: string) => {\n if (!message) return false;\n const normalized = message.toLowerCase();\n return (\n normalized.includes('failed to fetch') ||\n normalized.includes('networkerror') ||\n normalized.includes('network error') ||\n normalized.includes('connection refused') ||\n normalized.includes('unable to connect') ||\n normalized.includes('fetch error') ||\n normalized.includes('econnrefused') ||\n normalized.includes('http 500') ||\n normalized.includes('internal server error') ||\n normalized.includes('proxy error')\n );\n }, []);\n\n const buildRedirectTarget = useCallback(() => {\n if (!returnUrl) return '/';\n if (!returnUrl.startsWith('/oauth/authorize')) return returnUrl;\n const token = getToken();\n if (!token) return returnUrl;\n try {\n const origin = window.location.origin;\n const url = new URL(returnUrl, origin);\n url.searchParams.set('token', token);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n const separator = returnUrl.includes('?') ? '&' : '?';\n return `${returnUrl}${separator}token=${encodeURIComponent(token)}`;\n }\n }, [returnUrl]);\n\n const redirectAfterLogin = useCallback(() => {\n if (returnUrl) {\n window.location.assign(buildRedirectTarget());\n } else {\n navigate('/');\n }\n }, [buildRedirectTarget, navigate, returnUrl]);\n\n useEffect(() => {\n if (!auth.loading && auth.isAuthenticated) redirectAfterLogin();\n }, [auth.isAuthenticated, auth.loading, redirectAfterLogin]);\n\n useEffect(() => {\n const params = new URLSearchParams(location.search);\n const errorCode = params.get('error');\n if (errorCode) {\n const i18nKey = `auth.error.${errorCode}`;\n const translated = t(i18nKey);\n setSocialError(translated !== i18nKey ? translated : t('auth.socialLoginFailed'));\n }\n }, [location.search, t]);\n\n useEffect(() => {\n const loadAuthProviders = async () => {\n const publicConfig = await getPublicConfig();\n setAllowRegistration(publicConfig.allowRegistration === true);\n const betterAuth = publicConfig.betterAuth;\n if (!betterAuth?.enabled) {\n setSocialProviders({ google: false, github: false, oidc: false });\n return;\n }\n setBetterAuthBasePath(betterAuth.basePath);\n setPasswordLoginDisabled(betterAuth.disablePasswordLogin === true);\n setOidcProviderId(betterAuth.providers?.oidc?.providerId || 'oidc');\n setSocialProviders({\n google: betterAuth.providers?.google?.enabled === true,\n github: betterAuth.providers?.github?.enabled === true,\n oidc: betterAuth.providers?.oidc?.enabled === true,\n });\n };\n loadAuthProviders();\n }, []);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSocialError(null);\n setLoading(true);\n try {\n if (!username || !password) {\n setError(t('auth.emptyFields'));\n setLoading(false);\n return;\n }\n if (registering) {\n if (password !== confirmPassword) {\n setError(t('auth.passwordsNotMatch'));\n return;\n }\n if (await register(username, password)) redirectAfterLogin();\n return;\n }\n const result = await login(username, password);\n if (result.success) {\n if (result.isUsingDefaultPassword) setShowDefaultPasswordWarning(true);\n else redirectAfterLogin();\n } else {\n const message = result.message;\n setError(\n isServerUnavailableError(message) ? t('auth.serverUnavailable') : t('auth.loginFailed'),\n );\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : undefined;\n setError(\n isServerUnavailableError(message) ? t('auth.serverUnavailable') : t('auth.loginError'),\n );\n } finally {\n setLoading(false);\n }\n };\n\n const handleSocialLogin = async (provider: SocialProvider) => {\n setSocialError(null);\n setSocialLoading(provider);\n try {\n if (provider === 'oidc') {\n await startOidcLogin({\n providerId: oidcProviderId,\n callbackURL: returnUrl || '/',\n errorCallbackURL: `${getBasePath()}/login`,\n basePathOverride: betterAuthBasePath,\n });\n return;\n }\n\n const client = createBetterAuthClient(betterAuthBasePath);\n await client.signIn.social({\n provider,\n callbackURL: returnUrl || '/',\n errorCallbackURL: `${getBasePath()}/login`,\n });\n } catch (err) {\n console.error('Social login error:', err);\n setSocialError(t('auth.socialLoginFailed'));\n setSocialLoading(null);\n }\n };\n\n const formError = error || (registering ? auth.error : null);\n\n const handleCloseWarning = () => {\n setShowDefaultPasswordWarning(false);\n redirectAfterLogin();\n };\n\n return (\n <div\n className=\"relative min-h-screen w-full overflow-hidden\"\n style={{ background: 'var(--hub-bg)', color: 'var(--hub-ink)' }}\n >\n {/* Top-right controls */}\n <div className=\"absolute top-3 right-4 z-20 flex items-center gap-1\">\n <a\n href=\"https://github.com/samanhappy/mcphub\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hub-icon-btn\"\n aria-label=\"GitHub Repository\"\n >\n <GitHubIcon className=\"h-4 w-4\" />\n </a>\n <a\n href=\"https://docs.mcphub.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hub-icon-btn\"\n aria-label=\"Documentation\"\n >\n <BookOpen className=\"h-4 w-4\" />\n </a>\n <ThemeSwitch />\n <LanguageSwitch />\n </div>\n\n {/* Subtle grid pattern (kept low-key, hair-line) */}\n <div className=\"pointer-events-none absolute inset-0 -z-10\">\n <svg\n className=\"h-full w-full\"\n style={{ opacity: 0.5 }}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <pattern id=\"grid\" width=\"32\" height=\"32\" patternUnits=\"userSpaceOnUse\">\n <path\n d=\"M 32 0 L 0 0 0 32\"\n fill=\"none\"\n stroke=\"var(--hub-line-2)\"\n strokeWidth=\"0.5\"\n />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" fill=\"url(#grid)\" />\n </svg>\n </div>\n\n <div className=\"relative mx-auto flex min-h-screen w-full max-w-md items-center justify-center px-6\">\n <div className=\"w-full space-y-8\">\n {/* Brand */}\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"relative grid place-items-center\"\n style={{\n width: 44,\n height: 44,\n borderRadius: 10,\n background: 'var(--hub-ink)',\n color: 'var(--hub-bg)',\n }}\n >\n <span className=\"hub-mono font-semibold\" style={{ fontSize: 18 }}>\n M\n </span>\n <span\n className=\"absolute\"\n style={{\n right: -2,\n bottom: -2,\n width: 8,\n height: 8,\n borderRadius: 50,\n background: 'var(--hub-ok)',\n boxShadow: '0 0 0 3px var(--hub-bg)',\n }}\n />\n </div>\n <div className=\"text-center\">\n <h1\n style={{\n fontSize: 20,\n fontWeight: 600,\n letterSpacing: '-0.02em',\n color: 'var(--hub-ink)',\n }}\n >\n {t('app.title')}\n </h1>\n <p className=\"hub-sub\" style={{ marginTop: 4 }}>\n {t('auth.slogan')}\n </p>\n </div>\n </div>\n\n {/* Login card */}\n <div\n className=\"hub-card\"\n style={{\n padding: '22px 22px 20px',\n boxShadow: '0 1px 2px rgba(0,0,0,0.02)',\n }}\n >\n {!passwordLoginDisabled && (\n <form className=\"space-y-3\" onSubmit={handleSubmit}>\n <div>\n <label\n htmlFor=\"username\"\n className=\"hub-sect block\"\n style={{ marginBottom: 6 }}\n >\n {t('auth.username')}\n </label>\n <input\n id=\"username\"\n name=\"username\"\n type=\"text\"\n autoComplete=\"username\"\n required\n className=\"hub-input\"\n placeholder={t('auth.username')}\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n />\n </div>\n <div>\n <label\n htmlFor=\"password\"\n className=\"hub-sect block\"\n style={{ marginBottom: 6 }}\n >\n {t('auth.password')}\n </label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n autoComplete={registering ? 'new-password' : 'current-password'}\n minLength={registering ? 8 : undefined}\n required\n className=\"hub-input\"\n placeholder={t('auth.password')}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </div>\n\n {registering && (\n <div>\n <p className=\"hub-sub mb-3\">{t('auth.passwordStrengthHint')}</p>\n <label htmlFor=\"confirmPassword\" className=\"hub-sect block mb-1.5\">\n {t('auth.confirmPassword')}\n </label>\n <input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type=\"password\"\n autoComplete=\"new-password\"\n required\n className=\"hub-input\"\n value={confirmPassword}\n onChange={(e) => setConfirmPassword(e.target.value)}\n />\n </div>\n )}\n\n {formError && (\n <div role=\"alert\"\n className=\"flex items-center gap-2\"\n style={{\n padding: '8px 10px',\n borderRadius: 7,\n border: '1px solid oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n fontSize: 12.5,\n }}\n >\n <AlertCircle size={13} className=\"flex-shrink-0\" />\n <span>{formError}</span>\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"hub-btn primary w-full justify-center\"\n style={{ height: 34 }}\n >\n {loading\n ? t('common.loading')\n : t(registering ? 'auth.createAccount' : 'auth.login')}\n </button>\n {allowRegistration && (\n <button\n type=\"button\"\n disabled={loading}\n className=\"hub-btn w-full justify-center\"\n onClick={() => {\n setRegistering(!registering);\n setError(null);\n setPassword('');\n setConfirmPassword('');\n }}\n >\n {t(registering ? 'auth.backToLogin' : 'auth.createAccount')}\n </button>\n )}\n </form>\n )}\n\n {(socialProviders.google || socialProviders.github || socialProviders.oidc) && (\n <div className={passwordLoginDisabled ? 'space-y-3' : 'mt-5 space-y-3'}>\n {!passwordLoginDisabled && (\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1\" style={{ background: 'var(--hub-line)' }} />\n <span\n className=\"hub-sect\"\n style={{ textTransform: 'uppercase', letterSpacing: '0.08em' }}\n >\n {t('auth.orContinue')}\n </span>\n <div className=\"h-px flex-1\" style={{ background: 'var(--hub-line)' }} />\n </div>\n )}\n\n {socialError && (\n <div\n className=\"flex items-center gap-2\"\n style={{\n padding: '8px 10px',\n borderRadius: 7,\n border: '1px solid oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n fontSize: 12.5,\n }}\n >\n <AlertCircle size={13} className=\"flex-shrink-0\" />\n <span>{socialError}</span>\n </div>\n )}\n\n <div className=\"space-y-2\">\n {socialProviders.google && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('google')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{ height: 34 }}\n >\n {socialLoading === 'google'\n ? t('auth.loggingIn')\n : t('auth.loginWithGoogle')}\n </button>\n )}\n {socialProviders.github && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('github')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{\n height: 34,\n background: 'var(--hub-ink)',\n color: 'var(--hub-bg)',\n borderColor: 'var(--hub-ink)',\n }}\n >\n <GitHubIcon className=\"h-3.5 w-3.5\" />\n {socialLoading === 'github'\n ? t('auth.loggingIn')\n : t('auth.loginWithGithub')}\n </button>\n )}\n {socialProviders.oidc && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('oidc')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{ height: 34 }}\n >\n {socialLoading === 'oidc'\n ? t('auth.loggingIn')\n : t('auth.loginWithOIDC')}\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n\n <p\n className=\"text-center hub-mono\"\n style={{ fontSize: 11, color: 'var(--hub-ink-3)' }}\n >\n v{import.meta.env.PACKAGE_VERSION}\n </p>\n </div>\n </div>\n\n <DefaultPasswordWarningModal\n isOpen={showDefaultPasswordWarning}\n onClose={handleCloseWarning}\n />\n </div>\n );\n};\n\nexport default LoginPage;\n"],"names":["DefaultPasswordWarningModal","isOpen","onClose","t","useTranslation","navigate","useNavigate","handleGoToSettings","passwordSection","clickTarget","handleBackdropClick","e","handleKeyDown","jsx","jsxs","sanitizeReturnUrl","value","origin","url","LoginPage","allowRegistration","setAllowRegistration","useState","registering","setRegistering","confirmPassword","setConfirmPassword","username","setUsername","password","setPassword","error","setError","loading","setLoading","socialLoading","setSocialLoading","socialError","setSocialError","betterAuthBasePath","setBetterAuthBasePath","passwordLoginDisabled","setPasswordLoginDisabled","socialProviders","setSocialProviders","oidcProviderId","setOidcProviderId","showDefaultPasswordWarning","setShowDefaultPasswordWarning","login","register","auth","useAuth","location","useLocation","returnUrl","useMemo","params","isServerUnavailableError","useCallback","message","normalized","buildRedirectTarget","token","getToken","separator","redirectAfterLogin","useEffect","errorCode","i18nKey","translated","publicConfig","getPublicConfig","betterAuth","_b","_a","_d","_c","_f","_e","_h","_g","handleSubmit","result","err","handleSocialLogin","provider","startOidcLogin","getBasePath","createBetterAuthClient","formError","handleCloseWarning","GitHubIcon","BookOpen","ThemeSwitch","LanguageSwitch","AlertCircle"],"mappings":"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"}
|