Skip to content
This repository has been archived by the owner on Mar 27, 2023. It is now read-only.

Commit

Permalink
Switch from DOT to JSON data for network graph
Browse files Browse the repository at this point in the history
  • Loading branch information
Michel Zimmer committed Sep 5, 2022
1 parent 736166d commit e964300
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 481 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ LABEL org.opencontainers.image.vendor="neuland – Büro für Informatik GmbH"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.title="bandwhichd-ui"
LABEL org.opencontainers.image.description="bandwhichd ui displaying network topology and statistics"
LABEL org.opencontainers.image.version="0.5.0"
LABEL org.opencontainers.image.version="0.6.0"
COPY --from=build --chown=root:root /home/node/dist /usr/share/nginx/html
18 changes: 10 additions & 8 deletions mocks/apiHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,27 @@ const handleWithMocks =
});

request.on("end", () => {
if (request.method !== "GET"
|| request.url !== "/api/v1/stats") {
if (request.url !== "/api/v1/stats") {
response.writeHead(404);
response.end();
return;
}

if (request.method !== "GET") {
response.writeHead(405, {
"Allow": "GET",
});
response.end();
return;
}

if (chunks.length > 0) {
response.writeHead(400);
response.end();
return;
}

const format =
request.headers.accept === "text/vnd.graphviz; q=1.0"
? "dot"
: "json";

const filePath = path.join(process.cwd(), 'mocks', `stats.${format}`);
const filePath = path.join(process.cwd(), 'mocks', `stats.json`);
const fileStat = fs.statSync(filePath);

response.writeHead(200, {
Expand Down
441 changes: 0 additions & 441 deletions mocks/stats.dot

This file was deleted.

2 changes: 1 addition & 1 deletion mocks/stats.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bandwhichd-ui",
"version": "0.5.0",
"version": "0.6.0",
"description": "bandwhichd ui displaying network topology and statistics",
"license": "MIT",
"private": true,
Expand Down
77 changes: 49 additions & 28 deletions src/Graph.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import React, { useEffect, useRef, useState } from "react";
import * as VisNetwork from "vis-network";
import { HostId } from "./Stats";
import { HostId, Stats } from "./Stats";

import styles from "./Graph.module.css";

const fetchData = async (): Promise<string> => {
const response = await window.fetch("/api/v1/stats", {
method: "GET",
headers: {
"Accept": "text/vnd.graphviz; q=1.0"
}
});
return response.text();
}
import { Seq } from "immutable";

export interface GraphProps {
maybeStats: Stats | null;
maybeSelectedHostId: HostId | null,
setMaybeSelectedHostId: (maybeSelectedHostId: HostId | null) => void,
}
Expand All @@ -26,34 +18,63 @@ export const Graph: React.FC<GraphProps> =
const networkRef = useRef<VisNetwork.Network | null>(null);

useEffect(() => {
if (containerRef.current === null) {
if (containerRef.current === null
|| props.maybeStats === null) {
return;
}
const container = containerRef.current;
const stats = props.maybeStats;

setIsLoading(true);
fetchData().then(data => {
// @ts-ignore
const parsedData = VisNetwork.parseDOTNetwork(data);
parsedData.options.physics = {
const hostNodes: Seq.Indexed<VisNetwork.Node> =
stats.hosts
.entrySeq()
.map(([hostId, host]) => ({
id: hostId,
label: host.hostname,
}));
const unmonitoredHostNodes: Seq.Indexed<VisNetwork.Node> =
stats.unmonitoredHosts
.entrySeq()
.map(([hostId, unmonitoredHost]) => ({
id: hostId,
label: unmonitoredHost.host,
}));
const edges: Seq.Indexed<VisNetwork.Edge> =
stats.hosts
.entrySeq()
.flatMap(([hostId, host]) =>
host.connections
.entrySeq()
.map(([otherHostId, _]) => ({
from: hostId,
to: otherHostId,
}))
);
const data: VisNetwork.Data = {
nodes: hostNodes.concat(unmonitoredHostNodes).toArray(),
edges: edges.toArray(),
};
const options: VisNetwork.Options = {
physics: {
solver: "forceAtlas2Based"
};
const network = new VisNetwork.Network(container, parsedData);
network.on("selectNode", (event) => {
props.setMaybeSelectedHostId(event.nodes[0]);
});
network.on("afterDrawing", (_) => {
setIsLoading(false);
});
networkRef.current = network;
}).catch(console.error);
}
};
const network = new VisNetwork.Network(container, data, options);
network.on("selectNode", (event) => {
props.setMaybeSelectedHostId(event.nodes[0]);
});
network.on("afterDrawing", (_) => {
setIsLoading(false);
});
networkRef.current = network;

return () => {
if (networkRef.current !== null) {
networkRef.current.destroy();
}
}
}, [containerRef]);
}, [containerRef, props.maybeStats]);

useEffect(() => {
if (networkRef.current !== null && props.maybeSelectedHostId !== null) {
Expand All @@ -62,7 +83,7 @@ export const Graph: React.FC<GraphProps> =
}, [networkRef, props.maybeSelectedHostId]);

return <section>
{ isLoading && <span className={styles.loading}>Loading…</span> }
{isLoading && <span className={styles.loading}>Loading…</span>}
<div className={styles.container} ref={containerRef}></div>
</section>;
};
2 changes: 1 addition & 1 deletion src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const Main: React.FC =

return <main className={styles.main}>
<NodeSelector {...{ maybeStats, maybeSelectedHostId, setMaybeSelectedHostId }} />
<Graph {...{ maybeSelectedHostId, setMaybeSelectedHostId }} />
<Graph {...{ maybeStats, maybeSelectedHostId, setMaybeSelectedHostId }} />
<HostDetails {...{ maybeStats, maybeSelectedHost, setMaybeSelectedHostId }} />
</main>;
};

0 comments on commit e964300

Please sign in to comment.