diff --git a/ROADMAP.md b/ROADMAP.md index 1e3c93e..de8a865 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -522,7 +522,8 @@ services/api.ts (1324L) | U31 | AIOps Agent CLI 组件 i18n 修复(AgentCLI + AgentCLIToolbar + AgentCLIHistory + AgentCLIEmptyState + ChatInputArea + agent-cli-constants.ts 6 文件 — Q7/Q35 拆分后丢失的 i18n 集成全部修复,新增 `aiops.cli.*` 命名空间 100 翻译键(8 子分类: toolbar/safety/tips/error/info/viewMode/placeholder/history/empty/input),SAFETY_MODES+TIPS_HOST+TIPS_KUBERNETES 常量数组改为 `getSafetyModes(t)`/`getTipsHost(t)`/`getTipsKubernetes(t)` 接收 TFunction 参数的工厂函数,全部 UI 硬编码中文清零,zh/en 7381→7481 +100 键对齐,tsc -b=0,npm build✓ (18.21s),ESLint=0/53/0,go build=0,17/17 测试通过) | P3 | **done** | | U32 | 全量 hash key 清理 + React Hooks 警告修复(151 个 hash-style flat key (s+hex 后缀) 全部重命名为语义化 nested key — monitor 58/kubernetes 42/aiops 17/agent 12/cloud 13/pipeline 6/system 3;58 个源文件 147 处 t()/i18n.t() 调用更新;3 个命名空间冲突修复(monitor.hostMonitor/agent.agentMonitor/aiops.aiAnalysisResult 原 string → .title 子键);React Hooks 警告 53→43 (-10): exhaustive-deps 4→0 + preserve-manual-memoization 5→0 + 变量遮蔽修复(filter(t)→filter(tg));zh/en 7480=7480 完全对齐 0 hash key 残留;tsc -b=0,npm build✓ (17.59s),ESLint=0/43/any=0,go build=0,17/17 测试通过) | P3 | **done** | | U33 | K8s 资源编辑器 + Pod 日志/Metrics i18n 补全(resource-visual-editors/ 5 文件: ConfigMap/Secret/Service/Ingress/PvcEditor 按钮文案+帮助文本+访问模式+IngressClass 提示全部 i18n;pod-logs-viewer/ 3 文件: ControlBar 导出/刷新/实时/停止+LogContentArea 加载中+LogsHeader 标题;PodLogsViewer 6 处错误消息+DialogTitle/Description;PodMetricsPage subtitle+表头+所有命名空间;17 处 toast description 模板字面量中文→i18n.t() 插值 (DeploymentEditAdvanced/Containers/Storage/View/Detail/Service/ResourceVisualEditor/NamespaceResourcePage/ClusterOverviewPage);5 处 confirm description (DeploymentView/EditService/Detail/WorkloadViewPage/MiddlewareMonitor/SiteMonitor/HealthProbeSection);5 处 subtitle 模板字面量 (PodMetricsPage/CapacityPage/EventsPage/KubernetesNodes/ClusterOverviewPage);新增 k8s.rve 14键+k8s.toast 18键+k8s.podMetrics 4键+k8s.podLogs 13键 共 49 翻译键;zh/en 7481→7524 +43 对齐;tsc -b=0,npm build✓ (17.76s),ESLint=0/43/any=0,go build=0,17/17 测试通过) | P3 | **done** | -| U34 | System & User 模块 i18n 清理(ProfilePage + ResetPasswordDialog + SystemRolesTab + LdapManagementSection 4 文件 — ProfilePage 从零接入 useTranslation + ResetPasswordDialog 从零接入 useTranslation + SystemRolesTab 权限分组标签(云资源/自动化/审批/审计)+toast+confirm description+角色计数+空状态+权限列表计数+编码标签+尾部文案全部 i18n + LdapManagementSection 验证按钮+根OU标签+创建按钮+导入按钮+编辑用户描述全部 i18n;新增 user.profile.* 14键+user.resetPwd.* 11键+system.* 16键 共 41 翻译键;UI 硬编码中文 ProfilePage 15→0 + ResetPasswordDialog 11→0 + SystemRolesTab 12→0 + LdapManagementSection 8→0;zh/en 7524→7565 +41 对齐;tsc -b=0,npm build✓ (16.05s),ESLint=0/43/any=0,go build=0,17/17 测试通过) | P3 | **done** | +| U34 | System & User 模块 i18n 清理(ProfilePage + ResetPasswordDialog + SystemRolesTab + LdapManagementSection 4 文件 — ProfilePage 从零接入 useTranslation + ResetPasswordDialog 从零接入 useTranslation + SystemRolesTab 权限分组标签(云资源/自动化/审批/审计)+toast+confirm description+角色计数+空状态+权限列表计数+编码标签+尾部文案全部 i18n + LdapManagementSection 验证按钮+根OU标签+创建按钮+导入按钮+编辑用户描述全部 i18n;新增 user.profile.* 14键+user.resetPwd.* 11键+system.* 16键 共 41 翻译键;UI 硬编码中文 ProfilePage 15→0 + ResetPasswordDialog 11→0 + SystemRolesTab 12→0 + LdapManagementSection 8→0;zh/en 7524→7565 +41 对齐;tsc -b=0, npm build✓ (16.05s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | +| U35 | Deploy + Task 模块残余 JSX 硬编码中文清理(PipelineRunPanel 12处 + CronJobTable 12处 + ExecutionHistoryDialog 10处 + ScrollButtons 2处 — 新增 deploy.runStatus.* 12键 + task.cronJobCol.* 14键 + task.execHistory.* 14键 + deploy.credCol.* 9键 + common.scrollToTop/scrollToBottom/success/failed/total 5键 共 54 翻译键;zh/en 7565→7616 +51 对齐;tsc -b=0, npm build✓ (17.02s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** | --- diff --git a/frontend/src/components/ScrollButtons.tsx b/frontend/src/components/ScrollButtons.tsx index 8dbbcd4..4ee5098 100644 --- a/frontend/src/components/ScrollButtons.tsx +++ b/frontend/src/components/ScrollButtons.tsx @@ -1,6 +1,7 @@ // ScrollButtons.tsx — 浮动滚动按钮(回到顶部/底部),AgentCLI 对话区复用 import { Button } from '@/components/ui/button'; import { ChevronUp, ChevronDown } from 'lucide-react'; +import i18n from '@/i18n'; export interface ScrollButtonsProps { show: boolean; @@ -21,7 +22,7 @@ export default function ScrollButtons({ show, atTop, atBottom, onScrollTop, onSc size="icon" className="h-8 w-8 rounded-full shadow-md border border-[var(--dg-border)] bg-[var(--surface-raised)]/95 opacity-90 hover:opacity-100" onClick={onScrollTop} - title="回到顶部" + title={i18n.t('common.scrollToTop')} > @@ -33,7 +34,7 @@ export default function ScrollButtons({ show, atTop, atBottom, onScrollTop, onSc size="icon" className="h-8 w-8 rounded-full shadow-md border border-[var(--dg-border)] bg-[var(--surface-raised)]/95 opacity-90 hover:opacity-100" onClick={onScrollBottom} - title="回到底部" + title={i18n.t('common.scrollToBottom')} > diff --git a/frontend/src/components/deploy/pipeline-manager/PipelineRunPanel.tsx b/frontend/src/components/deploy/pipeline-manager/PipelineRunPanel.tsx index a36c28a..1de8058 100644 --- a/frontend/src/components/deploy/pipeline-manager/PipelineRunPanel.tsx +++ b/frontend/src/components/deploy/pipeline-manager/PipelineRunPanel.tsx @@ -74,7 +74,7 @@ function PipelineQueuePanel({ pipeline }: { pipeline: Record }) {running}/{max} {queued > 0 && ( - 构建队列 ({queued}) + {i18n.t('deploy.runStatus.buildQueue')} ({queued}) )} @@ -90,7 +90,7 @@ function PipelineQueuePanel({ pipeline }: { pipeline: Record }) {String(run.triggered_by || '-')} ))} @@ -106,7 +106,7 @@ function PipelineQueuePanel({ pipeline }: { pipeline: Record }) Run #{id} ))} @@ -163,19 +163,19 @@ export function PipelineRunPanel({ pipeline, pipelineRuns, isLoadingRuns, onStop {r.status === 'success' ? ( - 成功 + {i18n.t('deploy.runStatus.success')} ) : r.status === 'failed' ? ( - 失败 + {i18n.t('deploy.runStatus.failed')} ) : r.status === 'running' ? ( - 执行中 + {i18n.t('deploy.runStatus.running')} ) : r.status === 'cancelled' ? ( - 已停止 + {i18n.t('deploy.runStatus.cancelled')} ) : ( {String(r.status)} @@ -189,11 +189,11 @@ export function PipelineRunPanel({ pipeline, pipelineRuns, isLoadingRuns, onStop
{(r.status === 'running' || r.status === 'pending') && ( )}
@@ -208,14 +208,14 @@ export function PipelineRunPanel({ pipeline, pipelineRuns, isLoadingRuns, onStop - 执行日志 #{String(logRun?.build_number ?? logRun?.id ?? '')} + {i18n.t('deploy.runStatus.execLog', { number: String(logRun?.build_number ?? logRun?.id ?? '') })}
- 触发方式: {String(logRun?.triggered_by || 'manual')} - 分支: {String(logRun?.branch || '-')} - 耗时: {fmtDuration(logRun?.duration as number | undefined)} + {i18n.t('deploy.runStatus.triggerMethod')} {String(logRun?.triggered_by || 'manual')} + {i18n.t('deploy.runStatus.branch')} {String(logRun?.branch || '-')} + {i18n.t('deploy.runStatus.duration')} {fmtDuration(logRun?.duration as number | undefined)}
{logs.length === 0 ? ( diff --git a/frontend/src/components/task/CronJobTable.tsx b/frontend/src/components/task/CronJobTable.tsx index 9e5e1c3..0c9cd8e 100644 --- a/frontend/src/components/task/CronJobTable.tsx +++ b/frontend/src/components/task/CronJobTable.tsx @@ -48,14 +48,14 @@ export function CronJobTable({ className="border-[var(--dg-border)]" /> - 任务 - 调度 - 类型 - 开关 - 最近 - 上次执行 - 成功率 - 操作 + {t('task.cronJobCol.task')} + {t('task.cronJobCol.schedule')} + {t('task.cronJobCol.type')} + {t('task.cronJobCol.switch')} + {t('task.cronJobCol.recent')} + {t('task.cronJobCol.lastExec')} + {t('task.cronJobCol.successRate')} + {t('task.cronJobCol.actions')} @@ -122,7 +122,7 @@ export function CronJobTable({ variant="ghost" size="icon" className="h-7 w-7 dg-text-green hover:bg-emerald-500/10" - title="立即执行" + title={t('task.cronJobCol.execNow')} disabled={isExecuting} onClick={() => onExecute(job.id)} > @@ -136,7 +136,7 @@ export function CronJobTable({ variant="ghost" size="icon" className="h-7 w-7" - title="执行历史" + title={t('task.cronJobCol.execHistory')} onClick={() => onHistory(job)} > @@ -145,7 +145,7 @@ export function CronJobTable({ variant="ghost" size="icon" className="h-7 w-7" - title={job.enabled ? '禁用' : '启用'} + title={job.enabled ? t('task.cronJobCol.disable') : t('task.cronJobCol.enable')} onClick={() => onToggle(job.id)} > {job.enabled ? : } @@ -155,7 +155,7 @@ export function CronJobTable({ variant="ghost" size="icon" className="h-7 w-7" - title="编辑" + title={t('task.cronJobCol.edit')} onClick={() => onEdit(job)} > @@ -166,7 +166,7 @@ export function CronJobTable({ variant="ghost" size="icon" className="h-7 w-7" - title="删除" + title={t('task.cronJobCol.delete')} onClick={() => onDelete(job)} > diff --git a/frontend/src/components/task/ExecutionHistoryDialog.tsx b/frontend/src/components/task/ExecutionHistoryDialog.tsx index 541b408..36cc015 100644 --- a/frontend/src/components/task/ExecutionHistoryDialog.tsx +++ b/frontend/src/components/task/ExecutionHistoryDialog.tsx @@ -118,7 +118,7 @@ export function ExecutionHistoryDialog({ [executions, viewingExecId], ); - const title = taskName ? `执行历史 — ${taskName}` : '全部执行历史'; + const title = taskName ? `${t('task.execHistory.title')} — ${taskName}` : t('task.execHistory.title'); return ( @@ -126,7 +126,7 @@ export function ExecutionHistoryDialog({ {title} - 近 7 天趋势与执行日志(最近 100 条) + {t('task.execHistory.recentTrend', { defaultValue: '近 7 天趋势与执行日志(最近 100 条)' })} @@ -137,7 +137,7 @@ export function ExecutionHistoryDialog({ ) : executions.length === 0 ? (
-

暂无执行记录

+

{t('task.execHistory.noRecords', { defaultValue: '暂无执行记录' })}

) : (
@@ -146,27 +146,27 @@ export function ExecutionHistoryDialog({
{stats.success}
-
成功 · {stats.successRate}%
+
{t('common.success', { defaultValue: '成功' })} · {stats.successRate}%
{stats.failed}
-
失败 · {stats.failedRate}%
+
{t('common.failed', { defaultValue: '失败' })} · {stats.failedRate}%
{stats.total}
-
总计
+
{t('common.total', { defaultValue: '总计' })}
-
最近 7 天
+
{t('task.execHistory.last7days', { defaultValue: '最近 7 天' })}
{trend.map((item) => { const heightPct = item.total > 0 ? Math.max((item.total / trendMax) * 100, 12) : 4; @@ -197,10 +197,10 @@ export function ExecutionHistoryDialog({ - {!taskId && 任务} - 状态 - 耗时 - 执行时间 + {!taskId && {t('task.cronJobCol.task')}} + {t('task.execHistory.status')} + {t('task.execHistory.duration')} + {t('task.execHistory.startTime')} @@ -256,7 +256,7 @@ export function ExecutionHistoryDialog({
{viewingExec && !viewingExec.output && ( -

该记录无输出日志

+

{t('task.execHistory.noOutput')}

)}
)} diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 8d45e77..4c420b3 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -514,7 +514,9 @@ "request.tokenExpired": "Session expired, please log in again", "days": "days", "seconds": "sec", - "copyManually": "Please manually select and copy" + "copyManually": "Please manually select and copy", + "scrollToTop": "Scroll to top", + "scrollToBottom": "Scroll to bottom" }, "menu": { "dashboard": "Dashboard", @@ -2381,6 +2383,31 @@ "namePlaceholder": "e.g., Backend Team", "subtitle": "User groups - batch authorize pipeline access", "memberCount": "Total Members" + }, + "runStatus": { + "success": "Success", + "failed": "Failed", + "running": "Running", + "cancelled": "Stopped", + "cancel": "Cancel", + "log": "Log", + "stop": "Stop", + "execLog": "Execution Log #{{number}}", + "triggerMethod": "Trigger:", + "branch": "Branch:", + "duration": "Duration:", + "buildQueue": "Build Queue" + }, + "credCol": { + "name": "Credential Name", + "type": "Type", + "tags": "Tags", + "actions": "Actions", + "used": "Used", + "unused": "Unused", + "copyRef": "Copy Reference ID", + "testConn": "Test Connection", + "noTags": "No tags" } }, "k8s": { @@ -5218,6 +5245,38 @@ "toastExecConfirm": "Confirm batch execution", "toastExecConfirmDesc": "This will execute the command on {{count}} hosts. Please verify the command is safe:\n\n{{command}}", "noOutput": "(no output)" + }, + "cronJobCol": { + "task": "Task", + "schedule": "Schedule", + "type": "Type", + "switch": "Toggle", + "recent": "Recent", + "lastExec": "Last Run", + "successRate": "Success Rate", + "actions": "Actions", + "execNow": "Execute Now", + "execHistory": "Run History", + "disable": "Disable", + "enable": "Enable", + "edit": "Edit", + "delete": "Delete" + }, + "execHistory": { + "title": "Execution History", + "exitCode": "Exit Code", + "output": "Output", + "duration": "Duration", + "startTime": "Start Time", + "endTime": "End Time", + "target": "Target", + "status": "Status", + "noOutput": "No output", + "copyOutput": "Copy Output", + "copied": "Copied to clipboard", + "recentTrend": "Last 7 days trends and execution logs (latest 100)", + "noRecords": "No execution records", + "last7days": "Last 7 days" } }, "rbac": { diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index 5832f63..b186e63 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -514,7 +514,9 @@ "request.tokenExpired": "登录已过期,请重新登录", "days": "天", "seconds": "秒", - "copyManually": "请手动选中内容后复制" + "copyManually": "请手动选中内容后复制", + "scrollToTop": "回到顶部", + "scrollToBottom": "回到底部" }, "menu": { "dashboard": "仪表盘", @@ -2381,6 +2383,31 @@ "namePlaceholder": "例如: 后端开发组", "subtitle": "用户组 — 批量授权流水线访问权限", "memberCount": "成员总数" + }, + "runStatus": { + "success": "成功", + "failed": "失败", + "running": "执行中", + "cancelled": "已停止", + "cancel": "取消", + "log": "日志", + "stop": "停止", + "execLog": "执行日志 #{{number}}", + "triggerMethod": "触发方式:", + "branch": "分支:", + "duration": "耗时:", + "buildQueue": "构建队列" + }, + "credCol": { + "name": "凭据名称", + "type": "类型", + "tags": "标签", + "actions": "操作", + "used": "已使用", + "unused": "未使用", + "copyRef": "复制引用ID", + "testConn": "测试连接", + "noTags": "无标签" } }, "k8s": { @@ -5218,6 +5245,38 @@ "toastExecConfirm": "确认批量执行命令", "toastExecConfirmDesc": "将在 {{count}} 台主机上执行该命令,请确认命令安全:\n\n{{command}}", "noOutput": "(无输出)" + }, + "cronJobCol": { + "task": "任务", + "schedule": "调度", + "type": "类型", + "switch": "开关", + "recent": "最近", + "lastExec": "上次执行", + "successRate": "成功率", + "actions": "操作", + "execNow": "立即执行", + "execHistory": "执行历史", + "disable": "禁用", + "enable": "启用", + "edit": "编辑", + "delete": "删除" + }, + "execHistory": { + "title": "执行历史", + "exitCode": "退出码", + "output": "输出", + "duration": "耗时", + "startTime": "开始时间", + "endTime": "结束时间", + "target": "目标", + "status": "状态", + "noOutput": "暂无输出", + "copyOutput": "复制输出", + "copied": "已复制到剪贴板", + "recentTrend": "近 7 天趋势与执行日志(最近 100 条)", + "noRecords": "暂无执行记录", + "last7days": "最近 7 天" } }, "rbac": {