fix(uptime): показывать реальные наблюдения и пропуски RTT на дашборде

This commit is contained in:
Denozordec committed 2026-10-03 23:42:45 +07:00
1 parent 8f65d1620d
commit 9d3129372b
18 files changed
+169 -203

No files matched your search

+11 -10
View File
@@ -10,7 +10,6 @@ import {
traffic as mockTraffic,
vxlanTunnels as mockVxlan,
type GreTunnel,
type PingProbe,
type Server,
} from "@/lib/data"
import { useDataSource } from "@/lib/data-source"
@@ -30,6 +29,7 @@ import type { FiltersRulesetRow, RouteOptimizerSpeedProbe } from "@/lib/route-op
import { updateDashboardSource, type DashboardSource, type DashboardSources } from "@/lib/dashboard-source-state"
import {can,ensureAuthConfig} from "@/lib/auth"
import type {DashboardProbe} from "@/lib/dashboard-probes"
import {parseDashboardServers,parseDashboardProbes,type DashboardServerRow} from "@/lib/dashboard-readers"
import {parseDashboardTraffic,type DashboardTraffic} from "@/lib/dashboard-traffic"
import {parseDashboardBgp,type DashboardBgp} from "@/lib/dashboard-bgp"
@@ -115,8 +115,8 @@ export interface AttentionRow {
export type LatencyBlock =
| { kind: "loading" }
| { kind: "empty"; message: string }
| { kind: "mock"; series: Record<string, number[]>; labels?: Record<string, string>; subtitle: string }
| { kind: "live"; series: Record<string, number[]>; labels?: Record<string, string>; subtitle: string }
| { kind: "mock"; series: Record<string, (number|null)[]>; labels?: Record<string, string>; subtitle: string }
| { kind: "live"; series: Record<string, (number|null)[]>; labels?: Record<string, string>; subtitle: string }
function apiGreToGreTunnel(t: ApiGreTunnelRow): GreTunnel {
return {
@@ -206,7 +206,7 @@ export function useDashboardLive() {
const isLive = prefsHydrated && mode === "live"
const apiFetch = useMemo(() => makeApiFetch(backendUrl), [backendUrl])
const [liveProbes, setLiveProbes] = useState<PingProbe[] | null>(null)
const [liveProbes, setLiveProbes] = useState<DashboardProbe[] | null>(null)
const [liveServers, setLiveServers] = useState<Server[] | null>(null)
const [overlayItems, setOverlayItems] = useState<OverlayItem[] | null>(null)
const [bgp, setBgp] = useState<DashboardBgp | null>(null)
@@ -258,7 +258,7 @@ export function useDashboardLive() {
const results = { probes: overviewRes, servers: serversRes, bgp: br, gre: greRes, wg: wgRes, traffic: trafficRes, vxlan: vxRes }
for (const [key, result] of Object.entries(results)) {
recordSource(key as DashboardSource, result.status === "rejected"
? result.reason instanceof Error ? result.reason.message : "Источник недоступен" : null,key==="traffic"&&trafficRes.status==="fulfilled"?trafficRes.value.sampledAt??undefined:undefined)
? result.reason instanceof Error ? result.reason.message : "Источник недоступен" : null,key==="traffic"&&trafficRes.status==="fulfilled"?trafficRes.value.sampledAt??undefined:key==="probes"&&overviewRes.status==="fulfilled"?overviewRes.value.sampledAt??undefined:undefined)
}
const failures = Object.values(results).filter(result => result.status === "rejected").length
setError(failures ? "Не все источники обновлены. Последние полученные данные сохранены." : null)
@@ -573,7 +573,7 @@ export function useDashboardLive() {
kind: "live",
series,
labels,
subtitle: "Средний RTT · 1 ч · до 8 узлов",
subtitle: "Средний измеренный RTT · 1 ч · до 8 узлов",
}
}, [prefsHydrated, isLive, liveProbes, loading, liveServers])
@@ -603,13 +603,13 @@ export function useDashboardLive() {
const attentionProbes: AttentionRow[] = useMemo(() => {
return enabledProbes
.filter((p) => p.status === "down" || p.status === "warn")
.filter((p) => p.status === "down" || p.status === "warn" || p.status === "unknown")
.map((p) => ({
id: p.id,
title: p.name,
hint: p.status === "warn" ? "Предупреждение" : "Ошибка",
hint: p.status === "unknown" ? "Статус неизвестен" : p.status === "warn" ? "Предупреждение" : "Ошибка",
href: "/uptime?probe=" + encodeURIComponent(p.id),
tone: p.status === "warn" ? ("warning" as const) : ("destructive" as const),
tone: p.status === "warn" || p.status === "unknown" ? ("warning" as const) : ("destructive" as const),
}))
}, [enabledProbes])
@@ -645,7 +645,7 @@ export function useDashboardLive() {
},
reliable: {
servers: !isLive || (liveServers !== null && !sources.servers?.error && liveServers.every(s=>s.status!=="unknown")),
probes: !isLive || (liveProbes !== null && !sources.probes?.error),
probes: !isLive || (liveProbes !== null && !sources.probes?.error && liveProbes.filter(p=>p.enabled).every(p=>p.status!=="unknown")),
overlay: !isLive || ["gre", "wg", "vxlan"].every(key => sources[key as DashboardSource]?.receivedAt != null && !sources[key as DashboardSource]?.error),
},
retry: () => {
@@ -665,6 +665,7 @@ export function useDashboardLive() {
probeDown,
probeWarn,
probeCount: enabledProbes.length,
unknownProbeCount:enabledProbes.filter(p=>p.status==="unknown").length,
latency,
recentEvents,
eventsLoading,