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** |
|
| 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** |
|
| 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** |
|
| 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** |
|
| 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** |
|
| 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")}
|
{t("agent.agentmonitortsx.s8h9i0j1k")}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription className="dg-text-secondary">
|
<DialogDescription className="dg-text-secondary">
|
||||||
在 {cmdHost} 上执行命令
|
{t('common.executeOn', { host: cmdHost })}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export function HostDetailDialog({
|
|||||||
<div className="flex items-center justify-between mb-2">
|
<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">
|
<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" />
|
<Activity className="h-4 w-4 dg-text-blue" />
|
||||||
指标趋势
|
{i18n.t('common.metricTrend')}
|
||||||
</span>
|
</span>
|
||||||
<Select value={String(hours)} onValueChange={(v) => setHours(Number(v))}>
|
<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">
|
<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>
|
<div>
|
||||||
<span className="text-sm font-medium text-[var(--dg-text-primary)] flex items-center gap-1.5 mb-2">
|
<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" />
|
<Network className="h-4 w-4 dg-text-blue" />
|
||||||
端口发现 ({ports.length})
|
{i18n.t('common.portDiscovery', { count: ports.length })}
|
||||||
</span>
|
</span>
|
||||||
{ports.length === 0 ? (
|
{ports.length === 0 ? (
|
||||||
<p className="text-xs dg-text-muted"> {i18n.t('agent.hostDetailDialog.noPortData')} </p>
|
<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"
|
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||||
>
|
>
|
||||||
<Terminal className="h-4 w-4 mr-1.5" />
|
<Terminal className="h-4 w-4 mr-1.5" />
|
||||||
远程命令
|
{i18n.t('common.remoteCommand')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={onClose} className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">
|
<Button variant="outline" onClick={onClose} className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">
|
||||||
关闭
|
{i18n.t('common.close')}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ export function AIPredictiveAnalytics() {
|
|||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
{getTrendIcon(prediction.trend)}
|
{getTrendIcon(prediction.trend)}
|
||||||
<span className={`text-sm ${trendColorClass(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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function PredictiveCapacityTab({
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||||
<HardDrive className="h-5 w-5 dg-text-yellow" />
|
<HardDrive className="h-5 w-5 dg-text-yellow" />
|
||||||
容量规划预警
|
{t('aiops.capacity.warningTitle')}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
{!loading && forecasts.length > 0 && (
|
{!loading && forecasts.length > 0 && (
|
||||||
<Button
|
<Button
|
||||||
@@ -57,7 +57,7 @@ export function PredictiveCapacityTab({
|
|||||||
) : (
|
) : (
|
||||||
<Sparkles className="h-3.5 w-3.5 mr-1" />
|
<Sparkles className="h-3.5 w-3.5 mr-1" />
|
||||||
)}
|
)}
|
||||||
AI 深度解读
|
{t('aiops.capacity.aiInsight')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export function PredictiveCostTab({
|
|||||||
<div className="flex items-center gap-1 mt-1 text-xs">
|
<div className="flex items-center gap-1 mt-1 text-xs">
|
||||||
{getTrendIcon(summary.trend)}
|
{getTrendIcon(summary.trend)}
|
||||||
<span className={trendColorClass(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>
|
||||||
<span className="dg-text-muted ml-1">{t('aiops.predictivecost.s5o6p7q8r', { pct: summary.confidence })}</span>
|
<span className="dg-text-muted ml-1">{t('aiops.predictivecost.s5o6p7q8r', { pct: summary.confidence })}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -198,7 +198,7 @@ export function PredictiveCostTab({
|
|||||||
<div className="flex items-center gap-1 text-sm">
|
<div className="flex items-center gap-1 text-sm">
|
||||||
{getTrendIcon(dim.trend)}
|
{getTrendIcon(dim.trend)}
|
||||||
<span className={trendColorClass(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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -278,8 +278,8 @@ export function PredictiveCostTab({
|
|||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm dg-text-secondary mt-2">
|
<p className="text-sm dg-text-secondary mt-2">
|
||||||
当前 {formatCurrency(risk.current)} / 阈值 {formatCurrency(risk.threshold)}
|
{t('aiops.capacity.currentThreshold', { current: formatCurrency(risk.current), threshold: formatCurrency(risk.threshold) })}
|
||||||
,预测 {formatCurrency(risk.predicted)}
|
{t('aiops.capacity.predictedLabel', { predicted: formatCurrency(risk.predicted) })}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-4 mt-2 text-xs dg-text-muted">
|
<div className="flex items-center gap-4 mt-2 text-xs dg-text-muted">
|
||||||
<span>{risk.timeframe}</span>
|
<span>{risk.timeframe}</span>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export function BillingRecordDialog({ open, onOpenChange, editingRecord, onSucce
|
|||||||
}
|
}
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
onSuccess();
|
onSuccess();
|
||||||
toast('保存成功');
|
toast(i18n.t("common.saveSuccess"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function BillingRuleDialog({ open, onOpenChange, editingRule, onSuccess }
|
|||||||
}
|
}
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
onSuccess();
|
onSuccess();
|
||||||
toast('保存成功');
|
toast(i18n.t("common.saveSuccess"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
toast.error(i18n.t('kubernetes.msg.saveFailed'), { description: (e as JsonData).message });
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -97,9 +97,7 @@ export default function CapacityPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadCapacity} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadCapacity} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={exportCSV}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={exportCSV}>
|
||||||
<Download className="h-4 w-4 mr-1" />
|
<Download className="h-4 w-4 mr-1" />
|
||||||
CSV
|
CSV
|
||||||
|
|||||||
@@ -99,9 +99,7 @@ export default function ClusterOverviewPage() {
|
|||||||
) : undefined}
|
) : undefined}
|
||||||
actions={(
|
actions={(
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* 节点列表 // Logan.Li */}
|
{/* 节点列表 // Logan.Li */}
|
||||||
@@ -188,7 +186,7 @@ export default function ClusterOverviewPage() {
|
|||||||
<Boxes className="h-4 w-4 text-[var(--dg-green)]" />{i18n.t("common.namespaceLabel")}
|
<Boxes className="h-4 w-4 text-[var(--dg-green)]" />{i18n.t("common.namespaceLabel")}
|
||||||
</h2>
|
</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">
|
<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>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function DeploymentEditContainers({ clusterCode, namespace, deploymentNam
|
|||||||
return (
|
return (
|
||||||
<Card className="dg-card">
|
<Card className="dg-card">
|
||||||
<CardContent className="p-8 text-center dg-text-muted">
|
<CardContent className="p-8 text-center dg-text-muted">
|
||||||
未获取到 manifest 数据,请使用 YAML 编辑模式直接修改。
|
{i18n.t('common.noManifestHint')}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@@ -136,7 +136,7 @@ export function DeploymentEditContainers({ clusterCode, namespace, deploymentNam
|
|||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||||
<KeyRound className="h-4 w-4 dg-text-yellow" />
|
<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>
|
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-muted text-[10px]">{i18n.t('k8s.podLevel')}</Badge>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
|||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||||
<Database className="h-4 w-4 dg-text-green" />
|
<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>
|
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary">{entries.length}</Badge>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<p className="text-[11px] dg-text-muted mt-1"> {i18n.t('kubernetes.storage.volumeDesc')} </p>
|
<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 ? (
|
{entries.length === 0 ? (
|
||||||
<div className="text-center py-10 dg-text-muted text-sm border border-dashed border-[var(--dg-border)] rounded-lg">
|
<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" />
|
<Database className="h-8 w-8 mx-auto mb-2 dg-text-muted" />
|
||||||
未配置数据卷,点击「添加数据卷」开始
|
{i18n.t('common.noVolumeHint')}
|
||||||
</div>
|
</div>
|
||||||
) : entries.map((entry, i) => {
|
) : entries.map((entry, i) => {
|
||||||
const vol = entry.volume;
|
const vol = entry.volume;
|
||||||
@@ -282,7 +282,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
|||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<p className="text-[11px] dg-text-muted flex items-center gap-1.5">
|
<p className="text-[11px] dg-text-muted flex items-center gap-1.5">
|
||||||
<Container className="h-3.5 w-3.5 dg-text-blue" />
|
<Container className="h-3.5 w-3.5 dg-text-blue" />
|
||||||
将上述数据卷挂载到容器
|
{i18n.t('common.mountToContainers')}
|
||||||
</p>
|
</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)}>
|
<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")}
|
<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)]">
|
<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 })}
|
<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)]'}`}>
|
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>
|
||||||
<button type="button" onClick={() => updateMount(i, mi, { readOnly: false })}
|
<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)]'}`}>
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -221,9 +221,7 @@ export default function EventsPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { loadEvents(); loadSummary(); }} disabled={loading}>
|
<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' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -101,9 +101,7 @@ export function KubernetesNodes() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadNodes} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadNodes} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -137,9 +137,7 @@ export default function NamespaceManagementPage() {
|
|||||||
actions={(
|
actions={(
|
||||||
<>
|
<>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button size="sm" className="dg-btn-primary">
|
<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>
|
<SelectContent className="max-h-[300px]">{namespaces.map((ns) => <SelectItem key={ns} value={ns}>{ns}</SelectItem>)}</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
{BULK_EXPORT_TYPES.includes(type) && (
|
{BULK_EXPORT_TYPES.includes(type) && (
|
||||||
<>
|
<>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary text-xs" onClick={handleExportCSV} title={i18n.t('k8s.nsResourcePage.exportCsv')}>
|
<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)]">
|
<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">
|
<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)]" />
|
<Container className="h-4 w-4 text-[var(--dg-blue)]" />
|
||||||
Pod 详情
|
{i18n.t('common.podDetail')}
|
||||||
</h3>
|
</h3>
|
||||||
<button className="text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)]" onClick={onClose}>✕</button>
|
<button className="text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)]" onClick={onClose}>✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -115,9 +115,7 @@ export default function PodMetricsPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadMetrics} disabled={loading}>
|
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadMetrics} disabled={loading}>
|
||||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />{i18n.t('common.refresh')}</Button>
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
|
|||||||
<MetaIcon className={`h-5 w-5 shrink-0 ${meta.color}`} />
|
<MetaIcon className={`h-5 w-5 shrink-0 ${meta.color}`} />
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h2 className="text-lg font-bold text-[var(--dg-text-primary)] truncate">
|
<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>
|
</h2>
|
||||||
<p
|
<p
|
||||||
className="text-xs text-[var(--dg-text-muted)] truncate"
|
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">
|
<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)}
|
<input type="checkbox" checked={hostNetwork} onChange={e => onHostNetworkChange(e.target.checked)}
|
||||||
className="accent-blue-500" />
|
className="accent-blue-500" />
|
||||||
hostNetwork(共享主机网络命名空间)
|
{i18n.t('common.hostNetworkDesc')}
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
<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)}
|
<input type="checkbox" checked={hostIPC} onChange={e => onHostIPCChange(e.target.checked)}
|
||||||
className="accent-blue-500" />
|
className="accent-blue-500" />
|
||||||
hostIPC(共享主机 IPC 命名空间)
|
{i18n.t('common.hostIPCDesk')}
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
<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)}
|
<input type="checkbox" checked={hostPID} onChange={e => onHostPIDChange(e.target.checked)}
|
||||||
className="accent-blue-500" />
|
className="accent-blue-500" />
|
||||||
hostPID(共享主机 PID 命名空间)
|
{i18n.t('common.hostPIDDesk')}
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center gap-2 text-xs text-[var(--dg-text-secondary)] cursor-pointer">
|
<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)}
|
<input type="checkbox" checked={shareProcessNamespace} onChange={e => onShareProcessNamespaceChange(e.target.checked)}
|
||||||
className="accent-blue-500" />
|
className="accent-blue-500" />
|
||||||
shareProcessNamespace(共享进程命名空间)
|
{i18n.t('common.shareProcessNamespaceDesc')}
|
||||||
</label>
|
</label>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// PodMiscCard.tsx — Pod 级别杂项设置卡片 (Q21 提取)
|
// PodMiscCard.tsx — Pod 级别杂项设置卡片 (Q21 提取)
|
||||||
// dnsPolicy / restartPolicy / schedulerName / terminationGracePeriodSeconds / serviceAccountName
|
// dnsPolicy / restartPolicy / schedulerName / terminationGracePeriodSeconds / serviceAccountName
|
||||||
import { Settings } from 'lucide-react';
|
import { Settings } from 'lucide-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
@@ -25,11 +26,12 @@ export function PodMiscCard({
|
|||||||
terminationGracePeriodSeconds, onTerminationGracePeriodSecondsChange,
|
terminationGracePeriodSeconds, onTerminationGracePeriodSecondsChange,
|
||||||
serviceAccountName, onServiceAccountNameChange,
|
serviceAccountName, onServiceAccountNameChange,
|
||||||
}: PodMiscCardProps) {
|
}: PodMiscCardProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Card className="dg-card">
|
<Card className="dg-card">
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
<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>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="pt-0 grid grid-cols-2 gap-3">
|
<CardContent className="pt-0 grid grid-cols-2 gap-3">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// PodSecurityCard.tsx — Pod 安全上下文 (securityContext) 卡片 (Q21 提取)
|
// PodSecurityCard.tsx — Pod 安全上下文 (securityContext) 卡片 (Q21 提取)
|
||||||
import { Shield } from 'lucide-react';
|
import { Shield } from 'lucide-react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
@@ -21,11 +22,12 @@ export function PodSecurityCard({
|
|||||||
podRunAsGroup, onPodRunAsGroupChange,
|
podRunAsGroup, onPodRunAsGroupChange,
|
||||||
podRunAsNonRoot, onPodRunAsNonRootChange,
|
podRunAsNonRoot, onPodRunAsNonRootChange,
|
||||||
}: PodSecurityCardProps) {
|
}: PodSecurityCardProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Card className="dg-card">
|
<Card className="dg-card">
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
<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>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="pt-0 grid grid-cols-2 gap-3">
|
<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)]">
|
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
<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>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -224,7 +225,7 @@ export function DataTable<T = Record<string, unknown>>(
|
|||||||
data,
|
data,
|
||||||
rowKey,
|
rowKey,
|
||||||
searchable = false,
|
searchable = false,
|
||||||
searchPlaceholder = '搜索...',
|
searchPlaceholder = undefined,
|
||||||
searchKeys,
|
searchKeys,
|
||||||
sortable: globalSortable = false,
|
sortable: globalSortable = false,
|
||||||
pagination: enablePagination = false,
|
pagination: enablePagination = false,
|
||||||
@@ -237,7 +238,7 @@ export function DataTable<T = Record<string, unknown>>(
|
|||||||
exportFilename = 'export.csv',
|
exportFilename = 'export.csv',
|
||||||
columnToggle = false,
|
columnToggle = false,
|
||||||
loading = false,
|
loading = false,
|
||||||
emptyText = '暂无数据',
|
emptyText = undefined,
|
||||||
emptyRender,
|
emptyRender,
|
||||||
onRowClick,
|
onRowClick,
|
||||||
rowClassName,
|
rowClassName,
|
||||||
@@ -247,6 +248,9 @@ export function DataTable<T = Record<string, unknown>>(
|
|||||||
toolbarExtra,
|
toolbarExtra,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const effectiveSearchPlaceholder = searchPlaceholder ?? t('common.searchPlaceholder');
|
||||||
|
const effectiveEmptyText = emptyText ?? t('common.noData');
|
||||||
// ── Search state ──
|
// ── Search state ──
|
||||||
const [searchTerm, setSearchTerm] = React.useState('');
|
const [searchTerm, setSearchTerm] = React.useState('');
|
||||||
|
|
||||||
@@ -405,7 +409,7 @@ export function DataTable<T = Record<string, unknown>>(
|
|||||||
type="text"
|
type="text"
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
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)]"
|
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>
|
</div>
|
||||||
@@ -532,7 +536,7 @@ export function DataTable<T = Record<string, unknown>>(
|
|||||||
colSpan={visibleColumns.length + (selectable ? 1 : 0)}
|
colSpan={visibleColumns.length + (selectable ? 1 : 0)}
|
||||||
className="text-center text-[var(--dg-text-muted)] py-16"
|
className="text-center text-[var(--dg-text-muted)] py-16"
|
||||||
>
|
>
|
||||||
{emptyRender ? emptyRender() : emptyText}
|
{emptyRender ? emptyRender() : effectiveEmptyText}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -636,7 +636,33 @@
|
|||||||
"last1Hour": "Last 1 hour",
|
"last1Hour": "Last 1 hour",
|
||||||
"currentHost": "Current host: {{host}}",
|
"currentHost": "Current host: {{host}}",
|
||||||
"minutes30": "30 min",
|
"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": {
|
"menu": {
|
||||||
"aiAgentCli": "Agent CLI",
|
"aiAgentCli": "Agent CLI",
|
||||||
@@ -3713,7 +3739,8 @@
|
|||||||
"kubectlTerminalDesc": "Kubernetes cluster command-line terminal",
|
"kubectlTerminalDesc": "Kubernetes cluster command-line terminal",
|
||||||
"podLevel": "Pod Level",
|
"podLevel": "Pod Level",
|
||||||
"podNameLabel": "Pod Name",
|
"podNameLabel": "Pod Name",
|
||||||
"podManagePolicy": "Pod Management Policy"
|
"podManagePolicy": "Pod Management Policy",
|
||||||
|
"uploadFile": "Upload"
|
||||||
},
|
},
|
||||||
"monitor": {
|
"monitor": {
|
||||||
"acknowledge": "Acknowledge",
|
"acknowledge": "Acknowledge",
|
||||||
@@ -8021,7 +8048,10 @@
|
|||||||
"expectedToReach": "Expected to",
|
"expectedToReach": "Expected to",
|
||||||
"days": "days",
|
"days": "days",
|
||||||
"afterReachThreshold": "until threshold reached",
|
"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)",
|
"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",
|
"capacityPlanning": "Capacity Planning",
|
||||||
|
|||||||
@@ -636,7 +636,33 @@
|
|||||||
"last1Hour": "最近 1 小时",
|
"last1Hour": "最近 1 小时",
|
||||||
"currentHost": "当前主机: {{host}}",
|
"currentHost": "当前主机: {{host}}",
|
||||||
"minutes30": "30分钟",
|
"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": {
|
"menu": {
|
||||||
"aiAgentCli": "Agent CLI",
|
"aiAgentCli": "Agent CLI",
|
||||||
@@ -3713,7 +3739,8 @@
|
|||||||
"kubectlTerminalDesc": "Kubernetes 集群命令行终端",
|
"kubectlTerminalDesc": "Kubernetes 集群命令行终端",
|
||||||
"podLevel": "Pod 级别",
|
"podLevel": "Pod 级别",
|
||||||
"podNameLabel": "Pod 名称",
|
"podNameLabel": "Pod 名称",
|
||||||
"podManagePolicy": "Pod 管理策略"
|
"podManagePolicy": "Pod 管理策略",
|
||||||
|
"uploadFile": "上传"
|
||||||
},
|
},
|
||||||
"monitor": {
|
"monitor": {
|
||||||
"acknowledge": "确认告警",
|
"acknowledge": "确认告警",
|
||||||
@@ -8021,7 +8048,10 @@
|
|||||||
"expectedToReach": "预计",
|
"expectedToReach": "预计",
|
||||||
"days": "天",
|
"days": "天",
|
||||||
"afterReachThreshold": "后达到阈值",
|
"afterReachThreshold": "后达到阈值",
|
||||||
"aiSuggestion": "AI建议"
|
"aiSuggestion": "AI建议",
|
||||||
|
"warningTitle": "容量规划预警",
|
||||||
|
"currentThreshold": "当前 {{current}} / 阈值 {{threshold}}",
|
||||||
|
"predictedLabel": ",预测 {{predicted}}"
|
||||||
},
|
},
|
||||||
"capacityPlanPrompt": "根据以下主机资源使用数据,提供成本优化和容量规划建议(识别闲置/过载主机,给出缩容/扩容建议)",
|
"capacityPlanPrompt": "根据以下主机资源使用数据,提供成本优化和容量规划建议(识别闲置/过载主机,给出缩容/扩容建议)",
|
||||||
"capacityPlanning": "容量规划",
|
"capacityPlanning": "容量规划",
|
||||||
|
|||||||
Reference in new issue
Block a user