use network probes

This commit is contained in:
henrygd
2026-04-21 15:29:46 -04:00
parent a95376b4a2
commit 48fe407292
6 changed files with 326 additions and 191 deletions

View File

@@ -1,13 +1,11 @@
import { lazy, useEffect, useRef, useState } from "react"
import { lazy } from "react"
import { useIntersectionObserver } from "@/lib/use-intersection-observer"
import { chartTimeData, cn } from "@/lib/utils"
import { NetworkProbeRecord, NetworkProbeStatsRecord } from "@/types"
import { LatencyChart } from "./charts/probes-charts"
import { SystemData } from "./use-system-data"
import { cn } from "@/lib/utils"
import { LatencyChart, LossChart } from "./charts/probes-charts"
import type { SystemData } from "./use-system-data"
import { $chartTime } from "@/lib/stores"
import { useStore } from "@nanostores/react"
import system from "../system"
import { getStats, appendData } from "./chart-data"
import { useNetworkProbesData } from "@/lib/use-network-probes"
const ContainersTable = lazy(() => import("../../containers-table/containers-table"))
@@ -44,75 +42,43 @@ export function LazySystemdTable({ systemId }: { systemId: string }) {
const NetworkProbesTable = lazy(() => import("@/components/network-probes-table/network-probes-table"))
const cache = new Map<string, any>()
export function LazyNetworkProbesTable({ systemId, systemData }: { systemId: string; systemData: SystemData }) {
const { grid, chartData } = systemData ?? {}
const [probes, setProbes] = useState<NetworkProbeRecord[]>([])
const chartTime = useStore($chartTime)
const [probeStats, setProbeStats] = useState<NetworkProbeStatsRecord[]>([])
const { isIntersecting, ref } = useIntersectionObserver()
const statsRequestId = useRef(0)
// get stats when system "changes." (Not just system to system,
// also when new info comes in via systemManager realtime connection, indicating an update)
useEffect(() => {
if (!systemId || !chartTime || chartTime === "1m") {
return
}
const { expectedInterval } = chartTimeData[chartTime]
const ss_cache_key = `${systemId}${chartTime}`
const requestId = ++statsRequestId.current
const cachedProbeStats = cache.get(ss_cache_key) as NetworkProbeStatsRecord[] | undefined
// Render from cache immediately if available
if (cachedProbeStats?.length) {
setProbeStats(cachedProbeStats)
// Skip the fetch if the latest cached point is recent enough that no new point is expected yet
const lastCreated = cachedProbeStats.at(-1)?.created as number | undefined
if (lastCreated && Date.now() - lastCreated < expectedInterval * 0.9) {
return
}
}
getStats<NetworkProbeStatsRecord>("network_probe_stats", systemId, chartTime, cachedProbeStats).then(
(probeStats) => {
// If another request has been made since this one, ignore the results
if (requestId !== statsRequestId.current) {
return
}
// make new system stats
let probeStatsData = (cache.get(ss_cache_key) || []) as NetworkProbeStatsRecord[]
if (probeStats.length) {
probeStatsData = appendData(probeStatsData, probeStats, expectedInterval, 100)
cache.set(ss_cache_key, probeStatsData)
}
setProbeStats(probeStatsData)
}
)
}, [system, chartTime, probes])
return (
<div ref={ref} className={cn(isIntersecting && "contents")}>
{isIntersecting && (
<>
<NetworkProbesTable systemId={systemId} probes={probes} setProbes={setProbes} />
{!!chartData && (
<LatencyChart
probeStats={probeStats}
grid={grid}
probes={probes}
chartData={chartData}
empty={!probeStats.length}
/>
)}
</>
)}
{isIntersecting && <ProbesTable systemId={systemId} systemData={systemData} />}
</div>
)
}
function ProbesTable({ systemId, systemData }: { systemId: string; systemData: SystemData }) {
const { grid, chartData } = systemData ?? {}
const chartTime = useStore($chartTime)
const { probes, probeStats } = useNetworkProbesData({ systemId, loadStats: !!chartData, chartTime })
return (
<>
<NetworkProbesTable systemId={systemId} probes={probes} />
{!!chartData && !!probes.length && (
<div className="grid xl:grid-cols-2 gap-4">
<LatencyChart
probeStats={probeStats}
grid={grid}
probes={probes}
chartData={chartData}
empty={!probeStats.length}
/>
<LossChart
probeStats={probeStats}
grid={grid}
probes={probes}
chartData={chartData}
empty={!probeStats.length}
/>
</div>
)}
</>
)
}