122 lines
3.1 KiB
TypeScript
122 lines
3.1 KiB
TypeScript
/**
|
|
* React hook for fetching a single jail's detailed metadata.
|
|
*/
|
|
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { addIgnoreIp, delIgnoreIp, fetchJail, reloadJail, setJailIdle, startJail, stopJail, toggleIgnoreSelf as toggleIgnoreSelfApi } from "../api/jails";
|
|
import { handleFetchError } from "../utils/fetchError";
|
|
import type { Jail } from "../types/jail";
|
|
|
|
export interface UseJailDetailResult {
|
|
jail: Jail | null;
|
|
ignoreList: string[];
|
|
ignoreSelf: boolean;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refresh: () => void;
|
|
addIp: (ip: string) => Promise<void>;
|
|
removeIp: (ip: string) => Promise<void>;
|
|
toggleIgnoreSelf: (on: boolean) => Promise<void>;
|
|
start: () => Promise<void>;
|
|
stop: () => Promise<void>;
|
|
reload: () => Promise<void>;
|
|
setIdle: (on: boolean) => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* Fetch and manage the detail view for a single jail.
|
|
*/
|
|
export function useJailDetail(name: string): UseJailDetailResult {
|
|
const [jail, setJail] = useState<Jail | null>(null);
|
|
const [ignoreList, setIgnoreList] = useState<string[]>([]);
|
|
const [ignoreSelf, setIgnoreSelf] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const abortRef = useRef<AbortController | null>(null);
|
|
|
|
const load = useCallback(() => {
|
|
abortRef.current?.abort();
|
|
const ctrl = new AbortController();
|
|
abortRef.current = ctrl;
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
fetchJail(name)
|
|
.then((res) => {
|
|
if (!ctrl.signal.aborted) {
|
|
setJail(res.jail);
|
|
setIgnoreList(res.ignore_list);
|
|
setIgnoreSelf(res.ignore_self);
|
|
}
|
|
})
|
|
.catch((err: unknown) => {
|
|
if (!ctrl.signal.aborted) {
|
|
handleFetchError(err, setError, "Failed to fetch jail detail");
|
|
}
|
|
})
|
|
.finally(() => {
|
|
if (!ctrl.signal.aborted) {
|
|
setLoading(false);
|
|
}
|
|
});
|
|
}, [name]);
|
|
|
|
useEffect(() => {
|
|
load();
|
|
return (): void => {
|
|
abortRef.current?.abort();
|
|
};
|
|
}, [load]);
|
|
|
|
const addIp = useCallback(async (ip: string): Promise<void> => {
|
|
await addIgnoreIp(name, ip);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const removeIp = useCallback(async (ip: string): Promise<void> => {
|
|
await delIgnoreIp(name, ip);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const toggleIgnoreSelf = useCallback(async (on: boolean): Promise<void> => {
|
|
await toggleIgnoreSelfApi(name, on);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const start = useCallback(async (): Promise<void> => {
|
|
await startJail(name);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const stop = useCallback(async (): Promise<void> => {
|
|
await stopJail(name);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const reload = useCallback(async (): Promise<void> => {
|
|
await reloadJail(name);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
const setIdle = useCallback(async (on: boolean): Promise<void> => {
|
|
await setJailIdle(name, on);
|
|
load();
|
|
}, [name, load]);
|
|
|
|
return {
|
|
jail,
|
|
ignoreList,
|
|
ignoreSelf,
|
|
loading,
|
|
error,
|
|
refresh: load,
|
|
addIp,
|
|
removeIp,
|
|
toggleIgnoreSelf,
|
|
start,
|
|
stop,
|
|
reload,
|
|
setIdle,
|
|
};
|
|
}
|