"use client"; import { Background, BackgroundVariant, Controls, MiniMap, Panel, ReactFlow } from "@xyflow/react"; import { useCallback, useMemo, useState } from "react"; import "@xyflow/react/dist/style.css"; import { useGraphLayout } from "@/hooks/use-graph-layout"; import type { TopologyFilters, TopologyGraph, TopologyNodeData } from "@/lib/topology-types"; import { filterEdges, filterNodes } from "@/lib/topology-utils"; import { NodeDetailsPanel } from "./controls/node-details-panel"; import { TopologyToolbar } from "./controls/topology-toolbar"; import { nodeTypes } from "./nodes/node-types"; interface TopologyCanvasProps { graph: TopologyGraph; } export function TopologyCanvas({ graph }: TopologyCanvasProps) { const [selectedNode, setSelectedNode] = useState(null); const [filters, setFilters] = useState({ showServers: true, showProxies: true, showK8sNodes: true, showConnections: true, searchQuery: "", }); const filteredNodes = useMemo(() => { return filterNodes(graph.nodes, filters); }, [graph.nodes, filters]); const filteredEdges = useMemo(() => { if (!filters.showConnections) return []; const visibleNodeIds = new Set(filteredNodes.map((node) => node.id)); return filterEdges(graph.edges, visibleNodeIds); }, [graph.edges, filteredNodes, filters.showConnections]); const { nodes, edges } = useGraphLayout({ nodes: filteredNodes, edges: filteredEdges, }); const onNodeClick = useCallback((_event: React.MouseEvent, node: any) => { setSelectedNode(node.data as TopologyNodeData); }, []); const onPaneClick = useCallback(() => { setSelectedNode(null); }, []); const handleCloseDetails = useCallback(() => { setSelectedNode(null); }, []); return (
{ const data = node.data as TopologyNodeData; const colors = { healthy: "#22c55e", degraded: "#eab308", unhealthy: "#ef4444", unknown: "#94a3b8", }; return colors[data.status] || "#94a3b8"; }} maskColor="rgba(0, 0, 0, 0.05)" className="bg-white/80 backdrop-blur-sm border shadow-lg" />
); }