import { createContext, memo, useContext, type Dispatch, type SetStateAction } from "react"; import { ReactFlow, Background, BackgroundVariant, Controls, ControlButton, MiniMap, Handle, Position, ConnectionLineType, ConnectionMode, SelectionMode, applyNodeChanges, applyEdgeChanges, type Connection, type Edge, type Node, type NodeChange, type EdgeChange, type NodeProps, type ReactFlowInstance, } from "@xyflow/react"; import "@xyflow/react/dist/style.css"; import { WorldScatterLayer, type WorldScatterPoint } from "./WorldScatterLayer"; import { ParallelEdge } from "./ParallelEdge"; import { isAggregateEdgeId } from "./linkDisplay"; import type { ToolMode, ToolModeBehavior } from "./toolMode"; import type { TopologyViewRole, TopologyWorldTransform } from "../../types"; import { isPlaceholderSource } from "./searchUtils"; import { nodeIconTone } from "./vendorTone"; import { levelToneKey } from "./levelTone"; import type { NodeAlarmSummary } from "./alarmOverlay"; export { isPlaceholderSource }; export type NeNodeData = { label: string; managed_ne_id: string; ume_ne_id: string; ne_ip: string; vendor: string; connect_status: string; managed_source?: string; /** Fabric classify level (from graph). */ level?: number | null; /** Fabric role alias (external|core|aggregation|access|edge). */ fabric_role?: string; kind?: "ne" | "region" | "layer"; folder_id?: string; view_id?: string; role?: TopologyViewRole | string; subtitle?: string; node_count?: number; }; export type TopoDisplayOpts = { hideIp: boolean; hideVendor: boolean; hidePorts: boolean; connectMode: boolean; showPlaceholderBadge: boolean; showConnectStatus: boolean; showAlarmOverlay: boolean; showLevelColors: boolean; worldVisualLod: "dot" | "pin" | "full"; }; const TopoDisplayContext = createContext({ hideIp: true, hideVendor: true, hidePorts: true, connectMode: false, showPlaceholderBadge: false, showConnectStatus: true, showAlarmOverlay: true, showLevelColors: true, worldVisualLod: "full", }); const TopoAlarmContext = createContext>(new Map()); const emptyAlarmMap: ReadonlyMap = new Map(); const SEP = " / "; function normalizeConnectStatus(raw: string | undefined): "pass" | "fail" | "testing" | "unknown" { const s = String(raw || "").trim().toLowerCase(); if (s === "pass" || s === "ok") return "pass"; if (s === "fail" || s === "error") return "fail"; if (s === "testing") return "testing"; return "unknown"; } function RouterIcon() { return (