Files
siftlode/frontend/src/lib/useHistoryList.ts
T
peter 24448e7c6f feat(activity): one Activity page — runs, admin actions, server log and quota under one filter bar
The audit log, the server log and the admin quota view were three pages (the quota one a Stats tab),
each with its own filters, and the background runs had no list at all. Now one page ("Napló" /
"Activity") reads all four, each still its own table on the server: a shared bar (text, a period of
1 h to 90 days defaulting to 7, an account) and each tab's own filters, the whole view in the URL.
The old page ids open their tab.

Server side: the audit log and the new run list (`/api/admin/runs`) filter and page like the server
log, through one keyset helper (`routes/_keyset`) the log now shares; an audit row keeps the request
it was made in (migration 0111), so its log lines are a pivot away, as a run's are (`lrun`). The
quota breakdown takes since/until and one account. The Scheduler rows get a history button to their
job's runs.

Also fixed on the way: re-saving the value in force on the Configuration page staged its override
without committing it (the commit sat inside the audit branch), so the save was lost.
2026-10-18 03:45:18 +02:00

34 lines
1.3 KiB
TypeScript

import { useMemo } from "react";
import { keepPreviousData, useInfiniteQuery } from "@tanstack/react-query";
import type { HistoryPage } from "./api";
/** A history list read a page at a time, newest first (the server's keyset paging): the rows loaded
* so far, the accounts they name, and whether there is an older page to ask for. While a filter
* change loads, the previous filter's rows stay on screen (dimmed by the caller) and no older page is
* offered — the cursor on screen belongs to the rows of the old filter. */
export function useHistoryList<T>(
queryKey: readonly unknown[],
fetchPage: (before: string | null) => Promise<HistoryPage<T>>,
) {
const list = useInfiniteQuery({
queryKey,
queryFn: ({ pageParam }) => fetchPage(pageParam),
initialPageParam: null as string | null,
getNextPageParam: (last) => last.next_cursor ?? undefined,
placeholderData: keepPreviousData,
});
const rows = useMemo(() => list.data?.pages.flatMap((p) => p.items) ?? [], [list.data]);
const accounts = useMemo(
() =>
Object.assign({}, ...(list.data?.pages.map((p) => p.accounts) ?? [])) as Record<
string,
string
>,
[list.data],
);
return { list, rows, accounts, hasOlder: !list.isPlaceholderData && list.hasNextPage };
}
export type HistoryList<T> = ReturnType<typeof useHistoryList<T>>;