fix(i18n): 回退到稳定的 32% 覆盖率状态 (tsc + Vite 构建通过)

批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换:
- 翻译词典: 22 namespaces, 3600+ keys
- 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy)
- 语言切换器在 Header 中可用 (🇨🇳/🇺🇸)
- tsc 零错误, Vite 构建成功
This commit is contained in:
attacker committed 2026-07-03 02:02:29 +08:00
1 parent ecec73989b
commit 72bfb0e12d
191 files changed
+5057 -7592

No files matched your search

@@ -11,7 +11,6 @@ import { toast } from 'sonner';
import { useCredentialDetail } from '@/hooks/api';
import type { SecretType } from './types';
import { TYPE_CONFIG, TYPE_BADGE_CLASS } from './constants';
import { useTranslation } from 'react-i18next';
export interface CredDetailDialogProps {
open: boolean;
@@ -21,14 +20,13 @@ export interface CredDetailDialogProps {
// 凭据详情弹窗 // Logan.Li
export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProps) {
const { t } = useTranslation();
const [showMap, setShowMap] = useState<Record<string, boolean>>({});
const { data: detail, isLoading: loading } = useCredentialDetail(credId, open);
if (!open || !credId) return null;
const toggleShow = (key: string) => setShowMap(prev => ({ ...prev, [key]: !prev[key] }));
const copyValue = (val: string) => { navigator.clipboard.writeText(val); toast.success(t('common.copied')); };
const copyValue = (val: string) => { navigator.clipboard.writeText(val); toast.success('已复制'); };
const st = detail?.secret_type as SecretType;
const cfg = TYPE_CONFIG[st];
@@ -79,39 +77,39 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
</DialogTitle>
</DialogHeader>
{loading ? (
<div className="text-center py-8 text-[var(--dg-text-muted)]">{t('common.loading')}</div>
<div className="text-center py-8 text-[var(--dg-text-muted)]">加载中...</div>
) : detail ? (
<div className="space-y-4">
{/* 基本信息 // Logan.Li */}
<div className="grid grid-cols-2 gap-3 text-sm">
<div><span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.s5b4786')}</span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div>
<div><span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.se91f5a')}</span>
<div><span className="text-[var(--dg-text-muted)]">名称:</span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div>
<div><span className="text-[var(--dg-text-muted)]">类型:</span>
<Badge variant="outline" className={`text-xs ml-1 ${TYPE_BADGE_CLASS[st] || ''}`}>{cfg?.label || st}</Badge>
</div>
<div><span className="text-[var(--dg-text-muted)]">{t('approval.detail.statusLabel')}</span>
<div><span className="text-[var(--dg-text-muted)]">状态:</span>
{detailRecord?.is_active
? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" />{t('common.enable')}</Badge>
: <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" />{t('common.disable')}</Badge>}
? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" />启用</Badge>
: <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" />禁用</Badge>}
{detailRecord?.expires_at && new Date(detailRecord.expires_at as string) < new Date() && (
<Badge className="bg-yellow-500/20 dg-text-yellow text-xs ml-1"><AlertTriangle className="h-3 w-3 mr-0.5" />{t('monitor.sslExpired')}</Badge>
<Badge className="bg-yellow-500/20 dg-text-yellow text-xs ml-1"><AlertTriangle className="h-3 w-3 mr-0.5" />已过期</Badge>
)}
</div>
<div className="col-span-2 cursor-pointer" onClick={() => copyValue((detailRecord?.env_prefix as string) || '')}>
<span className="text-[var(--dg-text-muted)]">{t('deploy.cred.refIdLabel')}</span>
<code className="text-[var(--dg-blue)] font-mono text-xs">{detailRecord?.env_prefix as string || t('common.none')}</code>
<span className="text-[var(--dg-text-muted)]">引用ID:</span>
<code className="text-[var(--dg-blue)] font-mono text-xs">{detailRecord?.env_prefix as string || '无'}</code>
<Copy className="h-3 w-3 inline ml-1 text-[var(--dg-text-muted)]" />
</div>
{(detailRecord?.tags as string[])?.length > 0 && (
<div className="col-span-2">
<span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.s1655dd')}</span>
<span className="text-[var(--dg-text-muted)]">标签:</span>
{(detailRecord?.tags as string[]).map((t: string) => (
<Badge key={t} variant="outline" className="text-xs ml-1 border-[var(--dg-border)]">{t}</Badge>
))}
</div>
)}
<div className="col-span-2"><span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.s4a4e3b')}</span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || t('common.none')}</span></div>
<div><span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.s76d768')}</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div>
<div><span className="text-[var(--dg-text-muted)]">{t('deploy.creddetaildialog.s3820b7')}</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div>
<div className="col-span-2"><span className="text-[var(--dg-text-muted)]">描述:</span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || '无'}</span></div>
<div><span className="text-[var(--dg-text-muted)]">创建:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div>
<div><span className="text-[var(--dg-text-muted)]">更新:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div>
</div>
{/* 密钥数据 // Logan.Li */}
@@ -120,41 +118,41 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
<Key className="h-4 w-4 text-yellow-500" />密钥数据
</div>
<div className="p-3 rounded-md bg-yellow-500/5 border border-yellow-500/20 mb-3">
<p className="text-xs dg-text-yellow/80">{t('deploy.creddetaildialog.s03b218')}</p>
<p className="text-xs dg-text-yellow/80">以下内容包含敏感信息,请妥善保管,不要泄露给他人。</p>
</div>
{st === 'ssh' && <>
<Field label=t('deploy.creddetaildialog.s2272f5') value={content.ssh_user} />
<Field label=t('deploy.creddetaildialog.s3f284a') value={content.ssh_port} />
<Field label=t('system.sshPassword') value={content.password} sensitive fieldKey="ssh_password" />
<Field label=t('system.sshPrivateKey') value={content.private_key} sensitive fieldKey="ssh_private_key" />
<Field label=t('system.sshPublicKey') value={content.public_key} fieldKey="ssh_public_key" />
<Field label="SSH 用户" value={content.ssh_user} />
<Field label="SSH 端口" value={content.ssh_port} />
<Field label="SSH 密码" value={content.password} sensitive fieldKey="ssh_password" />
<Field label="私钥" value={content.private_key} sensitive fieldKey="ssh_private_key" />
<Field label="公钥" value={content.public_key} fieldKey="ssh_public_key" />
</>}
{st === 'docker' && <>
<Field label=t('deploy.form.registryAddr') value={content.server} />
<Field label=t('login.username') value={content.username} />
<Field label=t('login.password') value={content.password} sensitive fieldKey="docker_password" />
<Field label="Registry 地址" value={content.server} />
<Field label="用户名" value={content.username} />
<Field label="密码" value={content.password} sensitive fieldKey="docker_password" />
</>}
{st === 'tls' && <>
<Field label=t('deploy.creddetaildialog.sd40b51') value={content.cert} sensitive fieldKey="tls_cert" />
<Field label=t('system.sshPrivateKey') value={content.key} sensitive fieldKey="tls_key" />
<Field label=t('deploy.creddetaildialog.sa24356') value={content.ca} sensitive fieldKey="tls_ca" />
<Field label="证书" value={content.cert} sensitive fieldKey="tls_cert" />
<Field label="私钥" value={content.key} sensitive fieldKey="tls_key" />
<Field label="CA 证书" value={content.ca} sensitive fieldKey="tls_ca" />
</>}
{st === 'aksk' && <>
<Field label="Access Key ID" value={content.access_key} />
<Field label="Secret Access Key" value={content.secret_key} sensitive fieldKey="aksk_secret_key" />
</>}
{st === 'database' && <>
<Field label=t('deploy.creddetaildialog.s84b916') value={String(content.db_type || '').toUpperCase()} />
<Field label=t('agent.agentHost') value={content.host} />
<Field label=t('server.csv.port') value={content.port} />
<Field label=t('deploy.creddetaildialog.s5ccbbd') value={content.db_name} />
<Field label=t('login.username') value={content.username} />
<Field label=t('login.password') value={content.password} sensitive fieldKey="db_password" />
<Field label="数据库类型" value={String(content.db_type || '').toUpperCase()} />
<Field label="主机" value={content.host} />
<Field label="端口" value={content.port} />
<Field label="数据库名" value={content.db_name} />
<Field label="用户名" value={content.username} />
<Field label="密码" value={content.password} sensitive fieldKey="db_password" />
</>}
{st === 'api' && <>
<Field label="API Key" value={content.api_key} sensitive fieldKey="api_key" />
<Field label=t('deploy.creddetaildialog.s48ec34') value={content.endpoint} />
<Field label="API 端点" value={content.endpoint} />
</>}
{st === 'generic' && <>
<Field label="Key" value={content.generic_key} />
@@ -164,17 +162,17 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
{/* 引用提示 // Logan.Li */}
<div className="border-t border-[var(--dg-border)] pt-3">
<div className="text-xs text-[var(--dg-text-muted)] mb-2">{t('deploy.cred.refHint')}</div>
<div className="text-xs text-[var(--dg-text-muted)] mb-2">在流水线/脚本中引用此凭据:</div>
<code className="text-xs bg-[var(--dg-bg-tertiary)] px-3 py-1.5 rounded block text-[var(--dg-blue)]">
{'${'}{String(detailRecord?.variable_name || String(detailRecord?.name || '').toUpperCase().replace(/[^A-Z0-9]/g, '_'))}{'}'}
</code>
</div>
</div>
) : (
<div className="text-center py-8 text-[var(--dg-text-muted)]">{t('deploy.cred.noCredData')}</div>
<div className="text-center py-8 text-[var(--dg-text-muted)]">未找到凭据数据</div>
)}
<DialogFooter>
<Button variant="outline" onClick={onClose}>{t('common.close')}</Button>
<Button variant="outline" onClick={onClose}>关闭</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -9,7 +9,6 @@ import { toast } from 'sonner';
import { credentialApi } from '@/api';
import type { Credential, SecretType } from './types';
import { TYPE_CONFIG } from './constants';
import { useTranslation } from 'react-i18next';
export interface CredFormDialogProps {
open: boolean;
@@ -20,7 +19,6 @@ export interface CredFormDialogProps {
// 凭据新增/编辑弹窗 // Logan.Li
export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDialogProps) {
const { t } = useTranslation();
const isEdit = !!editData;
const [name, setName] = useState('');
const [varName, setVarName] = useState('');
@@ -97,7 +95,7 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
const toggleShow = (key: string) => setShowMap(prev => ({ ...prev, [key]: !prev[key] }));
const handleSubmit = async () => {
if (!name.trim()) { toast.error(t('deploy.cred.nameRequired')); return; }
if (!name.trim()) { toast.error('请填写凭据名称'); return; }
setSubmitting(true);
try {
const payload: Record<string, unknown> = {
@@ -143,16 +141,16 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
if (isEdit) {
await credentialApi.update(editData!.id, payload);
toast.success(t('deploy.toast.updated'));
toast.success('已更新');
} else {
await credentialApi.create(payload);
toast.success(t('deploy.toast.created'));
toast.success('已创建');
}
onSaved();
onClose();
} catch (e: unknown) {
const err = e as { response?: { data?: { message?: string } } };
toast.error(err?.response?.data?.message || t('common.operationFailed'));
toast.error(err?.response?.data?.message || '操作失败');
} finally { setSubmitting(false); }
};
@@ -192,25 +190,25 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
<DialogHeader>
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
<TIicon className={`h-5 w-5 ${TI?.color || ''}`} />
{isEdit ? t('pipeline.editCred') : t('pipeline.addCred')}
{isEdit ? '编辑凭据' : '新增凭据'}
</DialogTitle>
<DialogDescription className="text-[var(--dg-text-muted)] text-xs">
{TI?.desc || t('deploy.cred.descDefault')}
{TI?.desc || '管理敏感凭据信息'}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-2">
{/* 基本信息 // Logan.Li */}
<div className="border-b border-[var(--dg-border)] pb-3">
<div className="text-xs font-medium text-[var(--dg-text-secondary)] mb-2">{t('deploy.label.basicInfo')}</div>
<div className="text-xs font-medium text-[var(--dg-text-secondary)] mb-2">基本信息</div>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('pipeline.credName')} <span className="dg-text-red">*</span></Label>
<Input value={name} onChange={e => setName(e.target.value)} placeholder=t('deploy.credformdialog.s97afec')
<Label className="text-[var(--dg-text-secondary)] text-xs">凭据名称 <span className="dg-text-red">*</span></Label>
<Input value={name} onChange={e => setName(e.target.value)} placeholder="如:生产环境 SSH"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('pipeline.varAlias')}</Label>
<Input value={varName} onChange={e => setVarName(e.target.value)} placeholder=t('deploy.credformdialog.s92c3a5')
<Label className="text-[var(--dg-text-secondary)] text-xs">变量别名</Label>
<Input value={varName} onChange={e => setVarName(e.target.value)} placeholder="如:MYSQL_PROD"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono text-sm" />
</div>
<div className="space-y-1">
@@ -229,14 +227,14 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
</Select>
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('common.tag')}</Label>
<Input value={tags} onChange={e => setTags(e.target.value)} placeholder=t('deploy.credformdialog.s29e67e')
<Label className="text-[var(--dg-text-secondary)] text-xs">标签</Label>
<Input value={tags} onChange={e => setTags(e.target.value)} placeholder="生产环境, 阿里云"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
</div>
<div className="mt-2 space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('common.description')}</Label>
<Input value={description} onChange={e => setDescription(e.target.value)} placeholder=t('deploy.credformdialog.s9216f1')
<Label className="text-[var(--dg-text-secondary)] text-xs">描述</Label>
<Input value={description} onChange={e => setDescription(e.target.value)} placeholder="可选备注信息"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
</div>
@@ -245,32 +243,32 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
<div>
<div className="text-xs font-medium text-[var(--dg-text-secondary)] mb-2 flex items-center gap-2">
<TIicon className="h-3.5 w-3.5" />{TI?.label || secretType} 配置
{isEdit && <span className="text-[var(--dg-text-muted)]">{t('deploy.credformdialog.s088965')}</span>}
{isEdit && <span className="text-[var(--dg-text-muted)]">(仅填写需要修改的字段)</span>}
</div>
{secretType === 'ssh' && (
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.credformdialog.s2272f5')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">SSH 用户</Label>
<Input value={sshUser} onChange={e => setSshUser(e.target.value)} placeholder="root"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.credformdialog.s3f284a')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">SSH 端口</Label>
<Input value={sshPort} onChange={e => setSshPort(e.target.value)} placeholder="22" type="number"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div className="col-span-2">
<FieldWithToggle label=t('system.sshPassword') value={sshPassword} onChange={setSshPassword}
placeholder=t('deploy.credformdialog.se98d4e') fieldKey="ssh_pwd" />
<FieldWithToggle label="SSH 密码" value={sshPassword} onChange={setSshPassword}
placeholder="密码(或留空用密钥)" fieldKey="ssh_pwd" />
</div>
<div className="col-span-2">
<FieldWithToggle label=t('deploy.credformdialog.sfcef97') value={sshPrivateKey} onChange={setSshPrivateKey}
placeholder=t('deploy.credformdialog.s824277') fieldKey="ssh_pk" isLong />
<FieldWithToggle label="私钥内容" value={sshPrivateKey} onChange={setSshPrivateKey}
placeholder="粘贴 SSH 私钥..." fieldKey="ssh_pk" isLong />
</div>
<div className="col-span-2">
<FieldWithToggle label=t('deploy.credformdialog.s6fc01d') value={sshPublicKey} onChange={setSshPublicKey}
placeholder=t('deploy.credformdialog.s5eccd4') fieldKey="ssh_pub" isLong />
<FieldWithToggle label="公钥内容" value={sshPublicKey} onChange={setSshPublicKey}
placeholder="粘贴 SSH 公钥..." fieldKey="ssh_pub" isLong />
</div>
</div>
)}
@@ -278,28 +276,28 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
{secretType === 'docker' && (
<div className="grid grid-cols-2 gap-3">
<div className="col-span-2 space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.form.registryAddr')} <span className="dg-text-red">*</span></Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">Registry 地址 <span className="dg-text-red">*</span></Label>
<Input value={dockerServer} onChange={e => setDockerServer(e.target.value)} placeholder="registry.example.com"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('login.username')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">用户名</Label>
<Input value={dockerUsername} onChange={e => setDockerUsername(e.target.value)} placeholder="admin"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div><FieldWithToggle label=t('login.password') value={dockerPassword} onChange={setDockerPassword}
placeholder=t('deploy.credformdialog.s929297') fieldKey="docker_pwd" required /></div>
<div><FieldWithToggle label="密码" value={dockerPassword} onChange={setDockerPassword}
placeholder="Registry 密码" fieldKey="docker_pwd" required /></div>
</div>
)}
{secretType === 'tls' && (
<div className="space-y-3">
<FieldWithToggle label=t('deploy.credformdialog.s3391e4') value={tlsCert} onChange={setTlsCert}
<FieldWithToggle label="证书 (PEM)" value={tlsCert} onChange={setTlsCert}
placeholder="-----BEGIN CERTIFICATE-----" fieldKey="tls_cert" isLong required />
<FieldWithToggle label=t('deploy.credformdialog.s517151') value={tlsKey} onChange={setTlsKey}
<FieldWithToggle label="私钥 (PEM)" value={tlsKey} onChange={setTlsKey}
placeholder="-----BEGIN PRIVATE KEY-----" fieldKey="tls_key" isLong required />
<FieldWithToggle label=t('deploy.credformdialog.sa24356') value={tlsCa} onChange={setTlsCa}
placeholder=t('deploy.credformdialog.s7db02d') fieldKey="tls_ca" isLong />
<FieldWithToggle label="CA 证书" value={tlsCa} onChange={setTlsCa}
placeholder="CA 证书内容..." fieldKey="tls_ca" isLong />
</div>
)}
@@ -312,7 +310,7 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
</div>
<div className="col-span-2">
<FieldWithToggle label="Secret Access Key" value={akskSecretKey} onChange={setAkskSecretKey}
placeholder=t('deploy.credformdialog.sdef8f6') fieldKey="aksk_sk" required />
placeholder="输入 Secret Key" fieldKey="aksk_sk" required />
</div>
</div>
)}
@@ -320,7 +318,7 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
{secretType === 'database' && (
<div className="grid grid-cols-3 gap-3">
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.credformdialog.s84b916')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">数据库类型</Label>
<Select value={dbType} onValueChange={setDbType}>
<SelectTrigger className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]">
<SelectValue />
@@ -336,34 +334,34 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
</Select>
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('agent.agentHost')} <span className="dg-text-red">*</span></Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">主机 <span className="dg-text-red">*</span></Label>
<Input value={dbHost} onChange={e => setDbHost(e.target.value)} placeholder="10.0.0.1"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('server.csv.port')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">端口</Label>
<Input value={dbPort} onChange={e => setDbPort(e.target.value)} placeholder="3306" type="number"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.credformdialog.s5ccbbd')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">数据库名</Label>
<Input value={dbName} onChange={e => setDbName(e.target.value)} placeholder="aiops"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('login.username')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">用户名</Label>
<Input value={dbUsername} onChange={e => setDbUsername(e.target.value)} placeholder="root"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" />
</div>
<div><FieldWithToggle label=t('login.password') value={dbPassword} onChange={setDbPassword}
placeholder=t('deploy.credformdialog.s58b49c') fieldKey="db_pwd" /></div>
<div><FieldWithToggle label="密码" value={dbPassword} onChange={setDbPassword}
placeholder="数据库密码" fieldKey="db_pwd" /></div>
</div>
)}
{secretType === 'api' && (
<div className="space-y-3">
<div className="space-y-1">
<Label className="text-[var(--dg-text-secondary)] text-xs">{t('deploy.credformdialog.s48ec34')}</Label>
<Label className="text-[var(--dg-text-secondary)] text-xs">API 端点</Label>
<Input value={apiEndpoint} onChange={e => setApiEndpoint(e.target.value)} placeholder="https://api.example.com"
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono" />
</div>
@@ -380,15 +378,15 @@ export function CredFormDialog({ open, onClose, onSaved, editData }: CredFormDia
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono" />
</div>
<FieldWithToggle label="Value" value={genericValue} onChange={setGenericValue}
placeholder=t('deploy.credformdialog.s63ec0a') fieldKey="generic_val" required />
placeholder="密钥值" fieldKey="generic_val" required />
</div>
)}
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={onClose}>{t('common.cancel')}</Button>
<Button variant="outline" onClick={onClose}>取消</Button>
<Button onClick={handleSubmit} disabled={submitting} className="bg-[var(--dg-blue)] hover:bg-[var(--dg-blue)]/80">
{submitting ? i18n.t('k8s.topology.saving') : (isEdit ? i18n.t('common.update') : i18n.t('common.create'))}
{submitting ? '保存中...' : (isEdit ? '更新' : '创建')}
</Button>
</DialogFooter>
</DialogContent>
@@ -4,16 +4,15 @@ import {
Key, Server, Container, Shield, Cloud, Database, FileText, Globe,
} from 'lucide-react';
import type { SecretType } from './types';
import i18n from '@/i18n';
export const TYPE_CONFIG: Record<SecretType, { label: string; icon: typeof Key; color: string; desc: string }> = {
ssh: { label: i18n.t('system.sshKey'), icon: Server, color: 'dg-text-yellow', desc: i18n.t('deploy.constants.sedc7f9') },
docker: { label: i18n.t('pipeline.dockerCred'), icon: Container, color: 'dg-text-cyan', desc: i18n.t('deploy.constants.sbd6cf1') },
tls: { label: i18n.t('deploy.constants.sfa5a64'), icon: Shield, color: 'dg-text-green', desc: i18n.t('deploy.constants.s43f00c') },
aksk: { label: i18n.t('deploy.constants.sb82698'), icon: Cloud, color: 'dg-text-purple', desc: i18n.t('deploy.constants.s564e98') },
database: { label: i18n.t('system.dbCredential'), icon: Database, color: 'dg-text-blue', desc: i18n.t('deploy.constants.se47498') },
api: { label: i18n.t('system.apiKeys'), icon: Globe, color: 'dg-text-orange', desc: i18n.t('deploy.constants.sb3edf0') },
generic: { label: i18n.t('deploy.constants.s1d319b'), icon: FileText, color: 'dg-text-secondary', desc: i18n.t('deploy.constants.s51b5b2') },
ssh: { label: 'SSH 密钥', icon: Server, color: 'dg-text-yellow', desc: 'SSH 私钥/公钥/密码' },
docker: { label: 'Docker 凭证', icon: Container, color: 'dg-text-cyan', desc: 'Docker Registry 登录凭据' },
tls: { label: 'TLS 证书', icon: Shield, color: 'dg-text-green', desc: 'TLS/SSL 证书与私钥' },
aksk: { label: 'AKSK 密钥', icon: Cloud, color: 'dg-text-purple', desc: '云服务 AccessKey/SecretKey' },
database: { label: '数据库凭证', icon: Database, color: 'dg-text-blue', desc: '数据库连接信息' },
api: { label: 'API 密钥', icon: Globe, color: 'dg-text-orange', desc: 'API Token/Key + 端点' },
generic: { label: '通用凭证', icon: FileText, color: 'dg-text-secondary', desc: '自定义 Key/Value 键值对' },
};
export const TYPE_BADGE_CLASS: Record<SecretType, string> = {