diff --git a/apps/web/src/components/infra/host-grid.tsx b/apps/web/src/components/infra/host-grid.tsx new file mode 100644 index 000000000..8a098eaa0 --- /dev/null +++ b/apps/web/src/components/infra/host-grid.tsx @@ -0,0 +1,111 @@ +'use client' + +/** + * HostGrid - 2×2 主機緊湊 Grid + * ================================ + * 每格:hostname + IP + CPU/RAM + 3條關鍵服務 mini 列 + * hover 橘紅邊框,異常指標用警示色 + * 統帥鐵律:無數據顯示 "--",禁止假數據 + */ + +export interface HostService { + name: string + healthy: boolean +} + +export interface HostInfo { + hostname: string + ip: string + cpuPct: number | null + ramPct: number | null + services: HostService[] +} + +export interface HostGridProps { + hosts: HostInfo[] +} + +function MetricBar({ value, warn = 80, critical = 90 }: { value: number | null; warn?: number; critical?: number }) { + if (value === null) return -- + const color = value >= critical ? '#cc2200' : value >= warn ? '#F59E0B' : '#22C55E' + return ( + {value}% + ) +} + +export function HostGrid({ hosts }: HostGridProps) { + // 補足至 4 格(不足時顯示空格) + const slots = [...hosts, ...Array(Math.max(0, 4 - hosts.length)).fill(null)] + + return ( +
+ {slots.map((host: HostInfo | null, idx) => ( +
host && ((e.currentTarget as HTMLDivElement).style.borderColor = '#d97757')} + onMouseLeave={e => host && ((e.currentTarget as HTMLDivElement).style.borderColor = '#e0ddd4')} + > + {host ? ( + <> + {/* Hostname + IP */} +
+
+
+ + {host.hostname} + +
+ {host.ip} +
+ + {/* CPU / RAM */} +
+ + CPU + + + RAM + +
+ + {/* 3 關鍵服務 mini 列 */} +
+ {host.services.slice(0, 3).map((svc, si) => ( +
+
+ + {svc.name} + +
+ ))} +
+ + ) : ( +
+ -- +
+ )} +
+ ))} +
+ ) +} + +export default HostGrid