fix(ui): сохранять переходные и неизвестные состояния OSPF
This commit is contained in:
1 parent
c18c148a23
commit
3dc25628af
9 files changed
+82
-22
No files matched your search
+13
-15
@@ -1,5 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { normalizeOspfState, normalizeBfdState, ospfNodeState, type OspfNeighborState, type BfdState } from "@/lib/ospf-state"
|
||||
import { useMemo, useState, useEffect, useRef } from "react"
|
||||
import { ospfCatalogSchema, ospfServersSchema, ospfOptimizeSchema, type OspfCatalog } from "@/lib/ospf-response"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
@@ -62,7 +63,7 @@ interface OspfNeighbor {
|
||||
remoteLabel: string
|
||||
remoteRouterId: string
|
||||
area: string
|
||||
state: "Full" | "2-Way" | "ExStart" | "Down"
|
||||
state: OspfNeighborState
|
||||
cost: number
|
||||
uptime: string
|
||||
priority: number
|
||||
@@ -88,7 +89,7 @@ interface BfdSession {
|
||||
serverLabel: string
|
||||
localAddr: string
|
||||
remoteAddr: string
|
||||
state: "Up" | "Down" | "Init" | "AdminDown"
|
||||
state: BfdState
|
||||
interval: number // txInterval ms
|
||||
multiplier: number
|
||||
iface: string
|
||||
@@ -139,8 +140,7 @@ function isRefInterfaceName(name: string): boolean {
|
||||
// ─── backend → frontend mappers ───────────────────────────────────────────────
|
||||
|
||||
function backendToNeighbor(b: BackendNeighbor, ifaceMap: Map<string, number>): OspfNeighbor {
|
||||
const validStates = ["Full", "2-Way", "ExStart", "Down"]
|
||||
const state = validStates.includes(b.state) ? b.state as OspfNeighbor["state"] : "Down"
|
||||
const state = normalizeOspfState(b.state)
|
||||
const costKey = `${b.serverId}::${b.interface}`
|
||||
return {
|
||||
id: `${b.serverId}-${b.id}`,
|
||||
@@ -176,8 +176,7 @@ function backendToItem(b: BackendInterface): OspfItem {
|
||||
}
|
||||
|
||||
function backendToBfdSession(b: BackendBfdSession): BfdSession {
|
||||
const validStates = ["Up", "Down", "Init", "AdminDown"]
|
||||
const state = validStates.includes(b.state) ? b.state as BfdSession["state"] : "Down"
|
||||
const state = normalizeBfdState(b.state)
|
||||
return {
|
||||
id: `${b.serverId}-${b.id}`,
|
||||
serverId: String(b.serverId),
|
||||
@@ -283,6 +282,8 @@ const TOPO_H = 360
|
||||
const NODE_R = 34
|
||||
|
||||
const NODE_THEME = {
|
||||
Pending: { fill: "#2d1e06", stroke: "#fbbf24", glow: "transparent" },
|
||||
Unknown: { fill: "#111827", stroke: "#9ca3af", glow: "transparent" },
|
||||
Full: { fill: "#0f2d1f", stroke: "#4ade80", glow: "rgba(74,222,128,0.18)" },
|
||||
"2-Way":{ fill: "#2d1e06", stroke: "#fbbf24", glow: "rgba(251,191,36,0.14)" },
|
||||
Down: { fill: "#2d0f0f", stroke: "#f87171", glow: "transparent" },
|
||||
@@ -290,6 +291,7 @@ const NODE_THEME = {
|
||||
}
|
||||
|
||||
const EDGE_COLOR: Record<string, string> = {
|
||||
Attempt: "#fbbf24", Init: "#fbbf24", ExStart: "#fbbf24", Exchange: "#fbbf24", Loading: "#fbbf24", Unknown: "#9ca3af",
|
||||
Full: "#4ade80",
|
||||
"2-Way":"#fbbf24",
|
||||
Down: "#f87171",
|
||||
@@ -413,10 +415,7 @@ function TopologyGraph({ graphNodes, graphEdges, highlightId, selectedId, showDo
|
||||
|
||||
function nodeState(id: string): keyof typeof NODE_THEME {
|
||||
const involved = graphEdges.filter(e => e.from === id || e.to === id)
|
||||
if (!involved.length) return "none"
|
||||
if (involved.some(e => e.state === "Full")) return "Full"
|
||||
if (involved.some(e => e.state === "2-Way")) return "2-Way"
|
||||
return "Down"
|
||||
return ospfNodeState(involved.map(edge => edge.state))
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -568,10 +567,7 @@ function NodeDetailPanel({
|
||||
const partCnt = adjacencies.filter(a => a.state === "2-Way").length
|
||||
|
||||
// derive state from edges
|
||||
let panelState: keyof typeof NODE_THEME = "none"
|
||||
if (adjacencies.some(a => a.state === "Full")) panelState = "Full"
|
||||
else if (adjacencies.some(a => a.state === "2-Way")) panelState = "2-Way"
|
||||
else if (adjacencies.length) panelState = "Down"
|
||||
const panelState = ospfNodeState(adjacencies.map(edge => edge.state))
|
||||
|
||||
const theme = NODE_THEME[panelState]
|
||||
const siteFill =
|
||||
@@ -926,6 +922,7 @@ function NeighborsTab({
|
||||
const [selectedId, setSelectedId] = useState<string | null>(null)
|
||||
const [showDots, setShowDots] = useState(true)
|
||||
|
||||
dataIncomplete = dataIncomplete || neighbors.some(n => n.state === "Unknown")
|
||||
const fullCount = neighbors.filter(n => n.state === "Full").length
|
||||
|
||||
return (
|
||||
@@ -1054,6 +1051,7 @@ function RoutesTab({ routes }: { routes: OspfRoute[] }) {
|
||||
// ─── BFD tab ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function BfdTab({ sessions, dataIncomplete }: { sessions: BfdSession[]; dataIncomplete: boolean }) {
|
||||
dataIncomplete = dataIncomplete || sessions.some(b => b.state === "Unknown")
|
||||
const upCount = sessions.filter(b => b.state === "Up").length
|
||||
const downCount = sessions.filter(b => b.state === "Down" || b.state === "AdminDown").length
|
||||
const initCount = sessions.filter(b => b.state === "Init").length
|
||||
@@ -1094,7 +1092,7 @@ function BfdTab({ sessions, dataIncomplete }: { sessions: BfdSession[]; dataInco
|
||||
},
|
||||
{
|
||||
id: "init",
|
||||
label: "Init / другие",
|
||||
label: "Init",
|
||||
value: dataIncomplete ? "—" : initCount,
|
||||
icon: <LayersIcon className="size-4" />,
|
||||
iconClassName: initCount > 0 ? "text-warning" : "text-muted-foreground",
|
||||
|
||||
Reference in new issue
Block a user