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
@@ -1,4 +1,5 @@
|
||||
// DnsHostSection.tsx — DNS 配置 + 主机别名 // Logan.Li
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Globe, MapPin, Plus, Trash2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -36,6 +37,7 @@ export function DnsHostSection({
|
||||
hostAliases,
|
||||
onHostAliasesChange,
|
||||
}: DnsHostSectionProps) {
|
||||
const { t } = useTranslation();
|
||||
const addDnsOption = () => onDnsOptionsChange([...dnsOptions, { name: '', value: '' }]);
|
||||
const updateDnsOption = (index: number, patch: Partial<DnsOptionEntry>) =>
|
||||
onDnsOptionsChange(dnsOptions.map((o, i) => (i === index ? { ...o, ...patch } : o)));
|
||||
@@ -53,16 +55,16 @@ export function DnsHostSection({
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Globe className="h-4 w-4 text-indigo-400" />DNS 配置 (dnsConfig)
|
||||
<Globe className="h-4 w-4 text-indigo-400" />{t('k8s.dnsHost.dnsConfigTitle')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-3">
|
||||
<p className="text-[11px] dg-text-muted">
|
||||
提示:dnsConfig 通常与 <code className="dg-text-secondary">dnsPolicy: None</code> 搭配使用。每行一个值。
|
||||
{t('k8s.dnsHost.hintPrefix')} <code className="dg-text-secondary">dnsPolicy: None</code> {t('k8s.dnsHost.hintSuffix')}
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="dg-text-muted text-xs">nameservers(每行一个 IP)</Label>
|
||||
<Label className="dg-text-muted text-xs">{t('k8s.dnsHost.nameservers')}</Label>
|
||||
<textarea
|
||||
value={dnsNameservers}
|
||||
onChange={e => onDnsNameserversChange(e.target.value)}
|
||||
@@ -72,7 +74,7 @@ export function DnsHostSection({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="dg-text-muted text-xs">searches(搜索域,每行一个)</Label>
|
||||
<Label className="dg-text-muted text-xs">{t('k8s.dnsHost.searches')}</Label>
|
||||
<textarea
|
||||
value={dnsSearches}
|
||||
onChange={e => onDnsSearchesChange(e.target.value)}
|
||||
@@ -84,13 +86,13 @@ export function DnsHostSection({
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<Label className="dg-text-secondary text-xs">options(DNS 选项)</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.dnsHost.options')}</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={addDnsOption}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
<Plus className="h-3 w-3 mr-1" />{t('common.add')}
|
||||
</Button>
|
||||
</div>
|
||||
{dnsOptions.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted italic">未配置</p>
|
||||
<p className="text-xs dg-text-muted italic">{t('k8s.dnsHost.notConfigured')}</p>
|
||||
) : (
|
||||
dnsOptions.map((o, i) => (
|
||||
<div key={i} className="flex items-center gap-2 mb-1.5">
|
||||
@@ -104,7 +106,7 @@ export function DnsHostSection({
|
||||
<Input
|
||||
value={o.value}
|
||||
onChange={e => updateDnsOption(i, { value: e.target.value })}
|
||||
placeholder="5(可留空)"
|
||||
placeholder={`5${t('k8s.dnsHost.optionalHint')}`}
|
||||
className="flex-1 h-7 dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
<Button size="icon" variant="ghost" className="h-6 w-6 dg-text-red" onClick={() => removeDnsOption(i)}>
|
||||
@@ -120,18 +122,18 @@ export function DnsHostSection({
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<MapPin className="h-4 w-4 dg-text-yellow" />主机别名 (hostAliases)
|
||||
<MapPin className="h-4 w-4 dg-text-yellow" />{t('k8s.dnsHost.hostAliasTitle')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-2">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<Label className="dg-text-secondary text-xs">IP → 主机名映射(注入 Pod 的 /etc/hosts)</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.dnsHost.hostAliasHint')}</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={addHostAlias}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
<Plus className="h-3 w-3 mr-1" />{t('common.add')}
|
||||
</Button>
|
||||
</div>
|
||||
{hostAliases.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted italic">未配置</p>
|
||||
<p className="text-xs dg-text-muted italic">{t('k8s.dnsHost.notConfigured')}</p>
|
||||
) : (
|
||||
hostAliases.map((a, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
@@ -158,4 +160,4 @@ export function DnsHostSection({
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// SchedulingSection.tsx — 调度:节点名称 / 标签选择器 / 节点亲和性 // Logan.Li
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Loader2, Plus, Server, Trash2 } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -31,10 +32,10 @@ export interface SchedulingSectionProps {
|
||||
nodeLabels: Record<string, string[]>;
|
||||
}
|
||||
|
||||
const SCHEDULE_MODES: Array<{ key: ScheduleMode; label: string }> = [
|
||||
{ key: 'nodeName', label: '节点名称' },
|
||||
{ key: 'nodeSelector', label: '标签选择器' },
|
||||
{ key: 'nodeAffinity', label: '节点亲和性' },
|
||||
const SCHEDULE_MODES: Array<{ key: ScheduleMode }> = [
|
||||
{ key: 'nodeName' },
|
||||
{ key: 'nodeSelector' },
|
||||
{ key: 'nodeAffinity' },
|
||||
];
|
||||
|
||||
export function SchedulingSection({
|
||||
@@ -50,12 +51,13 @@ export function SchedulingSection({
|
||||
onUpdateLabelSelector,
|
||||
nodeLabels,
|
||||
}: SchedulingSectionProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Server className="h-4 w-4 dg-text-green" />调度 (Scheduling)
|
||||
<Server className="h-4 w-4 dg-text-green" />{t('k8s.scheduling.title')}
|
||||
</CardTitle>
|
||||
<div className="flex items-center gap-1 bg-[var(--dg-bg-tertiary)] rounded-lg p-0.5 border border-[var(--dg-border)]">
|
||||
{SCHEDULE_MODES.map(m => (
|
||||
@@ -68,24 +70,24 @@ export function SchedulingSection({
|
||||
: 'dg-text-secondary hover:text-[var(--dg-text-secondary)]'
|
||||
}`}
|
||||
>
|
||||
{m.label}
|
||||
{t(`k8s.scheduling.mode.${m.key}`)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs dg-text-muted mt-1">
|
||||
{scheduleMode === 'nodeName' && 'Pod 将直接调度到指定节点'}
|
||||
{scheduleMode === 'nodeSelector' && 'Pod 将调度到匹配标签的节点'}
|
||||
{scheduleMode === 'nodeAffinity' && '通过亲和性规则控制 Pod 调度到指定节点'}
|
||||
{scheduleMode === 'nodeName' && t('k8s.scheduling.hint.nodeName')}
|
||||
{scheduleMode === 'nodeSelector' && t('k8s.scheduling.hint.nodeSelector')}
|
||||
{scheduleMode === 'nodeAffinity' && t('k8s.scheduling.hint.nodeAffinity')}
|
||||
</p>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0">
|
||||
{scheduleMode === 'nodeName' && (
|
||||
<div className="space-y-2">
|
||||
<Label className="dg-text-secondary text-xs">请选择节点</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.scheduling.selectNode')}</Label>
|
||||
{nodesLoading ? (
|
||||
<div className="flex items-center gap-1 dg-text-muted text-xs">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />加载节点列表...
|
||||
<Loader2 className="h-3 w-3 animate-spin" />{t('k8s.scheduling.loadingNodes')}
|
||||
</div>
|
||||
) : (
|
||||
<select
|
||||
@@ -93,7 +95,7 @@ export function SchedulingSection({
|
||||
onChange={e => onNodeNameChange(e.target.value)}
|
||||
className="h-8 w-full bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-2"
|
||||
>
|
||||
<option value="">(不指定)</option>
|
||||
<option value="">{t('k8s.scheduling.notSpecified')}</option>
|
||||
{availableNodes.map(n => (
|
||||
<option key={n.name} value={n.name}>
|
||||
{n.name} {n.ip ? `(${n.ip})` : ''}
|
||||
@@ -103,7 +105,7 @@ export function SchedulingSection({
|
||||
)}
|
||||
{nodeName && (
|
||||
<div className="text-[10px] dg-text-muted">
|
||||
已选择: <code className="bg-[var(--dg-bg-tertiary)] px-1 py-0.5 rounded dg-text-green">{nodeName}</code>
|
||||
{t('k8s.scheduling.selected')} <code className="bg-[var(--dg-bg-tertiary)] px-1 py-0.5 rounded dg-text-green">{nodeName}</code>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -112,13 +114,13 @@ export function SchedulingSection({
|
||||
{scheduleMode === 'nodeSelector' && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="dg-text-secondary text-xs">请选择标签</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.scheduling.selectLabel')}</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={onAddLabelSelector}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
<Plus className="h-3 w-3 mr-1" />{t('k8s.scheduling.add')}
|
||||
</Button>
|
||||
</div>
|
||||
{labelSelectorKv.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted italic">未配置标签选择器</p>
|
||||
<p className="text-xs dg-text-muted italic">{t('k8s.scheduling.noLabelSelector')}</p>
|
||||
) : (
|
||||
labelSelectorKv.map((n, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
@@ -127,7 +129,7 @@ export function SchedulingSection({
|
||||
onChange={e => onUpdateLabelSelector(i, { key: e.target.value, value: '' })}
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
>
|
||||
<option value="">选择标签</option>
|
||||
<option value="">{t('k8s.scheduling.selectLabelPlaceholder')}</option>
|
||||
{Object.entries(nodeLabels).map(([k, vals]) => (
|
||||
<option key={k} value={k}>{k} ({vals.length})</option>
|
||||
))}
|
||||
@@ -138,7 +140,7 @@ export function SchedulingSection({
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
disabled={!n.key}
|
||||
>
|
||||
<option value="">选择值</option>
|
||||
<option value="">{t('k8s.scheduling.selectValuePlaceholder')}</option>
|
||||
{(nodeLabels[n.key] || []).map(v => (
|
||||
<option key={v} value={v}>{v}</option>
|
||||
))}
|
||||
@@ -161,14 +163,14 @@ export function SchedulingSection({
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="dg-text-secondary text-xs">
|
||||
请选择标签 <span className="dg-text-muted">(生成 requiredDuringScheduling 规则)</span>
|
||||
{t('k8s.scheduling.selectLabelAffinity')} <span className="dg-text-muted">{t('k8s.scheduling.affinityRuleHint')}</span>
|
||||
</Label>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-secondary" onClick={onAddLabelSelector}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
<Plus className="h-3 w-3 mr-1" />{t('k8s.scheduling.add')}
|
||||
</Button>
|
||||
</div>
|
||||
{labelSelectorKv.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted italic">未配置亲和性规则</p>
|
||||
<p className="text-xs dg-text-muted italic">{t('k8s.scheduling.noAffinityRule')}</p>
|
||||
) : (
|
||||
labelSelectorKv.map((n, i) => (
|
||||
<div key={i} className="flex items-center gap-2">
|
||||
@@ -177,7 +179,7 @@ export function SchedulingSection({
|
||||
onChange={e => onUpdateLabelSelector(i, { key: e.target.value, value: '' })}
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
>
|
||||
<option value="">选择标签</option>
|
||||
<option value="">{t('k8s.scheduling.selectLabelPlaceholder')}</option>
|
||||
{Object.entries(nodeLabels).map(([k, vals]) => (
|
||||
<option key={k} value={k}>{k} ({vals.length})</option>
|
||||
))}
|
||||
@@ -188,7 +190,7 @@ export function SchedulingSection({
|
||||
className="flex-1 h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1.5"
|
||||
disabled={!n.key}
|
||||
>
|
||||
<option value="">选择值</option>
|
||||
<option value="">{t('k8s.scheduling.selectValuePlaceholder')}</option>
|
||||
{(nodeLabels[n.key] || []).map(v => (
|
||||
<option key={v} value={v}>{v}</option>
|
||||
))}
|
||||
|
||||
Reference in new issue
Block a user