mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
web ui beginnings
This commit is contained in:
8
webui/.proxyrc
Normal file
8
webui/.proxyrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"/apiproxy": {
|
||||
"target": "http://localhost:8080/",
|
||||
"pathRewrite": {
|
||||
"^/apiproxy": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
import "./App.scss";
|
||||
import { Home } from "./Home";
|
||||
import { PeerState } from "./PeerState";
|
||||
import { peerStateLoader } from "./PeerStatePlumbing";
|
||||
import { ErrorGate } from "./ErrorGate";
|
||||
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
@@ -21,11 +23,19 @@ const router = createBrowserRouter(
|
||||
// return redirect("/home");
|
||||
// }
|
||||
},
|
||||
errorElement: <ErrorGate />,
|
||||
},
|
||||
{
|
||||
path: "/home",
|
||||
element: <Home />,
|
||||
children: [{ path: "peers", element: <PeerState /> }],
|
||||
children: [
|
||||
{
|
||||
path: "peers",
|
||||
element: <PeerState />,
|
||||
loader: peerStateLoader,
|
||||
},
|
||||
],
|
||||
errorElement: <ErrorGate />,
|
||||
},
|
||||
],
|
||||
{ basename: "/webui" },
|
||||
|
||||
7
webui/src/ErrorGate.tsx
Normal file
7
webui/src/ErrorGate.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { useRouteError } from "react-router-dom";
|
||||
|
||||
export function ErrorGate() {
|
||||
const error = useRouteError();
|
||||
console.error(error);
|
||||
return <div>{JSON.stringify(error)}</div>;
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
import "./PeerState.scss";
|
||||
import { useLoaderData } from "react-router-dom";
|
||||
import { LoaderToType } from "./commonPlumbing";
|
||||
import { peerStateLoader } from "./PeerStatePlumbing";
|
||||
|
||||
export function PeerState() {
|
||||
return <div id={"PeerState"}>peerstate</div>;
|
||||
const loaderData = useLoaderData() as LoaderToType<typeof peerStateLoader>;
|
||||
|
||||
const availablePeers = loaderData?.availablePeers.map((p) => {
|
||||
return <div>{p.uuid}</div>;
|
||||
});
|
||||
|
||||
return <div id={"PeerState"}>{availablePeers}</div>;
|
||||
}
|
||||
|
||||
7
webui/src/PeerStatePlumbing.tsx
Normal file
7
webui/src/PeerStatePlumbing.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { getAvailablePeers } from "./api/PeerState";
|
||||
|
||||
export async function peerStateLoader() {
|
||||
return {
|
||||
availablePeers: await getAvailablePeers(),
|
||||
};
|
||||
}
|
||||
13
webui/src/api/PeerState.ts
Normal file
13
webui/src/api/PeerState.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { fetchJSON_throws } from "./utils";
|
||||
import {
|
||||
AvailablePeerInfoToResp,
|
||||
TAvailablePeerInfoArrTo,
|
||||
TAvailablePeerInfoToResp,
|
||||
} from "./dto";
|
||||
|
||||
export async function getAvailablePeers(): Promise<TAvailablePeerInfoArrTo> {
|
||||
return fetchJSON_throws<
|
||||
TAvailablePeerInfoToResp,
|
||||
typeof AvailablePeerInfoToResp
|
||||
>("/objects-manage/available-peers", "GET", AvailablePeerInfoToResp);
|
||||
}
|
||||
@@ -33,3 +33,18 @@ export type TTokenTo = z.infer<typeof TokenTo>;
|
||||
|
||||
export const TokenToResp = CreateAPIResponse(TokenTo);
|
||||
export type TTokenToResp = z.infer<typeof TokenToResp>;
|
||||
|
||||
export const AvailablePeerInfoTo = z.object({
|
||||
uuid: z.string(),
|
||||
addr: z.string(),
|
||||
port: z.number(),
|
||||
});
|
||||
export type TAvailablePeerInfoTo = z.infer<typeof AvailablePeerInfoTo>;
|
||||
|
||||
export const AvailablePeerInfoArrTo = z.array(AvailablePeerInfoTo);
|
||||
export type TAvailablePeerInfoArrTo = z.infer<typeof AvailablePeerInfoArrTo>;
|
||||
|
||||
export const AvailablePeerInfoToResp = CreateAPIResponse(
|
||||
AvailablePeerInfoArrTo,
|
||||
);
|
||||
export type TAvailablePeerInfoToResp = z.infer<typeof AvailablePeerInfoToResp>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { isError } from "./dto";
|
||||
import { isError, TErrorTo } from "./dto";
|
||||
|
||||
declare const process: {
|
||||
env: {
|
||||
@@ -8,7 +8,9 @@ declare const process: {
|
||||
};
|
||||
|
||||
const apiRoot: string =
|
||||
process.env.NODE_ENV == "production" ? "" : "http://localhost:8080";
|
||||
process.env.NODE_ENV == "production"
|
||||
? ""
|
||||
: "http://localhost:1234/apiproxy";
|
||||
|
||||
let token: string | null;
|
||||
|
||||
@@ -88,3 +90,21 @@ export async function fetchJSONAuth<T, P extends { parse: (arg: string) => T }>(
|
||||
throw new Error("Not logged in");
|
||||
}
|
||||
}
|
||||
|
||||
function errorCheck<A extends unknown[], R>(
|
||||
fn: (...args: A) => R,
|
||||
): (...args: A) => Promise<Exclude<Awaited<R>, TErrorTo>> {
|
||||
return async (...args: A): Promise<Exclude<Awaited<R>, TErrorTo>> => {
|
||||
const ret = await fn(...args);
|
||||
if (isError(ret)) {
|
||||
throw ret;
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const fetchJSON_throws = errorCheck(fetchJSON);
|
||||
export const fetchJSONAuth_throws = errorCheck(fetchJSONAuth);
|
||||
|
||||
3
webui/src/commonPlumbing.ts
Normal file
3
webui/src/commonPlumbing.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type LoaderToType<T extends (...args: any) => any> =
|
||||
| Exclude<Awaited<ReturnType<T>>, Response>
|
||||
| undefined;
|
||||
Reference in New Issue
Block a user