From f65a53a174d5362d54dc4f2c06afef1985ebe1a5 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 4 Jun 2026 16:40:56 +0200 Subject: [PATCH] Room list: hide empty section when a filter is enabled (#33747) * fix: hide empty section when a filter is enabled * test: add unit tests --- .../stores/room-list-v3/RoomListStoreV3.ts | 16 ++++---- .../room-list-v3/RoomListStoreV3-test.ts | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/apps/web/src/stores/room-list-v3/RoomListStoreV3.ts b/apps/web/src/stores/room-list-v3/RoomListStoreV3.ts index 7004efc090..a85e5cd28e 100644 --- a/apps/web/src/stores/room-list-v3/RoomListStoreV3.ts +++ b/apps/web/src/stores/room-list-v3/RoomListStoreV3.ts @@ -459,14 +459,16 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient { * @returns An array of sections */ private getSections(filterKeys?: FilterKey[]): Section[] { - return this.sortedTags.map((tag) => { - const filters = filterBoolean([this.filterByTag.get(tag)?.key, ...(filterKeys || [])]); + return this.sortedTags + .map((tag) => { + const filters = filterBoolean([this.filterByTag.get(tag)?.key, ...(filterKeys ?? [])]); - return { - tag, - rooms: Array.from(this.roomSkipList?.getRoomsInActiveSpace(filters) || []), - }; - }); + return { + tag, + rooms: Array.from(this.roomSkipList?.getRoomsInActiveSpace(filters) || []), + }; + }) + .filter((section) => !filterKeys || section.rooms.length > 0); } /** diff --git a/apps/web/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts b/apps/web/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts index adc53d7477..4ca1a710f0 100644 --- a/apps/web/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts +++ b/apps/web/test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts @@ -976,6 +976,45 @@ describe("RoomListStoreV3", () => { expect(favSection.rooms).toContain(rooms[7]); }); + it("hides empty sections when filters are applied", async () => { + enableSections(); + const { rooms } = getClientAndRooms(); + + // Mark room 3 as favourite; it's the only unread room + rooms[3].tags[DefaultTagID.Favourite] = {}; + jest.spyOn(RoomNotificationStateStore.instance, "getRoomState").mockImplementation((room) => { + const state = { + hasUnreadCount: room === rooms[3], + } as unknown as RoomNotificationState; + return state; + }); + + const store = new RoomListStoreV3Class(dispatcher); + await store.start(); + + // With the unread filter, only the Favourite section has matching rooms. + // The Chats and LowPriority sections should be hidden because they're empty. + const { sections } = store.getSortedRoomsInActiveSpace([FilterEnum.UnreadFilter]); + expect(sections).toHaveLength(1); + expect(sections[0].tag).toBe(DefaultTagID.Favourite); + expect(sections[0].rooms).toContain(rooms[3]); + }); + + it("shows empty sections when no filters are applied", async () => { + enableSections(); + getClientAndRooms(); + + // No rooms are tagged, so Favourite and LowPriority sections will be empty + const store = new RoomListStoreV3Class(dispatcher); + await store.start(); + + const { sections } = store.getSortedRoomsInActiveSpace(); + // All three sections should be present even though Favourite/LowPriority are empty + expect(sections).toHaveLength(3); + expect(findSection(sections, DefaultTagID.Favourite)!.rooms).toHaveLength(0); + expect(findSection(sections, DefaultTagID.LowPriority)!.rooms).toHaveLength(0); + }); + it("sections respect space filtering", async () => { enableSections(); const { rooms } = getClientAndRooms();