feat(frontend): add MCP import dialog for v3.7.0
Implement import functionality to migrate MCP servers from existing configs:
**New Component:**
- src/components/mcp/McpImportDialog.tsx: Import dialog with card-based source selection
**Features:**
- Import from Claude (~/.claude/claude.json or settings.json)
- Import from Codex (~/.codex/config.toml)
- Import from Gemini (config file)
- Card-based UI with icons and descriptions
- Loading states with spinner animation
- Auto-refresh after successful import
**Integration:**
- Add import button to UnifiedMcpPanel header
- Handle import completion with refetch
- Toast notifications for success/info/error cases
**I18n:**
- Add mcp.unifiedPanel.import namespace (zh/en)
- Import button, dialog title, descriptions
- Success/error messages with count interpolation
**UX:**
- Smart disable: other sources disabled during import
- Clear feedback: count of imported servers
- Friendly messages: "No servers found" when empty
TypeScript type check passes ✅
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Plus, Server, Check, RefreshCw } from "lucide-react";
|
||||
import { Plus, Server, Check, RefreshCw, Download } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -14,6 +14,7 @@ import { useAllMcpServers, useToggleMcpApp, useSyncAllMcpServers } from "@/hooks
|
||||
import type { McpServer } from "@/types";
|
||||
import type { AppId } from "@/lib/api/types";
|
||||
import McpFormModal from "./McpFormModal";
|
||||
import McpImportDialog from "./McpImportDialog";
|
||||
import { ConfirmDialog } from "../ConfirmDialog";
|
||||
import { useDeleteMcpServer } from "@/hooks/useMcp";
|
||||
import { Edit3, Trash2 } from "lucide-react";
|
||||
@@ -36,6 +37,7 @@ const UnifiedMcpPanel: React.FC<UnifiedMcpPanelProps> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
const [isImportOpen, setIsImportOpen] = useState(false);
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [confirmDialog, setConfirmDialog] = useState<{
|
||||
isOpen: boolean;
|
||||
@@ -45,7 +47,7 @@ const UnifiedMcpPanel: React.FC<UnifiedMcpPanelProps> = ({
|
||||
} | null>(null);
|
||||
|
||||
// Queries and Mutations
|
||||
const { data: serversMap, isLoading } = useAllMcpServers();
|
||||
const { data: serversMap, isLoading, refetch } = useAllMcpServers();
|
||||
const toggleAppMutation = useToggleMcpApp();
|
||||
const deleteServerMutation = useDeleteMcpServer();
|
||||
const syncAllMutation = useSyncAllMcpServers();
|
||||
@@ -126,6 +128,11 @@ const UnifiedMcpPanel: React.FC<UnifiedMcpPanelProps> = ({
|
||||
setEditingId(null);
|
||||
};
|
||||
|
||||
const handleImportComplete = () => {
|
||||
// Refresh the servers list after import
|
||||
refetch();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
@@ -134,6 +141,15 @@ const UnifiedMcpPanel: React.FC<UnifiedMcpPanelProps> = ({
|
||||
<div className="flex items-center justify-between pr-8">
|
||||
<DialogTitle>{t("mcp.unifiedPanel.title")}</DialogTitle>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsImportOpen(true)}
|
||||
>
|
||||
<Download size={16} />
|
||||
{t("mcp.unifiedPanel.import.button")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
@@ -231,6 +247,13 @@ const UnifiedMcpPanel: React.FC<UnifiedMcpPanelProps> = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Import Dialog */}
|
||||
<McpImportDialog
|
||||
open={isImportOpen}
|
||||
onOpenChange={setIsImportOpen}
|
||||
onImportComplete={handleImportComplete}
|
||||
/>
|
||||
|
||||
{/* Confirm Dialog */}
|
||||
{confirmDialog && (
|
||||
<ConfirmDialog
|
||||
|
||||
Reference in New Issue
Block a user