Refactor jail detail hooks: split into useJailData and useJailCommands
- Split monolithic useJailDetail hook into separate concerns - Created useJailData for fetching and managing jail data - Created useJailCommands for jail operations (power, console, etc.) - Updated JailDetailPage to use new hooks - Updated tests to reflect new hook structure - Removed old useJailDetail hook Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
78
frontend/src/hooks/useJailData.ts
Normal file
78
frontend/src/hooks/useJailData.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* React hook for fetching a single jail's detailed metadata.
|
||||
*
|
||||
* Reads jail data: configuration, ignore list, ignore self flag, and related state.
|
||||
* Does not handle mutations — use `useJailCommands` for write operations.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { fetchJail } from "../api/jails";
|
||||
import { handleFetchError } from "../utils/fetchError";
|
||||
import type { Jail } from "../types/jail";
|
||||
|
||||
export interface UseJailDataResult {
|
||||
jail: Jail | null;
|
||||
ignoreList: string[];
|
||||
ignoreSelf: boolean;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and manage the detail view for a single jail.
|
||||
*
|
||||
* @param name - The name of the jail to fetch.
|
||||
* @returns Jail data and refresh function.
|
||||
*/
|
||||
export function useJailData(name: string): UseJailDataResult {
|
||||
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 refresh = 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(() => {
|
||||
refresh();
|
||||
return (): void => {
|
||||
abortRef.current?.abort();
|
||||
};
|
||||
}, [refresh]);
|
||||
|
||||
return {
|
||||
jail,
|
||||
ignoreList,
|
||||
ignoreSelf,
|
||||
loading,
|
||||
error,
|
||||
refresh,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user