import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog'; 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 { Plus, Key, Globe, Container } from 'lucide-react'; import { toast } from 'sonner'; import { credentialApi, deployApi } from '@/api'; import type { JsonData } from '@/types/common'; interface Repo { id: number; name: string; url: string; credential_id: number | null; } interface Registry { id: number; name: string; registry_url: string; namespace: string; credential_id: number | null; } interface Credential { id: number; name: string; secret_type: string; summary: string; } interface Props { open: boolean; onOpenChange: (v: boolean) => void; type: 'repo' | 'registry'; editId: number | null; repos: Repo[]; registries: Registry[]; onSave: () => void; } export default function CredentialFormDialog({ open, onOpenChange, type, editId, repos, registries, onSave }: Props) { const { t } = useTranslation(); const isRepo = type === 'repo'; const [name, setName] = useState(''); const [desc, setDesc] = useState(''); const [url, setUrl] = useState(''); const [namespace, setNamespace] = useState(''); const [credentialId, setCredentialId] = useState(''); const [credentials, setCredentials] = useState([]); const [saving, setSaving] = useState(false); // Docker 仓库 → docker 类型;Git 仓库 → api 或 docker 类型 const filteredCredentials = credentials.filter(c => isRepo ? true : c.secret_type === 'docker' ); const loadCredentials = async () => { try { const res: JsonData = await credentialApi.list({ page_size: 100 }); setCredentials(res?.list || []); } catch { /* silent */ } }; useEffect(() => { loadCredentials(); if (editId) { if (isRepo) { const r = repos.find(x => x.id === editId); if (r) { setName(r.name); setDesc(''); setUrl(r.url); setCredentialId(r.credential_id || ''); } } else { const r = registries.find(x => x.id === editId); if (r) { setName(r.name); setDesc(''); setUrl(r.registry_url); setNamespace(r.namespace || ''); setCredentialId(r.credential_id || ''); } } } else { setName(''); setDesc(''); setUrl(''); setNamespace(''); setCredentialId(''); } }, [editId, open, isRepo]); const handleSave = async () => { if (!name.trim() || !url.trim()) { toast.error(t('deploy.form.nameAddrRequired')); return; } setSaving(true); try { const cid = credentialId ? Number(credentialId) : null; const payload = isRepo ? { name: name.trim(), description: desc.trim(), url: url.trim(), credential_id: cid } : { name: name.trim(), description: desc.trim(), registry_url: url.trim(), namespace: namespace.trim(), credential_id: cid }; if (editId) { if (isRepo) await deployApi.updateRepo(editId, payload); else await deployApi.updateRegistry(editId, payload); toast.success(t('deploy.toast.updated')); } else { if (isRepo) await deployApi.createRepo(payload); else await deployApi.createRegistry(payload); toast.success(t('deploy.toast.created')); } onOpenChange(false); onSave(); } catch { toast.error(t('deploy.toast.saveFailed')); } finally { setSaving(false); } }; const CredIcon = isRepo ? Globe : Container; return ( {editId ? t('common.edit') : t('common.add')} {isRepo ? t('deploy.credForm.gitRepo') : t('deploy.credForm.imageRegistry')}
setName(e.target.value)} placeholder={isRepo ? t('deploy.credForm.repoNamePlaceholder') : t('deploy.credForm.registryNamePlaceholder')} className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
setUrl(e.target.value)} placeholder={isRepo ? 'http://10.10.10.72:9000/group/repo.git' : 'http://10.10.10.72'} className="font-mono text-sm bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
{!isRepo &&
setNamespace(e.target.value)} placeholder={t('deploy.credForm.namespacePlaceholder')} className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
} {/* 关联凭证 */}
{filteredCredentials.length === 0 && (

{t('deploy.credForm.noCredHint', { type: isRepo ? '' : t('deploy.credForm.dockerPwd') })}

)}
); }