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:
1 parent
ecec73989b
commit
72bfb0e12d
191 files changed
+5057
-7592
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Plus, Pencil, Trash2, RefreshCw, GitBranch, Container, Globe, Settings2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -18,7 +19,6 @@ import { deployApi } from '@/api';
|
||||
import CredentialFormDialog from './CredentialFormDialog';
|
||||
import ToolConfigTab from './ToolConfigTab';
|
||||
import type { JsonData } from '@/types/common';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface Repo {
|
||||
id: number; name: string; description: string; url: string;
|
||||
@@ -67,31 +67,31 @@ function EnvFormDialog({ open, onClose, onSaved, editData }: { open: boolean; on
|
||||
toast.success(editData ? t('deploy.toast.updated') : t('deploy.toast.created'));
|
||||
onSaved();
|
||||
onClose();
|
||||
} catch { toast.error(t('common.operationFailed')); }
|
||||
} catch { toast.error(t('deploy.toast.operationFailed')); }
|
||||
finally { setSubmitting(false); }
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onClose}>
|
||||
<DialogContent>
|
||||
<DialogHeader><DialogTitle>{editData ? t('pipeline.editEnv') : t('pipeline.addEnv')}</DialogTitle></DialogHeader>
|
||||
<DialogHeader><DialogTitle>{editData ? t('deploy.env.editEnv') : t('deploy.env.addEnv')}</DialogTitle></DialogHeader>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-1"><Label>{t('pipeline.envLabel')}</Label><Input value={name} onChange={e => setName(e.target.value)} placeholder="production" /></div>
|
||||
<div className="space-y-1"><Label>{t('system.userDisplayName')}</Label><Input value={displayName} onChange={e => setDisplayName(e.target.value)} placeholder=t('pipeline.prodEnv') /></div>
|
||||
<div className="space-y-1"><Label>{t('pipeline.envType')}</Label>
|
||||
<div className="space-y-1"><Label>{t('deploy.env.envLabel')}</Label><Input value={name} onChange={e => setName(e.target.value)} placeholder="production" /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.table.displayName')}</Label><Input value={displayName} onChange={e => setDisplayName(e.target.value)} placeholder={t('deploy.env.prodEnv')} /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.env.envType')}</Label>
|
||||
<Select value={envType} onValueChange={setEnvType}>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="production">{t('pipeline.prodEnv')}</SelectItem>
|
||||
<SelectItem value="staging">{t('pipeline.staging')}</SelectItem>
|
||||
<SelectItem value="testing">{t('pipeline.testEnv')}</SelectItem>
|
||||
<SelectItem value="development">{t('pipeline.devEnv')}</SelectItem>
|
||||
<SelectItem value="production">{t('deploy.env.prodEnv')}</SelectItem>
|
||||
<SelectItem value="staging">{t('deploy.env.staging')}</SelectItem>
|
||||
<SelectItem value="testing">{t('deploy.env.testEnv')}</SelectItem>
|
||||
<SelectItem value="development">{t('deploy.env.devEnv')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-1"><Label>{t('deploy.deploycredentials.sc06ac4')}</Label><Input value={color} onChange={e => setColor(e.target.value)} type="color" className="w-16 h-9 p-1" /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.deploycredentials.s65dd48')}</Label><Input value={sortOrder} onChange={e => setSortOrder(Number(e.target.value))} type="number" /></div>
|
||||
<div className="space-y-1"><Label>{t('common.description')}</Label><Input value={description} onChange={e => setDescription(e.target.value)} placeholder=t('common.optional') /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.table.color')}</Label><Input value={color} onChange={e => setColor(e.target.value)} type="color" className="w-16 h-9 p-1" /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.table.sortOrder')}</Label><Input value={sortOrder} onChange={e => setSortOrder(Number(e.target.value))} type="number" /></div>
|
||||
<div className="space-y-1"><Label>{t('deploy.form.desc')}</Label><Input value={description} onChange={e => setDescription(e.target.value)} placeholder={t('common.optional')} /></div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button variant="outline" onClick={onClose}>{t('common.cancel')}</Button>
|
||||
@@ -136,32 +136,32 @@ export default function DeployCredentials() {
|
||||
useEffect(() => { fetchAll(); }, []);
|
||||
|
||||
const handleDelete = async (type: 'repo' | 'registry' | 'env', item: JsonData) => {
|
||||
const ok = await _confirm({ title: t('common.delete'), description: t('deploy.deploycredentials.s999d97', { item.name || item.display_name: item.name || item.display_name }), confirmText: t('common.delete'), variant: 'destructive' });
|
||||
const ok = await _confirm({ title: t('common.delete'), description: t('deploy.toast.deleteConfirm', { name: item.name || item.display_name }), confirmText: t('common.delete'), variant: 'destructive' });
|
||||
if (!ok) return;
|
||||
try {
|
||||
if (type === 'repo') await deployApi.deleteRepo(item.id);
|
||||
else if (type === 'registry') await deployApi.deleteRegistry(item.id);
|
||||
else await deployApi.deleteEnvironment(item.id);
|
||||
toast.success(t('alert.deleted'));
|
||||
toast.success(t('deploy.toast.deleted'));
|
||||
fetchAll();
|
||||
} catch { toast.error(t('common.deleteFailed')); }
|
||||
} catch { toast.error(t('deploy.toast.deleteFailed')); }
|
||||
};
|
||||
|
||||
const envTypeLabel: Record<string, string> = { production: t('pipeline.production'), staging: t('pipeline.staging'), testing: t('common.test'), development: t('pipeline.development') };
|
||||
const envTypeLabel: Record<string, string> = { production: t('deploy.env.production'), staging: t('deploy.env.staging'), testing: t('deploy.env.testing'), development: t('deploy.env.development') };
|
||||
|
||||
const pageTabs = [
|
||||
{ id: 'repos', label: t('deploy.deploycredentials.sd71d03'), badge: repos.length || undefined },
|
||||
{ id: 'registries', label: t('pipeline.registry'), badge: registries.length || undefined },
|
||||
{ id: 'environments', label: t('pipeline.envManage'), badge: environments.length || undefined },
|
||||
{ id: 'build-nodes', label: t('pipeline.buildNode') },
|
||||
{ id: 'repos', label: t('deploy.credForm.gitRepo'), badge: repos.length || undefined },
|
||||
{ id: 'registries', label: t('deploy.credForm.imageRegistry'), badge: registries.length || undefined },
|
||||
{ id: 'environments', label: t('deploy.label.envManage'), badge: environments.length || undefined },
|
||||
{ id: 'build-nodes', label: t('deploy.deployNav.buildNodes') },
|
||||
{ id: 'tools', label: t('deploy.tool.title') },
|
||||
];
|
||||
|
||||
return (
|
||||
<PageShell
|
||||
variant="list"
|
||||
title=t('menu.deployConfig')
|
||||
subtitle=t('deploy.deploycredentials.s15a730')
|
||||
title={t('deploy.label.releaseConfig')}
|
||||
subtitle={t('deploy.credForm.pageSubtitle')}
|
||||
icon={<Settings2 className="h-5 w-5" />}
|
||||
loading={loading}
|
||||
tabs={pageTabs}
|
||||
@@ -170,13 +170,13 @@ export default function DeployCredentials() {
|
||||
actions={activeTab === 'build-nodes' ? undefined : (
|
||||
<>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={fetchAll}>
|
||||
<RefreshCw className="w-4 h-4 mr-1" />刷新
|
||||
<RefreshCw className="w-4 h-4 mr-1" />{t('common.refresh')}
|
||||
</Button>
|
||||
<Button size="sm" className="dg-btn-primary" onClick={() => { setEditType('repo'); setEditingId(null); setEditorOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-1" />新增 Git 仓库
|
||||
<Plus className="w-4 h-4 mr-1" />{t('deploy.credForm.newRepo')}
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onClick={() => { setEditType('registry'); setEditingId(null); setEditorOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-1" />新增镜像仓库
|
||||
<Plus className="w-4 h-4 mr-1" />{t('deploy.credForm.newRegistry')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
@@ -184,17 +184,17 @@ export default function DeployCredentials() {
|
||||
>
|
||||
{activeTab === 'repos' && (
|
||||
repos.length === 0 ? (
|
||||
<PageEmpty icon={<GitBranch className="h-10 w-10" />} title=t('deploy.deploycredentials.sb19733') />
|
||||
<PageEmpty icon={<GitBranch className="h-10 w-10" />} title={t('deploy.credForm.noRepo')} />
|
||||
) : (
|
||||
<ContentPanel noPadding>
|
||||
<div className="overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
|
||||
<tr>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.name')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.name')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">{t('deploy.table.repoUrl')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.cred.authMethod')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.status')}</th>
|
||||
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -224,18 +224,18 @@ export default function DeployCredentials() {
|
||||
|
||||
{activeTab === 'registries' && (
|
||||
registries.length === 0 ? (
|
||||
<PageEmpty icon={<Container className="h-10 w-10" />} title=t('deploy.deploycredentials.sdf33f0') />
|
||||
<PageEmpty icon={<Container className="h-10 w-10" />} title={t('deploy.credForm.noRegistry')} />
|
||||
) : (
|
||||
<ContentPanel noPadding>
|
||||
<div className="overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
|
||||
<tr>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.name')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.name')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">Registry URL</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden sm:table-cell">{t('k8s.column.namespace')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.deploycredentials.sb7158a')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)] hidden sm:table-cell">{t('deploy.credForm.namespace')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.cred.authMethod')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.status')}</th>
|
||||
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -274,8 +274,8 @@ export default function DeployCredentials() {
|
||||
{environments.length === 0 ? (
|
||||
<PageEmpty
|
||||
icon={<Globe className="h-10 w-10" />}
|
||||
title=t('pipeline.noEnv')
|
||||
description=t('deploy.deploycredentials.sac4fb6')
|
||||
title="暂无环境配置"
|
||||
description='点击"新增环境"创建'
|
||||
action={(
|
||||
<Button size="sm" onClick={() => { setEditEnv(null); setEnvDialogOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-1" />新增环境
|
||||
@@ -288,13 +288,13 @@ export default function DeployCredentials() {
|
||||
<table className="w-full text-sm">
|
||||
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
|
||||
<tr>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('pipeline.envLabel')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('system.userDisplayName')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.type')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.color')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.sort')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">{t('common.status')}</th>
|
||||
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">{t('common.actions')}</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">环境标识</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">显示名称</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">类型</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">颜色</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">排序</th>
|
||||
<th className="px-3 py-2 text-left font-medium text-[var(--dg-text-secondary)]">状态</th>
|
||||
<th className="px-3 py-2 text-right font-medium text-[var(--dg-text-secondary)]">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -311,7 +311,7 @@ export default function DeployCredentials() {
|
||||
<td className="px-3 py-2"><div className="w-6 h-6 rounded border" style={{ backgroundColor: env.color }} /></td>
|
||||
<td className="px-3 py-2 text-[var(--dg-text-secondary)]">{env.sort_order}</td>
|
||||
<td className="px-3 py-2">
|
||||
<Badge className={env.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{env.enabled ? t('common.enable') : t('common.disable')}</Badge>
|
||||
<Badge className={env.enabled ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-[var(--dg-bg-active)]/20 dg-text-secondary border-[var(--dg-border)]'}>{env.enabled ? '启用' : '禁用'}</Badge>
|
||||
</td>
|
||||
<td className="px-3 py-2 text-right">
|
||||
<div className="flex justify-end gap-1">
|
||||
|
||||
Reference in new issue
Block a user