Spaces:
Sleeping
Sleeping
Download frontend/hooks/useLogsQuery.ts from Aynkhn/Face-Expression-Analyzer: direct link, hf CLI and curl.
- Browser
- Download file 2.08 kB
-
https://huggingface.co/spaces/Aynkhn/Face-Expression-Analyzer/resolve/main/frontend/hooks/useLogsQuery.ts
- Command line
-
hf download hf://spaces/Aynkhn/Face-Expression-Analyzer/frontend/hooks/useLogsQuery.ts
-
curl -L -o useLogsQuery.ts https://huggingface.co/spaces/Aynkhn/Face-Expression-Analyzer/resolve/main/frontend/hooks/useLogsQuery.ts
2.08 kB
| "use client"; | |
| import { useCallback, useEffect, useRef, useState } from "react"; | |
| import { listLogs, type ApiError } from "@/lib/api-client"; | |
| import type { LogQueryParams, LogsPage } from "@/types/log"; | |
| export type QueryState<T> = | |
| | { status: "loading"; data: T | null } | |
| | { status: "success"; data: T } | |
| | { status: "empty"; data: T } | |
| | { status: "error"; error: ApiError; data: T | null }; | |
| /** | |
| * Fetch a page of logs. | |
| * | |
| * Two behaviours the dashboard previously lacked. Failures are surfaced instead of | |
| * being swallowed into `console.error` and falling through to the empty state, so a | |
| * dead backend no longer looks like an empty database. And each request aborts the | |
| * one before it, so rapidly changing a filter cannot leave an older response | |
| * arriving last and overwriting the newer one. | |
| */ | |
| export function useLogsQuery(params: LogQueryParams) { | |
| const [state, setState] = useState<QueryState<LogsPage>>({ status: "loading", data: null }); | |
| const abortRef = useRef<AbortController | null>(null); | |
| const [reloadToken, setReloadToken] = useState(0); | |
| const key = JSON.stringify(params); | |
| useEffect(() => { | |
| abortRef.current?.abort(); | |
| const controller = new AbortController(); | |
| abortRef.current = controller; | |
| setState((previous) => ({ status: "loading", data: previous.data })); | |
| void (async () => { | |
| const result = await listLogs(JSON.parse(key) as LogQueryParams, controller.signal); | |
| if (controller.signal.aborted) return; | |
| if (!result.ok) { | |
| // A cancelled request is not a failure to report; a newer one is running. | |
| if (result.error.kind === "aborted") return; | |
| setState((previous) => ({ status: "error", error: result.error, data: previous.data })); | |
| return; | |
| } | |
| setState({ | |
| status: result.data.items.length === 0 ? "empty" : "success", | |
| data: result.data, | |
| }); | |
| })(); | |
| return () => controller.abort(); | |
| }, [key, reloadToken]); | |
| const refetch = useCallback(() => setReloadToken((token) => token + 1), []); | |
| return { ...state, refetch }; | |
| } | |