diff --git a/apps/client/src/features/page/queries/invalidate-on-update-page.test.ts b/apps/client/src/features/page/queries/invalidate-on-update-page.test.ts index 38b7f883..b2d0fa7a 100644 --- a/apps/client/src/features/page/queries/invalidate-on-update-page.test.ts +++ b/apps/client/src/features/page/queries/invalidate-on-update-page.test.ts @@ -75,6 +75,65 @@ describe("invalidateOnUpdatePage — pointwise embed-cache patch", () => { expect(p1.title).toBe("Keep"); }); + // The sidebar-pages cache (InfiniteData) is patched on the same event. It must + // carry the SAME undefined-guard as the embed path above — otherwise a + // title-only event's icon:undefined would wipe the sidebar entry's icon. + const sidebarKey = ["sidebar-pages", { pageId: "parent-1", spaceId: "s1" }]; + const seedSidebar = () => + h.qc.setQueryData(sidebarKey, { + pageParams: [undefined], + pages: [ + { + items: [ + { id: "p1", title: "Old", icon: "📄", spaceId: "s1" } as IPage, + { id: "p2", title: "Other", icon: "📁", spaceId: "s1" } as IPage, + ], + }, + ], + }); + const sidebarItem = (id: string) => { + const data = h.qc.getQueryData(sidebarKey) as { + pages: { items: IPage[] }[]; + }; + return data.pages[0].items.find((p) => p.id === id)!; + }; + + it("sidebar cache: title-only event updates title but PRESERVES the icon", () => { + seedSidebar(); + + invalidateOnUpdatePage( + "s1", + "parent-1", + "p1", + "New Title", + undefined as unknown as string, + ); + + const p1 = sidebarItem("p1"); + expect(p1.title).toBe("New Title"); + expect(p1.icon).toBe("📄"); // preserved, not wiped + // Sibling untouched. + const p2 = sidebarItem("p2"); + expect(p2.title).toBe("Other"); + expect(p2.icon).toBe("📁"); + }); + + it("sidebar cache: icon-only event updates icon but PRESERVES the title", () => { + seedSidebar(); + + invalidateOnUpdatePage( + "s1", + "parent-1", + "p1", + undefined as unknown as string, + "🚀", + ); + + const p1 = sidebarItem("p1"); + expect(p1.icon).toBe("🚀"); + expect(p1.title).toBe("Old"); // preserved, not wiped + }); + it("does not touch a subtree that lacks the updated node", () => { const otherKey = ["page-tree", "unrelated"]; const before = [ diff --git a/apps/client/src/features/page/queries/page-query.ts b/apps/client/src/features/page/queries/page-query.ts index 525070b8..4d43ab2b 100644 --- a/apps/client/src/features/page/queries/page-query.ts +++ b/apps/client/src/features/page/queries/page-query.ts @@ -636,7 +636,14 @@ export function invalidateOnUpdatePage( ...page, items: page.items.map((sidebarPage: IPage) => sidebarPage.id === id - ? { ...sidebarPage, title: title, icon: icon } + ? { + ...sidebarPage, + // Guard undefined so a title-only event can't wipe the icon + // (and vice versa) in the sidebar-pages cache — mirrors the + // embed-cache patch above. + ...(title !== undefined ? { title } : {}), + ...(icon !== undefined ? { icon } : {}), + } : sidebarPage, ), })),