feat(i18n): deploy 模块(Pipeline/Credential)国际化增量迁移 — 翻译键 deploy 命名空间(455键) + CredentialManager 补全 3 处 UI 文案

- PipelineManager.tsx: 流水线全量翻译(标题/搜索/CRUD/阶段/任务/运行/横幅)
- CredentialManager.tsx: 操作按钮 title 属性补全(编辑/禁用启用/删除)
- zh-CN.json + en-US.json: deploy 命名空间 455 键完全对齐
- 总翻译键: 1019(zh) = 1019(en)
- tsc -b 零错误, npm build 成功(17.42s)
This commit is contained in:
attacker committed 2026-06-30 22:10:26 +08:00
1 parent ed7a5c07a7
commit 01967bc52b
4 files changed
+1053 -67

No files matched your search

@@ -1,4 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { import {
Plus, Pencil, Trash2, RefreshCw, Key, Shield, Search, Plus, Pencil, Trash2, RefreshCw, Key, Shield, Search,
Clock, CheckCircle2, XCircle, Zap, Clock, CheckCircle2, XCircle, Zap,
@@ -17,6 +18,7 @@ import { CredFormDialog } from './credential-manager/CredFormDialog';
// 凭据管理页编排器 // Logan.Li // 凭据管理页编排器 // Logan.Li
export default function CredentialManager() { export default function CredentialManager() {
const { t } = useTranslation();
const confirm = useConfirm(); const confirm = useConfirm();
const [dialogOpen, setDialogOpen] = useState(false); const [dialogOpen, setDialogOpen] = useState(false);
const [editing, setEditing] = useState<Credential | null>(null); const [editing, setEditing] = useState<Credential | null>(null);
@@ -38,28 +40,28 @@ export default function CredentialManager() {
const handleDelete = async (cred: Credential) => { const handleDelete = async (cred: Credential) => {
const ok = await confirm({ const ok = await confirm({
title: '删除凭据', title: t('deploy.cred.deleteCred'),
description: `确定删除凭据「${cred.name}」?此操作不可撤销。`, description: t('deploy.pipeline.deleteConfirm', { name: cred.name }),
confirmText: '删除', confirmText: t('common.delete'),
variant: 'destructive', variant: 'destructive',
}); });
if (!ok) return; if (!ok) return;
try { try {
await deleteMutation.mutateAsync(cred.id); await deleteMutation.mutateAsync(cred.id);
toast.success('已删除'); toast.success(t('deploy.toast.deleted'));
} catch { toast.error('删除失败'); } } catch { toast.error(t('deploy.toast.deleteFailed')); }
}; };
const handleToggleActive = async (cred: Credential) => { const handleToggleActive = async (cred: Credential) => {
try { try {
await toggleActiveMutation.mutateAsync({ id: cred.id, isActive: !cred.is_active }); await toggleActiveMutation.mutateAsync({ id: cred.id, isActive: !cred.is_active });
toast.success(cred.is_active ? '已禁用' : '已启用'); toast.success(cred.is_active ? t('deploy.toast.disabled') : t('deploy.toast.enabled'));
} catch { toast.error('操作失败'); } } catch { toast.error(t('deploy.toast.operationFailed')); }
}; };
const handleCopyPrefix = (prefix: string) => { const handleCopyPrefix = (prefix: string) => {
navigator.clipboard.writeText(prefix); navigator.clipboard.writeText(prefix);
toast.success('引用 ID 已复制'); toast.success(t('deploy.cred.refIdCopied'));
}; };
const typeOptions = Object.entries(TYPE_CONFIG) as [SecretType, typeof TYPE_CONFIG[SecretType]][]; const typeOptions = Object.entries(TYPE_CONFIG) as [SecretType, typeof TYPE_CONFIG[SecretType]][];
@@ -68,17 +70,17 @@ export default function CredentialManager() {
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h2 className="text-lg font-semibold text-[var(--dg-text-primary)]">凭据管理</h2> <h2 className="text-lg font-semibold text-[var(--dg-text-primary)]">{t('deploy.cred.title')}</h2>
<p className="text-sm text-[var(--dg-text-muted)] mt-0.5"> <p className="text-sm text-[var(--dg-text-muted)] mt-0.5">
统一管理 SSH 密钥、Docker 密码、AKSK、数据库等敏感凭据(AES 加密存储) {t('deploy.cred.subtitle')}
</p> </p>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button variant="outline" size="sm" onClick={() => refetch()}> <Button variant="outline" size="sm" onClick={() => refetch()}>
<RefreshCw className="w-4 h-4 mr-1" />刷新 <RefreshCw className="w-4 h-4 mr-1" />{t('common.refresh')}
</Button> </Button>
<Button size="sm" onClick={() => { setEditing(null); setDialogOpen(true); }}> <Button size="sm" onClick={() => { setEditing(null); setDialogOpen(true); }}>
<Plus className="w-4 h-4 mr-1" />新增凭据 <Plus className="w-4 h-4 mr-1" />{t('deploy.cred.addCredential')}
</Button> </Button>
</div> </div>
</div> </div>
@@ -87,10 +89,10 @@ export default function CredentialManager() {
<div className="flex items-center gap-3 flex-wrap"> <div className="flex items-center gap-3 flex-wrap">
<Select value={filterType} onValueChange={setFilterType}> <Select value={filterType} onValueChange={setFilterType}>
<SelectTrigger className="w-[140px] bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] h-9 text-sm"> <SelectTrigger className="w-[140px] bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] h-9 text-sm">
<SelectValue placeholder="全部类型" /> <SelectValue placeholder={t('deploy.label.allType')} />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all">全部类型</SelectItem> <SelectItem value="all">{t('deploy.label.allType')}</SelectItem>
{typeOptions.map(([k, v]) => ( {typeOptions.map(([k, v]) => (
<SelectItem key={k} value={k}> <SelectItem key={k} value={k}>
<span className="flex items-center gap-2"><v.icon className="h-3.5 w-3.5" />{v.label}</span> <span className="flex items-center gap-2"><v.icon className="h-3.5 w-3.5" />{v.label}</span>
@@ -101,23 +103,23 @@ export default function CredentialManager() {
<div className="relative flex-1 max-w-xs"> <div className="relative flex-1 max-w-xs">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-muted)]" /> <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-muted)]" />
<Input value={filterSearch} onChange={e => setFilterSearch(e.target.value)} <Input value={filterSearch} onChange={e => setFilterSearch(e.target.value)}
placeholder="搜索名称、描述..." placeholder={t('deploy.label.searchPlaceholder')}
className="pl-8 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] h-9 text-sm" /> className="pl-8 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] h-9 text-sm" />
</div> </div>
<span className="text-xs text-[var(--dg-text-muted)]">{credentials.length} 个凭据</span> <span className="text-xs text-[var(--dg-text-muted)]">{t('deploy.cred.credCount', { count: credentials.length })}</span>
</div> </div>
{loading ? ( {loading ? (
<div className="text-center py-16 text-[var(--dg-text-secondary)]"> <div className="text-center py-16 text-[var(--dg-text-secondary)]">
<Zap className="w-6 h-6 animate-spin mx-auto mb-2 text-[var(--dg-blue)]" />加载中... <Zap className="w-6 h-6 animate-spin mx-auto mb-2 text-[var(--dg-blue)]" />{t('deploy.label.loading')}
</div> </div>
) : credentials.length === 0 ? ( ) : credentials.length === 0 ? (
<div className="text-center py-16 border border-dashed border-[var(--dg-border)] rounded-lg"> <div className="text-center py-16 border border-dashed border-[var(--dg-border)] rounded-lg">
<Shield className="w-12 h-12 mx-auto mb-3 text-[var(--dg-text-muted)]" /> <Shield className="w-12 h-12 mx-auto mb-3 text-[var(--dg-text-muted)]" />
<p className="text-[var(--dg-text-secondary)] mb-2">暂无凭据</p> <p className="text-[var(--dg-text-secondary)] mb-2">{t('deploy.cred.noCredentials')}</p>
<p className="text-xs text-[var(--dg-text-muted)] mb-4">创建 SSH、Docker、AKSK 等类型的凭据,供流水线和服务器使用</p> <p className="text-xs text-[var(--dg-text-muted)] mb-4">{t('deploy.cred.subtitle')}</p>
<Button onClick={() => { setEditing(null); setDialogOpen(true); }}> <Button onClick={() => { setEditing(null); setDialogOpen(true); }}>
<Plus className="w-4 h-4 mr-1" />创建第一个凭据 <Plus className="w-4 h-4 mr-1" />{t('deploy.cred.createFirst')}
</Button> </Button>
</div> </div>
) : ( ) : (
@@ -125,13 +127,13 @@ export default function CredentialManager() {
<table className="w-full text-sm"> <table className="w-full text-sm">
<thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]"> <thead className="bg-[var(--dg-bg-tertiary)] border-b border-[var(--dg-border)]">
<tr> <tr>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">名称</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.name')}</th>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">类型</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.type')}</th>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">摘要</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden md:table-cell">{t('deploy.table.repoUrl')}</th>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden lg:table-cell">标签</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden lg:table-cell">{t('deploy.table.tagLabel')}</th>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden xl:table-cell">引用ID</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)] hidden xl:table-cell">{t('deploy.cred.refId')}</th>
<th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">状态</th> <th className="px-3 py-2.5 text-left font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.status')}</th>
<th className="px-3 py-2.5 text-right font-medium text-[var(--dg-text-secondary)]">操作</th> <th className="px-3 py-2.5 text-right font-medium text-[var(--dg-text-secondary)]">{t('deploy.table.actions')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -181,28 +183,28 @@ export default function CredentialManager() {
<td className="px-3 py-2.5"> <td className="px-3 py-2.5">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
{cred.is_active ? ( {cred.is_active ? (
<Badge className="bg-green-500/20 text-green-400 text-xs border-0">启用</Badge> <Badge className="bg-green-500/20 text-green-400 text-xs border-0">{t('common.enable')}</Badge>
) : ( ) : (
<Badge className="bg-red-500/20 text-red-400 text-xs border-0">禁用</Badge> <Badge className="bg-red-500/20 text-red-400 text-xs border-0">{t('common.disable')}</Badge>
)} )}
{isExpired && ( {isExpired && (
<Badge className="bg-yellow-500/20 text-yellow-400 text-xs border-0"><Clock className="h-2.5 w-2.5 mr-0.5" />过期</Badge> <Badge className="bg-yellow-500/20 text-yellow-400 text-xs border-0"><Clock className="h-2.5 w-2.5 mr-0.5" />{t('deploy.status.expired')}</Badge>
)} )}
</div> </div>
</td> </td>
<td className="px-3 py-2.5 text-right" onClick={(e) => e.stopPropagation()}> <td className="px-3 py-2.5 text-right" onClick={(e) => e.stopPropagation()}>
<div className="flex justify-end gap-1"> <div className="flex justify-end gap-1">
<Button variant="ghost" size="icon" className="h-7 w-7" <Button variant="ghost" size="icon" className="h-7 w-7"
onClick={() => { setEditing(cred as Credential); setDialogOpen(true); }} title="编辑"> onClick={() => { setEditing(cred as Credential); setDialogOpen(true); }} title={t('common.edit')}>
<Pencil className="w-3.5 h-3.5" /> <Pencil className="w-3.5 h-3.5" />
</Button> </Button>
<Button variant="ghost" size="icon" className="h-7 w-7" <Button variant="ghost" size="icon" className="h-7 w-7"
onClick={() => handleToggleActive(cred as Credential)} onClick={() => handleToggleActive(cred as Credential)}
title={cred.is_active ? '禁用' : '启用'}> title={cred.is_active ? t('common.disable') : t('common.enable')}>
{cred.is_active ? <XCircle className="w-3.5 h-3.5 text-yellow-500" /> : <CheckCircle2 className="w-3.5 h-3.5 text-green-500" />} {cred.is_active ? <XCircle className="w-3.5 h-3.5 text-yellow-500" /> : <CheckCircle2 className="w-3.5 h-3.5 text-green-500" />}
</Button> </Button>
<Button variant="ghost" size="icon" className="h-7 w-7 text-red-500" <Button variant="ghost" size="icon" className="h-7 w-7 text-red-500"
onClick={() => handleDelete(cred as Credential)} title="删除"> onClick={() => handleDelete(cred as Credential)} title={t('common.delete')}>
<Trash2 className="w-3.5 h-3.5" /> <Trash2 className="w-3.5 h-3.5" />
</Button> </Button>
</div> </div>
@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { import {
@@ -28,6 +29,7 @@ import { PipelineCreateDialog } from './pipeline-manager/PipelineCreateDialog';
// 流水线列表页编排器 // Logan.Li // 流水线列表页编排器 // Logan.Li
export function PipelineManager() { export function PipelineManager() {
const { t } = useTranslation();
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const { data: pipelines = [], isLoading: loading, refetch: refetchPipelines } = usePipelines(); const { data: pipelines = [], isLoading: loading, refetch: refetchPipelines } = usePipelines();
const { triggerMutation, deleteMutation, stopRunMutation } = usePipelineMutations(); const { triggerMutation, deleteMutation, stopRunMutation } = usePipelineMutations();
@@ -41,11 +43,11 @@ export function PipelineManager() {
const confirm = useConfirm(); const confirm = useConfirm();
const ENV_TYPES = [ const ENV_TYPES = [
{ key: 'all', label: '全部', icon: Layers, color: '#6B7280' }, { key: 'all', label: t('deploy.env.all'), icon: Layers, color: '#6B7280' },
{ key: 'production', label: '生产', icon: ShieldCheck, color: '#EF4444' }, { key: 'production', label: t('deploy.env.production'), icon: ShieldCheck, color: '#EF4444' },
{ key: 'testing', label: '测试', icon: CheckCircle, color: '#F59E0B' }, { key: 'testing', label: t('deploy.env.testing'), icon: CheckCircle, color: '#F59E0B' },
{ key: 'staging', label: '预发布', icon: Globe, color: '#8B5CF6' }, { key: 'staging', label: t('deploy.env.staging'), icon: Globe, color: '#8B5CF6' },
{ key: 'development', label: '开发', icon: Code, color: '#3B82F6' }, { key: 'development', label: t('deploy.env.development'), icon: Code, color: '#3B82F6' },
]; ];
// 同步运行中的任务 ID // Logan.Li // 同步运行中的任务 ID // Logan.Li
@@ -86,20 +88,20 @@ export function PipelineManager() {
const handleTrigger = async (pipelineId: number, code: string) => { const handleTrigger = async (pipelineId: number, code: string) => {
try { try {
await triggerMutation.mutateAsync(code); await triggerMutation.mutateAsync(code);
toast.success('已触发'); toast.success(t('deploy.toast.triggered'));
loadRuns(pipelineId, code); loadRuns(pipelineId, code);
refetchPipelines(); refetchPipelines();
} catch { } catch {
toast.error('触发失败'); toast.error(t('deploy.toast.triggerFailed'));
} }
}; };
const handleStop = async (pipelineId: number, code: string, runId: number | string) => { const handleStop = async (pipelineId: number, code: string, runId: number | string) => {
const ok = await confirm({ title: '停止运行', description: '确定要停止此运行吗?', variant: 'destructive' }); const ok = await confirm({ title: t('deploy.run.stopRun'), description: t('deploy.run.stopConfirm'), variant: 'destructive' });
if (!ok) return; if (!ok) return;
try { try {
await stopRunMutation.mutateAsync({ code, runId }); await stopRunMutation.mutateAsync({ code, runId });
toast.success('已停止'); toast.success(t('deploy.toast.stopped'));
loadRuns(pipelineId, code); loadRuns(pipelineId, code);
setRunningRunMap((prev) => { setRunningRunMap((prev) => {
const n = { ...prev }; const n = { ...prev };
@@ -107,7 +109,7 @@ export function PipelineManager() {
return n; return n;
}); });
} catch { } catch {
toast.error('停止失败'); toast.error(t('deploy.toast.stopFailed'));
} }
}; };
@@ -120,9 +122,9 @@ export function PipelineManager() {
(r) => r.status === 'running' || r.status === 'pending', (r) => r.status === 'running' || r.status === 'pending',
); );
if (running) await handleStop(pipelineId, code, running.id as number | string); if (running) await handleStop(pipelineId, code, running.id as number | string);
else toast.error('未找到运行中的任务'); else toast.error(t('deploy.pipeline.noRunningTask'));
} catch { } catch {
toast.error('停止失败'); toast.error(t('deploy.toast.stopFailed'));
} }
return; return;
} }
@@ -131,17 +133,17 @@ export function PipelineManager() {
const handleDelete = async (pipeline: Record<string, unknown>) => { const handleDelete = async (pipeline: Record<string, unknown>) => {
const ok = await confirm({ const ok = await confirm({
title: '删除流水线', title: t('deploy.pipeline.deletePipeline'),
description: `确定删除「${pipeline.name}」?`, description: t('deploy.pipeline.deleteConfirm', { name: pipeline.name }),
variant: 'destructive', variant: 'destructive',
}); });
if (!ok) return; if (!ok) return;
try { try {
await deleteMutation.mutateAsync(pipeline.id as number | string); await deleteMutation.mutateAsync(pipeline.id as number | string);
toast.success('已删除'); toast.success(t('deploy.toast.deleted'));
refetchPipelines(); refetchPipelines();
} catch { } catch {
toast.error('删除失败'); toast.error(t('deploy.toast.deleteFailed'));
} }
}; };
@@ -157,14 +159,14 @@ export function PipelineManager() {
<div className="space-y-5"> <div className="space-y-5">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-2xl font-bold text-[var(--dg-text-primary)]">流水线</h1> <h1 className="text-2xl font-bold text-[var(--dg-text-primary)]">{t('deploy.pipeline.title')}</h1>
<p className="text-sm text-[var(--dg-text-secondary)] mt-1">CI/CD 构建 · 部署 · 发布一体化</p> <p className="text-sm text-[var(--dg-text-secondary)] mt-1">{t('deploy.pipeline.subtitle')}</p>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Button variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]" onClick={() => refetchPipelines()}> <Button variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]" onClick={() => refetchPipelines()}>
<Clock className={`h-4 w-4 mr-2 ${loading ? 'animate-spin' : ''}`} />刷新 <Clock className={`h-4 w-4 mr-2 ${loading ? 'animate-spin' : ''}`} />{t('common.refresh')}
</Button> </Button>
<Button onClick={() => setNewOpen(true)}><Plus className="h-4 w-4 mr-2" />新建流水线</Button> <Button onClick={() => setNewOpen(true)}><Plus className="h-4 w-4 mr-2" />{t('deploy.pipeline.newPipeline')}</Button>
</div> </div>
</div> </div>
@@ -173,45 +175,45 @@ export function PipelineManager() {
<div className="flex-1 space-y-1.5"> <div className="flex-1 space-y-1.5">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<GitBranch className="h-3 w-3 text-indigo-400" /> <GitBranch className="h-3 w-3 text-indigo-400" />
<span className="text-[10px] font-semibold text-indigo-400">构建</span> <span className="text-[10px] font-semibold text-indigo-400">{t('deploy.banner.build')}</span>
<ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" /> <ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" />
<Rocket className="h-3 w-3 text-red-400" /> <Rocket className="h-3 w-3 text-red-400" />
<span className="text-[10px] font-semibold text-red-400">部署</span> <span className="text-[10px] font-semibold text-red-400">{t('deploy.banner.deploy')}</span>
<ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" /> <ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" />
<div className="flex items-center gap-1 px-2 py-0.5 rounded bg-blue-400/10 border border-blue-400/20"> <div className="flex items-center gap-1 px-2 py-0.5 rounded bg-blue-400/10 border border-blue-400/20">
<Server className="h-3 w-3 text-blue-400" /> <Server className="h-3 w-3 text-blue-400" />
<span className="text-[10px] font-medium text-blue-400">SSH 主机</span> <span className="text-[10px] font-medium text-blue-400">{t('deploy.banner.sshHost')}</span>
</div> </div>
</div> </div>
<p className="text-[9px] text-[var(--dg-text-secondary)] opacity-40 pl-1">传统主机 SCP 部署 · 无需镜像仓库</p> <p className="text-[9px] text-[var(--dg-text-secondary)] opacity-40 pl-1">{t('deploy.banner.sshDesc')}</p>
</div> </div>
<div className="w-px bg-[var(--dg-border)]" /> <div className="w-px bg-[var(--dg-border)]" />
<div className="flex-1 space-y-1.5"> <div className="flex-1 space-y-1.5">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<GitBranch className="h-3 w-3 text-indigo-400" /> <GitBranch className="h-3 w-3 text-indigo-400" />
<span className="text-[10px] font-semibold text-indigo-400">构建</span> <span className="text-[10px] font-semibold text-indigo-400">{t('deploy.banner.build')}</span>
<ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" /> <ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" />
<Container className="h-3 w-3 text-cyan-400" /> <Container className="h-3 w-3 text-cyan-400" />
<span className="text-[10px] font-semibold text-cyan-400">镜像仓库</span> <span className="text-[10px] font-semibold text-cyan-400">{t('deploy.banner.imageRegistry')}</span>
<ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" /> <ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" />
<Rocket className="h-3 w-3 text-red-400" /> <Rocket className="h-3 w-3 text-red-400" />
<span className="text-[10px] font-semibold text-red-400">部署</span> <span className="text-[10px] font-semibold text-red-400">{t('deploy.banner.deploy')}</span>
<ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" /> <ArrowRight className="h-2.5 w-2.5 text-[var(--dg-text-secondary)] opacity-30" />
<div className="flex items-center gap-1 px-2 py-0.5 rounded bg-emerald-400/10 border border-emerald-400/20"> <div className="flex items-center gap-1 px-2 py-0.5 rounded bg-emerald-400/10 border border-emerald-400/20">
<Network className="h-3 w-3 text-emerald-400" /> <Network className="h-3 w-3 text-emerald-400" />
<span className="text-[10px] font-medium text-emerald-400">Kubernetes</span> <span className="text-[10px] font-medium text-emerald-400">{t('deploy.banner.kubernetes')}</span>
</div> </div>
</div> </div>
<p className="text-[9px] text-[var(--dg-text-secondary)] opacity-40 pl-1">容器化部署 · 需镜像仓库推送</p> <p className="text-[9px] text-[var(--dg-text-secondary)] opacity-40 pl-1">{t('deploy.banner.k8sDesc')}</p>
</div> </div>
<span className="self-center ml-2 text-[10px] text-[var(--dg-text-secondary)] opacity-30 tracking-wide whitespace-nowrap">全流程可视化</span> <span className="self-center ml-2 text-[10px] text-[var(--dg-text-secondary)] opacity-30 tracking-wide whitespace-nowrap">{t('deploy.banner.fullFlow')}</span>
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="relative max-w-md flex-1"> <div className="relative max-w-md flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-secondary)]" /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--dg-text-secondary)]" />
<Input <Input
placeholder="搜索流水线..." placeholder={t('deploy.pipeline.searchPlaceholder')}
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]" className="pl-10 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
@@ -244,9 +246,9 @@ export function PipelineManager() {
) : filtered.length === 0 ? ( ) : filtered.length === 0 ? (
<div className="text-center py-16 text-[var(--dg-text-secondary)]"> <div className="text-center py-16 text-[var(--dg-text-secondary)]">
<Workflow className="h-10 w-10 mx-auto mb-3 opacity-30" /> <Workflow className="h-10 w-10 mx-auto mb-3 opacity-30" />
<p className="text-sm">暂无流水线</p> <p className="text-sm">{t('deploy.pipeline.noData')}</p>
<Button variant="outline" className="mt-4" onClick={() => setNewOpen(true)}> <Button variant="outline" className="mt-4" onClick={() => setNewOpen(true)}>
<Plus className="h-4 w-4 mr-1" />创建第一个流水线 <Plus className="h-4 w-4 mr-1" />{t('deploy.pipeline.createFirst')}
</Button> </Button>
</div> </div>
) : ( ) : (
@@ -275,4 +277,4 @@ export function PipelineManager() {
<PipelineCreateDialog open={newOpen} onOpenChange={setNewOpen} onCreated={refetchPipelines} /> <PipelineCreateDialog open={newOpen} onOpenChange={setNewOpen} onCreated={refetchPipelines} />
</div> </div>
); );
} }
+491
View File
@@ -654,5 +654,496 @@
"closed": "Closed" "closed": "Closed"
} }
} }
},
"deploy": {
"pipeline": {
"title": "Pipelines",
"subtitle": "CI/CD Build · Deploy · Release All-in-One",
"newPipeline": "New Pipeline",
"createFirst": "Create your first pipeline",
"searchPlaceholder": "Search pipelines...",
"noData": "No pipelines",
"triggered": "Triggered",
"triggerFailed": "Trigger failed",
"stopRun": "Stop Run",
"stopConfirm": "Are you sure you want to stop this run?",
"stopped": "Stopped",
"stopFailed": "Stop failed",
"noRunningTask": "No running task found",
"deletePipeline": "Delete Pipeline",
"deleteConfirm": "Delete \"{{name}}\"?",
"deleted": "Deleted",
"deleteFailed": "Delete failed",
"detail": "Pipeline Detail",
"notExist": "Pipeline does not exist",
"config": "Pipeline Config",
"name": "Pipeline Name",
"namePlaceholder": "Enter pipeline name",
"type": "Pipeline Type",
"stages": "Pipeline Stages ({{count}})",
"allStages": "All Stages",
"noStages": "No stage configuration",
"clickToAddStage": "Click \"Add Stage\" to start",
"addStage": "Add Stage",
"newStage": "New Stage",
"addTask": "Add Task",
"newTask": "New Task",
"taskEdit": "Task Editor",
"selectTaskHint": "Select a task to start editing",
"matchPreview": "Pipeline Match Preview",
"created": "Pipeline created",
"createFailed": "Create failed",
"saving": "Saving...",
"save": "Save",
"editPipeline": "Edit Pipeline",
"modifyConfig": "Modify Pipeline Config",
"configureNew": "Configure new CI/CD pipeline",
"editMode": "Save Changes",
"createMode": "Create Pipeline",
"desc": "No description",
"buildNumber": "Build",
"runs": "Run Count",
"neverRun": "Never run",
"runNow": "Run Now",
"executing": "Executing...",
"logOutput": "No log output",
"noLogStage": "No log output for this stage",
"realtimeOutput": "Pipeline running, real-time output...",
"buildDir": "Pipeline Build Directory Terminal",
"fileBrowser": "File Browser #{{buildNumber}}",
"buildDirFiles": "Pipeline Build Directory File Browser",
"workspaceTerminal": "Workspace Terminal #{{buildNumber}}",
"execLog": "Execution Log #{{number}}",
"release": "Release #{{number}}",
"all": "All ({{count}})"
},
"stage": {
"checkout": "Checkout",
"build": "Build",
"image": "Image Build",
"deploy": "Deploy",
"test": "Test",
"custom": "Custom",
"tasks": "{{count}} tasks",
"selectOrder": "Select stages in order",
"checkoutDesc": "Pull code",
"buildDesc": "Build & package",
"imageDesc": "Push image",
"deployDesc": "Deploy to Kubernetes",
"testDesc": "Code inspection",
"checkoutNeedGit": "Checkout stage requires Git URL",
"imageNeedDocker": "Image build stage requires Docker credential",
"suggestDocker": "Recommended credential",
"needDocker": "Docker credential required"
},
"env": {
"all": "All",
"production": "Production",
"testing": "Testing",
"staging": "Staging",
"development": "Development",
"prodEnv": "Production",
"testEnv": "Testing",
"stagingEnv": "Staging",
"devEnv": "Development",
"selectEnv": "Select Environment",
"envType": "Environment Type",
"envGroup": "Environment Group",
"envLabel": "Environment ID",
"selectEnvHint": "Pipeline runs will be linked to the selected environment",
"addEnv": "Add Environment",
"editEnv": "Edit Environment",
"envManage": "Environments ({{count}})",
"noEnvConfig": "No environment config, click \"Add Environment\" to create"
},
"trigger": {
"manual": "Manual",
"manualTrigger": "Manual Trigger",
"manualExec": "Manual Execution",
"gitPush": "Git Push Trigger",
"gitPushAuto": "Git Push Auto Trigger",
"cron": "Cron Schedule",
"webhook": "Webhook Trigger",
"externalWebhook": "External Webhook Call",
"method": "Trigger Method",
"triggerBuild": "Trigger Build",
"settings": "Trigger Settings",
"listenBranch": "Listen Branch",
"excludeBranch": "Exclude Branch",
"cronExpr": "Cron Expression",
"every5min": "Every 5 minutes",
"everyHour": "Every hour",
"everyDay2": "Daily at 2:00",
"everySunday": "Every Sunday",
"tagRelease": "Tag Release",
"branchTag": "Branch / Tag",
"noTriggerMode": "Manual"
},
"run": {
"status": "Status",
"triggeredBy": "Triggered By",
"triggerMode": "Trigger Method",
"duration": "Duration",
"startTime": "Start Time",
"branch": "Branch",
"commit": "Code",
"noRecords": "No execution records",
"noRecordsHint": "No execution records, click \"Run Now\" to trigger a build",
"stopRun": "Stop Run",
"stopConfirm": "Are you sure you want to stop this run?",
"buildStatus": "Build Status",
"buildLog": "Build Log",
"execStage": "Execution Stage",
"fullFlowVisual": "Full-flow Visualization"
},
"status": {
"pending": "Pending",
"running": "Running",
"success": "Success",
"failed": "Failed",
"stopped": "Stopped",
"building": "Building",
"deploying": "Deploying",
"succeeded": "Succeeded",
"failed_deploy": "Deploy Failed",
"rolledBack": "Rolled Back",
"pendingRelease": "Pending Release",
"pendingApproval": "Pending Approval",
"approved": "Approved",
"rejected": "Rejected",
"cancelled": "Cancelled",
"expired": "Expired",
"created": "Created",
"updated": "Updated",
"deleted": "Deleted",
"enabled": "Enabled",
"disabled": "Disabled",
"installed": "Installed",
"notInstalled": "Not Installed",
"installing": "Installing"
},
"cred": {
"title": "Credentials",
"subtitle": "Manage SSH keys, Docker passwords, AKSK, database and other sensitive credentials (AES encrypted)",
"addCredential": "Add Credential",
"createFirst": "Create your first credential",
"searchPlaceholder": "Search credentials...",
"credName": "Credential Name",
"nameRequired": "Please enter credential name",
"credType": "Type",
"authMethod": "Auth Method",
"noCredentials": "No credentials",
"credCount": "{{count}} credentials",
"editCred": "Edit Credential",
"newCred": "New Credential",
"deleteCred": "Delete Credential",
"credData": "Secret Data",
"noCredData": "Credential data not found",
"refId": "Reference ID",
"refIdCopied": "Reference ID copied",
"refHint": "Reference this credential in pipelines/scripts:",
"credDetail": "Credential Detail",
"refIdLabel": "Reference ID:",
"descDefault": "Manage sensitive credentials",
"suggestLink": "Recommended credential",
"notLinked": "Not linked",
"notLinkedCred": "No credential",
"selectDocker": "Select Docker credential",
"selectDockerPwd": "Select Docker password credential",
"selectApiCred": "Select credential (API/password etc.)",
"selectCred": "Select credential",
"linkedCred": "Linked Credential"
},
"release": {
"title": "Application Release",
"subtitle": "Manage application version releases and approval workflows",
"newRelease": "New Release",
"searchApp": "Search app name or version...",
"noRecords": "No release records",
"appName": "App Name",
"version": "Version",
"versionNo": "Version Number",
"releaseDesc": "Release Notes",
"releaseProgress": "Release Progress",
"releaseDetail": "Release Detail",
"approve": "Approve Release",
"approveFail": "Approval failed",
"approveHint": "After approval, it will enter the ready-to-deploy state",
"reject": "Reject",
"rejectFail": "Reject failed",
"deploy": "Deploy",
"deployStarted": "Deployment started",
"deployFail": "Deploy failed",
"confirmDeploy": "Confirm Deploy",
"rollback": "Rollback",
"rollbackSuccess": "Rollback succeeded",
"rollbackFail": "Rollback failed",
"confirmRollback": "Confirm Rollback",
"redeploy": "Redeploy",
"redeployFail": "Redeploy failed",
"redeployed": "Redeployment triggered",
"submitApp": "Submit Request",
"submitFail": "Release request submitted",
"createNew": "Create new application version release request",
"appPlaceholder": "e.g., demo-jar backend deployment",
"nameVerRequired": "Please enter app name and version",
"getReleaseFail": "Failed to get release list",
"deployEnv": "Deploy Environment:",
"targetEnv": "Target Environment",
"releaseConfig": "Release Config Management",
"releaseRecords": "Release Records ({{count}})",
"releaseFlow": "Release Flow",
"releasePerson": "Released By",
"releaseManage": "Release Management"
},
"tool": {
"title": "Tool Config",
"subtitle": "Manage DevOps tool installation strategy: pre-installed, lazy-load on first use, or disabled",
"installMethod": "Install Method",
"preinstall": "Pre-install",
"lazyLoad": "Lazy Load",
"selectVersion": "Select Version",
"versionPrompt": "{{name}} — Please select a version to install",
"noConfig": "No tool config, please check backend seed data",
"getToolFail": "Failed to get tool config",
"installed": "Installed",
"notInstalled": "Not installed",
"installing": "Installing",
"test": "Test",
"install": "Install"
},
"rbac": {
"title": "Deploy Permissions",
"subtitle": "Jenkins-style Role Strategy — Assign roles by pipeline code regex matching",
"newRole": "New Item Role",
"newGroup": "New User Group",
"assignToUser": "Assign roles to users",
"userGroupManage": "User Group Management",
"groupDesc": "Create user groups, authorize groups to pipelines, group members automatically inherit permissions",
"noRoles": "No Item Roles",
"noGroups": "No user groups, click \"New User Group\" to create",
"noDirectUsers": "No direct users",
"noGroupAuth": "No group authorization — Create a group in \"",
"noGroupAuthSuffix": "\" page, then authorize here",
"directUsers": "👤 Direct User Authorization ({{count}})",
"groupAssignments": "👥 Group Authorization ({{count}})",
"rolePattern": "Regex Match Pattern",
"regexEmpty": "Regex cannot be empty",
"noMatch": "No match — please adjust the regex",
"regexError": "❌ Invalid regex syntax",
"matchCount": "{{count}} matches",
"matchPreview": "Pipeline Match Preview",
"roleHint": "— Select a role to see which pipelines match",
"owner": "Owner",
"editor": "Editor",
"viewer": "Viewer",
"ownerRole": "Owner",
"editorRole": "Editor",
"viewerRole": "Viewer",
"assigned": "Assigned",
"assignedRoles": "Assigned roles:",
"addUser": "Add User",
"selectUser": "Select User",
"selectUserPlaceholder": "Select user...",
"selectRole": "Select Role",
"assign": "Assign",
"assignFail": "Assign failed",
"memberManage": "Members ({{count}})",
"addMember": "Add User",
"removeMember": "Remove Member",
"removeConfirm": "Are you sure you want to remove this member?",
"removeFail": "Remove failed",
"noMembers": "No members",
"addedMember": "Member added",
"removed": "Removed",
"groupNewTitle": "New User Group",
"groupEditTitle": "Edit User Group",
"groupName": "Group Name",
"groupPlaceholder": "Enter group name",
"createGroup": "Create",
"creating": "Creating...",
"deleteGroup": "Delete User Group",
"deleteRole": "Delete Role",
"userCol": "User",
"noUserRole": "This user has not been assigned any Item Role"
},
"banner": {
"build": "Build",
"deploy": "Deploy",
"sshHost": "SSH Host",
"kubernetes": "Kubernetes",
"imageRegistry": "Image Registry",
"sshDesc": "Traditional host SCP deployment · No registry needed",
"k8sDesc": "Containerized deployment · Requires registry push",
"fullFlow": "Full-flow Visualization"
},
"template": {
"go": "Go Project",
"goDesc": "For Go backend projects",
"java": "Java Project",
"javaDesc": "For Java Spring Boot projects",
"nodejs": "Node.js Project",
"nodejsDesc": "For Node.js frontend projects",
"python": "Python Project",
"pythonDesc": "For Python projects",
"selectTemplate": "Select Template",
"mavenBuild": "Maven Build",
"dependencyInstall": "Dependency Install",
"unitTest": "Unit Test",
"healthCheck": "Health Check",
"package": "Package",
"verify": "Verify",
"detect": "Detect"
},
"var": {
"title": "Variables",
"addVar": "Add Variable",
"varName": "Variable Name",
"varValue": "Variable Value",
"varAlias": "Variable Alias",
"noVars": "No variables, click \"Add Variable\" to create",
"envVar": "Environment Variables",
"envVarOptional": "Environment Variables (optional)"
},
"table": {
"name": "Name",
"code": "Code",
"codeCol": "Repository",
"type": "Type",
"status": "Status",
"env": "Environment",
"duration": "Duration",
"trigger": "Trigger",
"triggerBy": "Triggered By",
"startTime": "Start Time",
"actions": "Actions",
"sortOrder": "Sort",
"modifyTime": "Modified",
"size": "Size",
"color": "Color",
"icon": "Icon",
"displayName": "Display Name",
"envId": "Env ID",
"successRate": "Success Rate",
"todayRelease": "Today's Releases",
"defaultBranch": "Default Branch",
"repoUrl": "Repository URL",
"tagLabel": "Tag",
"version": "Version",
"user": "User",
"category": "Category"
},
"form": {
"name": "Name",
"nameStar": "Name *",
"nameRequired": "Please enter a name",
"code": "Code (unique identifier)",
"desc": "Description",
"descOptional": "Description (optional)",
"repoUrlStar": "Repository URL *",
"registryUrlStar": "Registry URL *",
"nameAddrRequired": "Please enter name and address",
"concurrent": "Concurrent Executors",
"concurrentHint": "Set to 1 for sequential execution, default 2 allows parallel builds",
"serial": "1 — Sequential",
"gitCred": "Git Credential",
"jobName": "Job Name",
"envVars": "Environment Variables",
"deployMode": "Deploy Mode",
"deployTarget": "Deploy Target",
"commitId": "Commit ID (optional)",
"dockerfilePath": "Dockerfile Path",
"buildCache": "Build Cache",
"cachePaths": "Separate multiple paths with commas, same Key will hit existing cache",
"registryAddr": "Registry Address",
"imageName": "Image Name:",
"varRef": "(${'{VAR_NAME}'} reference)",
"scriptType": "Script Type",
"scriptContent": "Script Content",
"buildQueue": "Build Queue",
"defaultNamespace": "Default Namespace",
"defaultEnabled": "Enabled by default",
"notSpecified": "Not specified",
"save": "Save",
"cancel": "Cancel",
"create": "Create",
"update": "Update"
},
"toast": {
"saved": "Saved",
"updated": "Updated",
"deleted": "Deleted",
"created": "Created",
"enabled": "Enabled",
"disabled": "Disabled",
"installed": "Installed",
"triggered": "Triggered",
"stopped": "Stopped",
"added": "Added",
"removed": "Removed",
"revoked": "Revoked",
"approved": "Approved",
"rejected": "Rejected",
"cancelled": "Cancelled",
"expired": "Expired",
"rolledBack": "Rolled back",
"redeployed": "Redeployment triggered",
"assigned": "Assigned",
"createdPipeline": "Pipeline created",
"releaseSubmitted": "Release request submitted",
"deployStarted": "Deployment started",
"saveFailed": "Save failed",
"updateFailed": "Update failed",
"deleteFailed": "Delete failed",
"createFailed": "Create failed",
"triggerFailed": "Trigger failed",
"stopFailed": "Stop failed",
"addFailed": "Add failed",
"removeFailed": "Remove failed",
"revokeFailed": "Revoke failed",
"approveFailed": "Approve failed",
"rejectFailed": "Reject failed",
"deployFailed": "Deploy failed",
"rollbackFailed": "Rollback failed",
"redeployFailed": "Redeploy failed",
"assignFailed": "Assign failed",
"batchDeleteFailed": "Batch delete failed",
"cancelFailed": "Cancel failed",
"operationFailed": "Operation failed",
"getDataFailed": "Failed to get data",
"loadFailed": "Load failed",
"saveSuccess": "Saved successfully"
},
"label": {
"basicInfo": "Basic Info",
"flowConfig": "Flow Config",
"triggerSettings": "Trigger Settings",
"variables": "Variables",
"credentials": "Credentials",
"environments": "Environments",
"toolConfig": "Tool Config",
"releaseConfig": "Release Config",
"releaseRecords": "Release Records",
"permission": "Permissions",
"userGroups": "User Groups",
"roles": "Roles",
"gitRepo": "Git Repos ({{count}})",
"registry": "Registries ({{count}})",
"envManage": "Environments ({{count}})",
"advanced": "Advanced",
"loading": "Loading...",
"emptyDir": "Directory is empty",
"browse": "Browse",
"record": "Record",
"log": "Log",
"run": "Run",
"execute": "Execute",
"download": "Download",
"searchPlaceholder": "Search name, description...",
"allStatus": "All Status",
"allEnv": "All Environments",
"allType": "All Types",
"pagination": "{{n}}/page"
}
} }
} }
+491
View File
@@ -654,5 +654,496 @@
"closed": "已关闭" "closed": "已关闭"
} }
} }
},
"deploy": {
"pipeline": {
"title": "流水线",
"subtitle": "CI/CD 构建 · 部署 · 发布一体化",
"newPipeline": "新建流水线",
"createFirst": "创建第一个流水线",
"searchPlaceholder": "搜索流水线...",
"noData": "暂无流水线",
"triggered": "已触发",
"triggerFailed": "触发失败",
"stopRun": "停止运行",
"stopConfirm": "确定要停止此运行吗?",
"stopped": "已停止",
"stopFailed": "停止失败",
"noRunningTask": "未找到运行中的任务",
"deletePipeline": "删除流水线",
"deleteConfirm": "确定删除「{{name}}」?",
"deleted": "已删除",
"deleteFailed": "删除失败",
"detail": "流水线详情",
"notExist": "流水线不存在",
"config": "流水线配置",
"name": "流水线名称",
"namePlaceholder": "请输入流水线名称",
"type": "流水线类型",
"stages": "流水线阶段 ({{count}})",
"allStages": "全阶段",
"noStages": "暂无阶段配置",
"clickToAddStage": "点击「添加阶段」开始",
"addStage": "添加阶段",
"newStage": "新阶段",
"addTask": "添加任务",
"newTask": "新任务",
"taskEdit": "任务编辑",
"selectTaskHint": "选择一个任务开始编辑",
"matchPreview": "流水线命中预览",
"created": "流水线已创建",
"createFailed": "创建失败",
"saving": "保存中...",
"save": "保存",
"editPipeline": "编辑流水线",
"modifyConfig": "修改流水线配置",
"configureNew": "配置新的 CI/CD 流水线",
"editMode": "保存修改",
"createMode": "创建流水线",
"desc": "暂无描述",
"buildNumber": "构建",
"runs": "运行次数",
"neverRun": "从未运行",
"runNow": "立即执行",
"executing": "执行中...",
"logOutput": "暂无日志输出",
"noLogStage": "该阶段暂无日志输出",
"realtimeOutput": "流水线执行中,实时输出...",
"buildDir": "流水线构建目录终端",
"fileBrowser": "文件浏览器 #{{buildNumber}}",
"buildDirFiles": "流水线构建目录文件浏览",
"workspaceTerminal": "Workspace 终端 #{{buildNumber}}",
"execLog": "执行日志 #{{number}}",
"release": "发布 #{{number}}",
"all": "全部 ({{count}})"
},
"stage": {
"checkout": "代码检出",
"build": "构建",
"image": "镜像打包",
"deploy": "部署",
"test": "测试",
"custom": "自定义",
"tasks": "{{count}} 任务",
"selectOrder": "按顺序选择阶段",
"checkoutDesc": "拉取代码",
"buildDesc": "构建打包",
"imageDesc": "推送镜像",
"deployDesc": "部署到Kubernetes",
"testDesc": "代码检查",
"checkoutNeedGit": "代码检出阶段需要填写 Git URL",
"imageNeedDocker": "镜像打包阶段需要关联 Docker 凭证",
"suggestDocker": "建议关联凭证",
"needDocker": "需要关联 Docker 凭证"
},
"env": {
"all": "全部",
"production": "生产",
"testing": "测试",
"staging": "预发布",
"development": "开发",
"prodEnv": "生产环境",
"testEnv": "测试环境",
"stagingEnv": "预发环境",
"devEnv": "开发环境",
"selectEnv": "选择环境",
"envType": "环境类型",
"envGroup": "环境分组",
"envLabel": "环境标识",
"selectEnvHint": "选择后流水线执行记录会关联到对应环境",
"addEnv": "新增环境",
"editEnv": "编辑环境",
"envManage": "环境管理 ({{count}})",
"noEnvConfig": "暂无环境配置,点击\"新增环境\"创建"
},
"trigger": {
"manual": "手动",
"manualTrigger": "手动触发",
"manualExec": "手动触发执行",
"gitPush": "Git Push 触发",
"gitPushAuto": "Git Push 自动触发",
"cron": "Cron 定时执行",
"webhook": "Webhook 触发",
"externalWebhook": "外部 Webhook 调用",
"method": "触发方式",
"triggerBuild": "触发构建",
"settings": "触发设置",
"listenBranch": "监听分支",
"excludeBranch": "排除分支",
"cronExpr": "Cron 表达式",
"every5min": "每5分钟",
"everyHour": "每小时",
"everyDay2": "每天2点",
"everySunday": "每周日",
"tagRelease": "Tag 发版",
"branchTag": "分支 / Tag",
"noTriggerMode": "手动"
},
"run": {
"status": "状态",
"triggeredBy": "触发人",
"triggerMode": "触发方式",
"duration": "耗时",
"startTime": "开始时间",
"branch": "分支",
"commit": "代码",
"noRecords": "暂无执行记录",
"noRecordsHint": "暂无执行记录,点击\"立即执行\"触发构建",
"stopRun": "停止运行",
"stopConfirm": "确定要停止此运行吗?",
"buildStatus": "构建执行状态",
"buildLog": "构建日志",
"execStage": "执行阶段",
"fullFlowVisual": "全流程可视化"
},
"status": {
"pending": "待执行",
"running": "运行中",
"success": "成功",
"failed": "失败",
"stopped": "已停止",
"building": "构建中",
"deploying": "发布中",
"succeeded": "发布成功",
"failed_deploy": "发布失败",
"rolledBack": "已回滚",
"pendingRelease": "待发布",
"pendingApproval": "待审批",
"approved": "已审批",
"rejected": "已驳回",
"cancelled": "已取消",
"expired": "已过期",
"created": "已创建",
"updated": "已更新",
"deleted": "已删除",
"enabled": "已启用",
"disabled": "已禁用",
"installed": "已安装",
"notInstalled": "未安装",
"installing": "安装中"
},
"cred": {
"title": "凭据管理",
"subtitle": "统一管理 SSH 密钥、Docker 密码、AKSK、数据库等敏感凭据(AES 加密存储)",
"addCredential": "新增凭据",
"createFirst": "创建第一个凭据",
"searchPlaceholder": "搜索凭据...",
"credName": "凭据名称",
"nameRequired": "请填写凭据名称",
"credType": "类型",
"authMethod": "认证方式",
"noCredentials": "暂无凭据",
"credCount": "{{count}} 个凭据",
"editCred": "编辑凭据",
"newCred": "新增凭据",
"deleteCred": "删除凭据",
"credData": "密钥数据",
"noCredData": "未找到凭据数据",
"refId": "引用ID",
"refIdCopied": "引用 ID 已复制",
"refHint": "在流水线/脚本中引用此凭据:",
"credDetail": "凭据详情",
"refIdLabel": "引用ID:",
"descDefault": "管理敏感凭据信息",
"suggestLink": "建议关联凭证",
"notLinked": "不关联",
"notLinkedCred": "不关联凭证",
"selectDocker": "选择 Docker 凭证",
"selectDockerPwd": "选择 Docker 密码凭据",
"selectApiCred": "选择凭据(API/密码等)",
"selectCred": "选择凭证",
"linkedCred": "关联凭证"
},
"release": {
"title": "应用发布",
"subtitle": "管理应用版本发布与审批流程",
"newRelease": "新建发布",
"searchApp": "搜索应用名称或版本...",
"noRecords": "暂无发布记录",
"appName": "应用名称",
"version": "版本",
"versionNo": "版本号",
"releaseDesc": "发布说明",
"releaseProgress": "发布进度",
"releaseDetail": "发布详情",
"approve": "审批发布",
"approveFail": "审批失败",
"approveHint": "确认审批后将进入部署就绪状态",
"reject": "驳回",
"rejectFail": "驳回失败",
"deploy": "部署",
"deployStarted": "部署已启动",
"deployFail": "部署失败",
"confirmDeploy": "确认部署",
"rollback": "回滚",
"rollbackSuccess": "回滚成功",
"rollbackFail": "回滚失败",
"confirmRollback": "确认回滚",
"redeploy": "重新部署",
"redeployFail": "重新部署失败",
"redeployed": "已重新触发部署",
"submitApp": "提交申请",
"submitFail": "发布申请已提交",
"createNew": "创建新的应用版本发布申请",
"appPlaceholder": "例如: demo-jar 后端部署",
"nameVerRequired": "请填写应用名称和版本号",
"getReleaseFail": "获取发布列表失败",
"deployEnv": "部署环境:",
"targetEnv": "目标环境",
"releaseConfig": "发布配置管理",
"releaseRecords": "发布记录 ({{count}})",
"releaseFlow": "发布流程",
"releasePerson": "发布人",
"releaseManage": "发布管理"
},
"tool": {
"title": "工具配置",
"subtitle": "管理 DevOps 工具的安装策略:预装在镜像中、首次使用自动下载(懒加载)、或禁用不安装",
"installMethod": "安装方式",
"preinstall": "预装",
"lazyLoad": "懒加载",
"selectVersion": "选择安装版本",
"versionPrompt": "{{name}} — 请选择要安装的版本",
"noConfig": "暂无工具配置,请检查后端种子数据",
"getToolFail": "获取工具配置失败",
"installed": "已安装",
"notInstalled": "未安装",
"installing": "安装中",
"test": "测试",
"install": "安装"
},
"rbac": {
"title": "发布权限",
"subtitle": "Jenkins-style Role Strategy — 按流水线 code 正则匹配分配角色",
"newRole": "新建 Item Role",
"newGroup": "新建用户组",
"assignToUser": "分配角色给用户",
"userGroupManage": "用户组管理",
"groupDesc": "创建用户组,将组授权给流水线,组内成员自动获得流水线权限",
"noRoles": "暂无 Item Role",
"noGroups": "暂无用户组,点击「新建用户组」创建",
"noDirectUsers": "暂无直接用户",
"noGroupAuth": "暂无组授权 — 在「",
"noGroupAuthSuffix": "」页面创建组后,可在此授权",
"directUsers": "👤 直接用户授权 ({{count}})",
"groupAssignments": "👥 用户组授权 ({{count}})",
"rolePattern": "正则匹配 Pattern",
"regexEmpty": "正则不能为空",
"noMatch": "无匹配 — 请调整正则表达式",
"regexError": "❌ 正则语法错误",
"matchCount": "{{count}} 条",
"matchPreview": "流水线命中预览",
"roleHint": "— 选择一个角色查看哪些流水线会被匹配",
"owner": "拥有者",
"editor": "编辑者",
"viewer": "查看者",
"ownerRole": "拥有者 (owner)",
"editorRole": "编辑者 (editor)",
"viewerRole": "查看者 (viewer)",
"assigned": "已分配",
"assignedRoles": "已分配角色:",
"addUser": "添加用户",
"selectUser": "选择用户",
"selectUserPlaceholder": "选择用户...",
"selectRole": "选择角色",
"assign": "分配",
"assignFail": "分配失败",
"memberManage": "成员管理 ({{count}})",
"addMember": "添加用户",
"removeMember": "移除成员",
"removeConfirm": "确定要移除此成员吗?",
"removeFail": "移除失败",
"noMembers": "暂无成员",
"addedMember": "已添加成员",
"removed": "已移除",
"groupNewTitle": "新建用户组",
"groupEditTitle": "编辑用户组",
"groupName": "组名",
"groupPlaceholder": "请输入组名",
"createGroup": "创建",
"creating": "创建中...",
"deleteGroup": "删除用户组",
"deleteRole": "删除角色",
"userCol": "用户",
"noUserRole": "该用户尚未分配任何 Item Role"
},
"banner": {
"build": "构建",
"deploy": "部署",
"sshHost": "SSH 主机",
"kubernetes": "Kubernetes",
"imageRegistry": "镜像仓库",
"sshDesc": "传统主机 SCP 部署 · 无需镜像仓库",
"k8sDesc": "容器化部署 · 需镜像仓库推送",
"fullFlow": "全流程可视化"
},
"template": {
"go": "Go 项目",
"goDesc": "适用于 Go 后端项目",
"java": "Java 项目",
"javaDesc": "适用于 Java Spring Boot 项目",
"nodejs": "Node.js 项目",
"nodejsDesc": "适用于 Node.js 前端项目",
"python": "Python 项目",
"pythonDesc": "适用于 Python 项目",
"selectTemplate": "选择模板",
"mavenBuild": "Maven构建",
"dependencyInstall": "依赖安装",
"unitTest": "单元测试",
"healthCheck": "健康检查",
"package": "打包",
"verify": "验证",
"detect": "检测"
},
"var": {
"title": "变量",
"addVar": "添加变量",
"varName": "变量名",
"varValue": "变量值",
"varAlias": "变量别名",
"noVars": "暂无变量,点击\"添加变量\"新增",
"envVar": "环境变量",
"envVarOptional": "环境变量 (可选)"
},
"table": {
"name": "名称",
"code": "代码",
"codeCol": "代码仓库",
"type": "类型",
"status": "状态",
"env": "环境",
"duration": "耗时",
"trigger": "触发方式",
"triggerBy": "触发人",
"startTime": "开始时间",
"actions": "操作",
"sortOrder": "排序",
"modifyTime": "修改时间",
"size": "大小",
"color": "颜色",
"icon": "图标",
"displayName": "显示名称",
"envId": "环境标识",
"successRate": "成功率",
"todayRelease": "今日发布",
"defaultBranch": "默认分支",
"repoUrl": "仓库 URL",
"tagLabel": "标签",
"version": "版本",
"user": "用户",
"category": "分类"
},
"form": {
"name": "名称",
"nameStar": "名称 *",
"nameRequired": "请填写名称",
"code": "代码 (唯一标识)",
"desc": "描述",
"descOptional": "描述 (可选)",
"repoUrlStar": "仓库 URL *",
"registryUrlStar": "Registry URL *",
"nameAddrRequired": "请填写名称和地址",
"concurrent": "并发执行数",
"concurrentHint": "设为 1 则按顺序串行执行,默认 2 可并发构建",
"serial": "1 — 串行",
"gitCred": "Git 凭证",
"jobName": "Job 名称",
"envVars": "环境变量",
"deployMode": "部署模式",
"deployTarget": "部署目标",
"commitId": "Commit ID (可选)",
"dockerfilePath": "Dockerfile 路径",
"buildCache": "构建缓存",
"cachePaths": "多个路径用逗号分隔,相同的 Key 会命中已有缓存",
"registryAddr": "Registry 地址",
"imageName": "镜像命名:",
"varRef": "(${'{VAR_NAME}'} 引用)",
"scriptType": "脚本类型",
"scriptContent": "脚本内容",
"buildQueue": "构建队列",
"defaultNamespace": "默认命名空间",
"defaultEnabled": "默认启用",
"notSpecified": "不指定",
"save": "保存",
"cancel": "取消",
"create": "创建",
"update": "更新"
},
"toast": {
"saved": "已保存",
"updated": "已更新",
"deleted": "已删除",
"created": "已创建",
"enabled": "已启用",
"disabled": "已禁用",
"installed": "已安装",
"triggered": "已触发",
"stopped": "已停止",
"added": "已添加",
"removed": "已移除",
"revoked": "已撤销",
"approved": "已审批",
"rejected": "已驳回",
"cancelled": "已取消",
"expired": "已过期",
"rolledBack": "已回滚",
"redeployed": "已重新触发部署",
"assigned": "已分配",
"createdPipeline": "流水线已创建",
"releaseSubmitted": "发布申请已提交",
"deployStarted": "部署已启动",
"saveFailed": "保存失败",
"updateFailed": "更新失败",
"deleteFailed": "删除失败",
"createFailed": "创建失败",
"triggerFailed": "触发失败",
"stopFailed": "停止失败",
"addFailed": "添加失败",
"removeFailed": "移除失败",
"revokeFailed": "撤销失败",
"approveFailed": "审批失败",
"rejectFailed": "驳回失败",
"deployFailed": "部署失败",
"rollbackFailed": "回滚失败",
"redeployFailed": "重新部署失败",
"assignFailed": "分配失败",
"batchDeleteFailed": "批量删除失败",
"cancelFailed": "取消失败",
"operationFailed": "操作失败",
"getDataFailed": "获取数据失败",
"loadFailed": "加载失败",
"saveSuccess": "保存成功"
},
"label": {
"basicInfo": "基本信息",
"flowConfig": "流程配置",
"triggerSettings": "触发设置",
"variables": "变量",
"credentials": "凭据",
"environments": "环境",
"toolConfig": "工具配置",
"releaseConfig": "发布配置",
"releaseRecords": "发布记录",
"permission": "发布权限",
"userGroups": "用户组",
"roles": "角色",
"gitRepo": "Git 仓库 ({{count}})",
"registry": "镜像仓库 ({{count}})",
"envManage": "环境管理 ({{count}})",
"advanced": "高级",
"loading": "加载中...",
"emptyDir": "目录为空",
"browse": "浏览",
"record": "记录",
"log": "日志",
"run": "运行",
"execute": "执行",
"download": "下载",
"searchPlaceholder": "搜索名称、描述...",
"allStatus": "全部状态",
"allEnv": "全部环境",
"allType": "全部类型",
"pagination": "{{n}}条/页"
}
} }
} }