import { useState, useEffect, useCallback, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/components/ui/dialog'; import MCPForm from '@/app/home/mcp/components/mcp-form/MCPForm'; import type { MCPFormHandle } from '@/app/home/mcp/components/mcp-form/MCPForm'; import { httpClient, systemInfo } from '@/app/infra/http/HttpClient'; import { useSidebarData } from '@/app/home/components/home-sidebar/SidebarDataContext'; import { useTranslation } from 'react-i18next'; import { Trash2 } from 'lucide-react'; import { toast } from 'sonner'; export default function MCPDetailContent({ id }: { id: string }) { const isCreateMode = id === 'new'; const navigate = useNavigate(); const { t } = useTranslation(); const { refreshMCPServers, mcpServers, setDetailEntityName } = useSidebarData(); // Set breadcrumb entity name useEffect(() => { if (isCreateMode) { setDetailEntityName(t('mcp.createServer')); } else { const server = mcpServers.find((s) => s.id === id); setDetailEntityName(server?.name ?? id); } return () => setDetailEntityName(null); }, [id, isCreateMode, mcpServers, setDetailEntityName, t]); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); // Track whether the form has unsaved changes const [formDirty, setFormDirty] = useState(false); // Ref to MCPForm for triggering test from header const formRef = useRef(null); const [mcpTesting, setMcpTesting] = useState(false); // Enable state managed here so the header switch works const [serverEnabled, setServerEnabled] = useState(true); const [enableLoaded, setEnableLoaded] = useState(false); // Fetch server enable state useEffect(() => { if (!isCreateMode) { httpClient.getMCPServer(id).then((res) => { const server = res.server ?? res; setServerEnabled(server.enable ?? true); setEnableLoaded(true); }); } }, [id, isCreateMode]); const handleEnableToggle = useCallback( async (checked: boolean) => { const prev = serverEnabled; setServerEnabled(checked); try { await httpClient.toggleMCPServer(id, checked); refreshMCPServers(); } catch { setServerEnabled(prev); toast.error(t('mcp.modifyFailed')); } }, [id, serverEnabled, refreshMCPServers, t], ); function handleFormSubmit() { // Re-sync enable state after form save httpClient.getMCPServer(id).then((res) => { const server = res.server ?? res; setServerEnabled(server.enable ?? true); }); refreshMCPServers(); } function handleServerDeleted() { refreshMCPServers(); navigate('/home/mcp'); } function handleNewServerCreated(serverName: string) { refreshMCPServers(); navigate(`/home/mcp?id=${encodeURIComponent(serverName)}`); } function confirmDelete() { httpClient .deleteMCPServer(id) .then(() => { setShowDeleteConfirm(false); toast.success(t('mcp.deleteSuccess')); handleServerDeleted(); }) .catch((err) => { toast.error(t('mcp.deleteFailed') + (err.msg || '')); }); } // Check extensions limit before creating async function checkExtensionsLimit(): Promise { const maxExtensions = systemInfo.limitation?.max_extensions ?? -1; if (maxExtensions < 0) return true; try { const [pluginsResp, mcpResp] = await Promise.all([ httpClient.getPlugins(), httpClient.getMCPServers(), ]); const total = (pluginsResp.plugins?.length ?? 0) + (mcpResp.servers?.length ?? 0); if (total >= maxExtensions) { toast.error( t('limitation.maxExtensionsReached', { max: maxExtensions }), ); return false; } } catch { // If we can't check, let backend handle it } return true; } // ==================== Create Mode ==================== if (isCreateMode) { return (
{/* Header */}

{t('mcp.createServer')}

{/* Content */}
); } // ==================== Edit Mode ==================== return ( <>
{/* Header: title + enable switch + save button */}

{t('mcp.editServer')}

{enableLoaded && (
)}
{/* Content */}
{/* Card: Danger Zone */} {t('mcp.dangerZone')} {t('mcp.dangerZoneDescription')}

{t('mcp.deleteMCPAction')}

{t('mcp.deleteMCPHint')}

{/* Delete confirmation dialog */} {t('mcp.confirmDeleteTitle')} {t('mcp.confirmDeleteServer')}
{t('mcp.confirmDeleteServer')}
); }