feat(i18n): 增量国际化迁移 — deploy/kubernetes/monitor/task 全模块 + 补全 28 缺失翻译键
迁移范围: - deploy 模块 (PipelineEditor/PipelineDetailDialog/PipelineFormDialog/PipelineRunDialog/ReleaseCreateDialog/ReleaseDetailDialog/ReleaseManager/ToolConfigTab/JobRoleCreateDialog 等 14 文件) - kubernetes 模块 (YamlEditorToolbar/DeploymentHpaTab/DeploymentLogsTab/DeploymentPodsTab/DnsHostSection/SchedulingSection/EventsTab/HPACronHPATab/HistoryTab/PodsTab/ServicesTab/ActionModals 等 12 文件) - monitor 模块 (AlertEventsTab/AlertCenterDetail/DatasourcePage/LogAlertBell/LogCenter/LogCenterArchBanner/StatChartPanel/LogRoleCreateDialog 等 8 文件) - task 模块 (CronJobStatsPanel/CronJobTable/CronJobViewDialog/ExecutionHistoryDialog 4 文件) - layout (PageEmpty/PageLoading 2 文件) - site-monitor/snmp-monitor 模块 (6 文件) 翻译键: 3975 → 4003 (+28 缺失键补全), 22 命名空间, zh-CN/en-US 完全对齐 新增命名空间: agent/aiops/cloud/kubernetes/monitor/pipeline/rbac/system/task/ui 验证: go build✅ tsc -b=0 npm build✅ (20.78s) 17/17 集成测试通过
This commit is contained in:
1 parent
eddf01dd79
commit
63e4c220d4
59 files changed
+6713
-641
No files matched your search
@@ -3,6 +3,7 @@ import {
|
||||
Area, Bar, BarChart, CartesianGrid, Cell, ComposedChart, Line,
|
||||
ReferenceArea, ReferenceLine, Tooltip, XAxis, YAxis,
|
||||
} from 'recharts';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Globe, Network, Radio, Shield, Wifi } from 'lucide-react';
|
||||
import type { SiteResult, SiteTask } from '../helpers';
|
||||
import { fmtMs, fmtSslDays, normalizeProbeType } from '../helpers';
|
||||
@@ -35,16 +36,18 @@ function SelectionArea({ left, right }: { left: string; right: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function HttpObs({ task, results, rangeLabel = '近 6 小时' }: Props) {
|
||||
function HttpObs({ task, results, rangeLabel }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const rl = rangeLabel ?? t('monitor.siteProtocol.rangeDefault');
|
||||
const s = analyzeHttpResults(results, task);
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{[
|
||||
{ label: `期望 ${s.expectedCode}`, value: s.okCount, tone: 'dg-text-green' },
|
||||
{ label: `${t('monitor.siteProtocol.http.expectedPrefix')} ${s.expectedCode}`, value: s.okCount, tone: 'dg-text-green' },
|
||||
{ label: '4xx', value: s.err4xx, tone: 'dg-text-yellow' },
|
||||
{ label: '5xx', value: s.err5xx, tone: 'dg-text-red' },
|
||||
{ label: '超时/其他', value: s.otherErr, tone: 'dg-text-red' },
|
||||
{ label: t('monitor.siteProtocol.http.timeoutOther'), value: s.otherErr, tone: 'dg-text-red' },
|
||||
].map((item) => (
|
||||
<div key={item.label} className="bg-[var(--dg-bg-secondary)] rounded-lg px-3 py-2 text-center">
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]">{item.label}</p>
|
||||
@@ -54,7 +57,7 @@ function HttpObs({ task, results, rangeLabel = '近 6 小时' }: Props) {
|
||||
</div>
|
||||
<SiteChartCard
|
||||
icon={<Globe className="h-3.5 w-3.5 text-[var(--dg-text-muted)]" />}
|
||||
title={`HTTP 状态码时序(${rangeLabel})`}
|
||||
title={`${t('monitor.siteProtocol.http.statusCodeTitle')}(${rl})`}
|
||||
empty={s.chart.length === 0}
|
||||
>
|
||||
{(h) => (
|
||||
@@ -64,8 +67,8 @@ function HttpObs({ task, results, rangeLabel = '近 6 小时' }: Props) {
|
||||
<CartesianGrid strokeDasharray="3 3" stroke={MONITOR_CHART_GRID} vertical={false} />
|
||||
<XAxis dataKey="time" tick={MONITOR_CHART_TICK} tickLine={false} axisLine={{ stroke: MONITOR_CHART_GRID }} interval="preserveStartEnd" />
|
||||
<YAxis tick={MONITOR_CHART_TICK} tickLine={false} axisLine={false} width={36} domain={[0, 'auto']} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => `HTTP ${v}`} nameFormatter={() => '状态码'} />} />
|
||||
<ReferenceLine y={s.expectedCode} stroke="var(--dg-green)" strokeDasharray="4 4" label={{ value: `期望${s.expectedCode}`, fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => `HTTP ${v}`} nameFormatter={() => t('monitor.siteProtocol.http.statusCodeName')} />} />
|
||||
<ReferenceLine y={s.expectedCode} stroke="var(--dg-green)" strokeDasharray="4 4" label={{ value: `${t('monitor.siteProtocol.http.expectedPrefix')}${s.expectedCode}`, fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Bar dataKey="code" radius={[2, 2, 0, 0]} maxBarSize={14} isAnimationActive={false}>
|
||||
{displayData.map((d, i) => (
|
||||
<Cell key={`${d.time}-${i}`} fill={d.ok ? 'var(--dg-green)' : d.code >= 500 ? 'var(--dg-red)' : d.code >= 400 ? '#eab308' : 'var(--dg-red)'} />
|
||||
@@ -77,22 +80,23 @@ function HttpObs({ task, results, rangeLabel = '近 6 小时' }: Props) {
|
||||
</MonitorRangeChartFrame>
|
||||
)}
|
||||
</SiteChartCard>
|
||||
<SiteEventTimeline title="4xx / 5xx / 超时事件" events={s.events} />
|
||||
<SiteEventTimeline title={t('monitor.siteProtocol.http.timelineTitle')} events={s.events} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SslObs({ task, results }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const s = analyzeSslResults(results, task);
|
||||
const sslInfo = fmtSslDays(s.days);
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{[
|
||||
{ label: '证书到期', value: s.expiry || '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: '剩余天数', value: sslInfo.text, tone: sslInfo.tone },
|
||||
{ label: '签发者', value: s.issuer ? (s.issuer.length > 16 ? `${s.issuer.slice(0, 16)}…` : s.issuer) : '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: '握手延迟', value: fmtMs(s.handshakeMs), tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: t('monitor.siteProtocol.ssl.expiry'), value: s.expiry || '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: t('monitor.siteProtocol.ssl.remainingDays'), value: sslInfo.text, tone: sslInfo.tone },
|
||||
{ label: t('monitor.siteProtocol.ssl.issuer'), value: s.issuer ? (s.issuer.length > 16 ? `${s.issuer.slice(0, 16)}…` : s.issuer) : '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: t('monitor.siteProtocol.ssl.handshakeLatency'), value: fmtMs(s.handshakeMs), tone: 'text-[var(--dg-text-primary)]' },
|
||||
].map((item) => (
|
||||
<div key={item.label} className="bg-[var(--dg-bg-secondary)] rounded-lg px-3 py-2 text-center">
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]">{item.label}</p>
|
||||
@@ -102,7 +106,7 @@ function SslObs({ task, results }: Props) {
|
||||
</div>
|
||||
<SiteChartCard
|
||||
icon={<Shield className="h-3.5 w-3.5 text-[var(--dg-text-muted)]" />}
|
||||
title="证书剩余天数趋势"
|
||||
title={t('monitor.siteProtocol.ssl.daysTrendTitle')}
|
||||
height={220}
|
||||
empty={s.chart.length === 0}
|
||||
>
|
||||
@@ -113,9 +117,9 @@ function SslObs({ task, results }: Props) {
|
||||
<CartesianGrid strokeDasharray="3 3" stroke={MONITOR_CHART_GRID} vertical={false} />
|
||||
<XAxis dataKey="time" tick={MONITOR_CHART_TICK} tickLine={false} axisLine={{ stroke: MONITOR_CHART_GRID }} />
|
||||
<YAxis tick={MONITOR_CHART_TICK} tickLine={false} axisLine={false} width={32} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => `${v} 天`} nameFormatter={() => '剩余'} />} />
|
||||
<ReferenceLine y={30} stroke="#eab308" strokeDasharray="4 4" label={{ value: '30天', fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<ReferenceLine y={7} stroke="var(--dg-red)" strokeDasharray="4 4" label={{ value: '7天', fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => `${v} ${t('monitor.siteProtocol.ssl.daysUnit')}`} nameFormatter={() => t('monitor.siteProtocol.ssl.daysName')} />} />
|
||||
<ReferenceLine y={30} stroke="#eab308" strokeDasharray="4 4" label={{ value: t('monitor.siteProtocol.ssl.ref30days'), fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<ReferenceLine y={7} stroke="var(--dg-red)" strokeDasharray="4 4" label={{ value: t('monitor.siteProtocol.ssl.ref7days'), fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Line type="monotone" dataKey="days" stroke="var(--dg-blue)" strokeWidth={2} dot={false} isAnimationActive={false} />
|
||||
<SelectionArea left={refLeft} right={refRight} />
|
||||
</ComposedChart>
|
||||
@@ -123,24 +127,26 @@ function SslObs({ task, results }: Props) {
|
||||
</MonitorRangeChartFrame>
|
||||
)}
|
||||
</SiteChartCard>
|
||||
<SiteEventTimeline title="证书 / 握手异常" events={s.events} />
|
||||
<SiteEventTimeline title={t('monitor.siteProtocol.ssl.timelineTitle')} events={s.events} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LatencyObs({ results, mode, rangeLabel = '近 6 小时' }: Props & { mode: 'PING' | 'DNS' }) {
|
||||
function LatencyObs({ results, mode, rangeLabel }: Props & { mode: 'PING' | 'DNS' }) {
|
||||
const { t } = useTranslation();
|
||||
const rl = rangeLabel ?? t('monitor.siteProtocol.rangeDefault');
|
||||
const s = mode === 'PING' ? analyzePingResults(results) : analyzeDnsResults(results);
|
||||
const label = mode === 'PING' ? 'PING 延迟波动' : 'DNS 解析延迟';
|
||||
const label = mode === 'PING' ? t('monitor.siteProtocol.latency.pingLabel') : t('monitor.siteProtocol.latency.dnsLabel');
|
||||
const Icon = mode === 'PING' ? Wifi : Radio;
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
|
||||
{[
|
||||
{ label: '平均', value: fmtMs(s.avg) },
|
||||
{ label: '最小', value: fmtMs(s.min) },
|
||||
{ label: '最大', value: fmtMs(s.max) },
|
||||
{ label: t('monitor.siteProtocol.latency.avg'), value: fmtMs(s.avg) },
|
||||
{ label: t('monitor.siteProtocol.latency.min'), value: fmtMs(s.min) },
|
||||
{ label: t('monitor.siteProtocol.latency.max'), value: fmtMs(s.max) },
|
||||
{ label: 'P95', value: fmtMs(s.p95) },
|
||||
{ label: '波动次数', value: String(s.spikeCount), tone: s.spikeCount > 0 ? 'dg-text-yellow' : undefined },
|
||||
{ label: t('monitor.siteProtocol.latency.spikeCount'), value: String(s.spikeCount), tone: s.spikeCount > 0 ? 'dg-text-yellow' : undefined },
|
||||
].map((item) => (
|
||||
<div key={item.label} className="bg-[var(--dg-bg-secondary)] rounded-lg px-3 py-2 text-center">
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]">{item.label}</p>
|
||||
@@ -150,7 +156,7 @@ function LatencyObs({ results, mode, rangeLabel = '近 6 小时' }: Props & { mo
|
||||
</div>
|
||||
<SiteChartCard
|
||||
icon={<Icon className="h-3.5 w-3.5 text-[var(--dg-text-muted)]" />}
|
||||
title={`${label}(${rangeLabel})`}
|
||||
title={`${label}(${rl})`}
|
||||
empty={s.chart.length === 0}
|
||||
>
|
||||
{(h) => (
|
||||
@@ -160,8 +166,8 @@ function LatencyObs({ results, mode, rangeLabel = '近 6 小时' }: Props & { mo
|
||||
<CartesianGrid strokeDasharray="3 3" stroke={MONITOR_CHART_GRID} vertical={false} />
|
||||
<XAxis dataKey="time" tick={MONITOR_CHART_TICK} tickLine={false} axisLine={{ stroke: MONITOR_CHART_GRID }} interval="preserveStartEnd" />
|
||||
<YAxis tick={MONITOR_CHART_TICK} tickLine={false} axisLine={false} width={42} tickFormatter={(v: number) => (v >= 1000 ? `${(v / 1000).toFixed(1)}s` : `${v}ms`)} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v, name) => (name === 'latency' ? fmtMs(v) : String(v))} nameFormatter={(name) => (name === 'latency' ? '延迟' : name)} />} />
|
||||
<ReferenceLine y={s.avg} stroke="var(--dg-blue)" strokeDasharray="4 4" label={{ value: '均值', fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v, name) => (name === 'latency' ? fmtMs(v) : String(v))} nameFormatter={(name) => (name === 'latency' ? t('monitor.siteProtocol.latency.latencyName') : name)} />} />
|
||||
<ReferenceLine y={s.avg} stroke="var(--dg-blue)" strokeDasharray="4 4" label={{ value: t('monitor.siteProtocol.latency.avgLabel'), fontSize: 10, fill: 'var(--dg-text-muted)' }} />
|
||||
<Line type="monotone" dataKey="latency" stroke="var(--dg-blue)" strokeWidth={2} dot={false} isAnimationActive={false} />
|
||||
<SelectionArea left={refLeft} right={refRight} />
|
||||
</ComposedChart>
|
||||
@@ -169,20 +175,22 @@ function LatencyObs({ results, mode, rangeLabel = '近 6 小时' }: Props & { mo
|
||||
</MonitorRangeChartFrame>
|
||||
)}
|
||||
</SiteChartCard>
|
||||
<SiteEventTimeline title="延迟尖峰 / 失败事件" events={s.events} />
|
||||
<SiteEventTimeline title={t('monitor.siteProtocol.latency.timelineTitle')} events={s.events} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TcpObs({ results, rangeLabel = '近 6 小时' }: Props) {
|
||||
function TcpObs({ results, rangeLabel }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const rl = rangeLabel ?? t('monitor.siteProtocol.rangeDefault');
|
||||
const s = analyzeTcpResults(results);
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
|
||||
{[
|
||||
{ label: `连通率(${rangeLabel})`, value: s.upRate, tone: 'dg-text-green' },
|
||||
{ label: '不通次数', value: String(s.failCount), tone: s.failCount > 0 ? 'dg-text-red' : 'text-[var(--dg-text-primary)]' },
|
||||
{ label: '最近失败', value: s.lastFailAt || '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
{ label: `${t('monitor.siteProtocol.tcp.upRate')}(${rl})`, value: s.upRate, tone: 'dg-text-green' },
|
||||
{ label: t('monitor.siteProtocol.tcp.failCount'), value: String(s.failCount), tone: s.failCount > 0 ? 'dg-text-red' : 'text-[var(--dg-text-primary)]' },
|
||||
{ label: t('monitor.siteProtocol.tcp.lastFail'), value: s.lastFailAt || '--', tone: 'text-[var(--dg-text-primary)]' },
|
||||
].map((item) => (
|
||||
<div key={item.label} className="bg-[var(--dg-bg-secondary)] rounded-lg px-3 py-2 text-center">
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]">{item.label}</p>
|
||||
@@ -192,7 +200,7 @@ function TcpObs({ results, rangeLabel = '近 6 小时' }: Props) {
|
||||
</div>
|
||||
<SiteChartCard
|
||||
icon={<Network className="h-3.5 w-3.5 text-[var(--dg-text-muted)]" />}
|
||||
title="TCP 连通状态时序"
|
||||
title={t('monitor.siteProtocol.tcp.statusTitle')}
|
||||
height={200}
|
||||
empty={s.chart.length === 0}
|
||||
>
|
||||
@@ -202,7 +210,7 @@ function TcpObs({ results, rangeLabel = '近 6 小时' }: Props) {
|
||||
<ComposedChart data={displayData} margin={{ top: 4, right: 8, left: 0, bottom: 4 }} {...chartHandlers}>
|
||||
<XAxis dataKey="time" tick={MONITOR_CHART_TICK} tickLine={false} axisLine={{ stroke: MONITOR_CHART_GRID }} interval="preserveStartEnd" />
|
||||
<YAxis hide domain={[0, 100]} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => (v >= 100 ? '连通' : '不通')} nameFormatter={() => '状态'} />} />
|
||||
<Tooltip content={<MonitorChartTooltip valueFormatter={(v) => (v >= 100 ? t('monitor.siteProtocol.tcp.connected') : t('monitor.siteProtocol.tcp.disconnected'))} nameFormatter={() => t('monitor.siteProtocol.tcp.statusName')} />} />
|
||||
<Area type="stepAfter" dataKey="up" stroke="var(--dg-green)" fill="var(--dg-green)" fillOpacity={0.2} isAnimationActive={false} />
|
||||
<SelectionArea left={refLeft} right={refRight} />
|
||||
</ComposedChart>
|
||||
@@ -210,7 +218,7 @@ function TcpObs({ results, rangeLabel = '近 6 小时' }: Props) {
|
||||
</MonitorRangeChartFrame>
|
||||
)}
|
||||
</SiteChartCard>
|
||||
<SiteEventTimeline title="TCP 不通时间点" events={s.events} emptyText="近期 TCP 均连通" />
|
||||
<SiteEventTimeline title={t('monitor.siteProtocol.tcp.timelineTitle')} events={s.events} emptyText={t('monitor.siteProtocol.tcp.emptyText')} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -222,4 +230,4 @@ export function SiteProtocolObs({ task, results, rangeLabel }: Props) {
|
||||
if (type === 'DNS') return <LatencyObs task={task} results={results} mode="DNS" rangeLabel={rangeLabel} />;
|
||||
if (type === 'TCP') return <TcpObs task={task} results={results} rangeLabel={rangeLabel} />;
|
||||
return <HttpObs task={task} results={results} rangeLabel={rangeLabel} />;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user