import { useState, useEffect } from 'react'; import { Key, Eye, EyeOff } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; import { toast } from 'sonner'; import { credentialApi } from '@/api'; import type { Credential, SecretType } from './types'; import { TYPE_CONFIG } from './constants'; export interface CredFormDialogProps { open: boolean; onClose: () => void; onSaved: () => void; editData: Credential | null; } // 凭据新增/编辑弹窗 // Logan.Li export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDialogProps) { const isEdit = !!editData; const [name, setName] = useState(''); const [varName, setVarName] = useState(''); const [secretType, setSecretType] = useState('ssh'); const [description, setDescription] = useState(''); const [tags, setTags] = useState(''); const [isActive, setIsActive] = useState(true); const [submitting, setSubmitting] = useState(false); const [showMap, setShowMap] = useState>({}); // SSH 字段 // Logan.Li const [sshUser, setSshUser] = useState('root'); const [sshPort, setSshPort] = useState('22'); const [sshPassword, setSshPassword] = useState(''); const [sshPrivateKey, setSshPrivateKey] = useState(''); const [sshPublicKey, setSshPublicKey] = useState(''); // Docker 字段 const [dockerServer, setDockerServer] = useState(''); const [dockerUsername, setDockerUsername] = useState(''); const [dockerPassword, setDockerPassword] = useState(''); // TLS 字段 const [tlsCert, setTlsCert] = useState(''); const [tlsKey, setTlsKey] = useState(''); const [tlsCa, setTlsCa] = useState(''); // AKSK 字段 const [, setAkskProvider] = useState(''); const [akskAccessKey, setAkskAccessKey] = useState(''); const [akskSecretKey, setAkskSecretKey] = useState(''); const [, setAkskRegion] = useState(''); // 数据库字段 const [dbType, setDbType] = useState('mysql'); const [dbHost, setDbHost] = useState(''); const [dbPort, setDbPort] = useState('3306'); const [dbName, setDbName] = useState(''); const [dbUsername, setDbUsername] = useState(''); const [dbPassword, setDbPassword] = useState(''); // API 字段 const [apiKey, setApiKey] = useState(''); const [apiEndpoint, setApiEndpoint] = useState(''); // 通用字段 const [genericKey, setGenericKey] = useState(''); const [genericValue, setGenericValue] = useState(''); useEffect(() => { if (!open) return; if (editData) { setName(editData.name); setVarName(editData.variable_name || ''); setSecretType(editData.secret_type); setDescription(editData.description || ''); setTags((editData.tags || []).join(', ')); setIsActive(editData.is_active); // 编辑时不预填类型字段,仅修改用户填写的项 // Logan.Li setSshUser(''); setSshPort('22'); setSshPassword(''); setSshPrivateKey(''); setSshPublicKey(''); setDockerServer(''); setDockerUsername(''); setDockerPassword(''); setTlsCert(''); setTlsKey(''); setTlsCa(''); setAkskProvider(''); setAkskAccessKey(''); setAkskSecretKey(''); setAkskRegion(''); setDbType('mysql'); setDbHost(''); setDbPort('3306'); setDbName(''); setDbUsername(''); setDbPassword(''); setApiKey(''); setApiEndpoint(''); setGenericKey(''); setGenericValue(''); } else { setName(''); setVarName(''); setSecretType('ssh'); setDescription(''); setTags(''); setIsActive(true); setSshUser('root'); setSshPort('22'); setSshPassword(''); setSshPrivateKey(''); setSshPublicKey(''); setDockerServer(''); setDockerUsername(''); setDockerPassword(''); setTlsCert(''); setTlsKey(''); setTlsCa(''); setAkskProvider(''); setAkskAccessKey(''); setAkskSecretKey(''); setAkskRegion(''); setDbType('mysql'); setDbHost(''); setDbPort('3306'); setDbName(''); setDbUsername(''); setDbPassword(''); setApiKey(''); setApiEndpoint(''); setGenericKey(''); setGenericValue(''); } setShowMap({}); }, [editData, open]); const toggleShow = (key: string) => setShowMap(prev => ({ ...prev, [key]: !prev[key] })); const handleSubmit = async () => { if (!name.trim()) { toast.error('请填写凭据名称'); return; } setSubmitting(true); try { const payload: Record = { name: name.trim(), secret_type: secretType, description: description.trim(), tags: tags.split(',').map(t => t.trim()).filter(Boolean), is_active: isActive, }; if (varName.trim()) payload.variable_name = varName.trim(); if (secretType === 'ssh') { if (sshUser.trim()) payload.ssh_user = sshUser.trim(); if (sshPort) payload.ssh_port = parseInt(sshPort) || 22; if (sshPassword.trim()) payload.ssh_password = sshPassword.trim(); if (sshPrivateKey.trim()) payload.ssh_private_key = sshPrivateKey.trim(); if (sshPublicKey.trim()) payload.ssh_public_key = sshPublicKey.trim(); } else if (secretType === 'docker') { if (dockerServer.trim()) payload.docker_server = dockerServer.trim(); if (dockerUsername.trim()) payload.docker_username = dockerUsername.trim(); if (dockerPassword.trim()) payload.docker_password = dockerPassword.trim(); } else if (secretType === 'tls') { if (tlsCert.trim()) payload.tls_cert = tlsCert.trim(); if (tlsKey.trim()) payload.tls_key = tlsKey.trim(); if (tlsCa.trim()) payload.tls_ca = tlsCa.trim(); } else if (secretType === 'aksk') { if (akskAccessKey.trim()) payload.aksk_access_key = akskAccessKey.trim(); if (akskSecretKey.trim()) payload.aksk_secret_key = akskSecretKey.trim(); } else if (secretType === 'database') { if (dbType.trim()) payload.db_type = dbType.trim(); if (dbHost.trim()) payload.db_host = dbHost.trim(); if (dbPort) payload.db_port = parseInt(dbPort) || 3306; if (dbName.trim()) payload.db_name = dbName.trim(); if (dbUsername.trim()) payload.db_username = dbUsername.trim(); if (dbPassword.trim()) payload.db_password = dbPassword.trim(); } else if (secretType === 'api') { if (apiKey.trim()) payload.api_key = apiKey.trim(); if (apiEndpoint.trim()) payload.api_endpoint = apiEndpoint.trim(); } else if (secretType === 'generic') { if (genericKey.trim()) payload.generic_key = genericKey.trim(); if (genericValue.trim()) payload.generic_value = genericValue.trim(); } if (isEdit) { await credentialApi.update(editData!.id, payload); toast.success('已更新'); } else { await credentialApi.create(payload); toast.success('已创建'); } onSaved(); onClose(); } catch (e: unknown) { const err = e as { response?: { data?: { message?: string } } }; toast.error(err?.response?.data?.message || '操作失败'); } finally { setSubmitting(false); } }; const FieldWithToggle = ({ label, value, onChange, placeholder, fieldKey, required, isLong }: { label: string; value: string; onChange: (v: string) => void; placeholder: string; fieldKey: string; required?: boolean; isLong?: boolean; }) => { const show = showMap[fieldKey]; return (
{isLong ? (