From b23d15453d150b9719140cfcad5591e7fdf638d6 Mon Sep 17 00:00:00 2001 From: BOHA Date: Sun, 7 Jun 2026 15:34:06 +0200 Subject: [PATCH] fix(audit-log): stop replaying the page entrance animation on every filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AuditLog uses a raw useQuery with the filters in the queryKey and a page-level early return (if isPending && no rows → ), which sits ABOVE . On any filter change the new queryKey had no cached data, so isPending flipped true with empty rows, the early return unmounted the whole PageEnter subtree, and it remounted (replaying the staggered entrance) when data arrived. Add placeholderData: keepPreviousData so rows persist through the refetch (isPending stays false, subtree never unmounts), and dim the table via isFetching instead of isPending. Verified by DOM node-identity: the PageEnter root survives a filter (no remount). The paginated list pages were already immune (usePaginatedQuery bakes in keepPreviousData). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/admin/pages/AuditLog.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/admin/pages/AuditLog.tsx b/src/admin/pages/AuditLog.tsx index 9269eae..6ff410b 100644 --- a/src/admin/pages/AuditLog.tsx +++ b/src/admin/pages/AuditLog.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery, keepPreviousData } from "@tanstack/react-query"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import { useAuth } from "../context/AuthContext"; @@ -128,7 +128,11 @@ export default function AuditLog() { // cleanupDays stored as string for the kit Select; converted to number at the boundary const [cleanupDaysStr, setCleanupDaysStr] = useState("90"); - const { data: logsData, isPending } = useQuery({ + const { + data: logsData, + isPending, + isFetching, + } = useQuery({ queryKey: [ "audit-log", { @@ -169,6 +173,10 @@ export default function AuditLog() { }, }; }, + // Keep the current rows on screen while a filter refetches, so the page + // doesn't drop to (which unmounts PageEnter and replays the + // whole entrance animation on every filter change). + placeholderData: keepPreviousData, }); const logs: AuditLogEntry[] = logsData?.data ?? []; @@ -352,7 +360,7 @@ export default function AuditLog() { - + columns={columns} rows={logs}