fix(web): C2 拓撲元件 i18n — 10+ 處硬編碼中文改 useTranslations
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled

This commit is contained in:
OG T
2026-04-09 11:04:35 +08:00
parent 7153395267
commit 9e10305acc
5 changed files with 46 additions and 21 deletions

View File

@@ -808,12 +808,19 @@
},
"topology": {
"title": "Topology",
"subtitle": "Host architecture view",
"subtitle": "Service dependencies & health status",
"noHosts": "No host data available",
"fetchError": "Failed to load host data",
"services": "Services",
"cpu": "CPU",
"ram": "RAM"
"ram": "RAM",
"groupInfra": "Infrastructure",
"groupSecurity": "Security",
"groupK3s": "K3s Cluster",
"groupAiData": "AI/Data Center",
"allHealthy": "All Healthy",
"warning": "Warning",
"healthy": "Healthy"
},
"notifications": {
"title": "Notifications",

View File

@@ -809,12 +809,19 @@
},
"topology": {
"title": "拓撲圖",
"subtitle": "主機架構視圖",
"subtitle": "服務依賴與健康狀態",
"noHosts": "目前無主機資料",
"fetchError": "無法取得主機資料",
"services": "服務",
"cpu": "CPU",
"ram": "RAM"
"ram": "RAM",
"groupInfra": "基礎設施",
"groupSecurity": "安全中心",
"groupK3s": "K3s 叢集",
"groupAiData": "AI/數據中心",
"allHealthy": "全部健康",
"warning": "異常",
"healthy": "健康"
},
"notifications": {
"title": "通知",

View File

@@ -29,6 +29,7 @@ import {
} from '@xyflow/react'
import '@xyflow/react/dist/style.css'
import { useTranslations } from 'next-intl'
import { useTopologyData } from './hooks/useTopologyData'
import { ServiceNode } from './nodes/ServiceNode'
import { GroupNode } from './nodes/GroupNode'
@@ -72,6 +73,7 @@ export function ServiceTopology({
showMiniMap = false,
height = '100%',
}: ServiceTopologyProps) {
const t = useTranslations('dashboard')
const { nodes, edges, hostCount, serviceCount, healthyCount, warningCount } = useTopologyData()
// 空狀態
@@ -82,9 +84,9 @@ export function ServiceTopology({
height: typeof height === 'number' ? height : '100%',
color: '#87867f', fontSize: 13,
}}>
<div style={{ fontSize: 28, opacity: 0.3, marginBottom: 8 }}>🌐</div>
<div>...</div>
<div style={{ fontSize: 10, marginTop: 4 }}>Dashboard API </div>
<div style={{ fontSize: 28, opacity: 0.3, marginBottom: 8 }}>--</div>
<div>{t('waitingHostData')}</div>
<div style={{ fontSize: 10, marginTop: 4 }}>{t('dashboardConnecting')}</div>
</div>
)
}
@@ -99,10 +101,10 @@ export function ServiceTopology({
background: 'rgba(250,249,243,0.9)', padding: '4px 10px', borderRadius: 6,
border: '0.5px solid #e0ddd4',
}}>
<span>{hostCount} </span>
<span>{serviceCount} </span>
<span style={{ color: '#22C55E' }}>{healthyCount} </span>
{warningCount > 0 && <span style={{ color: '#F59E0B' }}>{warningCount} </span>}
<span>{hostCount} {t('hostsLabel')}</span>
<span>{serviceCount}</span>
<span style={{ color: '#22C55E' }}>{healthyCount}</span>
{warningCount > 0 && <span style={{ color: '#F59E0B' }}>{warningCount}</span>}
</div>
<ReactFlow

View File

@@ -21,11 +21,12 @@ import type { Node, Edge } from '@xyflow/react'
// 群組配置 (對應 host_aggregator.py HostRole)
// =============================================================================
const GROUP_CONFIG: Record<string, { label: string; color: string; borderColor: string; bgColor: string }> = {
devops: { label: '基礎設施', color: '#3B82F6', borderColor: 'rgba(59,130,246,0.25)', bgColor: 'rgba(59,130,246,0.02)' },
security: { label: '安全中心', color: '#cc2200', borderColor: 'rgba(204,34,0,0.25)', bgColor: 'rgba(204,34,0,0.02)' },
k3s: { label: 'K3s 叢集', color: '#A855F7', borderColor: 'rgba(168,85,247,0.25)', bgColor: 'rgba(168,85,247,0.02)' },
ai_web: { label: 'AI/數據中心', color: '#F97316', borderColor: 'rgba(249,115,22,0.25)', bgColor: 'rgba(249,115,22,0.02)' },
// C2: 群組標籤用 key 而非硬編碼中文i18n 在元件層處理)
const GROUP_CONFIG: Record<string, { labelKey: string; color: string; borderColor: string; bgColor: string }> = {
devops: { labelKey: 'infra', color: '#3B82F6', borderColor: 'rgba(59,130,246,0.25)', bgColor: 'rgba(59,130,246,0.02)' },
security: { labelKey: 'security', color: '#cc2200', borderColor: 'rgba(204,34,0,0.25)', bgColor: 'rgba(204,34,0,0.02)' },
k3s: { labelKey: 'k3s', color: '#A855F7', borderColor: 'rgba(168,85,247,0.25)', bgColor: 'rgba(168,85,247,0.02)' },
ai_web: { labelKey: 'aiData', color: '#F97316', borderColor: 'rgba(249,115,22,0.25)', bgColor: 'rgba(249,115,22,0.02)' },
}
// =============================================================================
@@ -85,7 +86,8 @@ export function useTopologyData(): TopologyData {
type: 'groupNode',
position: { x: (hostIdx % 2) * 350, y: Math.floor(hostIdx / 2) * 300 },
data: {
label: `${config.label} (${host.ip.split('.').pop()})`,
labelKey: config.labelKey,
ipSuffix: host.ip.split('.').pop(),
role: host.role,
status: host.status,
ip: host.ip,

View File

@@ -13,8 +13,15 @@
import { memo, type CSSProperties } from 'react'
import { type NodeProps } from '@xyflow/react'
import { useTranslations } from 'next-intl'
// C2: 群組標籤 i18n
const GROUP_LABELS: Record<string, string> = {
infra: 'groupInfra', security: 'groupSecurity', k3s: 'groupK3s', aiData: 'groupAiData',
}
function GroupNodeInner({ data }: NodeProps) {
const t = useTranslations('topology')
const d = data as Record<string, any>
const borderColor = d.borderColor || '#e0ddd4'
const bgColor = d.bgColor || 'rgba(0,0,0,0.01)'
@@ -39,15 +46,15 @@ function GroupNodeInner({ data }: NodeProps) {
{/* 群組標題 */}
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
<span style={{ fontSize: 12, fontWeight: 600, color: '#141413' }}>
{d.label}
{t(GROUP_LABELS[d.labelKey] || 'groupInfra')} (.{d.ipSuffix})
</span>
</div>
{/* 摘要 */}
<div style={{ fontSize: 10, color: '#555550' }}>
{totalSvc} · {hasWarning
? <span style={{ color: '#F59E0B' }}> {totalSvc - healthySvc} </span>
: <span style={{ color: '#22C55E' }}> </span>
{totalSvc} {t('services')} · {hasWarning
? <span style={{ color: '#F59E0B' }}>{totalSvc - healthySvc} {t('warning')}</span>
: <span style={{ color: '#22C55E' }}>{t('allHealthy')}</span>
}
</div>