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

Commit 98107b5

Browse files
author
Michel Zimmer
committed
Add hosts table page
1 parent cb25c1c commit 98107b5

25 files changed

+1080
-888
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ LABEL org.opencontainers.image.vendor="neuland – Büro für Informatik GmbH"
2626
LABEL org.opencontainers.image.licenses="MIT"
2727
LABEL org.opencontainers.image.title="bandwhichd-ui"
2828
LABEL org.opencontainers.image.description="bandwhichd ui displaying network topology and statistics"
29-
LABEL org.opencontainers.image.version="0.6.1"
29+
LABEL org.opencontainers.image.version="0.6.2"
3030
COPY --from=build --chown=root:root /home/node/dist /usr/share/nginx/html

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bandwhichd-ui",
3-
"version": "0.6.1",
3+
"version": "0.6.2",
44
"description": "bandwhichd ui displaying network topology and statistics",
55
"license": "MIT",
66
"private": true,
@@ -22,12 +22,12 @@
2222
"vis-network": "^9.1.2"
2323
},
2424
"devDependencies": {
25-
"@types/jest": "^28.1.8",
25+
"@types/jest": "^29.2.2",
2626
"@types/react": "^18.0.17",
2727
"@types/react-dom": "^18.0.6",
2828
"@vitejs/plugin-react": "^2.0.1",
2929
"esbuild-jest": "^0.5.0",
30-
"jest": "^28.1.3",
30+
"jest": "^29.3.1",
3131
"ts-css-modules-vite-plugin": "^1.0.18",
3232
"typescript": "^4.6.4",
3333
"vite": "^3.0.7"

src/App.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
import React from "react";
1+
import React, { useEffect, useState } from "react";
22
import { Footer } from "./Footer";
33
import { Header } from "./Header";
4-
import { Main } from "./Main";
4+
import { HostsPage } from "./hosts/HostsPage";
5+
import { PageId } from "./PageId";
6+
import { StartPage } from "./start/StartPage";
57

68
export const App: React.FC =
7-
() => <>
8-
<Header />
9-
<Main />
10-
<Footer />
11-
</>;
9+
() => {
10+
const [currentPageId, setCurrentPageId] = useState<PageId>(PageId.start);
11+
12+
return <>
13+
<Header {...{ currentPageId, setCurrentPageId }} />
14+
{
15+
currentPageId === PageId.start
16+
? <StartPage {...{ setCurrentPageId }}></StartPage>
17+
: currentPageId === PageId.hostsTable || currentPageId === PageId.hostsGraph
18+
? <HostsPage {...{ currentPageId, setCurrentPageId }}></HostsPage>
19+
: null
20+
}
21+
<Footer />
22+
</>;
23+
};

src/Footer.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.footer {
2-
background-color: #a01d31;
2+
background-color: #9e182f;
33
color: #ffffff;
44
padding: .5em;
55
text-align: center;

src/Header.module.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
.header {
2-
background-color: #afbc00;
2+
background-color: #a7af39;
33
padding: .5em;
44
text-align: right;
5+
}
6+
7+
.header nav {
8+
display: inline;
9+
}
10+
11+
.header nav ul {
12+
display: inline;
13+
list-style-type: none;
14+
}
15+
16+
.header nav ul li {
17+
display: inline;
518
}

src/Header.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
import React from "react";
22

33
import styles from "./Header.module.css"
4+
import { PageId } from "./PageId";
45

5-
export const Header: React.FC =
6-
() => <header className={styles.header}>Timeframe: 2 hours</header>;
6+
export interface HeaderProps {
7+
currentPageId: PageId,
8+
setCurrentPageId: (pageId: PageId) => void,
9+
}
10+
11+
export const Header: React.FC<HeaderProps> =
12+
({ setCurrentPageId }) =>
13+
<header className={styles.header}>
14+
<nav>
15+
<ul>
16+
<li>
17+
<button onClick={_ => setCurrentPageId(PageId.start)}>Start</button>
18+
</li>
19+
<li>
20+
<button onClick={_ => setCurrentPageId(PageId.hostsTable)}>Hosts table</button>
21+
</li>
22+
<li>
23+
<button onClick={_ => setCurrentPageId(PageId.hostsGraph)}>Hosts graph</button>
24+
</li>
25+
</ul>
26+
</nav>
27+
</header>;

src/Main.tsx

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/PageId.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const pageIdValues = [
2+
"hosts-graph",
3+
"hosts-table",
4+
"start",
5+
] as const;
6+
const pageIdTag = Symbol("PageId");
7+
export type PageId = string & { readonly _tag: typeof pageIdTag; };
8+
export namespace PageId {
9+
export const hostsGraph = "hosts-graph" as PageId;
10+
export const hostsTable = "hosts-table" as PageId;
11+
export const start = "start" as PageId;
12+
export const all = [ hostsGraph, hostsTable, start ] as const;
13+
}

src/hosts/HostsPage.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { useEffect, useState } from "react";
2+
import { PageId } from "../PageId";
3+
import { GraphPage } from "./graph/GraphPage";
4+
import { fetchStats, Host, HostId, Stats } from "./Stats";
5+
import { HostsTablePage } from "./table/HostsTablePage";
6+
7+
export interface HostsPageProps {
8+
currentPageId: PageId;
9+
setCurrentPageId: (currentPageId: PageId) => void;
10+
}
11+
12+
export const HostsPage: React.FC<HostsPageProps> =
13+
({ currentPageId, setCurrentPageId }) => {
14+
const [maybeStats, setMaybeStats] = useState<Stats | null>(null);
15+
const [maybeSelectedHostId, setMaybeSelectedHostId] = useState<HostId | null>(null);
16+
17+
useEffect(() => {
18+
fetchStats().then(stats => {
19+
setMaybeStats(stats);
20+
}).catch(console.error);
21+
}, []);
22+
23+
if (maybeStats === null) {
24+
return <p>Loading…</p>;
25+
}
26+
const stats = maybeStats;
27+
28+
const maybeSelectedHostWithoutId =
29+
maybeSelectedHostId === null
30+
? null
31+
: stats.hosts.get(maybeSelectedHostId, null)
32+
33+
const maybeSelectedHost: Host & { hostId: HostId } | null =
34+
maybeSelectedHostId === null || maybeSelectedHostWithoutId == null
35+
? null
36+
: { hostId: maybeSelectedHostId, ...maybeSelectedHostWithoutId };
37+
38+
const setSelectedHostIdAndViewGraph: (hostId: HostId) => void =
39+
(hostId) => {
40+
setMaybeSelectedHostId(hostId);
41+
setCurrentPageId(PageId.hostsGraph);
42+
};
43+
44+
return currentPageId === PageId.hostsTable
45+
? <HostsTablePage {...{ stats, setSelectedHostIdAndViewGraph }} />
46+
: <GraphPage {...{ maybeStats, maybeSelectedHost, maybeSelectedHostId, setMaybeSelectedHostId }} />
47+
};

src/Stats.ts renamed to src/hosts/Stats.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Map } from "immutable";
22
import * as Decoder from "io-ts/lib/Decoder"
3-
import { mapDecoder } from "./lib/immutable/io-ts/mapDecoder";
4-
import { parseBodyAsJson, rejectNonOk } from "./lib/es/response/promiseUtils";
5-
import { decode } from "./lib/io-ts/promiseUtils";
6-
import { undefinedAsNullDecoder } from "./lib/io-ts/undefinedAsNullDecoder";
3+
import { mapDecoder } from "../lib/immutable/io-ts/mapDecoder";
4+
import { parseBodyAsJson, rejectNonOk } from "../lib/es/response/promiseUtils";
5+
import { decode } from "../lib/io-ts/promiseUtils";
6+
import { undefinedAsNullDecoder } from "../lib/io-ts/undefinedAsNullDecoder";
77

88

99
const hostIdTag = Symbol("HostId");
@@ -41,6 +41,14 @@ const osReleaseDecoder = Decoder.struct({
4141
pretty_name: undefinedAsNullDecoder(osReleasePrettyNameDecoder),
4242
version_id: undefinedAsNullDecoder(osReleaseVersionIdDecoder),
4343
});
44+
export const osReleaseToString: (maybeOsRelease: OsRelease | null) => string =
45+
(maybeOsRelease) =>
46+
maybeOsRelease === null
47+
? "Unknown"
48+
: maybeOsRelease.pretty_name !== null
49+
&& maybeOsRelease.pretty_name.length > 0
50+
? maybeOsRelease.pretty_name
51+
: `${maybeOsRelease.id} ${maybeOsRelease.version_id}`;
4452

4553
export interface Connection { }
4654
const connectionDecoder = Decoder.struct({});

0 commit comments

Comments
 (0)