From b7dda91816c2f2a536618bb2793d3c7814451e4e Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sun, 14 Jun 2026 00:22:52 +0000 Subject: [PATCH] fix(mobile-inbox): ignore stale fetches after tab switch (core#2766 / CR2 #11478) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tag each /requests/pending fetch with an incrementing sequence token. - Clear rows immediately when the active kind changes so the user never sees approval cards under the Tasks tab while the new list is loading. - Ignore responses from superseded loads before calling setItems or setLoading(false). - Add regression test: approval fetch in-flight → switch to Tasks → old approval fetch resolves → Task tab stays empty. Fixes #2766 / CR2 #11478 Co-Authored-By: Claude --- canvas/src/components/mobile/MobileInbox.tsx | 28 +++++++-- .../mobile/__tests__/MobileInbox.test.tsx | 57 +++++++++++++++++-- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/canvas/src/components/mobile/MobileInbox.tsx b/canvas/src/components/mobile/MobileInbox.tsx index b25df58bd..7676aea1d 100644 --- a/canvas/src/components/mobile/MobileInbox.tsx +++ b/canvas/src/components/mobile/MobileInbox.tsx @@ -45,13 +45,31 @@ export function MobileInbox({ dark }: { dark: boolean }) { return () => { cancelled = true; }; }, []); + // Guard against stale fetches: when the user switches tabs, a previous + // in-flight fetch for the old kind must not overwrite the list after the + // new tab's load clears it (CR2 #11478). + const loadSeqRef = useRef(0); const load = useCallback(() => { + const seq = ++loadSeqRef.current; + // core#2766 / CR2 #11478: clear stale rows the moment the kind changes + // so the user never sees approval cards under the Tasks tab (or + // vice-versa) while the new list is still fetching. + setItems([]); setLoading(true); api .get(`/requests/pending?kind=${kind}`) - .then((rows) => setItems(Array.isArray(rows) ? rows : [])) - .catch(() => setItems([])) - .finally(() => setLoading(false)); + .then((rows) => { + if (seq !== loadSeqRef.current) return; // stale response + setItems(Array.isArray(rows) ? rows : []); + }) + .catch(() => { + if (seq !== loadSeqRef.current) return; // stale response + setItems([]); + }) + .finally(() => { + if (seq !== loadSeqRef.current) return; // stale response + setLoading(false); + }); }, [kind]); useEffect(() => { load(); }, [load]); @@ -169,7 +187,7 @@ export function MobileInbox({ dark }: { dark: boolean }) {