diff --git a/frontend/src/routes/_authenticated/traffic.tsx b/frontend/src/routes/_authenticated/traffic.tsx index a118448..5994d72 100644 --- a/frontend/src/routes/_authenticated/traffic.tsx +++ b/frontend/src/routes/_authenticated/traffic.tsx @@ -1,20 +1,233 @@ import { createFileRoute } from '@tanstack/react-router' -import { BarChart3 } from 'lucide-react' +import { useQuery } from '@tanstack/react-query' +import { BarChart3, Inbox } from 'lucide-react' +import { metricsApi, type FleetDevice } from '@/lib/api' +import { useAuth, isSuperAdmin } from '@/lib/auth' +import { useUIStore } from '@/lib/store' +import { Card, CardContent } from '@/components/ui/card' +import { cn } from '@/lib/utils' export const Route = createFileRoute('/_authenticated/traffic')({ component: TrafficPage, }) +function cpuColor(cpu: number | null): string { + if (cpu === null) return 'text-text-muted' + if (cpu < 50) return 'text-emerald-400' + if (cpu < 80) return 'text-yellow-400' + return 'text-red-400' +} + +function memColor(mem: number | null): string { + if (mem === null) return 'text-text-muted' + if (mem < 60) return 'text-emerald-400' + if (mem < 85) return 'text-yellow-400' + return 'text-red-400' +} + +function statusDot(status: string) { + const color = + status === 'online' + ? 'bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.6)]' + : status === 'degraded' + ? 'bg-yellow-400 shadow-[0_0_6px_rgba(250,204,21,0.6)]' + : 'bg-red-400 shadow-[0_0_6px_rgba(248,113,113,0.6)]' + return +} + function TrafficPage() { + const { user } = useAuth() + const selectedTenantId = useUIStore((s) => s.selectedTenantId) + const superAdmin = isSuperAdmin(user) + + const tenantId = superAdmin ? selectedTenantId : user?.tenant_id + + const { data: devices = [], isLoading } = useQuery({ + queryKey: ['fleet-summary', tenantId, superAdmin], + queryFn: () => + superAdmin && !tenantId + ? metricsApi.fleetSummaryAll() + : metricsApi.fleetSummary(tenantId!), + enabled: !!tenantId || superAdmin, + refetchInterval: 30_000, + }) + + // Sort by CPU load descending, nulls last + const sorted = [...devices].sort((a, b) => { + const aCpu = a.last_cpu_load ?? -1 + const bCpu = b.last_cpu_load ?? -1 + return bCpu - aCpu + }) + + const top10 = sorted.slice(0, 10) + + const avgCpu = + devices.length > 0 + ? devices.reduce((sum, d) => sum + (d.last_cpu_load ?? 0), 0) / devices.length + : null + + const avgMem = + devices.length > 0 + ? devices.reduce((sum, d) => sum + (d.last_memory_used_pct ?? 0), 0) / devices.length + : null + + const onlineCount = devices.filter((d) => d.status === 'online').length + return ( -
- Bandwidth monitoring and traffic analysis — coming soon. -
+ + {/* KPI Cards */} ++ Fleet Avg CPU +
++ {isLoading ? '--' : avgCpu !== null ? `${avgCpu.toFixed(1)}%` : 'N/A'} +
++ Fleet Avg Memory +
++ {isLoading ? '--' : avgMem !== null ? `${avgMem.toFixed(1)}%` : 'N/A'} +
++ Devices Online +
++ {isLoading ? '--' : `${onlineCount} / ${devices.length}`} +
+Loading fleet data...
++ No device data available +
+| + Hostname + | + {superAdmin && !tenantId && ( ++ Tenant + | + )} ++ IP Address + | ++ CPU Load + | ++ Memory % + | ++ Status + | +
|---|---|---|---|---|---|
| + {device.hostname} + | + {superAdmin && !tenantId && ( ++ {device.tenant_name} + | + )} ++ {device.ip_address} + | ++ {device.last_cpu_load !== null + ? `${device.last_cpu_load}%` + : '--'} + | ++ {device.last_memory_used_pct !== null + ? `${device.last_memory_used_pct.toFixed(1)}%` + : '--'} + | +
+
+ {statusDot(device.status)}
+
+ {device.status}
+
+
+ |
+
- Wireless monitoring and statistics — coming soon. -
+ + {/* KPI Cards */} ++ APs with Issues +
++ {isLoading ? '--' : issues.length} +
++ Worst Signal +
++ {isLoading ? '--' : worstSignal !== null ? `${worstSignal} dBm` : 'N/A'} +
++ Total Clients +
++ {isLoading ? '--' : totalClients} +
+Loading wireless data...
++ All Clear — no wireless issues detected +
+| + Hostname + | + {superAdmin && !tenantId && ( ++ Tenant + | + )} ++ Interface + | ++ Issue + | ++ Signal + | ++ CCQ + | ++ Clients + | ++ Frequency + | +
|---|---|---|---|---|---|---|---|
|
+
+
+ {issue.hostname}
+
+ |
+ {superAdmin && !tenantId && (
+ + {issue.tenant_name ?? '--'} + | + )} ++ {issue.interface} + | ++ {issue.issue} + | ++ {issue.signal !== null ? `${issue.signal} dBm` : '--'} + | ++ {issue.ccq !== null ? `${issue.ccq}%` : '--'} + | ++ {issue.client_count} + | ++ {issue.frequency ? `${issue.frequency} MHz` : '--'} + | +