This commit is contained in:
Arnaud 2024-10-11 17:58:13 +02:00
parent 677f2fcffb
commit 2246d4d78e
No known key found for this signature in database
GPG Key ID: 69D6CE281FCAE663
4 changed files with 106 additions and 119 deletions

View File

@ -1,5 +1,4 @@
import { test, expect } from '@playwright/test';
import { Buffer } from 'buffer';
import { readFileSync } from 'fs';
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';

46
package-lock.json generated
View File

@ -10,13 +10,13 @@
"license": "MIT",
"dependencies": {
"@codex-storage/marketplace-ui-components": "^0.0.18",
"@codex-storage/sdk-js": "^0.0.7",
"@codex-storage/sdk-js": "^0.0.8",
"@sentry/browser": "^8.32.0",
"@sentry/react": "^8.31.0",
"@tanstack/react-query": "^5.51.15",
"@tanstack/react-router": "^1.58.7",
"echarts": "^5.5.1",
"dotted-map": "^2.2.3",
"echarts": "^5.5.1",
"idb-keyval": "^6.2.1",
"lucide-react": "^0.445.0",
"react": "^18.3.1",
@ -378,9 +378,9 @@
}
},
"node_modules/@codex-storage/sdk-js": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/@codex-storage/sdk-js/-/sdk-js-0.0.7.tgz",
"integrity": "sha512-Ffp0hDxGxDv+PwcWZheDGnP1l9CagKQZgYgXNznF9TtQGFPWr3LAyN6xrfzv+XwDSlL2SQrJuLM2z8DLcRt2PA==",
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@codex-storage/sdk-js/-/sdk-js-0.0.8.tgz",
"integrity": "sha512-NSHwDpWmRVHlCJHUDVr7FZ0HBxpyoFNXHTjPqOPeQDaGlN+5Yzf/9aBU+lmYVdvIk68BQIzlScMIisRf8IYw9A==",
"dependencies": {
"valibot": "^0.32.0"
},
@ -567,11 +567,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"dev": true,
@ -2129,17 +2124,6 @@
"node": ">=4"
}
},
"node_modules/chart.js": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz",
"integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"pnpm": ">=8"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"dev": true,
@ -2276,6 +2260,15 @@
"url": "https://dotenvx.com"
}
},
"node_modules/dotted-map": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/dotted-map/-/dotted-map-2.2.3.tgz",
"integrity": "sha512-8hyOOHHLLVCcCisM3yb9hqp+3bJ7TSMcr1SfrUw8Wxp5UMqih35jIvUyagweCooJbz/EH1nC9GGuPysh7+YlAg==",
"dependencies": {
"@turf/boolean-point-in-polygon": "^6.0.1",
"proj4": "^2.6.1"
}
},
"node_modules/echarts": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.1.tgz",
@ -2290,15 +2283,6 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/dotted-map": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/dotted-map/-/dotted-map-2.2.3.tgz",
"integrity": "sha512-8hyOOHHLLVCcCisM3yb9hqp+3bJ7TSMcr1SfrUw8Wxp5UMqih35jIvUyagweCooJbz/EH1nC9GGuPysh7+YlAg==",
"dependencies": {
"@turf/boolean-point-in-polygon": "^6.0.1",
"proj4": "^2.6.1"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"dev": true,
@ -4662,4 +4646,4 @@
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
}
}
}

View File

