mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
API draft to manually set peer addresses
This commit is contained in:
4868
webui/package-lock.json
generated
4868
webui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,27 +10,31 @@
|
||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||
"dependencies": {
|
||||
"jwt-decode": "^4.0.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.24.0",
|
||||
"zod": "^3.23.8"
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-router": "^7.4.1",
|
||||
"react-router-dom": "^7.4.1",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"@parcel/resolver-default": {
|
||||
"packageExports": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@parcel/transformer-sass": "^2.12.0",
|
||||
"@parcel/transformer-typescript-tsc": "^2.12.0",
|
||||
"@parcel/validator-typescript": "^2.12.0",
|
||||
"@types/eslint": "^8.56.10",
|
||||
"@parcel/transformer-sass": "^2.14.4",
|
||||
"@parcel/transformer-typescript-tsc": "^2.14.4",
|
||||
"@parcel/validator-typescript": "^2.14.4",
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@types/eslint-config-prettier": "^6.11.3",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
||||
"@typescript-eslint/parser": "^7.14.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-react": "^7.34.3",
|
||||
"parcel": "^2.12.0",
|
||||
"prettier": "^3.3.2",
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
"eslint": "^9",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"parcel": "^2.14.4",
|
||||
"prettier": "^3.5.3",
|
||||
"process": "^0.11.10",
|
||||
"typescript": "^5.5.2"
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ export interface TPeerAvailableCardProps {
|
||||
|
||||
export function PeerAvailableCard({ peerInfo }: TPeerAvailableCardProps) {
|
||||
const fetcher = useFetcher();
|
||||
|
||||
return (
|
||||
<div className="peerAvailableCard">
|
||||
<div className={"peerInfo"}>
|
||||
@@ -22,8 +21,8 @@ export function PeerAvailableCard({ peerInfo }: TPeerAvailableCardProps) {
|
||||
action={"/home/peers"}
|
||||
>
|
||||
<button type="submit">connect</button>
|
||||
<input name="intent" hidden={true} value={"add_peer"} />
|
||||
<input name="uuid" hidden={true} value={peerInfo.uuid} />
|
||||
<input name="intent" hidden={true} defaultValue={"add_peer"} />
|
||||
<input name="uuid" hidden={true} defaultValue={peerInfo.uuid} />
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { TKnownPeerInfoTo } from "./api/dto";
|
||||
|
||||
import "./PeerKnownCard.scss";
|
||||
import { useFetcher } from "react-router-dom";
|
||||
import { useFetcher, useLoaderData } from "react-router-dom";
|
||||
import { LoaderToType } from "./commonPlumbing";
|
||||
import { peerStateLoader } from "./PeerStatePlumbing";
|
||||
|
||||
export interface TPeerKnownCardProps {
|
||||
peerInfo: TKnownPeerInfoTo;
|
||||
@@ -9,12 +11,42 @@ export interface TPeerKnownCardProps {
|
||||
|
||||
export function PeerKnownCard({ peerInfo }: TPeerKnownCardProps) {
|
||||
const fetcher = useFetcher();
|
||||
const loaderData = useLoaderData() as LoaderToType<typeof peerStateLoader>;
|
||||
|
||||
const addr = loaderData.peerAddresses.find(
|
||||
(item) => item.uuid === peerInfo.uuid,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="peerKnownCard">
|
||||
<div className={"peerInfo"}>
|
||||
<span>UUID: </span>
|
||||
<span>{peerInfo.uuid}</span>
|
||||
<div>
|
||||
<span>UUID: </span>
|
||||
<span>{peerInfo.uuid}</span>
|
||||
</div>
|
||||
<div>
|
||||
<fetcher.Form
|
||||
className="actions"
|
||||
method="put"
|
||||
action={"/home/peers"}
|
||||
>
|
||||
<input
|
||||
name="intent"
|
||||
hidden={true}
|
||||
defaultValue={"save_addr"}
|
||||
/>
|
||||
<input
|
||||
name="uuid"
|
||||
hidden={true}
|
||||
defaultValue={peerInfo.uuid}
|
||||
/>
|
||||
<input
|
||||
name="address"
|
||||
defaultValue={addr?.address || ""}
|
||||
/>
|
||||
<button type="submit">save</button>
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
</div>
|
||||
<fetcher.Form
|
||||
className="actions"
|
||||
@@ -22,8 +54,12 @@ export function PeerKnownCard({ peerInfo }: TPeerKnownCardProps) {
|
||||
action={"/home/peers"}
|
||||
>
|
||||
<button type="submit">remove</button>
|
||||
<input name="intent" hidden={true} value={"remove_peer"} />
|
||||
<input name="uuid" hidden={true} value={peerInfo.uuid} />
|
||||
<input
|
||||
name="intent"
|
||||
hidden={true}
|
||||
defaultValue={"remove_peer"}
|
||||
/>
|
||||
<input name="uuid" hidden={true} defaultValue={peerInfo.uuid} />
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import {
|
||||
getAvailablePeers,
|
||||
getKnownPeers,
|
||||
getPeerAddresses,
|
||||
putKnownPeer,
|
||||
putPeerAddress,
|
||||
removeKnownPeer,
|
||||
} from "./api/PeerState";
|
||||
import { ActionFunctionArgs } from "react-router-dom";
|
||||
@@ -10,10 +12,15 @@ export async function peerStateLoader() {
|
||||
return {
|
||||
availablePeers: await getAvailablePeers(),
|
||||
knownPeers: await getKnownPeers(),
|
||||
peerAddresses: await getPeerAddresses(),
|
||||
};
|
||||
}
|
||||
|
||||
export type PeerStateActionType = "add_peer" | "remove_peer" | unknown;
|
||||
export type PeerStateActionType =
|
||||
| "add_peer"
|
||||
| "remove_peer"
|
||||
| "save_addr"
|
||||
| unknown;
|
||||
|
||||
export async function peerStateAction({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
@@ -22,6 +29,11 @@ export async function peerStateAction({ request }: ActionFunctionArgs) {
|
||||
return await putKnownPeer(formData.get("uuid") as string);
|
||||
} else if (intent === "remove_peer") {
|
||||
return await removeKnownPeer(formData.get("uuid") as string);
|
||||
} else if (intent === "save_addr") {
|
||||
return await putPeerAddress(
|
||||
formData.get("uuid") as string,
|
||||
formData.get("address") as string,
|
||||
);
|
||||
} else {
|
||||
throw new Error("Malformed action: " + JSON.stringify(request));
|
||||
}
|
||||
|
||||
@@ -3,36 +3,73 @@ import {
|
||||
AvailablePeerInfoToResp,
|
||||
KnownPeerInfoToResp,
|
||||
NoContentToResp,
|
||||
PeerAddressInfoToResp,
|
||||
TAvailablePeerInfoArrTo,
|
||||
TAvailablePeerInfoToResp,
|
||||
TKnownPeerInfoArrTo,
|
||||
TKnownPeerInfoToResp,
|
||||
TNoContentToResp,
|
||||
TPeerAddressInfoArrTo,
|
||||
TPeerAddressInfoToResp,
|
||||
} from "./dto";
|
||||
|
||||
export async function getAvailablePeers(): Promise<TAvailablePeerInfoArrTo> {
|
||||
return fetchJSON_throws<
|
||||
TAvailablePeerInfoToResp,
|
||||
typeof AvailablePeerInfoToResp
|
||||
>("/objects-manage/available-peers", "GET", AvailablePeerInfoToResp);
|
||||
>("/peers-manage/available-peers", "GET", AvailablePeerInfoToResp);
|
||||
}
|
||||
|
||||
export async function getKnownPeers(): Promise<TKnownPeerInfoArrTo> {
|
||||
return fetchJSON_throws<TKnownPeerInfoToResp, typeof KnownPeerInfoToResp>(
|
||||
"/objects-manage/known-peers",
|
||||
"/peers-manage/known-peers",
|
||||
"GET",
|
||||
KnownPeerInfoToResp,
|
||||
);
|
||||
}
|
||||
|
||||
export async function putKnownPeer(uuid: string): Promise<TNoContentToResp> {
|
||||
return fetchJSON("/objects-manage/known-peers", "PUT", NoContentToResp, {
|
||||
return fetchJSON("/peers-manage/known-peers", "PUT", NoContentToResp, {
|
||||
uuid,
|
||||
});
|
||||
}
|
||||
|
||||
export async function removeKnownPeer(uuid: string): Promise<TNoContentToResp> {
|
||||
return fetchJSON("/objects-manage/known-peers", "DELETE", NoContentToResp, {
|
||||
return fetchJSON("/peers-manage/known-peers", "DELETE", NoContentToResp, {
|
||||
uuid,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPeerAddresses(): Promise<TPeerAddressInfoArrTo> {
|
||||
return fetchJSON_throws<
|
||||
TPeerAddressInfoToResp,
|
||||
typeof PeerAddressInfoToResp
|
||||
>("/peers-addr-manage", "GET", PeerAddressInfoToResp);
|
||||
}
|
||||
|
||||
export async function putPeerAddress(
|
||||
uuid: string,
|
||||
address: string,
|
||||
): Promise<TNoContentToResp> {
|
||||
return fetchJSON(
|
||||
`/peers-addr-manage/${uuid}`,
|
||||
"PUT",
|
||||
NoContentToResp,
|
||||
address,
|
||||
);
|
||||
}
|
||||
|
||||
export async function removePeerAddress(
|
||||
uuid: string,
|
||||
): Promise<TNoContentToResp> {
|
||||
return fetchJSON(`/peers-addr-manage/${uuid}`, "DELETE", NoContentToResp);
|
||||
}
|
||||
|
||||
export async function getPeerAddress(
|
||||
uuid: string,
|
||||
): Promise<TPeerAddressInfoToResp> {
|
||||
return fetchJSON_throws<
|
||||
TPeerAddressInfoToResp,
|
||||
typeof PeerAddressInfoToResp
|
||||
>(`/peers-addr-manage/${uuid}`, "GET", PeerAddressInfoToResp);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,19 @@ export type TKnownPeerInfoArrTo = z.infer<typeof KnownPeerInfoArrTo>;
|
||||
export const KnownPeerInfoToResp = CreateAPIResponse(KnownPeerInfoArrTo);
|
||||
export type TKnownPeerInfoToResp = z.infer<typeof KnownPeerInfoToResp>;
|
||||
|
||||
// PeerAddressInfo
|
||||
export const PeerAddressInfoTo = z.object({
|
||||
uuid: z.string(),
|
||||
address: z.string(),
|
||||
});
|
||||
export type TPeerAddressInfoTo = z.infer<typeof PeerAddressInfoTo>;
|
||||
|
||||
export const PeerAddressInfoArrTo = z.array(PeerAddressInfoTo);
|
||||
export type TPeerAddressInfoArrTo = z.infer<typeof PeerAddressInfoArrTo>;
|
||||
|
||||
export const PeerAddressInfoToResp = CreateAPIResponse(PeerAddressInfoArrTo);
|
||||
export type TPeerAddressInfoToResp = z.infer<typeof PeerAddressInfoToResp>;
|
||||
|
||||
// KnownPeerPut
|
||||
export const KnownPeerPutTo = z.object({ uuid: z.string() });
|
||||
export type TKnownPeerPutTo = z.infer<typeof KnownPeerPutTo>;
|
||||
|
||||
@@ -44,14 +44,17 @@ export async function fetchJSON<T, P extends { parse: (arg: string) => T }>(
|
||||
body?: string | Record<string, unknown> | File,
|
||||
headers?: Record<string, string>,
|
||||
): Promise<T> {
|
||||
const reqBody = () =>
|
||||
body instanceof File
|
||||
const reqBody = () => {
|
||||
if (typeof body === "string" || body instanceof String)
|
||||
return body.toString();
|
||||
return body instanceof File
|
||||
? (() => {
|
||||
const fd = new FormData();
|
||||
fd.append("file", body);
|
||||
return fd;
|
||||
})()
|
||||
: JSON.stringify(body);
|
||||
};
|
||||
|
||||
const reqHeaders = () =>
|
||||
body instanceof File
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
],
|
||||
"jsx": "react-jsx",
|
||||
"target": "es2015",
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "bundler",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
|
||||
Reference in New Issue
Block a user