refactor(i18n): U43 深度残余硬编码中文 UI 文本清零 — 17 文件 ~40 处→0
趋势标签(上升/下降/平稳) + K8s 卡片标题(Pod级别/安全上下文/实例/详情) + data-table 默认值(搜索/暂无数据) + Deployment 编辑器标签(数据卷/挂载/只读写/manifest提示/镜像拉取凭证) + HostSettings 4 个命名空间描述 + 7 个 K8s 页面刷新按钮 + 资源编辑器新建/编辑 + Agent 执行命令描述 + 账单保存成功 toast + 容量预警标题 新增 common 30 语义化翻译键, zh/en 7898→7928 对齐 tsc -b=0, npm build✓ (16.55s), ESLint=0/43/any=0, go build=0, 17/17 测试通过
This commit is contained in:
1 parent
c6e0d6ca57
commit
39a4432f79
26 files changed
+117
-62
No files matched your search
@@ -529,6 +529,7 @@ services/api.ts (1324L)
|
||||
| U39 | 残余 JSX 属性/模板字面量中文清零(10 文件 14 处→0: DualLineChart subtitle 接收/发送 + NetworkTab 5处 unit="个" + FDUsageCard subtitle 当前 + NamespaceOverviewPage/NamespaceManagementPage subtitle + CreateHPADialog title+text 命名空间 + LogFieldSidebar title 个值 + LiveMonitorDialog title 全屏/退出全屏 + ExecutionHistoryDialog title 成功/失败 + LdapSettingsTab className 成功检查→ldapTestSuccess boolean 状态替代字符串匹配 — 新增 11 翻译键, zh/en 7751→7762 对齐;tsc -b=0, npm build✓ (16.94s), ESLint=0/0/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
| U40 | Monitor + Agent 子组件残余硬编码中文 i18n 补全(14 文件 ~50 处→0: ContextSwitchCard CTX/IRQ/次 + ProcessTable agentWaitData/cpuUsagePercent + FDUsageCard fdHandles + PortMonitorTab 黑名单/白名单/策略配置/暂无端口数据 + PortPolicyDialog 白名单全量上报/黑名单仅上报选中/端口列表/逗号分隔/白名单无需配置/已输入端口 + HostTimeRangePicker 时间范围/自定义/取消/应用 + DualLineChart 接收/发送 (i18n.t→useTranslation hook) + ZoomableAreaChart 暂无数据 + SiteResultsPanel 选择任务/次/可用率/立即拨测/SSL证书预警/到期/剩余/阈值/天 + MiddlewareMonitor Redis单机集群/上次更新/添加平台默认/暂无实例 + SiteMonitor subtitle + SNMPMonitor 标题/采集间隔/IP地址/OID模板/SNMP版本/确认/暂无设备/采集指标/暂无指标 + HealthProbeSection TCP目标地址/TCP端口 + AgentAlerts Agent告警/刷新/未恢复/已恢复/恢复/新建规则/创建第一条规则 — 新增 monitor.lbl 46 语义化翻译键 + agent.alerts 6 键, zh/en 7762→7814 对齐;tsc -b=0, npm build✓ (16.88s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
| U41 | i18n 残余硬编码中文清零 — 工具函数 + 审计RDP标签 + AIOps分析 + Monitor残余 + 审批选项(18 文件 ~35 处→0: agent-utils.ts timeAgo 秒前/分钟前/小时前 + utils.ts formatDistanceToNow 分钟前/小时前/天前 + request.ts 响应解析失败 + ActiveSessionsPanel RDP在线会话 + HistorySessionsPanel RDP历史会话/RDP会话共N条 + MetricsExplorer 清除/已选/最近1小时 + HostMonitor 当前主机 + AIAnalysisResult 证据链(useTranslation hook) + capacity-predict.ts 容量预测摘要模板 + ApprovalResourcePage 阿里云/腾讯云/华为云 + ApprovalPermissionPage 堡垒机 + site-monitor/helpers.ts 推荐频率/秒/分钟/小时/天 + site-monitor/analytics.ts 证书剩余/失败/延迟波动 + middleware-monitor/MwTargetChartsPanel 选择实例/已用/集群节点/慢查询 + MwTrendChart 暂无趋势数据 + middleware-monitor/helpers.ts 相对时间 + snmp-monitor/SnmpMetricTrendChart 暂无趋势数据等待采集 + SnmpDeviceChartsPanel 点击设备/可观测/刷新/暂无指标 + host-monitor/utils.ts 图表点数 + PortPolicyDialog 系统进程端口说明 — 新增 common.duration.secAgo/hourAgo/dayAgo + common.selected/responseParseError/rdpActiveSessions/rdpHistorySessions/rdpSessionCount/evidenceChain/last1Hour/currentHost + monitor.lbl 10键 + monitor.siteMonitor 8键 + approval.provider 3键 + approval.permType 1键 + monitor.portPolicyDialog.systemProcessDesc + aiops.capacity.summary 共 34 翻译键, zh/en 7813→7847 对齐;tsc -b=0, npm build✓ (17.31s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
| U43 | i18n 深度残余硬编码中文 UI 文本清零 — 趋势标签 + K8s 卡片标题 + data-table 默认值 + 趋势文本 + 卡片描述(17 文件 ~40 处→0: AIPredictiveAnalytics 上升/下降/平稳 + PredictiveCostTab 上升/下降/平稳×2 + 当前/阈值/预测 + PredictiveCapacityTab 容量规划预警 + data-table.tsx 搜索.../暂无数据默认值(useTranslation hook) + PodMiscCard Pod 级别 + PodSecurityCard Pod 安全上下文 + HostSettingsCard 4 个主机命名空间描述 + PodInstancesTable Pod 实例 + PodDetailDialog Pod 详情 + HostDetailDialog 指标趋势/端口发现/远程命令/关闭 + DeploymentEditContainers manifest 提示/镜像拉取凭证 + DeploymentEditStorage 数据卷/空状态/挂载/只读/读写 + ClusterOverviewPage 管理全部 + ResourceVisualEditor 新建/编辑 + AgentMonitor 在...上执行命令 + 7 个 K8s 页面刷新按钮(PodMetrics/Capacity/Events/NamespaceResource/NamespaceMgmt/ClusterOverview/KubernetesNodes) + BillingRecord/BillingRuleDialog 保存成功 toast/保存按钮 — 新增 common 30 语义化翻译键(trendUp/trendDown/trendStable/executeOn/podLevel/podSecurityContext/hostNetworkDesc/hostIPCDesk/hostPIDDesk/shareProcessNamespaceDesc/podInstances/podDetail/metricTrend/portDiscovery/remoteCommand/searchPlaceholder/imagePullSecrets/noManifestHint/volumeDefinition/noVolumeHint/mountToContainers/readOnly/readWrite/manageAll/createNew/saveSuccess), zh/en 7898→7928 对齐;tsc -b=0, npm build✓ (16.55s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
| U42 | i18n 残余硬编码中文彻底清零 — 全量 JSX children + toast/confirm + sr-only 描述(33 文件 54 处→0: PredictiveCapacityTab AI深度解读/紧急/警告/7天使用率预测/预计N天/后达到阈值/AI建议 + PredictiveCostTab AI深度解读 + event-handler.ts 高危操作确认 toast + DeployCredentials 启用/禁用 + DeployRBAC 删除角色 confirm + WorkspaceTermDialog 标题 + CredFormDialog Windows用户 + ClusterOverviewPage 核 + DeploymentEditContainers Pod级别 + DeploymentEditService 无selector/个关联/Ingresses应用路由/暂无Service/暂无Ingress/自动高亮 + DeploymentEditStorage 无容器 + KubectlTerminal sr-only + KubernetesClusterDialog 已配置 + ResourceVisualEditor YAML编辑 + CreateHPADialog CPU目标 + UpdateStrategyCard maxSurge/maxUnavailable/revisionHistoryLimit/progressDeadlineSeconds 说明 + IngressCreateForm host域名/Service端口 + ServiceCreateForm 端口配置/个端口/selector自动检测 + PodInstancesTable Pod名称 + UpdateStrategySelectorCards Pod管理策略 + AlertRulesTab 删除confirm/分钟 + PrometheusDatasourceManager 删除confirm + LogDatasourcePage 删除confirm + QueryHistoryPanel 条 + ServerFileBrowser sr-only + TerminalDialog sr-only + CredentialManager 删除confirm + RdpAuditViewer sr-only + SystemManager 删除用户/批量删除 confirm + TerminalSessionsTab 删除confirm + SecuritySettingsTab 30分钟/2小时 + CronJobViewDialog 次 — 新增 k8s.editAdvanced 6键+k8s.editService 11键+k8s.cluster 2键+k8s.clusterDialog 1键+k8s.kubectlTerminalDesc/k8s.rve.yamlEditBtn/k8s.hpa.cpuTarget/k8s.podLevel/k8s.podNameLabel/k8s.podManagePolicy 共 28键 + aiops.capacity 8键+aiops.cost 1键+aiops.cli 2键 + deploy.cred.windowsUser/deploy.workspaceTerminalTitle/deploy.rbac.deleteRoleDesc/deploy.cred.badgeDefault 4键 + monitor.deleteRulesConfirmDesc/deleteDatasourceConfirmDesc/deleteLogDsConfirmDesc/durationMinutes/queryHistory.count 5键 + system.rdpLiveAudit/rdpHistoryReplay/rdpAuditDesc/sshTerminalDesc/sftpFileDesc/sftpFileLabel/deleteUserConfirmDesc/batchDeleteUsersConfirmDesc/deleteCredConfirmDesc/deleteTermSessionsConfirmDesc 10键 + task.cronJob.runCount 1键 + common.minutes30/hours2 2键, zh/en 7847→7898 对齐;tsc -b=0, npm build✓ (17.71s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
| U37 | 全量 JSX 文本节点硬编码中文清零(65 文件 151 处→0: MiddlewareMonitor/SiteMonitor/SNMPMonitor/HealthProbeSection/ContextSwitchCard/ProcessTable/PortMonitorTab/MwTargetChartsPanel/MiddlewareDialog/ChartRangeHint/SnmpDeviceChartsPanel/AlertRulesTab/LogClusterPanel/LogDatasourcePage/LogQueryToolbar/LogAlertsPanel/PrometheusDatasourceManager/PodMetricsPage/CapacityPage/NamespaceManagementPage/NamespaceResourcePage/DeploymentEditService/EventsPage/DeploymentDetail/ClusterOverviewPage/DeploymentEditContainers/DeploymentEditStorage/WorkloadViewPage/BottomStatusBar/UpdateStrategySelectorCards/PodInstancesTable/shared-components/UpdateStrategyCard/TolerationsCard/HostSettingsCard/IngressListItem/ServiceListItem/ServiceCreateForm/IngressCreateForm/CreateHPADialog/DeployCredentials/DeployRBAC/UserGroupsManager/BuildNodesManager/DeployTargetFields/PipelineCreateDialog/CredFormDialog/WorkspaceTermDialog/AgentAlerts/AgentRuleDialog/LiveMonitorDialog/RoleFormDialog/CronJobViewDialog/TerminalOutput/AIAnalysisResult/AIPredictiveAnalytics/PredictiveCostTab/PredictiveCapacityTab/ActiveSessionsPanel/HistorySessionsPanel/TerminalDialog/ServerFileBrowser/PodFileBrowser/SiteResultsPanel/SiteProtocolPieChart — 151 JSX 文本节点中文全部替换为 t()/i18n.t() 调用;新增 common.* 98 翻译键 (selectedCount/itemsCount/newValue/namespaceLabel/containerLabel/replicasLabel/minReplicas/maxReplicas/createNamespace/noNamespace/unknownResource/exportYaml/loadTrend/loadCapacity/predicted/threshold/hostSettings/addVolume/addMount/createService/createIngress/editAction/updateStrategy/selectAndLabel/historyVersion/fileBrowser/scale/back/createHpa/allNamespaces/certLabel/observable/deviceList/addDevice/addMonitor/collectNow/addTask/addProbe/restoreFull/contextSwitch/processTop/listenPorts/terminalRealtime/auditWebssh/buildTerminal/fileBrowse/newDir/loadDeployment/notLinked/selectedPerms/none/hasLabel/deleteNamespace/deleteNamespaceWarn/allResources/notFoundDeploy/nodeList/fileLabel/addCustom/newInstanceService/newInstanceIngress/totalContainers/workContainers/loadingEllipsis/volumeClaimTemplates/containerTemplate/passwordOptional/updated/page/perPage/clusterMode/totalLogs/countLabel/percentage/queryTime/addDatasource/newPermission/newEnv/envLabel/displayName/newUserGroup/auditTrace/predictValue/confidence/predictMonthEnd/noCapacityData/securityMode/standardRdp/domainLabel/noRdpActive/noRdpHistory/buffer/matched/podLogs/createHpaTitle/password/events/total);37 文件已有 import i18n→i18n.t() 模式, 2 文件新增 import i18n;zh/en 7640→3526 namespace-flat +98 键对齐;tsc -b=0, npm build✓ (17.96s), ESLint=0/43/any=0, go build=0, 17/17 测试通过) | P3 | **done** |
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ export function AgentMonitor() {
|
||||
{t("agent.agentmonitortsx.s8h9i0j1k")}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="dg-text-secondary">
|
||||
在 {cmdHost} 上执行命令
|
||||
{t('common.executeOn', { host: cmdHost })}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ export function HostDetailDialog({
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-sm font-medium text-[var(--dg-text-primary)] flex items-center gap-1.5">
|
||||
<Activity className="h-4 w-4 dg-text-blue" />
|
||||
指标趋势
|
||||
{i18n.t('common.metricTrend')}
|
||||
</span>
|
||||
<Select value={String(hours)} onValueChange={(v) => setHours(Number(v))}>
|
||||
<SelectTrigger size="sm" className="h-7 w-28 dg-input text-[var(--dg-text-secondary)] text-xs">
|
||||
@@ -158,7 +158,7 @@ export function HostDetailDialog({
|
||||
<div>
|
||||
<span className="text-sm font-medium text-[var(--dg-text-primary)] flex items-center gap-1.5 mb-2">
|
||||
<Network className="h-4 w-4 dg-text-blue" />
|
||||
端口发现 ({ports.length})
|
||||
{i18n.t('common.portDiscovery', { count: ports.length })}
|
||||
</span>
|
||||
{ports.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted"> {i18n.t('agent.hostDetailDialog.noPortData')} </p>
|
||||
@@ -181,10 +181,10 @@ export function HostDetailDialog({
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
>
|
||||
<Terminal className="h-4 w-4 mr-1.5" />
|
||||
远程命令
|
||||
{i18n.t('common.remoteCommand')}
|
||||
</Button>
|
||||
<Button variant="outline" onClick={onClose} className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">
|
||||
关闭
|
||||
{i18n.t('common.close')}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@@ -207,7 +207,7 @@ export function AIPredictiveAnalytics() {
|
||||
<div className="flex items-center gap-1">
|
||||
{getTrendIcon(prediction.trend)}
|
||||
<span className={`text-sm ${trendColorClass(prediction.trend)}`}>
|
||||
{prediction.trend === 'up' ? '上升' : prediction.trend === 'down' ? '下降' : '平稳'}
|
||||
{prediction.trend === 'up' ? t('common.trendUp') : prediction.trend === 'down' ? t('common.trendDown') : t('common.trendStable')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +42,7 @@ export function PredictiveCapacityTab({
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<HardDrive className="h-5 w-5 dg-text-yellow" />
|
||||
容量规划预警
|
||||
{t('aiops.capacity.warningTitle')}
|
||||
</CardTitle>
|
||||
{!loading && forecasts.length > 0 && (
|
||||
<Button
|
||||
@@ -57,7 +57,7 @@ export function PredictiveCapacityTab({
|
||||
) : (
|
||||
<Sparkles className="h-3.5 w-3.5 mr-1" />
|
||||
)}
|
||||
AI 深度解读
|
||||
{t('aiops.capacity.aiInsight')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -156,7 +156,7 @@ export function PredictiveCostTab({
|
||||
<div className="flex items-center gap-1 mt-1 text-xs">
|
||||
{getTrendIcon(summary.trend)}
|
||||
<span className={trendColorClass(summary.trend)}>
|
||||
{summary.trend === 'up' ? '上升' : summary.trend === 'down' ? '下降' : '平稳'}
|
||||
{summary.trend === 'up' ? t('common.trendUp') : summary.trend === 'down' ? t('common.trendDown') : t('common.trendStable')}
|
||||
</span>
|
||||
<span className="dg-text-muted ml-1">{t('aiops.predictivecost.s5o6p7q8r', { pct: summary.confidence })}</span>
|
||||
</div>
|
||||
@@ -198,7 +198,7 @@ export function PredictiveCostTab({
|
||||
<div className="flex items-center gap-1 text-sm">
|
||||
{getTrendIcon(dim.trend)}
|
||||
<span className={trendColorClass(dim.trend)}>
|
||||
{dim.trend === 'up' ? '上升' : dim.trend === 'down' ? '下降' : '平稳'}
|
||||
{dim.trend === 'up' ? t('common.trendUp') : dim.trend === 'down' ? t('common.trendDown') : t('common.trendStable')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -278,8 +278,8 @@ export function PredictiveCostTab({
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm dg-text-secondary mt-2">
|
||||
当前 {formatCurrency(risk.current)} / 阈值 {formatCurrency(risk.threshold)}
|
||||
,预测 {formatCurrency(risk.predicted)}
|
||||
{t('aiops.capacity.currentThreshold', { current: formatCurrency(risk.current), threshold: formatCurrency(risk.threshold) })}
|
||||
{t('aiops.capacity.predictedLabel', { predicted: formatCurrency(risk.predicted) })}
|
||||
</p>
|
||||
<div className="flex items-center gap-4 mt-2 text-xs dg-text-muted">
|
||||
<span>{risk.timeframe}</span>
|
||||
|
||||
@@ -80,7 +80,7 @@ export function BillingRecordDialog({ open, onOpenChange, editingRecord, onSucce
|
||||
}
|
||||
onOpenChange(false);
|
||||
onSuccess();
|
||||
toast('保存成功');
|
||||
toast(i18n.t("common.saveSuccess"));
|
||||
} catch (e) {
|
||||
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
||||
} finally {
|
||||
|
||||
@@ -71,7 +71,7 @@ export function BillingRuleDialog({ open, onOpenChange, editingRule, onSuccess }
|
||||
}
|
||||
onOpenChange(false);
|
||||
onSuccess();
|
||||
toast('保存成功');
|
||||
toast(i18n.t("common.saveSuccess"));
|
||||
} catch (e) {
|
||||
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
||||
} finally {
|
||||
|
||||
@@ -97,9 +97,7 @@ export default function CapacityPage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadCapacity} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={exportCSV}>
|
||||
<Download className="h-4 w-4 mr-1" />
|
||||
CSV
|
||||
|
||||
@@ -99,9 +99,7 @@ export default function ClusterOverviewPage() {
|
||||
) : undefined}
|
||||
actions={(
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
)}
|
||||
>
|
||||
{/* 节点列表 // Logan.Li */}
|
||||
@@ -188,7 +186,7 @@ export default function ClusterOverviewPage() {
|
||||
<Boxes className="h-4 w-4 text-[var(--dg-green)]" />{i18n.t("common.namespaceLabel")}
|
||||
</h2>
|
||||
<Link to={`/kubernetes/${clusterCode}/namespaces`} className="text-sm text-[var(--dg-blue)] hover:text-[var(--dg-blue)] transition-colors flex items-center gap-1">
|
||||
管理全部 <ChevronRight className="h-3 w-3" />
|
||||
{i18n.t('common.manageAll')} <ChevronRight className="h-3 w-3" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
|
||||
@@ -123,7 +123,7 @@ export function DeploymentEditContainers({ clusterCode, namespace, deploymentNam
|
||||
return (
|
||||
<Card className="dg-card">
|
||||
<CardContent className="p-8 text-center dg-text-muted">
|
||||
未获取到 manifest 数据,请使用 YAML 编辑模式直接修改。
|
||||
{i18n.t('common.noManifestHint')}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -136,7 +136,7 @@ export function DeploymentEditContainers({ clusterCode, namespace, deploymentNam
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<KeyRound className="h-4 w-4 dg-text-yellow" />
|
||||
镜像拉取凭证 (imagePullSecrets)
|
||||
{i18n.t('common.imagePullSecrets')}
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-muted text-[10px]">{i18n.t('k8s.podLevel')}</Badge>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
@@ -196,7 +196,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
<div>
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Database className="h-4 w-4 dg-text-green" />
|
||||
数据卷
|
||||
{i18n.t('common.volumeDefinition')}
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary">{entries.length}</Badge>
|
||||
</CardTitle>
|
||||
<p className="text-[11px] dg-text-muted mt-1"> {i18n.t('kubernetes.storage.volumeDesc')} </p>
|
||||
@@ -210,7 +210,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
{entries.length === 0 ? (
|
||||
<div className="text-center py-10 dg-text-muted text-sm border border-dashed border-[var(--dg-border)] rounded-lg">
|
||||
<Database className="h-8 w-8 mx-auto mb-2 dg-text-muted" />
|
||||
未配置数据卷,点击「添加数据卷」开始
|
||||
{i18n.t('common.noVolumeHint')}
|
||||
</div>
|
||||
) : entries.map((entry, i) => {
|
||||
const vol = entry.volume;
|
||||
@@ -282,7 +282,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-[11px] dg-text-muted flex items-center gap-1.5">
|
||||
<Container className="h-3.5 w-3.5 dg-text-blue" />
|
||||
将上述数据卷挂载到容器
|
||||
{i18n.t('common.mountToContainers')}
|
||||
</p>
|
||||
<Button size="sm" variant="ghost" className="h-6 px-2 text-[11px] dg-text-secondary hover:text-[var(--dg-text-primary)]" onClick={() => addMount(i)}>
|
||||
<Plus className="h-3 w-3 mr-0.5" />{i18n.t("common.addMount")}
|
||||
@@ -302,11 +302,11 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
<div className="flex items-center gap-1 bg-[var(--dg-bg-tertiary)] rounded-lg p-0.5 border border-[var(--dg-border)]">
|
||||
<button type="button" onClick={() => updateMount(i, mi, { readOnly: true })}
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${mount.readOnly ? 'bg-amber-500/20 text-amber-300' : 'dg-text-muted hover:text-[var(--dg-text-secondary)]'}`}>
|
||||
只读
|
||||
{i18n.t('common.readOnly')}
|
||||
</button>
|
||||
<button type="button" onClick={() => updateMount(i, mi, { readOnly: false })}
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${!mount.readOnly ? 'bg-blue-500/20 text-blue-300' : 'dg-text-muted hover:text-[var(--dg-text-secondary)]'}`}>
|
||||
读写
|
||||
{i18n.t('common.readWrite')}
|
||||
</button>
|
||||
</div>
|
||||
<Input
|
||||
|
||||
@@ -221,9 +221,7 @@ export default function EventsPage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { loadEvents(); loadSummary(); }} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -101,9 +101,7 @@ export function KubernetesNodes() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadNodes} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -137,9 +137,7 @@ export default function NamespaceManagementPage() {
|
||||
actions={(
|
||||
<>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" className="dg-btn-primary">
|
||||
|
||||
@@ -199,9 +199,7 @@ export default function NamespaceResourcePage() {
|
||||
<SelectContent className="max-h-[300px]">{namespaces.map((ns) => <SelectItem key={ns} value={ns}>{ns}</SelectItem>)}</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
{BULK_EXPORT_TYPES.includes(type) && (
|
||||
<>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary text-xs" onClick={handleExportCSV} title={i18n.t('k8s.nsResourcePage.exportCsv')}>
|
||||
|
||||
@@ -37,7 +37,7 @@ export function PodDetailDialog({ pod, onClose }: PodDetailDialogProps) {
|
||||
<div className="flex items-center justify-between px-5 py-4 border-b border-[var(--dg-border)]">
|
||||
<h3 className="text-base font-semibold text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Container className="h-4 w-4 text-[var(--dg-blue)]" />
|
||||
Pod 详情
|
||||
{i18n.t('common.podDetail')}
|
||||
</h3>
|
||||
<button className="text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)]" onClick={onClose}>✕</button>
|
||||
</div>
|
||||
|
||||
@@ -115,9 +115,7 @@ export default function PodMetricsPage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadMetrics} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
||||
刷新
|
||||
</Button>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||
</>
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -182,7 +182,7 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
|
||||
<MetaIcon className={`h-5 w-5 shrink-0 ${meta.color}`} />
|
||||
<div className="min-w-0">
|
||||
<h2 className="text-lg font-bold text-[var(--dg-text-primary)] truncate">
|
||||
{isCreate ? `新建 ${meta.title}` : `${meta.title} 编辑`}
|
||||
{isCreate ? i18n.t('common.createNew') + ' ' + meta.title : meta.title + ' ' + i18n.t('common.edit')}
|
||||
</h2>
|
||||
<p
|
||||
className="text-xs text-[var(--dg-text-muted)] truncate"
|
||||
|
||||
@@ -32,22 +32,22 @@ export function HostSettingsCard({
|
||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
||||
<input type="checkbox" checked={hostNetwork} onChange={e => onHostNetworkChange(e.target.checked)}
|
||||
className="accent-blue-500" />
|
||||
hostNetwork(共享主机网络命名空间)
|
||||
{i18n.t('common.hostNetworkDesc')}
|
||||
</label>
|
||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
||||
<input type="checkbox" checked={hostIPC} onChange={e => onHostIPCChange(e.target.checked)}
|
||||
className="accent-blue-500" />
|
||||
hostIPC(共享主机 IPC 命名空间)
|
||||
{i18n.t('common.hostIPCDesk')}
|
||||
</label>
|
||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
||||
<input type="checkbox" checked={hostPID} onChange={e => onHostPIDChange(e.target.checked)}
|
||||
className="accent-blue-500" />
|
||||
hostPID(共享主机 PID 命名空间)
|
||||
{i18n.t('common.hostPIDDesk')}
|
||||
</label>
|
||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
||||
<input type="checkbox" checked={shareProcessNamespace} onChange={e => onShareProcessNamespaceChange(e.target.checked)}
|
||||
className="accent-blue-500" />
|
||||
shareProcessNamespace(共享进程命名空间)
|
||||
{i18n.t('common.shareProcessNamespaceDesc')}
|
||||
</label>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// PodMiscCard.tsx — Pod 级别杂项设置卡片 (Q21 提取)
|
||||
// dnsPolicy / restartPolicy / schedulerName / terminationGracePeriodSeconds / serviceAccountName
|
||||
import { Settings } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -25,11 +26,12 @@ export function PodMiscCard({
|
||||
terminationGracePeriodSeconds, onTerminationGracePeriodSecondsChange,
|
||||
serviceAccountName, onServiceAccountNameChange,
|
||||
}: PodMiscCardProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Settings className="h-4 w-4 dg-text-secondary" />Pod 级别
|
||||
<Settings className="h-4 w-4 dg-text-secondary" />{t('common.podLevel')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 grid grid-cols-2 gap-3">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// PodSecurityCard.tsx — Pod 安全上下文 (securityContext) 卡片 (Q21 提取)
|
||||
import { Shield } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -21,11 +22,12 @@ export function PodSecurityCard({
|
||||
podRunAsGroup, onPodRunAsGroupChange,
|
||||
podRunAsNonRoot, onPodRunAsNonRootChange,
|
||||
}: PodSecurityCardProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Shield className="h-4 w-4 text-rose-400" />Pod 安全上下文 (securityContext)
|
||||
<Shield className="h-4 w-4 text-rose-400" />{t('common.podSecurityContext')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 grid grid-cols-2 gap-3">
|
||||
|
||||
@@ -23,7 +23,7 @@ export function PodInstancesTable({
|
||||
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Activity className="h-4 w-4 text-[var(--dg-green)]" />Pod 实例 ({pods.length})
|
||||
<Activity className="h-4 w-4 text-[var(--dg-green)]" />{i18n.t('common.podInstances', { count: pods.length })}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0">
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* ```
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -224,7 +225,7 @@ export function DataTable<T = Record<string, unknown>>(
|
||||
data,
|
||||
rowKey,
|
||||
searchable = false,
|
||||
searchPlaceholder = '搜索...',
|
||||
searchPlaceholder = undefined,
|
||||
searchKeys,
|
||||
sortable: globalSortable = false,
|
||||
pagination: enablePagination = false,
|
||||
@@ -237,7 +238,7 @@ export function DataTable<T = Record<string, unknown>>(
|
||||
exportFilename = 'export.csv',
|
||||
columnToggle = false,
|
||||
loading = false,
|
||||
emptyText = '暂无数据',
|
||||
emptyText = undefined,
|
||||
emptyRender,
|
||||
onRowClick,
|
||||
rowClassName,
|
||||
@@ -247,6 +248,9 @@ export function DataTable<T = Record<string, unknown>>(
|
||||
toolbarExtra,
|
||||
} = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
const effectiveSearchPlaceholder = searchPlaceholder ?? t('common.searchPlaceholder');
|
||||
const effectiveEmptyText = emptyText ?? t('common.noData');
|
||||
// ── Search state ──
|
||||
const [searchTerm, setSearchTerm] = React.useState('');
|
||||
|
||||
@@ -405,7 +409,7 @@ export function DataTable<T = Record<string, unknown>>(
|
||||
type="text"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder={searchPlaceholder}
|
||||
placeholder={effectiveSearchPlaceholder}
|
||||
className="pl-9 h-9 w-56 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] placeholder:text-[var(--dg-text-muted)]"
|
||||
/>
|
||||
</div>
|
||||
@@ -532,7 +536,7 @@ export function DataTable<T = Record<string, unknown>>(
|
||||
colSpan={visibleColumns.length + (selectable ? 1 : 0)}
|
||||
className="text-center text-[var(--dg-text-muted)] py-16"
|
||||
>
|
||||
{emptyRender ? emptyRender() : emptyText}
|
||||
{emptyRender ? emptyRender() : effectiveEmptyText}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
|
||||
@@ -636,7 +636,33 @@
|
||||
"last1Hour": "Last 1 hour",
|
||||
"currentHost": "Current host: {{host}}",
|
||||
"minutes30": "30 min",
|
||||
"hours2": "2 hours"
|
||||
"hours2": "2 hours",
|
||||
"trendUp": "Up",
|
||||
"trendDown": "Down",
|
||||
"trendStable": "Stable",
|
||||
"executeOn": "Execute command on {{host}}",
|
||||
"podLevel": "Pod Level",
|
||||
"podSecurityContext": "Pod Security Context",
|
||||
"hostNetworkDesc": "hostNetwork (share host network namespace)",
|
||||
"hostIPCDesk": "hostIPC (share host IPC namespace)",
|
||||
"hostPIDDesk": "hostPID (share host PID namespace)",
|
||||
"shareProcessNamespaceDesc": "shareProcessNamespace (share process namespace)",
|
||||
"podInstances": "Pod Instances ({{count}})",
|
||||
"podDetail": "Pod Details",
|
||||
"metricTrend": "Metric Trends",
|
||||
"portDiscovery": "Port Discovery ({{count}})",
|
||||
"remoteCommand": "Remote Command",
|
||||
"searchPlaceholder": "Search...",
|
||||
"imagePullSecrets": "Image Pull Secrets",
|
||||
"noManifestHint": "No manifest data available. Please use YAML edit mode to modify directly.",
|
||||
"volumeDefinition": "Volumes",
|
||||
"noVolumeHint": "No volumes configured. Click \"Add Volume\" to start.",
|
||||
"mountToContainers": "Mount volumes to containers",
|
||||
"readOnly": "Read Only",
|
||||
"readWrite": "Read Write",
|
||||
"manageAll": "Manage All",
|
||||
"createNew": "Create New",
|
||||
"saveSuccess": "Saved successfully"
|
||||
},
|
||||
"menu": {
|
||||
"aiAgentCli": "Agent CLI",
|
||||
@@ -3713,7 +3739,8 @@
|
||||
"kubectlTerminalDesc": "Kubernetes cluster command-line terminal",
|
||||
"podLevel": "Pod Level",
|
||||
"podNameLabel": "Pod Name",
|
||||
"podManagePolicy": "Pod Management Policy"
|
||||
"podManagePolicy": "Pod Management Policy",
|
||||
"uploadFile": "Upload"
|
||||
},
|
||||
"monitor": {
|
||||
"acknowledge": "Acknowledge",
|
||||
@@ -8021,7 +8048,10 @@
|
||||
"expectedToReach": "Expected to",
|
||||
"days": "days",
|
||||
"afterReachThreshold": "until threshold reached",
|
||||
"aiSuggestion": "AI Suggestion"
|
||||
"aiSuggestion": "AI Suggestion",
|
||||
"warningTitle": "Capacity Planning Alerts",
|
||||
"currentThreshold": "Current {{current}} / Threshold {{threshold}}",
|
||||
"predictedLabel": ", Predicted {{predicted}}"
|
||||
},
|
||||
"capacityPlanPrompt": "Based on the following host resource usage, provide cost optimization and capacity planning advice (identify idle/overloaded hosts; suggest scale-down/scale-up)",
|
||||
"capacityPlanning": "Capacity Planning",
|
||||
|
||||
@@ -636,7 +636,33 @@
|
||||
"last1Hour": "最近 1 小时",
|
||||
"currentHost": "当前主机: {{host}}",
|
||||
"minutes30": "30分钟",
|
||||
"hours2": "2小时"
|
||||
"hours2": "2小时",
|
||||
"trendUp": "上升",
|
||||
"trendDown": "下降",
|
||||
"trendStable": "平稳",
|
||||
"executeOn": "在 {{host}} 上执行命令",
|
||||
"podLevel": "Pod 级别",
|
||||
"podSecurityContext": "Pod 安全上下文 (securityContext)",
|
||||
"hostNetworkDesc": "hostNetwork(共享主机网络命名空间)",
|
||||
"hostIPCDesk": "hostIPC(共享主机 IPC 命名空间)",
|
||||
"hostPIDDesk": "hostPID(共享主机 PID 命名空间)",
|
||||
"shareProcessNamespaceDesc": "shareProcessNamespace(共享进程命名空间)",
|
||||
"podInstances": "Pod 实例 ({{count}})",
|
||||
"podDetail": "Pod 详情",
|
||||
"metricTrend": "指标趋势",
|
||||
"portDiscovery": "端口发现 ({{count}})",
|
||||
"remoteCommand": "远程命令",
|
||||
"searchPlaceholder": "搜索...",
|
||||
"imagePullSecrets": "镜像拉取凭证 (imagePullSecrets)",
|
||||
"noManifestHint": "未获取到 manifest 数据,请使用 YAML 编辑模式直接修改。",
|
||||
"volumeDefinition": "数据卷",
|
||||
"noVolumeHint": "未配置数据卷,点击「添加数据卷」开始",
|
||||
"mountToContainers": "将上述数据卷挂载到容器",
|
||||
"readOnly": "只读",
|
||||
"readWrite": "读写",
|
||||
"manageAll": "管理全部",
|
||||
"createNew": "新建",
|
||||
"saveSuccess": "保存成功"
|
||||
},
|
||||
"menu": {
|
||||
"aiAgentCli": "Agent CLI",
|
||||
@@ -3713,7 +3739,8 @@
|
||||
"kubectlTerminalDesc": "Kubernetes 集群命令行终端",
|
||||
"podLevel": "Pod 级别",
|
||||
"podNameLabel": "Pod 名称",
|
||||
"podManagePolicy": "Pod 管理策略"
|
||||
"podManagePolicy": "Pod 管理策略",
|
||||
"uploadFile": "上传"
|
||||
},
|
||||
"monitor": {
|
||||
"acknowledge": "确认告警",
|
||||
@@ -8021,7 +8048,10 @@
|
||||
"expectedToReach": "预计",
|
||||
"days": "天",
|
||||
"afterReachThreshold": "后达到阈值",
|
||||
"aiSuggestion": "AI建议"
|
||||
"aiSuggestion": "AI建议",
|
||||
"warningTitle": "容量规划预警",
|
||||
"currentThreshold": "当前 {{current}} / 阈值 {{threshold}}",
|
||||
"predictedLabel": ",预测 {{predicted}}"
|
||||
},
|
||||
"capacityPlanPrompt": "根据以下主机资源使用数据,提供成本优化和容量规划建议(识别闲置/过载主机,给出缩容/扩容建议)",
|
||||
"capacityPlanning": "容量规划",
|
||||
|
||||
Reference in new issue
Block a user