The dashboard now renders a progress bar for any running job — determinate when counts are reported, an indeterminate "working" sliver otherwise — so a scheduled run is as visible as a manual one (progress was never manual-only; the wiring is shared, but only some jobs reported and the display gated on counts). Poll faster (1.5s) while any job runs, easing back to 4s when idle, derived from the freshest data by react-query's functional refetchInterval. The earlier React-state approach to this stalled the live updates (the row froze on the first sampled value); useLiveQuery now accepts a function of the data. Trilingual phase labels for the newly-reporting jobs.
30 lines
1.3 KiB
TypeScript
30 lines
1.3 KiB
TypeScript
import { useQuery, type QueryKey } from "@tanstack/react-query";
|
|
|
|
// Reusable "live" polling query: a thin wrapper over react-query that refetches on an
|
|
// interval and — by leaving refetchIntervalInBackground at its default false — pauses while
|
|
// the tab is unfocused, so it doesn't poll a server nobody's watching. This is the shared
|
|
// live-progress mechanism: the Scheduler dashboard uses it now; the notification bell and the
|
|
// future yt-dlp job queue reuse it rather than each re-implementing polling.
|
|
export function useLiveQuery<T>(
|
|
key: QueryKey,
|
|
queryFn: () => Promise<T>,
|
|
// intervalMs may be a function of the latest data, so the poll cadence can adapt to it
|
|
// (e.g. poll faster while a job is running). react-query re-evaluates it after each fetch
|
|
// against fresh data — the right place for this, vs. a React state toggle that can lag or
|
|
// stall the live updates.
|
|
opts: { intervalMs?: number | ((data: T | undefined) => number); enabled?: boolean } = {}
|
|
) {
|
|
const { intervalMs = 4000, enabled = true } = opts;
|
|
return useQuery({
|
|
queryKey: key,
|
|
queryFn,
|
|
enabled,
|
|
refetchInterval: !enabled
|
|
? false
|
|
: typeof intervalMs === "function"
|
|
? (query) => intervalMs(query.state.data as T | undefined)
|
|
: intervalMs,
|
|
refetchIntervalInBackground: false,
|
|
staleTime: 0,
|
|
});
|
|
}
|