/** * Network Traffic Dashboard — Main Tab * Ball Studios */ import React, { useEffect, useState, useCallback } from 'react'; import { useParams } from 'react-router-dom'; import http from '@/api/http'; import LiveTrafficCards from './LiveTrafficCards'; import TrafficChart from './TrafficChart'; import PortTable from './PortTable'; import FlowGraph from './FlowGraph'; interface LiveStats { rx_bytes: number; tx_bytes: number; recorded_at: string; } interface HistoryPoint { rx_bytes: number; tx_bytes: number; recorded_at: string; } type Resolution = '5m' | '1h' | '1d'; export default function NetworkTab() { const { id: serverUuid } = useParams<{ id: string }>(); const [live, setLive] = useState(null); const [history, setHistory] = useState([]); const [ports, setPorts] = useState([]); const [flows, setFlows] = useState([]); const [resolution, setRes] = useState('5m'); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchLive = useCallback(async () => { if (!serverUuid) return; try { const { data } = await http.get(`/api/client/servers/${serverUuid}/addons/network/live`); setLive(data.data); } catch { // silently fail on live poll errors } }, [serverUuid]); const fetchHistory = useCallback(async () => { if (!serverUuid) return; const { data } = await http.get(`/api/client/servers/${serverUuid}/addons/network/history`, { params: { resolution }, }); setHistory(data.data ?? []); }, [serverUuid, resolution]); const fetchPorts = useCallback(async () => { if (!serverUuid) return; const { data } = await http.get(`/api/client/servers/${serverUuid}/addons/network/ports`); setPorts(data.data ?? []); }, [serverUuid]); const fetchFlows = useCallback(async () => { if (!serverUuid) return; const { data } = await http.get(`/api/client/servers/${serverUuid}/addons/network/flows`); setFlows(data.data ?? []); }, [serverUuid]); // Initial load useEffect(() => { setLoading(true); setError(null); Promise.all([fetchHistory(), fetchPorts(), fetchFlows()]) .catch(() => setError('Failed to load network data.')) .finally(() => setLoading(false)); }, [fetchHistory, fetchPorts, fetchFlows]); // Live polling — every 10s useEffect(() => { fetchLive(); const id = setInterval(fetchLive, 10_000); return () => clearInterval(id); }, [fetchLive]); if (loading) return
Loading network data…
; if (error) return
{error}
; return (

🌐 Network Traffic

{/* Live cards */} {/* Historical chart */}
Bandwidth Over Time
{(['5m', '1h', '1d'] as Resolution[]).map(r => ( ))}
{/* Port breakdown */}
Top Ports
{/* Flow graph */}
Container Traffic Flow
); }