"use client";
/**
* SystemMonitor — Real-time system metrics widget
*
* Displays CPU/memory/uptime and token throughput metrics.
* Fetches from /api/monitoring/health periodically.
*
* @module shared/components/SystemMonitor
*/
import { useState, useEffect, useRef } from "react";
import Card from "./Card";
const REFRESH_INTERVAL = 10000; // 10s
function formatUptime(seconds) {
if (!seconds) return "N/A";
const d = Math.floor(seconds / 86400);
const h = Math.floor((seconds % 86400) / 3600);
const m = Math.floor((seconds % 3600) / 60);
if (d > 0) return `${d}d ${h}h`;
if (h > 0) return `${h}h ${m}m`;
return `${m}m`;
}
function formatBytes(bytes) {
if (!bytes) return "0 B";
const units = ["B", "KB", "MB", "GB"];
let i = 0;
let val = bytes;
while (val >= 1024 && i < units.length - 1) {
val /= 1024;
i++;
}
return `${val.toFixed(1)} ${units[i]}`;
}
function MetricRow({ icon, label, value, color = "text-text-main" }) {
return (
);
}
export default function SystemMonitor({ compact = false }) {
const [metrics, setMetrics] = useState(null);
const [error, setError] = useState(false);
const mountedRef = useRef(true);
useEffect(() => {
mountedRef.current = true;
async function poll() {
try {
const res = await fetch("/api/monitoring/health");
if (!mountedRef.current) return;
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (!mountedRef.current) return;
setMetrics(data);
setError(false);
} catch {
if (mountedRef.current) setError(true);
}
}
poll();
const interval = setInterval(poll, REFRESH_INTERVAL);
return () => {
mountedRef.current = false;
clearInterval(interval);
};
}, []);
if (error && !metrics) {
return (
error
Unable to load system metrics
);
}
if (!metrics) {
return (
);
}
const memUsed = metrics.memory?.heapUsed || metrics.memoryUsage?.heapUsed || 0;
const memTotal = metrics.memory?.heapTotal || metrics.memoryUsage?.heapTotal || 1;
const memPercent = Math.round((memUsed / memTotal) * 100);
const memColor =
memPercent > 80 ? "text-red-400" : memPercent > 60 ? "text-amber-400" : "text-green-400";
if (compact) {
return (
{memPercent}% mem
⏱ {formatUptime(metrics.uptime)}
);
}
return (
monitoring
System Monitor
{metrics.version && (
)}
{metrics.activeConnections !== undefined && (
)}
{metrics.circuitBreakers && (
0 ? "text-amber-400" : "text-green-400"}
/>
)}
{/* Memory bar */}
80 ? "bg-red-400" : memPercent > 60 ? "bg-amber-400" : "bg-green-400"
}`}
style={{ width: `${memPercent}%` }}
role="progressbar"
aria-valuenow={memPercent}
aria-valuemin={0}
aria-valuemax={100}
aria-label={`Memory usage: ${memPercent}%`}
/>
);
}