fix(activity): an old audit/log link opens its tab, times read relative, one name for admin actions

Seen in the browser, not in the page's own tests: the navigation provider rewrites a retired page id
to `activity` before the page's chunk reads the URL, so `?page=audit` landed on the Runs tab. The
retired-page map now carries the params that open the successor's part (`at`), and the provider
writes them as it rewrites the page — on load and on Back alike.

A list time is relative with the exact second on hover (the DESIGN copy rule); a run moved over from
the audit log, whose start and end are one instant, shows no length instead of an invented "1 sec".
The audit log is called "admin actions" everywhere it is named (the clear button and its confirm, the
Configuration group, the cleanup job, which also prunes the run history its description left out).
This commit is contained in:
2026-10-18 04:00:38 +02:00
parent fe6308d844
commit c288ba147b
18 changed files with 133 additions and 92 deletions
@@ -219,6 +219,37 @@ describe("NavigationProvider · Back", () => {
expect(window.location.search).toBe("?page=files&keep=1");
});
// The audit log and the server log became the activity page's tabs: an old link, bookmark or entry
// opens that tab, with the filters it carried.
it("opens a retired page's tab on the page that replaced it", () => {
window.history.replaceState(null, "", "/?page=audit&keep=1");
const { result } = render();
expect(result.current.page).toBe("activity");
expect(window.location.search).toBe("?page=activity&keep=1&at=admin");
});
it("keeps a retired page's own filter as it opens its tab", () => {
window.history.replaceState(null, "", "/?page=logs&lreq=req-00000009");
render();
const url = new URLSearchParams(window.location.search);
expect([url.get("page"), url.get("at"), url.get("lreq")]).toEqual([
"activity",
"logs",
"req-00000009",
]);
});
it("opens a retired page's tab when Back lands on its entry", () => {
const { result } = render();
act(() => result.current.setPage("plex"));
act(() => {
window.history.replaceState({ sfPage: "audit" }, "", "/?page=audit");
window.dispatchEvent(new PopStateEvent("popstate", { state: { sfPage: "audit" } }));
});
expect(result.current.page).toBe("activity");
expect(window.location.search).toBe("?page=activity&at=admin");
});
// lib/history's own listener takes a spent focus stamp off the entry it lands on; the rewrite must
// not put it back, or the next landing there (an overlay closing) would refocus a stale item.
it("does not put back the focus stamp the landing spent", () => {