Room List - Implement a minimal view model (#29357)

* Implement enough of the new store to get a list of rooms

* Make it possible to swap sorting algorithm

* Don't attach to window object

We don't want the store to be created if the labs flag is off

* Remove the store class

Probably best to include this PR with the minimal vm implmentation

* Create a new room list store that wraps around the skip list

* Create a minimal view model

* Fix CI

* Add some basic tests for the store

* Write more tests

* Add some jsdoc comments

* Add more documentation

* Add more docs
This commit is contained in:
R Midhun Suresh
2025-03-03 16:42:00 +05:30
committed by GitHub
parent 3c57323595
commit 2da21248bb
7 changed files with 274 additions and 14 deletions

View File

@@ -0,0 +1,53 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { MatrixDispatcher } from "../../../../src/dispatcher/dispatcher";
import { RoomListStoreV3Class } from "../../../../src/stores/room-list-v3/RoomListStoreV3";
import { AsyncStoreWithClient } from "../../../../src/stores/AsyncStoreWithClient";
import { RecencySorter } from "../../../../src/stores/room-list-v3/skip-list/sorters/RecencySorter";
import { stubClient } from "../../../test-utils";
import { getMockedRooms } from "./skip-list/getMockedRooms";
import { AlphabeticSorter } from "../../../../src/stores/room-list-v3/skip-list/sorters/AlphabeticSorter";
describe("RoomListStoreV3", () => {
async function getRoomListStore() {
const client = stubClient();
const rooms = getMockedRooms(client);
client.getVisibleRooms = jest.fn().mockReturnValue(rooms);
jest.spyOn(AsyncStoreWithClient.prototype, "matrixClient", "get").mockReturnValue(client);
const fakeDispatcher = { register: jest.fn() } as unknown as MatrixDispatcher;
const store = new RoomListStoreV3Class(fakeDispatcher);
store.start();
return { client, rooms, store };
}
it("Provides an unsorted list of rooms", async () => {
const { store, rooms } = await getRoomListStore();
expect(store.getRooms()).toEqual(rooms);
});
it("Provides a sorted list of rooms", async () => {
const { store, rooms, client } = await getRoomListStore();
const sorter = new RecencySorter(client.getSafeUserId());
const sortedRooms = sorter.sort(rooms);
expect(store.getSortedRooms()).toEqual(sortedRooms);
});
it("Provides a way to resort", async () => {
const { store, rooms, client } = await getRoomListStore();
// List is sorted by recency, sort by alphabetical now
store.useAlphabeticSorting();
let sortedRooms = new AlphabeticSorter().sort(rooms);
expect(store.getSortedRooms()).toEqual(sortedRooms);
// Go back to recency sorting
store.useRecencySorting();
sortedRooms = new RecencySorter(client.getSafeUserId()).sort(rooms);
expect(store.getSortedRooms()).toEqual(sortedRooms);
});
});

View File

@@ -7,26 +7,15 @@ Please see LICENSE files in the repository root for full details.
import { shuffle } from "lodash";
import type { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import type { Room } from "matrix-js-sdk/src/matrix";
import type { Sorter } from "../../../../../src/stores/room-list-v3/skip-list/sorters";
import { mkMessage, mkStubRoom, stubClient } from "../../../../test-utils";
import { mkMessage, stubClient } from "../../../../test-utils";
import { RoomSkipList } from "../../../../../src/stores/room-list-v3/skip-list/RoomSkipList";
import { RecencySorter } from "../../../../../src/stores/room-list-v3/skip-list/sorters/RecencySorter";
import { AlphabeticSorter } from "../../../../../src/stores/room-list-v3/skip-list/sorters/AlphabeticSorter";
import { getMockedRooms } from "./getMockedRooms";
describe("RoomSkipList", () => {
function getMockedRooms(client: MatrixClient, roomCount: number = 100): Room[] {
const rooms: Room[] = [];
for (let i = 0; i < roomCount; ++i) {
const roomId = `!foo${i}:matrix.org`;
const room = mkStubRoom(roomId, `Foo Room ${i}`, client);
const event = mkMessage({ room: roomId, user: `@foo${i}:matrix.org`, ts: i + 1, event: true });
room.timeline.push(event);
rooms.push(room);
}
return rooms;
}
function generateSkipList(roomCount?: number): {
skipList: RoomSkipList;
rooms: Room[];

View File

@@ -0,0 +1,21 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { mkMessage, mkStubRoom } from "../../../../test-utils";
export function getMockedRooms(client: MatrixClient, roomCount: number = 100): Room[] {
const rooms: Room[] = [];
for (let i = 0; i < roomCount; ++i) {
const roomId = `!foo${i}:matrix.org`;
const room = mkStubRoom(roomId, `Foo Room ${i}`, client);
const event = mkMessage({ room: roomId, user: `@foo${i}:matrix.org`, ts: i + 1, event: true });
room.timeline.push(event);
rooms.push(room);
}
return rooms;
}