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() {