@ -12,7 +12,7 @@
"compile": "tsc --noEmit",
"build": "tsc -b && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"preview": "vite preview --host 127.0.0.1 --port 5173",
"format": "prettier --write ./src",
"test": "npx playwright test"
},
@ -25,7 +25,7 @@
],
"dependencies": {
"@codex-storage/marketplace-ui-components": "^0.0.18",
"@codex-storage/sdk-js": "^0.0.7",
"@codex-storage/sdk-js": "^0.0.8",
"@sentry/browser": "^8.32.0",
"@sentry/react": "^8.31.0",
"@tanstack/react-query": "^5.51.15",

View File

@ -13,90 +13,94 @@ import { CodexSdk } from "../../sdk/codex";
// This function accepts the same arguments as DottedMap in the example above.
const mapJsonString = getMapJSON({ height: 60, grid: "diagonal" });
const Peers = () => {
const [pins, setPins] = useState<[PeerPin, number][]>([]);
const { data } = useQuery({
queryFn: () =>
CodexSdk.debug()
.info()
.then((s) => Promises.rejectOnError(s)),
queryKey: ["debug"],
// No need to retry because if the connection to the node
// is back again, all the queries will be invalidated.
retry: false,
// The client node should be local, so display the cache value while
// making a background request looks good.
staleTime: 0,
// Refreshing when focus returns can be useful if a user comes back
// to the UI after performing an operation in the terminal.
refetchOnWindowFocus: true,
// Throw the error to the error boundary
throwOnError: true,
});
const onPinAdd = useCallback((pin: PeerPin) => {
setPins((val) => {
const [, quantity = 0] =
val.find(([p]) => p.lat === pin.lat && p.lng == pin.lng) || [];
return [...val, [pin, quantity + 1]];
});
}, []);
// Its safe to re-create the map at each render, because of the
// pre-computation its super fast ⚡️
const map = new DottedMap({ map: JSON.parse(mapJsonString) });
pins.map(([pin, quantity]) =>
map.addPin({
lat: pin.lat,
lng: pin.lng,
svgOptions: { color: "#d6ff79", radius: 0.8 * quantity },
})
);
const svgMap = map.getSVG({
radius: 0.42,
color: "#423B38",
shape: "circle",
backgroundColor: "#020300",
});
const headers = ["Country", "PeerId", "Active"];
const rows =
(data?.table?.nodes || []).map((node) => (
<Row
cells={[
<PeerCountryCell
onPinAdd={onPinAdd}
address={node.address}></PeerCountryCell>,
<Cell>{node.peerId}</Cell>,
<Cell>
{node.seen ? (
<div className="networkIndicator-point networkIndicator-point--online"></div>
) : (
<div className="networkIndicator-point networkIndicator-point--offline"></div>
)}
</Cell>,
]}></Row>
)) || [];
return (
<div className="peers">
{/* <img
src={`data:image/svg+xml;utf8,${encodeURIComponent(svgMap)}`}
className="peers-map"
/> */}
<div
className="peers-map"
dangerouslySetInnerHTML={{ __html: svgMap }}></div>
<Table headers={headers} rows={rows} className="peers-table" />
</div>
);
};
export const Route = createFileRoute("/dashboard/peers")({
component: () => {
const [pins, setPins] = useState<[PeerPin, number][]>([]);
const { data } = useQuery({
queryFn: () =>
CodexSdk.debug.info().then((s) => Promises.rejectOnError(s)),
queryKey: ["debug"],
// No need to retry because if the connection to the node
// is back again, all the queries will be invalidated.
retry: false,
// The client node should be local, so display the cache value while
// making a background request looks good.
staleTime: 0,
// Refreshing when focus returns can be useful if a user comes back
// to the UI after performing an operation in the terminal.
refetchOnWindowFocus: true,
// Throw the error to the error boundary
throwOnError: true,
});
const onPinAdd = useCallback((pin: PeerPin) => {
setPins((val) => {
const [, quantity = 0] =
val.find(([p]) => p.lat === pin.lat && p.lng == pin.lng) || [];
return [...val, [pin, quantity + 1]];
});
}, []);
// Its safe to re-create the map at each render, because of the
// pre-computation its super fast ⚡️
const map = new DottedMap({ map: JSON.parse(mapJsonString) });
pins.map(([pin, quantity]) =>
map.addPin({
lat: pin.lat,
lng: pin.lng,
svgOptions: { color: "#d6ff79", radius: 0.8 * quantity },
})
);
const svgMap = map.getSVG({
radius: 0.42,
color: "#423B38",
shape: "circle",
backgroundColor: "#020300",
});
const headers = ["Country", "PeerId", "Active"];
const rows =
((data as any)?.table?.nodes || []).map((node: any) => (
<Row
cells={[
<PeerCountryCell
onPinAdd={onPinAdd}
address={node.address}></PeerCountryCell>,
<Cell>{node.peerId}</Cell>,
<Cell>
{node.seen ? (
<div className="networkIndicator-point networkIndicator-point--online"></div>
) : (
<div className="networkIndicator-point networkIndicator-point--offline"></div>
)}
</Cell>,
]}></Row>
)) || [];
return (
<div className="peers">
{/* <img
src={`data:image/svg+xml;utf8,${encodeURIComponent(svgMap)}`}
className="peers-map"
/> */}
<div
className="peers-map"
dangerouslySetInnerHTML={{ __html: svgMap }}></div>
<Table headers={headers} rows={rows} className="peers-table" />
</div>
);
},
component: Peers,
});