fix(documents): cancel a layout read in flight before flipping the switch

A first read of the vault layout that was still running when the switch
was flipped landed afterwards and painted the old layout until the save
answered, so the switch jumped back for a moment.
This commit is contained in:
Marc-André Bombeck committed 2026-10-08 22:57:47 +02:00
1 parent 7525d2ed00
commit dd76b434c4
2 files changed
+42

No files matched your search

@@ -72,6 +72,41 @@ describe("runSetDocumentsLayout", () => {
await run;
});
it("is not undone by a first read still in flight", async () => {
const queryClient = new QueryClient();
let answerRead: (value: DocumentsLayout) => void = () => {};
const read = queryClient
.fetchQuery({
queryKey: key,
queryFn: () =>
new Promise<DocumentsLayout>((resolve) => {
answerRead = resolve;
}),
})
.catch(() => undefined);
let settle: (value: DocumentsLayout) => void = () => {};
vi.mocked(apiPut).mockReturnValue(
new Promise<DocumentsLayout>((resolve) => {
settle = resolve;
}),
);
const run = runSetDocumentsLayout({
patch: { view: "list" },
queryClient,
t,
});
// The read answers with the stored layout while the save is pending.
answerRead(STORED);
await read;
await new Promise((resolve) => setTimeout(resolve, 0));
expect(queryClient.getQueryData<DocumentsLayout>(key)?.view).toBe("list");
settle({ ...STORED, view: "list" });
await run;
expect(queryClient.getQueryData<DocumentsLayout>(key)?.view).toBe("list");
});
it("rolls back and says so when the save fails", async () => {
const queryClient = new QueryClient();
queryClient.setQueryData(key, STORED);
+7
View File
@@ -40,6 +40,13 @@ export async function runSetDocumentsLayout(deps: {
}): Promise<void> {
const { patch, queryClient, t } = deps;
const key = queryKeys.documentsLayout();
// A read still in flight (the first GET) would land after the flip and
// paint the old layout until the PUT answered. Cancel it first; only then
// is the flip safe, because a cancelled fetch reverts the cache as it
// settles. Without one in flight the flip stays synchronous.
if (queryClient.isFetching({ queryKey: key }) > 0) {
await queryClient.cancelQueries({ queryKey: key });
}
const previous = queryClient.getQueryData<DocumentsLayout>(key);
queryClient.setQueryData<DocumentsLayout>(key, {
...(previous ?? DEFAULT_DOCUMENTS_LAYOUT),