Room list: remove usage of old room list store in LoggedInView & InviteDialog (#33973)

* feat: add functions to dm and server notice in rls

* feat: use these functions in dialogs to get rid of old rls
This commit is contained in:
Florian Duros
2026-06-29 11:46:14 +00:00
committed by GitHub
parent 4462d6914c
commit 526b4b8c33
4 changed files with 133 additions and 12 deletions
@@ -34,12 +34,11 @@ import { SettingLevel } from "../../settings/SettingLevel";
import ResizeHandle from "../views/elements/ResizeHandle";
import { CollapseDistributor, Resizer } from "../../resizer";
import PlatformPeg from "../../PlatformPeg";
import { DefaultTagID } from "../../stores/room-list-v3/skip-list/tag";
import { hideToast as hideServerLimitToast, showToast as showServerLimitToast } from "../../toasts/ServerLimitToast";
import { Action } from "../../dispatcher/actions";
import LeftPanel from "./LeftPanel";
import { type ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload";
import RoomListStore from "../../stores/room-list/RoomListStore";
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
import NonUrgentToastContainer from "./NonUrgentToastContainer";
import { type IOOBData, type IThreepidInvite } from "../../stores/ThreepidInviteStore";
import Modal from "../../Modal";
@@ -389,8 +388,8 @@ class LoggedInView extends React.Component<IProps, IState> {
};
private onRoomStateEvents = (ev: MatrixEvent): void => {
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
if (serverNoticeList?.some((r) => r.roomId === ev.getRoomId())) {
const serverNoticeList = RoomListStoreV3.instance.getServerNoticeRooms();
if (serverNoticeList.some((r) => r.roomId === ev.getRoomId())) {
this.updateServerNoticeEvents();
}
};
@@ -422,8 +421,8 @@ class LoggedInView extends React.Component<IProps, IState> {
}
private updateServerNoticeEvents = async (): Promise<void> => {
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
if (!serverNoticeList) return;
const serverNoticeList = RoomListStoreV3.instance.getServerNoticeRooms();
if (!serverNoticeList.length) return;
const events: MatrixEvent[] = [];
let pinnedEventTs = 0;
@@ -26,8 +26,7 @@ import { abbreviateUrl } from "../../../utils/UrlUtils";
import IdentityAuthClient from "../../../IdentityAuthClient";
import { showAnyInviteErrors } from "../../../RoomInvite";
import { Action } from "../../../dispatcher/actions";
import { DefaultTagID } from "../../../stores/room-list-v3/skip-list/tag";
import RoomListStore from "../../../stores/room-list/RoomListStore";
import RoomListStoreV3 from "../../../stores/room-list-v3/RoomListStoreV3";
import SettingsStore from "../../../settings/SettingsStore";
import { UIFeature } from "../../../settings/UIFeature";
import { SearchResultAvatar } from "../avatars/SearchResultAvatar";
@@ -279,9 +278,9 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
public static buildRecents(excludedTargetIds: Set<string>): Result[] {
const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room
// Also pull in all the rooms tagged as DefaultTagID.DM so we don't miss anything. Sometimes the
// room list doesn't tag the room for the DMRoomMap, but does for the room list.
const dmTaggedRooms = RoomListStore.instance.orderedLists[DefaultTagID.DM] || [];
// Also pull in all the rooms that the room list tags as DMs so we don't miss anything: sometimes
// a room is absent from getUniqueRoomsWithIndividuals() above but is still tagged as a DM.
const dmTaggedRooms = RoomListStoreV3.instance.getDmRooms();
const myUserId = MatrixClientPeg.safeGet().getUserId();
for (const dmRoom of dmTaggedRooms) {
const otherMembers = dmRoom.getJoinedMembers().filter((u) => u.userId !== myUserId);
@@ -36,6 +36,7 @@ import { UnreadSorter } from "./skip-list/sorters/UnreadSorter";
import { getChangedOverrideRoomMutePushRules } from "./utils";
import { isRoomVisible } from "./isRoomVisible";
import { RoomSkipList } from "./skip-list/RoomSkipList";
import { getTagsForRoom } from "../../utils/room/getTagsForRoom";
import { ExcludeTagsFilter } from "./skip-list/filters/ExcludeTagsFilter";
import { TagFilter } from "./skip-list/filters/TagFilter";
import { filterBoolean } from "../../utils/arrays";
@@ -47,7 +48,7 @@ import {
getOrderedReorderableSections,
reorderSection,
} from "./section";
import { DefaultTagID } from "./skip-list/tag";
import { DefaultTagID, type TagID } from "./skip-list/tag";
/**
* These are the filters passed to the room skip list.
@@ -184,6 +185,30 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
};
}
/**
* Get the rooms in the currently active space that are tagged with the given tag.
* @param tag The tag to filter the rooms by.
*/
private getRoomsWithTagInActiveSpace(tag: TagID): Room[] {
return this.getSortedRoomsInActiveSpace()
.sections.flatMap((s) => s.rooms)
.filter((room) => getTagsForRoom(room).includes(tag));
}
/**
* Get the server notice rooms in the currently active space.
*/
public getServerNoticeRooms(): Room[] {
return this.getRoomsWithTagInActiveSpace(DefaultTagID.ServerNotice);
}
/**
* Get the direct message (DM) rooms in the currently active space.
*/
public getDmRooms(): Room[] {
return this.getRoomsWithTagInActiveSpace(DefaultTagID.DM);
}
/**
* Resort the list of rooms using a different algorithm.
* @param algorithm The sorting algorithm to use.
@@ -826,6 +826,104 @@ describe("RoomListStoreV3", () => {
).toContain(room);
});
});
describe("getServerNoticeRooms", () => {
it("returns only rooms tagged as server notice", async () => {
const { rooms } = getClientAndRooms();
// Tag rooms 8 and 27 as server notice rooms
[8, 27].forEach((i) => (rooms[i].tags[DefaultTagID.ServerNotice] = {}));
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
const result = store.getServerNoticeRooms();
expect(result).toHaveLength(2);
for (const i of [8, 27]) {
expect(result).toContain(rooms[i]);
}
});
it("returns an empty array when there are no server notice rooms", async () => {
getClientAndRooms();
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
expect(store.getServerNoticeRooms()).toEqual([]);
});
it("only returns rooms that belong to the active space", async () => {
const { client, rooms } = getClientAndRooms();
// Put rooms 6, 8, 13, 27, 75 into a space
const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 13, 27, 75], client);
// Room 8 (in the space) and room 50 (in Home only) are both server notices
rooms[8].tags[DefaultTagID.ServerNotice] = {};
rooms[50].tags[DefaultTagID.ServerNotice] = {};
// Activate the space
setupMocks(spaceRoom, roomIds);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
// Only the server notice room within the active space is returned
const result = store.getServerNoticeRooms();
expect(result).toEqual([rooms[8]]);
});
});
describe("getDmRooms", () => {
it("returns only rooms tagged as DM", async () => {
const { rooms } = getClientAndRooms();
// Rooms 8 and 27 are DMs (no explicit tags + present in the DM map)
const ids = [8, 27].map((i) => rooms[i].roomId);
jest.spyOn(DMRoomMap, "shared").mockImplementation((() => {
return {
getUserIdForRoomId: (id: string) => (ids.includes(id) ? "@myuser:matrix.org" : ""),
};
}) as () => DMRoomMap);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
const result = store.getDmRooms();
expect(result).toHaveLength(2);
for (const i of [8, 27]) {
expect(result).toContain(rooms[i]);
}
});
it("returns an empty array when there are no DM rooms", async () => {
// The top-level beforeEach mocks the DM map to match no rooms.
getClientAndRooms();
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
expect(store.getDmRooms()).toEqual([]);
});
it("only returns rooms that belong to the active space", async () => {
const { client, rooms } = getClientAndRooms();
// Put rooms 6, 8, 13, 27, 75 into a space
const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 13, 27, 75], client);
// Room 8 (in the space) and room 50 (in Home only) are both DMs
const ids = [rooms[8].roomId, rooms[50].roomId];
jest.spyOn(DMRoomMap, "shared").mockImplementation((() => {
return {
getUserIdForRoomId: (id: string) => (ids.includes(id) ? "@myuser:matrix.org" : ""),
};
}) as () => DMRoomMap);
// Activate the space
setupMocks(spaceRoom, roomIds);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();
// Only the DM room within the active space is returned
const result = store.getDmRooms();
expect(result).toEqual([rooms[8]]);
});
});
});
describe("Sections", () => {