import StatusBadge from './StatusBadge'; /** * Formats bytes to human-readable string. * @param {number} bytes * @returns {string} */ function formatBytes(bytes) { if (!bytes) return '0 B'; const units = ['B', 'KB', 'MB', 'GB', 'TB']; let i = 0; let v = bytes; while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; } return `${v.toFixed(1)} ${units[i]}`; } /** * Formats seconds to human-readable duration. * @param {number} seconds * @returns {string} */ function formatUptime(seconds) { if (!seconds) return 'N/A'; const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days) return `${days}d ${hours}h ${minutes}m`; if (hours) return `${hours}h ${minutes}m`; return `${minutes}m`; } /** * @param {{ node: { name: string; type: string; cpu: number; memory: { total: number; used: number }; status: string; uptime: number; load: number } }} props * @returns {import('react').ReactNode} */ export default function NodeCard({ node }) { const cpuPercent = Math.round((node.cpu || 0) * 100); const memPercent = node.memory?.total ? Math.round((node.memory.used / node.memory.total) * 100) : 0; return (

{node.name}

CPU {cpuPercent}%
Memory {formatBytes(node.memory?.used || 0)} / {formatBytes(node.memory?.total || 0)}
90 ? 'bg-status-red' : memPercent > 70 ? 'bg-status-yellow' : 'bg-accent' }`} style={{ width: `${Math.min(memPercent, 100)}%` }} />
Load: {node.load?.toFixed(2) || 'N/A'} Uptime: {formatUptime(node.uptime)}
); }