RoomListViewModel: Support primary filters in the view model (#29454)

* Track available filters and expose this info from the vm

- Adds a separate hook that tracks the filtered rooms and the available
  filters.
- When secondary filters are added, some of the primary filters will be
  selectively hidden. So track this info in the vm.

* Write tests

* Fix typescript error

* Fix translation

* Explain what a primary filter is
This commit is contained in:
R Midhun Suresh
2025-03-10 18:53:38 +05:30
committed by GitHub
parent af476905b6
commit fd91e78152
4 changed files with 145 additions and 14 deletions

View File

@@ -14,16 +14,19 @@ import { LISTS_UPDATE_EVENT } from "../../../../../src/stores/room-list/SlidingR
import { useRoomListViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import dispatcher from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions";
import { FilterKey } from "../../../../../src/stores/room-list-v3/skip-list/filters";
describe("RoomListViewModel", () => {
function mockAndCreateRooms() {
const rooms = range(10).map((i) => mkStubRoom(`foo${i}:matrix.org`, `Foo ${i}`, undefined));
jest.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace").mockImplementation(() => [...rooms]);
return rooms;
const fn = jest
.spyOn(RoomListStoreV3.instance, "getSortedRoomsInActiveSpace")
.mockImplementation(() => [...rooms]);
return { rooms, fn };
}
it("should return a list of rooms", async () => {
const rooms = mockAndCreateRooms();
const { rooms } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
expect(vm.current.rooms).toHaveLength(10);
@@ -33,7 +36,7 @@ describe("RoomListViewModel", () => {
});
it("should update list of rooms on event from room list store", async () => {
const rooms = mockAndCreateRooms();
const { rooms } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
const newRoom = mkStubRoom("bar:matrix.org", "Bar", undefined);
@@ -46,7 +49,7 @@ describe("RoomListViewModel", () => {
});
it("should dispatch view room action on openRoom", async () => {
const rooms = mockAndCreateRooms();
const { rooms } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
const fn = jest.spyOn(dispatcher, "dispatch");
@@ -59,4 +62,50 @@ describe("RoomListViewModel", () => {
}),
);
});
describe("Filters", () => {
it("should provide list of available filters", () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// should have 4 filters
expect(vm.current.primaryFilters).toHaveLength(4);
// check the order
for (const [i, name] of ["Unread", "Favourites", "People", "Rooms"].entries()) {
expect(vm.current.primaryFilters[i].name).toEqual(name);
expect(vm.current.primaryFilters[i].active).toEqual(false);
}
});
it("should get filtered rooms from RLS on toggle", () => {
const { fn } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Let's say we toggle the People toggle
const i = vm.current.primaryFilters.findIndex((f) => f.name === "People");
act(() => {
vm.current.primaryFilters[i].toggle();
});
expect(fn).toHaveBeenCalledWith([FilterKey.PeopleFilter]);
expect(vm.current.primaryFilters[i].active).toEqual(true);
});
it("should change active property on toggle", () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Let's say we toggle the People filter
const i = vm.current.primaryFilters.findIndex((f) => f.name === "People");
expect(vm.current.primaryFilters[i].active).toEqual(false);
act(() => {
vm.current.primaryFilters[i].toggle();
});
expect(vm.current.primaryFilters[i].active).toEqual(true);
// Let's say that we toggle the Favourite filter
const j = vm.current.primaryFilters.findIndex((f) => f.name === "Favourites");
act(() => {
vm.current.primaryFilters[j].toggle();
});
expect(vm.current.primaryFilters[i].active).toEqual(false);
expect(vm.current.primaryFilters[j].active).toEqual(true);
});
});
});

View File

@@ -27,7 +27,7 @@ describe("<RoomList />", () => {
matrixClient = stubClient();
const rooms = Array.from({ length: 10 }, (_, i) => mkRoom(matrixClient, `room${i}`));
vm = { rooms, openRoom: jest.fn() };
vm = { rooms, openRoom: jest.fn(), primaryFilters: [] };
// Needed to render a room list cell
DMRoomMap.makeShared(matrixClient);