import { useQuery } from '@tanstack/react-query' import { useState, useMemo, useEffect } from 'react' import apiClient from '@/api/client' import { monitoringApi } from '@/api/monitoring' import { storageApi } from '@/api/storage' import { formatBytes } from '@/lib/format' import { Cpu, MemoryStick, Clock, Activity, RefreshCw, TrendingDown, CheckCircle2, AlertTriangle } from 'lucide-react' import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts' export default function Dashboard() { const [activeTab, setActiveTab] = useState<'jobs' | 'logs' | 'alerts'>('jobs') const [networkDataPoints, setNetworkDataPoints] = useState>([]) const refreshInterval = 5 const { data: health } = useQuery({ queryKey: ['health'], queryFn: async () => { const response = await apiClient.get('/health') return response.data }, refetchInterval: refreshInterval * 1000, }) const { data: metrics } = useQuery({ queryKey: ['metrics'], queryFn: monitoringApi.getMetrics, refetchInterval: refreshInterval * 1000, }) const { data: alerts } = useQuery({ queryKey: ['alerts', 'dashboard'], queryFn: () => monitoringApi.listAlerts({ is_acknowledged: false, limit: 10 }), refetchInterval: refreshInterval * 1000, }) const { data: repositories = [] } = useQuery({ queryKey: ['storage', 'repositories'], queryFn: storageApi.listRepositories, }) // Calculate uptime (mock for now, would come from metrics) const uptime = metrics?.system?.uptime_seconds || 0 const days = Math.floor(uptime / 86400) const hours = Math.floor((uptime % 86400) / 3600) const minutes = Math.floor((uptime % 3600) / 60) // Mock active jobs (would come from tasks API) const activeJobs = [ { id: '1', name: 'Daily Backup: VM-Cluster-01', type: 'Replication', progress: 45, speed: '145 MB/s', status: 'running', eta: '1h 12m', }, { id: '2', name: 'ZFS Scrub: Pool-01', type: 'Maintenance', progress: 78, speed: '1.2 GB/s', status: 'running', }, ] // Mock system logs const systemLogs = [ { time: '10:45:22', level: 'INFO', source: 'systemd', message: 'Started User Manager for UID 1000.' }, { time: '10:45:15', level: 'WARN', source: 'smartd', message: 'Device: /dev/ada5, SMART Usage Attribute: 194 Temperature_Celsius changed from 38 to 41' }, { time: '10:44:58', level: 'INFO', source: 'kernel', message: 'ix0: link state changed to UP' }, { time: '10:42:10', level: 'INFO', source: 'zfs', message: 'zfs_arc_reclaim_thread: reclaiming 157286400 bytes ...' }, ] const totalStorage = Array.isArray(repositories) ? repositories.reduce((sum, repo) => sum + (repo?.size_bytes || 0), 0) : 0 const usedStorage = Array.isArray(repositories) ? repositories.reduce((sum, repo) => sum + (repo?.used_bytes || 0), 0) : 0 const storagePercent = totalStorage > 0 ? (usedStorage / totalStorage) * 100 : 0 // Initialize network data useEffect(() => { // Generate initial 30 data points const initialData = [] const now = Date.now() for (let i = 29; i >= 0; i--) { const time = new Date(now - i * 5000) const minutes = time.getMinutes().toString().padStart(2, '0') const seconds = time.getSeconds().toString().padStart(2, '0') const baseInbound = 800 + Math.random() * 400 const baseOutbound = 400 + Math.random() * 200 initialData.push({ time: `${minutes}:${seconds}`, inbound: Math.round(baseInbound), outbound: Math.round(baseOutbound), }) } setNetworkDataPoints(initialData) // Update data every 5 seconds const interval = setInterval(() => { setNetworkDataPoints((prev) => { const now = new Date() const minutes = now.getMinutes().toString().padStart(2, '0') const seconds = now.getSeconds().toString().padStart(2, '0') const baseInbound = 800 + Math.random() * 400 const baseOutbound = 400 + Math.random() * 200 const newPoint = { time: `${minutes}:${seconds}`, inbound: Math.round(baseInbound), outbound: Math.round(baseOutbound), } // Keep only last 30 points const updated = [...prev.slice(1), newPoint] return updated }) }, 5000) return () => clearInterval(interval) }, []) // Calculate current and peak throughput const currentThroughput = useMemo(() => { if (networkDataPoints.length === 0) return { inbound: 0, outbound: 0, total: 0 } const last = networkDataPoints[networkDataPoints.length - 1] return { inbound: last.inbound, outbound: last.outbound, total: last.inbound + last.outbound, } }, [networkDataPoints]) const peakThroughput = useMemo(() => { if (networkDataPoints.length === 0) return 0 return Math.max(...networkDataPoints.map((d) => d.inbound + d.outbound)) }, [networkDataPoints]) const systemStatus = health?.status === 'healthy' ? 'System Healthy' : 'System Degraded' const isHealthy = health?.status === 'healthy' return (
{/* Header */}

System Monitor

Real-time telemetry, storage health, and system event logs

{isHealthy && ( <> )} {!isHealthy && ( )} {systemStatus}
{/* Scrollable Content */}
{/* Top Stats Row */}
{/* CPU */}

CPU Load

{metrics?.system?.cpu_usage_percent?.toFixed(0) || 0}%

2%
{/* RAM */}

RAM Usage

{formatBytes(metrics?.system?.memory_used_bytes || 0, 1)}

/ {formatBytes(metrics?.system?.memory_total_bytes || 0, 1)}
{/* Storage Health */}

Storage Status

Online

No Errors
{/* Uptime */}

System Uptime

{days}d {hours}h {minutes}m

Last reboot: Manual Patching

{/* Middle Section: Charts & Storage */}
{/* Charts Column (2/3) */}
{/* Network Chart */}

Network Throughput

Inbound vs Outbound (eth0)

{(currentThroughput.total / 1000).toFixed(1)} Gbps

Peak: {(peakThroughput / 1000).toFixed(1)} Gbps

[`${value} Mbps`, '']} />
{/* Storage Chart */}

Storage Capacity

Repository usage

{storagePercent.toFixed(1)}%

Target: <90%

{/* Storage Info Column (1/3) */}

Storage Overview

{repositories?.length || 0} Repos
Total Capacity {formatBytes(totalStorage)}
Used: {formatBytes(usedStorage)} Free: {formatBytes(totalStorage - usedStorage)}
{/* Bottom Section: Tabs & Logs */}
{/* Tabs Header */}
{/* Tab Content */}
{activeTab === 'jobs' && (
{activeJobs.map((job) => ( ))}
Job Name Type Progress Speed Status
{job.name} {job.type}
{job.progress}%
{job.eta && (

ETA: {job.eta}

)}
{job.speed} Running
)} {activeTab === 'logs' && ( <>

Recent System Events

{systemLogs.map((log, idx) => ( ))}
{log.time} {log.level} {log.source} {log.message}
)} {activeTab === 'alerts' && (
{alerts?.alerts && alerts.alerts.length > 0 ? (
{alerts.alerts.map((alert) => (

{alert.title}

{alert.severity}

{alert.message}

{new Date(alert.created_at).toLocaleString()}

))}
) : (

No alerts

)}
)}
) }