import { useState, useCallback, useEffect } from 'react'; import { X, Loader2 } from 'lucide-react'; import { instanceApi } from '@/api/instance'; import { instanceGroupApi } from '@/api/instanceGroup'; /* ------------------------------------------------------------------ */ /* Types */ /* ------------------------------------------------------------------ */ interface InstanceData { id: number; name: string; db_type: string; host: string; port: number; username: string; database: string; env: string; access_mode: string; group_id?: number | null; } interface PermGroup { id: number; name: string; access_type?: string; } interface Props { instance: InstanceData; open: boolean; onClose: () => void; onSaved: () => void; } /* ------------------------------------------------------------------ */ /* Reusable Edit Instance Dialog */ /* ------------------------------------------------------------------ */ export default function EditInstanceDialog({ instance, open, onClose, onSaved }: Props) { const [name, setName] = useState(instance.name); const [host, setHost] = useState(instance.host); const [port, setPort] = useState(String(instance.port)); const [username, setUsername] = useState(instance.username); const [password, setPassword] = useState(''); const [database, setDatabase] = useState(instance.database || ''); const [env, setEnv] = useState(instance.env || 'development'); const [accessMode, setAccessMode] = useState(instance.access_mode || 'readwrite'); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(''); /* Sync when instance changes */ useEffect(() => { setName(instance.name); setHost(instance.host); setPort(String(instance.port)); setUsername(instance.username); setPassword(''); setDatabase(instance.database || ''); setEnv(instance.env || 'development'); setAccessMode(instance.access_mode || 'readwrite'); setError(''); }, [instance]); const handleSubmit = useCallback(async () => { if (!name.trim()) { setError('请填写名称'); return; } if (!host.trim()) { setError('请填写地址'); return; } setSubmitting(true); setError(''); try { await instanceApi.update(instance.id, { name: name.trim(), host: host.trim(), port: Number(port), username: username.trim() || undefined, password: password || undefined, database: database.trim() || undefined, env, access_mode: accessMode, }); onSaved(); } catch (e: unknown) { const msg = (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail || '保存失败'; setError(msg); } finally { setSubmitting(false); } }, [name, host, port, username, password, database, env, accessMode, instance.id, onSaved]); if (!open) return null; const inputCls = 'w-full px-3 py-2 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded-lg text-sm focus:border-blue-400 focus:outline-none transition-colors'; const labelCls = 'block text-xs font-medium text-[var(--dg-text-secondary)] mb-1'; return (