From ba4ee46514bc4fdc9f2145d19be4669c9c7e17fe Mon Sep 17 00:00:00 2001 From: OG T Date: Thu, 2 Apr 2026 21:36:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=E6=9E=B6=E6=A7=8B=E5=B8=AB=20Review?= =?UTF-8?q?=20=E4=BF=AE=E5=BE=A9=20=E2=80=94=20i18n/keyframe/=E5=9E=8B?= =?UTF-8?q?=E5=88=A5/=E7=89=88=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical: - flow-pipeline.tsx: 移除 4 個重複 lobster-bob keyframe,統一在父元件注入 修正 isResolved 路由邏輯,保留嚴重度視覺識別 (P0 resolved 仍用 StyleA) - incident-card.tsx: 修復 4 個硬編碼中文字串 (affectedServices/signalCount/statusLabel/aiProposal) 新增對應 i18n key 到 zh-TW.json + en.json Warning: - page.tsx: MetricItem type 提升至 module scope,pendingApprovals null 安全檢查 Metrics Strip 移除固定 height:68px 改為 auto + padding:8px Co-Authored-By: Claude Sonnet 4.6 --- apps/web/messages/en.json | 6 ++- apps/web/messages/zh-TW.json | 6 ++- apps/web/src/app/[locale]/page.tsx | 33 +++++++++------- .../src/components/incident/flow-pipeline.tsx | 39 ++++++++----------- .../src/components/incident/incident-card.tsx | 8 ++-- 5 files changed, 50 insertions(+), 42 deletions(-) diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index a1e2b4a5..384e2f39 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -310,7 +310,11 @@ "suggestedAction": "> Suggested action:", "authorize": "Authorize", "reject": "Reject", - "anomaly": "anomaly" + "anomaly": "anomaly", + "affectedServices": "Affected Services", + "signalCount": "Signals", + "statusLabel": "Status", + "aiProposal": "AI Proposal" } }, "status": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index c89f8bbf..5742acbd 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -311,7 +311,11 @@ "suggestedAction": "> 建議行動:", "authorize": "授權", "reject": "拒絕", - "anomaly": "異常" + "anomaly": "異常", + "affectedServices": "影響服務", + "signalCount": "信號數", + "statusLabel": "狀態", + "aiProposal": "AI 提案" } }, "status": { diff --git a/apps/web/src/app/[locale]/page.tsx b/apps/web/src/app/[locale]/page.tsx index 0f2fb259..dcaea2d1 100644 --- a/apps/web/src/app/[locale]/page.tsx +++ b/apps/web/src/app/[locale]/page.tsx @@ -20,6 +20,19 @@ import { OpenClawPanel } from '@/components/ai/openclaw-panel' import { HostGrid, type HostInfo } from '@/components/infra/host-grid' import { AppLayout } from '@/components/layout' +// ============================================================================= +// Types +// ============================================================================= + +interface MetricItem { + label: string + value: string | number + sub?: string + badge?: { text: string; color: string; bg: string } + sparkline?: { values: number[]; color: string } + valueColor?: string +} + // ============================================================================= // Mini Sparkline (SVG inline) // ============================================================================= @@ -118,14 +131,7 @@ export default function Home({ params }: { params: { locale: string } }) { // ── 7 Metrics Strip ───────────────────────────────────────────────────────── - type MetricItem = { - label: string - value: string | number - sub?: string - badge?: { text: string; color: string; bg: string } - sparkline?: { values: number[]; color: string } - valueColor?: string - } + const hasPendingApprovals = pendingApprovals !== null && pendingApprovals !== undefined && pendingApprovals > 0 const metrics: MetricItem[] = [ { @@ -144,9 +150,9 @@ export default function Home({ params }: { params: { locale: string } }) { { label: tDashboard('pendingApprovals'), value: pendingApprovals ?? '--', - sub: pendingApprovals > 0 ? undefined : tDashboard('stable'), - badge: pendingApprovals > 0 ? { text: tDashboard('pendingApprovals'), color: '#F59E0B', bg: 'rgba(245,158,11,0.08)' } : undefined, - valueColor: pendingApprovals > 0 ? '#F59E0B' : undefined, + sub: hasPendingApprovals ? undefined : tDashboard('stable'), + badge: hasPendingApprovals ? { text: `⏳ ${pendingApprovals}`, color: '#F59E0B', bg: 'rgba(245,158,11,0.08)' } : undefined, + valueColor: hasPendingApprovals ? '#F59E0B' : undefined, }, { label: tDashboard('autoRemediationRate'), @@ -184,8 +190,7 @@ export default function Home({ params }: { params: { locale: string } }) {
{/* 進度條軌道 */}
{/* 底部軌道 */} @@ -248,7 +244,6 @@ function PipelineStyleC({ activeStage, isResolved }: { activeStage: FlowStage; i return (
{FLOW_NODES.map((node, idx) => { const status = getNodeStatus(node.id, activeStage, isResolved) @@ -382,22 +371,28 @@ function PipelineStyleD({ activeStage, isResolved }: { activeStage: FlowStage; i ) } +// ── Shared Keyframes (injected once at top level to avoid duplication) ──────── + +const SHARED_KEYFRAMES = ` + @keyframes lobster-bob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-4px)} } + @keyframes dash-march { to { stroke-dashoffset: -20; } } +` + // ── Main Component ──────────────────────────────────────────────────────────── export function FlowPipeline({ activeStage, isResolved = false, severity = 'P3', tooltips: _tooltips }: FlowPipelineProps) { // 2026-04-02 Claude Code: severity → pipeline style mapping // P0=StyleA(脈衝光波) P1=StyleB(進度條) P2=StyleC(卡片步驟) P3=StyleD(時間軸) - if (isResolved || severity === 'P3') { - return - } - if (severity === 'P0') { - return - } - if (severity === 'P1') { - return - } - // P2 - return + // isResolved 傳入各 Style 自行處理顏色,保留嚴重度視覺識別 + return ( + <> + + {severity === 'P0' && } + {severity === 'P1' && } + {severity === 'P2' && } + {(severity === 'P3' || !['P0','P1','P2'].includes(severity)) && } + + ) } export default FlowPipeline diff --git a/apps/web/src/components/incident/incident-card.tsx b/apps/web/src/components/incident/incident-card.tsx index c04551f8..a6255d09 100644 --- a/apps/web/src/components/incident/incident-card.tsx +++ b/apps/web/src/components/incident/incident-card.tsx @@ -306,13 +306,13 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC flexWrap: 'wrap' as const, }}> - 影響服務 {incident.affected_services?.length ?? 0} + {t('affectedServices')} {incident.affected_services?.length ?? 0} - 信號數 {incident.signal_count ?? '--'} + {t('signalCount')} {incident.signal_count ?? '--'} - 狀態 {incident.status} + {t('statusLabel')} {incident.status}
@@ -340,7 +340,7 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC }} > - AI 提案: {decisionAction.slice(0, 50)}{decisionAction.length > 50 ? '...' : ''} + {t('aiProposal')}: {decisionAction.slice(0, 50)}{decisionAction.length > 50 ? '...' : ''} {aiExpanded ? '▲' : '▼'} {aiExpanded && (