107 lines
2.6 KiB
TypeScript
107 lines
2.6 KiB
TypeScript
import type { NetworkNode } from "@/api/client";
|
|
import { statusRGBA, rgbaToHex, type StatusColors } from "./graphColors";
|
|
|
|
export interface GraphNode {
|
|
id: string;
|
|
name: string;
|
|
entry: NetworkNode;
|
|
type: "self" | "peer" | "interface";
|
|
color: string;
|
|
size: number;
|
|
cluster?: string;
|
|
x?: number;
|
|
y?: number;
|
|
z?: number;
|
|
}
|
|
|
|
export interface GraphLink {
|
|
source: string;
|
|
target: string;
|
|
}
|
|
|
|
export interface GraphData {
|
|
nodes: GraphNode[];
|
|
links: GraphLink[];
|
|
clusterNames: string[];
|
|
}
|
|
|
|
function findParentIface(
|
|
entry: NetworkNode,
|
|
interfaces: NetworkNode[],
|
|
peerIndex: number,
|
|
): NetworkNode | undefined {
|
|
if (entry.interface) {
|
|
const iface = interfaces.find(i => i.name === entry.interface);
|
|
if (iface) return iface;
|
|
}
|
|
if (interfaces.length > 0) return interfaces[peerIndex % interfaces.length];
|
|
return undefined;
|
|
}
|
|
|
|
export function buildGraphData(
|
|
rawNodes: NetworkNode[],
|
|
prevPositions: Map<string, { x: number; y: number; z: number }>,
|
|
theme: StatusColors,
|
|
): GraphData {
|
|
const interfaces = rawNodes
|
|
.filter(e => e.type === "interface")
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
const selfNode = rawNodes.find(e => e.is_self && e.type !== "interface");
|
|
const peers = rawNodes.filter(e => !e.is_self && e.type !== "interface");
|
|
|
|
const nodes: GraphNode[] = [];
|
|
const links: GraphLink[] = [];
|
|
|
|
// Add interface nodes
|
|
for (const iface of interfaces) {
|
|
const prev = prevPositions.get(iface.hash);
|
|
nodes.push({
|
|
id: iface.hash,
|
|
name: iface.name,
|
|
entry: iface,
|
|
type: "interface",
|
|
color: rgbaToHex(theme.stale),
|
|
size: 2,
|
|
...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
|
|
});
|
|
}
|
|
|
|
// Add self node
|
|
if (selfNode) {
|
|
const prev = prevPositions.get(selfNode.hash);
|
|
nodes.push({
|
|
id: selfNode.hash,
|
|
name: selfNode.name,
|
|
entry: selfNode,
|
|
type: "self",
|
|
color: "#ffffff",
|
|
size: 2,
|
|
...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
|
|
});
|
|
}
|
|
|
|
// Add peer nodes + links to parent interface
|
|
peers.forEach((peer, i) => {
|
|
const prev = prevPositions.get(peer.hash);
|
|
const parentIface = findParentIface(peer, interfaces, i);
|
|
nodes.push({
|
|
id: peer.hash,
|
|
name: peer.name,
|
|
entry: peer,
|
|
type: "peer",
|
|
color: rgbaToHex(statusRGBA(peer, theme)),
|
|
size: 2,
|
|
cluster: parentIface?.name,
|
|
...(prev ? { x: prev.x, y: prev.y, z: prev.z } : {}),
|
|
});
|
|
|
|
if (parentIface) {
|
|
links.push({ source: parentIface.hash, target: peer.hash });
|
|
}
|
|
});
|
|
|
|
const clusterNames = interfaces.map(i => i.name);
|
|
|
|
return { nodes, links, clusterNames };
|
|
}
|