Files
siftlode/frontend/src/lib/logsUrlState.test.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

39 lines
1.3 KiB
TypeScript

// The admin log console's filters in the address bar: a link carries them, a hand-edited value the
// API would refuse degrades to "no filter", and a filter at its default leaves no key behind.
import { describe, expect, it } from "vitest";
import {
DEFAULT_LOGS_STATE,
logsParamsToState,
logsParamUpdates,
type LogsUrlState,
} from "./logsUrlState";
const params = (updates: Record<string, string | null>) =>
new URLSearchParams(Object.entries(updates).filter((e): e is [string, string] => e[1] !== null));
describe("logsUrlState", () => {
it("round-trips every filter", () => {
const state: LogsUrlState = {
group: "error",
sources: ["worker"],
event: "download.job.failed",
requestId: "req-abcdef12",
jobId: 42,
runId: 7,
};
expect(logsParamsToState(params(logsParamUpdates(state)))).toEqual(state);
});
it("leaves no key for a filter at its default", () => {
expect(Object.values(logsParamUpdates(DEFAULT_LOGS_STATE)).every((v) => v === null)).toBe(true);
});
it("drops a value the API would refuse instead of sending it", () => {
const state = logsParamsToState(
new URLSearchParams("lgrp=loud&lsrc=api,WORKER,x y&lev=Not.A.Code&lreq=short&ljob=0&lrun=-1"),
);
expect(state).toEqual({ ...DEFAULT_LOGS_STATE, sources: ["api"] });
});
});