This commit is contained in:
henrygd
2026-04-21 12:33:16 -04:00
parent 732983493a
commit a95376b4a2
6 changed files with 62 additions and 68 deletions

View File

@@ -97,15 +97,15 @@ export function getProbeColumns(longestName = 0, longestTarget = 0): ColumnDef<N
{
id: "latency",
accessorFn: (record) => record.latency,
// invertSorting: true,
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Latency`} Icon={ActivityIcon} />,
cell: ({ row }) => {
const val = row.original.latency
if (val === undefined) {
if (!val) {
return <span className="ms-1.5 text-muted-foreground">-</span>
}
let color = "bg-green-500"
if (!val || val > 200) {
if (val > 200) {
color = "bg-yellow-500"
}
if (val > 2000) {
@@ -125,18 +125,18 @@ export function getProbeColumns(longestName = 0, longestTarget = 0): ColumnDef<N
invertSorting: true,
header: ({ column }) => <HeaderButton column={column} name={t`Loss`} Icon={WifiOffIcon} />,
cell: ({ row }) => {
const val = row.original.loss
if (val === undefined) {
const { loss, latency } = row.original
if (loss === undefined || (!latency && !loss)) {
return <span className="ms-1.5 text-muted-foreground">-</span>
}
let color = "bg-green-500"
if (val > 0) {
color = val > 20 ? "bg-red-500" : "bg-yellow-500"
if (loss) {
color = loss > 20 ? "bg-red-500" : "bg-yellow-500"
}
return (
<span className="ms-1.5 tabular-nums flex gap-2 items-center">
<span className={cn("shrink-0 size-2 rounded-full", color)} />
{val}%
{loss}%
</span>
)
},

View File

@@ -188,7 +188,7 @@ export default function NetworkProbesTableNew({
<Trans>Network Probes</Trans>
</CardTitle>
<div className="text-sm text-muted-foreground flex items-center flex-wrap">
<Trans>ICMP/TCP/HTTP latency monitoring from this agent</Trans>
<Trans>ICMP/TCP/HTTP latency monitoring from agents</Trans>
</div>
</div>
<div className="md:ms-auto flex items-center gap-2">

View File

@@ -24,7 +24,7 @@ export function AddProbeDialog({ systemId }: { systemId?: string }) {
const [protocol, setProtocol] = useState<string>("icmp")
const [target, setTarget] = useState("")
const [port, setPort] = useState("")
const [probeInterval, setProbeInterval] = useState("60")
const [probeInterval, setProbeInterval] = useState("30")
const [name, setName] = useState("")
const [loading, setLoading] = useState(false)
const [selectedSystemId, setSelectedSystemId] = useState("")
@@ -37,7 +37,7 @@ export function AddProbeDialog({ systemId }: { systemId?: string }) {
setProtocol("icmp")
setTarget("")
setPort("")
setProbeInterval("60")
setProbeInterval("30")
setName("")
setSelectedSystemId("")
}
@@ -72,13 +72,13 @@ export function AddProbeDialog({ systemId }: { systemId?: string }) {
<Trans>Add {{ foo: t`Probe` }}</Trans>
</Button>
</DialogTrigger>
<DialogContent>
<DialogContent className="max-w-md">
<DialogHeader>
<DialogTitle>
<Trans>Add {{ foo: t`Network Probe` }}</Trans>
</DialogTitle>
<DialogDescription>
<Trans>Configure ICMP, TCP, or HTTP latency monitoring from this agent.</Trans>
<Trans>Configure latency monitoring from this agent.</Trans>
</DialogDescription>
</DialogHeader>
<form onSubmit={handleSubmit} className="grid gap-4 tabular-nums">

View File

@@ -11,7 +11,7 @@ import { RootDiskCharts, ExtraFsCharts } from "./system/charts/disk-charts"
import { BandwidthChart, ContainerNetworkChart } from "./system/charts/network-charts"
import { TemperatureChart, BatteryChart } from "./system/charts/sensor-charts"
import { GpuPowerChart, GpuDetailCharts } from "./system/charts/gpu-charts"
import { LazyContainersTable, LazySmartTable, LazySystemdTable, LazyNetworkProbesTableNew } from "./system/lazy-tables"
import { LazyContainersTable, LazySmartTable, LazySystemdTable, LazyNetworkProbesTable } from "./system/lazy-tables"
import { LoadAverageChart } from "./system/charts/load-average-chart"
import { ContainerIcon, CpuIcon, HardDriveIcon, TerminalSquareIcon } from "lucide-react"
import { GpuIcon } from "../ui/icons"
@@ -147,7 +147,7 @@ export default memo(function SystemDetail({ id }: { id: string }) {
{hasSystemd && <LazySystemdTable systemId={system.id} />}
<LazyNetworkProbesTableNew systemId={system.id} systemData={systemData} />
<LazyNetworkProbesTable systemId={system.id} systemData={systemData} />
{/* <LazyNetworkProbesTable system={system} chartData={chartData} grid={grid} probeStats={probeStats} /> */}
</>
@@ -197,7 +197,7 @@ export default memo(function SystemDetail({ id }: { id: string }) {
<SwapChart chartData={chartData} grid={grid} dataEmpty={dataEmpty} systemStats={systemStats} />
{pageBottomExtraMargin > 0 && <div style={{ marginBottom: pageBottomExtraMargin }}></div>}
</div>
<LazyNetworkProbesTableNew systemId={system.id} systemData={systemData} />
<LazyNetworkProbesTable systemId={system.id} systemData={systemData} />
{/* <LazyNetworkProbesTable system={system} chartData={chartData} grid={grid} probeStats={probeStats} /> */}
</TabsContent>

View File

@@ -1,5 +1,5 @@
import LineChartDefault, { DataPoint } from "@/components/charts/line-chart"
import { pinnedAxisDomain } from "@/components/ui/chart"
import LineChartDefault from "@/components/charts/line-chart"
import type { DataPoint } from "@/components/charts/line-chart"
import { toFixedFloat, decimalString } from "@/lib/utils"
import { useLingui } from "@lingui/react/macro"
import { ChartCard, FilterBar } from "../chart-card"
@@ -31,33 +31,44 @@ export function LatencyChart({
const { t } = useLingui()
const filter = useStore($filter)
const dataPoints: DataPoint<NetworkProbeStatsRecord>[] = useMemo(() => {
const { dataPoints, visibleKeys } = useMemo(() => {
const count = probes.length
return probes
.sort((a, b) => a.name.localeCompare(b.name))
.map((p, i) => {
const key = probeKey(p)
const filterTerms = filter
? filter
.toLowerCase()
.split(" ")
.filter((term) => term.length > 0)
: []
const filtered = filterTerms.length > 0 && !filterTerms.some((term) => key.toLowerCase().includes(term))
const strokeOpacity = filtered ? 0.1 : 1
return {
label: p.name || p.target,
dataKey: (record: NetworkProbeStatsRecord) => record.stats?.[key]?.[0] ?? null,
color: count <= 5 ? i + 1 : `hsl(${(i * 360) / count}, var(--chart-saturation), var(--chart-lightness))`,
strokeOpacity,
activeDot: !filtered,
}
const points: DataPoint<NetworkProbeStatsRecord>[] = []
const visibleKeys: string[] = []
probes.sort((a, b) => a.name.localeCompare(b.name))
const filterTerms = filter
? filter
.toLowerCase()
.split(" ")
.filter((term) => term.length > 0)
: []
for (let i = 0; i < count; i++) {
const p = probes[i]
const key = probeKey(p)
const filtered = filterTerms.length > 0 && !filterTerms.some((term) => key.toLowerCase().includes(term))
if (filtered) {
continue
}
visibleKeys.push(key)
points.push({
label: p.name || p.target,
dataKey: (record: NetworkProbeStatsRecord) => record.stats?.[key]?.[0] ?? "-",
color: count <= 5 ? i + 1 : `hsl(${(i * 360) / count}, var(--chart-saturation), var(--chart-lightness))`,
})
}
return { dataPoints: points, visibleKeys }
}, [probes, filter])
const filteredProbeStats = useMemo(() => {
if (!visibleKeys.length) return probeStats
return probeStats.filter((record) => visibleKeys.some((key) => record.stats?.[key] != null))
}, [probeStats, visibleKeys])
const legend = dataPoints.length < 10
return (
<ChartCard
legend
legend={legend}
cornerEl={<FilterBar store={$filter} />}
empty={empty}
title={t`Latency`}
@@ -66,13 +77,18 @@ export function LatencyChart({
>
<LineChartDefault
chartData={chartData}
customData={probeStats}
customData={filteredProbeStats}
dataPoints={dataPoints}
domain={pinnedAxisDomain()}
domain={["auto", "auto"]}
connectNulls
tickFormatter={(value) => `${toFixedFloat(value, value >= 10 ? 0 : 1)} ms`}
contentFormatter={({ value }) => `${decimalString(value, 2)} ms`}
legend
contentFormatter={({ value }) => {
if (value === "-") {
return value
}
return `${decimalString(value, 2)} ms`
}}
legend={legend}
filter={filter}
/>
</ChartCard>

View File

@@ -42,11 +42,11 @@ export function LazySystemdTable({ systemId }: { systemId: string }) {
)
}
const NetworkProbesTableNew = lazy(() => import("@/components/network-probes-table/network-probes-table"))
const NetworkProbesTable = lazy(() => import("@/components/network-probes-table/network-probes-table"))
const cache = new Map<string, any>()
export function LazyNetworkProbesTableNew({ systemId, systemData }: { systemId: string; systemData: SystemData }) {
export function LazyNetworkProbesTable({ systemId, systemData }: { systemId: string; systemData: SystemData }) {
const { grid, chartData } = systemData ?? {}
const [probes, setProbes] = useState<NetworkProbeRecord[]>([])
const chartTime = useStore($chartTime)
@@ -101,7 +101,7 @@ export function LazyNetworkProbesTableNew({ systemId, systemData }: { systemId:
<div ref={ref} className={cn(isIntersecting && "contents")}>
{isIntersecting && (
<>
<NetworkProbesTableNew systemId={systemId} probes={probes} setProbes={setProbes} />
<NetworkProbesTable systemId={systemId} probes={probes} setProbes={setProbes} />
{!!chartData && (
<LatencyChart
probeStats={probeStats}
@@ -116,25 +116,3 @@ export function LazyNetworkProbesTableNew({ systemId, systemData }: { systemId:
</div>
)
}
const NetworkProbesTable = lazy(() => import("@/components/routes/system/network-probes"))
export function LazyNetworkProbesTable({
system,
chartData,
grid,
probeStats,
}: {
system: any
chartData: any
grid: any
probeStats: any
}) {
const { isIntersecting, ref } = useIntersectionObserver()
return (
<div ref={ref} className={cn(isIntersecting && "contents")}>
{isIntersecting && (
<NetworkProbesTable system={system} chartData={chartData} grid={grid} realtimeProbeStats={probeStats} />
)}
</div>
)
}