From fda52666d60ece2f980f91b838413792c253f0c2 Mon Sep 17 00:00:00 2001 From: Oliver Kieselbach Date: Wed, 12 Aug 2026 17:19:52 +0200 Subject: [PATCH] web: clear set-state-in-effect lint warning on the annotations page The annotations overview pushed the ESLint warning count to 100, one over the frozen --max-warnings 99 cap, failing CI since 66d25f57's run. The react-hooks/set-state-in-effect rule flags any direct effect call into a state-setting useCallback, even with every setState behind an await. Restructure instead of suppressing: loading/error begin-state moves from fetchPage into the interaction sites (filter selects, load-more; mount is covered by the initial state), and the effect invokes fetchPage through an inner async wrapper so no setState is synchronously reachable. Lint is back to exactly 99. Co-Authored-By: Claude Fable 5 --- .../app/annotations/page.tsx | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/Web/autopilot-monitor-web/app/annotations/page.tsx b/src/Web/autopilot-monitor-web/app/annotations/page.tsx index faa7734e..5e119927 100644 --- a/src/Web/autopilot-monitor-web/app/annotations/page.tsx +++ b/src/Web/autopilot-monitor-web/app/annotations/page.tsx @@ -55,10 +55,11 @@ export default function AnnotationsPage() { const lanes = visibleLanes(user); + // Callers must set loading=true / loadError=null before invoking (the initial + // state covers the mount fetch) — no synchronous setState here, this runs + // inside the effect below. const fetchPage = useCallback( async (url: string, append: boolean) => { - setLoading(true); - setLoadError(null); try { const res = await authenticatedFetch(url, getAccessToken); if (res.status === 404) { @@ -83,13 +84,18 @@ export default function AnnotationsPage() { ); useEffect(() => { - fetchPage( - api.annotations.list({ - verdict: verdictFilter || undefined, - lane: laneFilter || undefined, - }), - false - ); + // Inner async wrapper: set-state-in-effect flags a direct call to a + // state-setting callback even when every setState sits behind an await. + const loadFirstPage = async () => { + await fetchPage( + api.annotations.list({ + verdict: verdictFilter || undefined, + lane: laneFilter || undefined, + }), + false + ); + }; + void loadFirstPage(); }, [fetchPage, verdictFilter, laneFilter]); return ( @@ -109,7 +115,11 @@ export default function AnnotationsPage() {