Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/stores/room-list-v3/RoomListStoreV3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,22 @@ import { FavouriteFilter } from "./skip-list/filters/FavouriteFilter";
import { UnreadFilter } from "./skip-list/filters/UnreadFilter";
import { PeopleFilter } from "./skip-list/filters/PeopleFilter";
import { RoomsFilter } from "./skip-list/filters/RoomsFilter";
import { InvitesFilter } from "./skip-list/filters/InvitesFilter";
import { MentionsFilter } from "./skip-list/filters/MentionsFilter";
import { LowPriorityFilter } from "./skip-list/filters/LowPriorityFilter";

/**
* These are the filters passed to the room skip list.
*/
const FILTERS = [new FavouriteFilter(), new UnreadFilter(), new PeopleFilter(), new RoomsFilter()];
const FILTERS = [
new FavouriteFilter(),
new UnreadFilter(),
new PeopleFilter(),
new RoomsFilter(),
new InvitesFilter(),
new MentionsFilter(),
new LowPriorityFilter(),
];

/**
* This store allows for fast retrieval of the room list in a sorted and filtered manner.
Expand Down
20 changes: 20 additions & 0 deletions src/stores/room-list-v3/skip-list/filters/InvitesFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
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 Room, KnownMembership } from "matrix-js-sdk/src/matrix";

import type { Filter } from ".";
import { FilterKey } from ".";

export class InvitesFilter implements Filter {
public matches(room: Room): boolean {
return room.getMyMembership() === KnownMembership.Invite;
}

public get key(): FilterKey.InvitesFilter {
return FilterKey.InvitesFilter;
}
}
20 changes: 20 additions & 0 deletions src/stores/room-list-v3/skip-list/filters/LowPriorityFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
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 { Room } from "matrix-js-sdk/src/matrix";
import type { Filter } from ".";
import { FilterKey } from ".";
import { DefaultTagID } from "../../../room-list/models";

export class LowPriorityFilter implements Filter {
public matches(room: Room): boolean {
return !!room.tags[DefaultTagID.LowPriority];
}

public get key(): FilterKey.LowPriorityFilter {
return FilterKey.LowPriorityFilter;
}
}
20 changes: 20 additions & 0 deletions src/stores/room-list-v3/skip-list/filters/MentionsFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
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 { Room } from "matrix-js-sdk/src/matrix";
import type { Filter } from ".";
import { FilterKey } from ".";
import { RoomNotificationStateStore } from "../../../notifications/RoomNotificationStateStore";

export class MentionsFilter implements Filter {
public matches(room: Room): boolean {
return RoomNotificationStateStore.instance.getRoomState(room).hasMentions;
}

public get key(): FilterKey.MentionsFilter {
return FilterKey.MentionsFilter;
}
}
3 changes: 3 additions & 0 deletions src/stores/room-list-v3/skip-list/filters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export const enum FilterKey {
UnreadFilter,
PeopleFilter,
RoomsFilter,
LowPriorityFilter,
MentionsFilter,
InvitesFilter,
}

export interface Filter {
Expand Down
71 changes: 71 additions & 0 deletions test/unit-tests/stores/room-list-v3/RoomListStoreV3-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,77 @@ describe("RoomListStoreV3", () => {
}
});

it("supports filtering invited rooms", async () => {
const { client, rooms } = getClientAndRooms();

// Let's add 5 rooms that we are invited to
const invitedRooms = getMockedRooms(client, 5);
for (const room of invitedRooms) {
room.getMyMembership = jest.fn().mockReturnValue(KnownMembership.Invite);
}

rooms.push(...invitedRooms);

// Let's choose 5 rooms to put in space
const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 100, 101, 102, 103, 104], client);
setupMocks(spaceRoom, roomIds);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();

const result = store.getSortedRoomsInActiveSpace([FilterKey.InvitesFilter]);
expect(result).toHaveLength(5);
for (const room of invitedRooms) {
expect(result).toContain(room);
}
});

it("supports filtering by mentions", async () => {
const { client, rooms } = getClientAndRooms();
// Let's choose 5 rooms to put in space
const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 13, 27, 75], client);

// Let's say 8, 27 have mentions
jest.spyOn(RoomNotificationStateStore.instance, "getRoomState").mockImplementation((room) => {
const state = {
hasMentions: [rooms[8], rooms[27]].includes(room),
} as unknown as RoomNotificationState;
return state;
});

setupMocks(spaceRoom, roomIds);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();

// Should only give us rooms at index 8 and 27
const result = store.getSortedRoomsInActiveSpace([FilterKey.MentionsFilter]);
expect(result).toHaveLength(2);
for (const i of [8, 27]) {
expect(result).toContain(rooms[i]);
}
});

it("supports filtering low priority rooms", async () => {
const { client, rooms } = getClientAndRooms();
// Let's choose 5 rooms to put in space
const { spaceRoom, roomIds } = createSpace(rooms, [6, 8, 13, 27, 75], client);

// Let's say that 8, 27 an 75 are low priority rooms
[8, 27, 75].forEach((i) => {
rooms[i].tags[DefaultTagID.LowPriority] = {};
});

setupMocks(spaceRoom, roomIds);
const store = new RoomListStoreV3Class(dispatcher);
await store.start();

// Sorted, filtered rooms should be 8, 27 and 75
const result = store.getSortedRoomsInActiveSpace([FilterKey.LowPriorityFilter]);
expect(result).toHaveLength(3);
for (const i of [8, 27, 75]) {
expect(result).toContain(rooms[i]);
}
});

it("supports multiple filters", async () => {
const { client, rooms } = getClientAndRooms();
// Let's choose 5 rooms to put in space
Expand Down