diff --git a/app/(main)/ospf/page.tsx b/app/(main)/ospf/page.tsx
index d4885c07..c9825098 100644
--- a/app/(main)/ospf/page.tsx
+++ b/app/(main)/ospf/page.tsx
@@ -46,13 +46,13 @@ interface OspfItem {
serverId: string
interfaceName: string
area: string
- cost: number
- active: boolean
+ cost: number | null
+ active: boolean | null
dataUnknown?: boolean
- type?: string
- useBfd?: boolean
- helloInterval?: number
- deadInterval?: number
+ type?: string | null
+ useBfd?: boolean | null
+ helloInterval?: number | null
+ deadInterval?: number | null
}
interface OspfNeighbor {
@@ -75,7 +75,7 @@ interface OspfRoute {
id: string
destination: string
type: "O" | "O IA" | "O E1" | "O E2"
- cost: number
+ cost: number | null
nextHop: string
via: string
serverId: string
@@ -106,31 +106,10 @@ interface BfdSession {
// ─── backend types ────────────────────────────────────────────────────────────
-interface BackendNeighbor {
- id: string; serverId: number; serverName: string; serverSite: string; serverCountry: string
- address: string; routerId: string; instance: string; area: string; areaId: string
- interface: string; state: string; uptime: string | null; stateChanges: number | null; priority: number | null
-}
-
-interface BackendInterface {
- id: string; serverId: number; serverName: string; serverSite: string; serverCountry: string
- instance: string; area: string; areaId: string; interface: string; cost: number
- type: string; disabled: boolean; inactive: boolean; priority: number
- helloInterval: number; deadInterval: number; useBfd: boolean
-}
-
-
-interface BackendBfdSession {
- id: string; serverId: number; serverName: string; serverSite: string; serverCountry: string
- localAddr: string; remoteAddr: string; interface: string; state: string; uptime: string | null
- multihop: boolean; multiplier: number | null; txInterval: number | null; rxInterval: number | null; holdTime: number | null
- packetsRx: number | null; packetsTx: number | null; stateChanges: number | null
-}
-
-interface BackendOspfRoute {
- id: string; serverId: number; serverName: string; serverSite: string
- destination: string; type: OspfRoute["type"]; cost: number; nextHop: string; via: string; area: string
-}
+type BackendNeighbor = OspfCatalog["neighbors"][number]
+type BackendInterface = OspfCatalog["interfaces"][number]
+type BackendBfdSession = OspfCatalog["bfdSessions"][number]
+type BackendOspfRoute = OspfCatalog["routes"][number]
function isRefInterfaceName(name: string): boolean {
@@ -168,7 +147,7 @@ function backendToItem(b: BackendInterface): OspfItem {
interfaceName: b.interface,
area: b.areaId,
cost: b.cost,
- active: !b.disabled && !b.inactive,
+ active: b.disabled === true || b.inactive === true ? false : b.disabled === false && b.inactive === false ? true : null,
type: b.type,
useBfd: b.useBfd,
helloInterval: b.helloInterval,
@@ -637,7 +616,7 @@ function NodeDetailPanel({
{iface.area === "0.0.0.0" ? "backbone" : `area ${iface.area}`}
- cost {iface.cost}
+ cost {iface.cost ?? "—"}
))}
@@ -696,7 +675,7 @@ function InterfacesTab({
return Object.values(byRouter).map(r => ({
...r,
areas: Object.entries(r.areas)
- .map(([area, areaItems]) => ({ area, items: [...areaItems].sort((a, b) => a.cost - b.cost) }))
+ .map(([area, areaItems]) => ({ area, items: [...areaItems].sort((a, b) => (a.cost ?? Infinity) - (b.cost ?? Infinity)) }))
.sort((a, b) => a.area.localeCompare(b.area)),
}))
}, [items])
@@ -765,7 +744,7 @@ function InterfacesTab({
function onDrop(routerKey: string, area: string, targetKey: string) {
if (!dragging || dragging === targetKey) { setDragging(null); setDragOver(null); return }
setItems(prev => {
- const areaItems = prev.filter(i => i.routerKey === routerKey && i.area === area).sort((a, b) => a.cost - b.cost)
+ const areaItems = prev.filter(i => i.routerKey === routerKey && i.area === area).sort((a, b) => (a.cost ?? Infinity) - (b.cost ?? Infinity))
const fromIdx = areaItems.findIndex(i => i.key === dragging)
const toIdx = areaItems.findIndex(i => i.key === targetKey)
if (fromIdx < 0 || toIdx < 0) return prev
@@ -785,6 +764,7 @@ function InterfacesTab({
return (
+ {isLive && filterServerId !== ALL_SERVERS_ID && !dataReady &&
Оптимизация недоступна до полного успешного опроса и подтверждения costs/состояний интерфейсов с правом записи.
}
{operationError &&
Оптимизация OSPF не подтверждена{operationError}}