import { AlertTriangle, CheckCircle2, Clock, Database, GitBranch, Loader2, Server, } from 'lucide-react'; import { useEffect, useState } from 'react'; interface HealthData { status: 'healthy' | 'ok' | 'degraded' | string; version?: string; environment?: string; uptime?: number; services?: { database?: { status: 'ok' | 'degraded' | 'not_configured' | string; latencyMs?: number | null; }; }; } function formatUptime(seconds: number): string { if (seconds < 60) return `${Math.round(seconds)}s`; if (seconds < 3600) return `${Math.round(seconds / 60)}m`; const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); return `${h}h ${m}m`; } function StatusDot({ ok }: { ok: boolean }) { return ( ); } export function ServiceStatusPanel() { const [health, setHealth] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); useEffect(() => { const baseUrl = import.meta.env.BASE_URL?.replace(/\/$/, '') || ''; const apiBase = baseUrl.replace(/\/command$/, ''); fetch(`${apiBase}/api/health`) .then(async (r) => { const data = await r.json().catch(() => null); if (data && (r.ok || r.status === 503)) { setHealth(data as HealthData); } else { setError(true); } setLoading(false); }) .catch(() => { setError(true); setLoading(false); }); }, []); const apiOk = !error && (health?.status === 'healthy' || health?.status === 'ok'); const dbStatus = health?.services?.database?.status; const dbOk = !error && dbStatus === 'ok'; const dbLatency = health?.services?.database?.latencyMs; const items = [ { icon: Server, label: 'API', value: loading ? '—' : error ? 'Unreachable' : health?.status === 'healthy' || health?.status === 'ok' ? 'Operational' : health?.status === 'degraded' ? 'Degraded' : (health?.status ?? 'Unknown'), ok: apiOk, }, { icon: Database, label: 'Database', value: loading ? '—' : error ? '—' : dbStatus === 'ok' ? `${dbLatency ?? '?'}ms` : dbStatus === 'not_configured' ? 'Not configured' : 'Degraded', ok: dbOk, }, { icon: Clock, label: 'Uptime', value: loading ? '—' : error ? '—' : health?.uptime != null ? formatUptime(health.uptime) : '—', ok: !error && health?.uptime != null, }, { icon: GitBranch, label: 'Version', value: loading ? '—' : error ? '—' : (health?.version ?? '—'), ok: !error && !!health?.version, }, ]; return ( Service Status {loading ? ( ) : error ? ( API unreachable ) : ( {health?.environment ?? 'live'} )} {items.map(({ icon: Icon, label, value, ok }) => ( {label} {!loading && } {value} ))} ); }