Fix HistoryPage stale appliedQuery effect and add mount query regression test

This commit is contained in:
2026-04-19 19:36:44 +02:00
parent 5446f6c3e1
commit 76c9f388a8
3 changed files with 26 additions and 7 deletions

View File

@@ -37,7 +37,7 @@ Issues are grouped by category and ordered roughly by severity. Each entry descr
--- ---
### TASK-002 — `HistoryPage` filter effect has a stale `appliedQuery` dependency ### TASK-002 — `HistoryPage` filter effect has a stale `appliedQuery` dependency (done)
**Where found:** `frontend/src/pages/HistoryPage.tsx` lines 214230. The `useEffect` lists `appliedQuery` as a dependency, reads it inside the effect, and then calls `setAppliedQuery` — which triggers the same effect again immediately. **Where found:** `frontend/src/pages/HistoryPage.tsx` lines 214230. The `useEffect` lists `appliedQuery` as a dependency, reads it inside the effect, and then calls `setAppliedQuery` — which triggers the same effect again immediately.

View File

@@ -6,7 +6,7 @@
* Rows with repeatedly-banned IPs are highlighted in amber. * Rows with repeatedly-banned IPs are highlighted in amber.
*/ */
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { import {
Badge, Badge,
Button, Button,
@@ -199,10 +199,14 @@ export function HistoryPage(): React.JSX.Element {
const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all"); const [originFilter, setOriginFilter] = useState<BanOriginFilter>("all");
const [jailFilter, setJailFilter] = useState(""); const [jailFilter, setJailFilter] = useState("");
const [ipFilter, setIpFilter] = useState(""); const [ipFilter, setIpFilter] = useState("");
const [appliedQuery, setAppliedQuery] = useState<HistoryQuery>({ const defaultQuery: HistoryQuery = {
range: "7d",
source: "archive", source: "archive",
page_size: PAGE_SIZE, page_size: PAGE_SIZE,
}); page: 1,
};
const [appliedQuery, setAppliedQuery] = useState<HistoryQuery>(defaultQuery);
const appliedQueryRef = useRef<HistoryQuery>(defaultQuery);
// Per-IP detail navigation // Per-IP detail navigation
const [selectedIp, setSelectedIp] = useState<string | null>(null); const [selectedIp, setSelectedIp] = useState<string | null>(null);
@@ -221,13 +225,14 @@ export function HistoryPage(): React.JSX.Element {
page_size: PAGE_SIZE, page_size: PAGE_SIZE,
}; };
if (areHistoryQueriesEqual(nextQuery, appliedQuery)) { if (areHistoryQueriesEqual(nextQuery, appliedQueryRef.current)) {
return; return;
} }
setPage(1); setPage(1);
setAppliedQuery(nextQuery); setAppliedQuery(nextQuery);
}, [range, originFilter, jailFilter, ipFilter, setPage, appliedQuery]); appliedQueryRef.current = nextQuery;
}, [range, originFilter, jailFilter, ipFilter, setPage]);
const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE)); const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));

View File

@@ -28,7 +28,7 @@ vi.mock("../../components/WorldMap", () => ({
})); }));
vi.mock("../../api/config", () => ({ vi.mock("../../api/config", () => ({
fetchMapColorThresholds: async () => ({ fetchMapColorThresholds: () => ({
threshold_low: 10, threshold_low: 10,
threshold_medium: 50, threshold_medium: 50,
threshold_high: 100, threshold_high: 100,
@@ -74,4 +74,18 @@ describe("HistoryPage", () => {
expect(lastQuery).toMatchObject({ origin: "blocklist" }); expect(lastQuery).toMatchObject({ origin: "blocklist" });
}); });
}); });
it("never calls history without the default range on mount", async () => {
render(
<FluentProvider theme={webLightTheme}>
<HistoryPage />
</FluentProvider>,
);
await waitFor(() => {
expect(lastQuery?.range).toBe("7d");
});
expect(mockUseHistory.mock.calls.every((call) => call[0].range === "7d")).toBe(true);
});
}); });