Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 0453b26

Browse files
kegsayt3chguy
andauthored
Sliding Sync: improve sort order, show subspace rooms, better tombstoned room handling (#9484)
* Add support for include_old_rooms and by_notification_level * Include subspaces when apply spaces filter * Remove stray is_tombstoned * tests: add SlidingRoomListStore jest tests; update proxy version in cypress * Add additional tests * Additional tests * Linting * Update test/stores/room-list/SlidingRoomListStore-test.ts Co-authored-by: Michael Telatynski <[email protected]>
1 parent 097ca43 commit 0453b26

File tree

8 files changed

+418
-43
lines changed

8 files changed

+418
-43
lines changed

cypress/plugins/sliding-sync/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ async function proxyStart(synapse: SynapseInstance): Promise<ProxyInstance> {
7777
const port = await getFreePort();
7878
console.log(new Date(), "starting proxy container...");
7979
const containerId = await dockerRun({
80-
image: "ghcr.io/matrix-org/sliding-sync-proxy:v0.4.0",
80+
image: "ghcr.io/matrix-org/sliding-sync-proxy:v0.6.0",
8181
containerName: "react-sdk-cypress-sliding-sync-proxy",
8282
params: [
8383
"--rm",

src/SlidingSyncManager.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ const DEFAULT_ROOM_SUBSCRIPTION_INFO = {
6363
required_state: [
6464
["*", "*"], // all events
6565
],
66+
include_old_rooms: {
67+
timeline_limit: 0,
68+
required_state: [ // state needed to handle space navigation and tombstone chains
69+
[EventType.RoomCreate, ""],
70+
[EventType.RoomTombstone, ""],
71+
[EventType.SpaceChild, "*"],
72+
[EventType.SpaceParent, "*"],
73+
],
74+
},
6675
};
6776

6877
export type PartialSlidingSyncRequest = {
@@ -121,6 +130,16 @@ export class SlidingSyncManager {
121130
[EventType.SpaceParent, "*"], // all space parents
122131
[EventType.RoomMember, this.client.getUserId()!], // lets the client calculate that we are in fact in the room
123132
],
133+
include_old_rooms: {
134+
timeline_limit: 0,
135+
required_state: [
136+
[EventType.RoomCreate, ""],
137+
[EventType.RoomTombstone, ""], // lets JS SDK hide rooms which are dead
138+
[EventType.SpaceChild, "*"], // all space children
139+
[EventType.SpaceParent, "*"], // all space parents
140+
[EventType.RoomMember, this.client.getUserId()!], // lets the client calculate that we are in fact in the room
141+
],
142+
},
124143
filters: {
125144
room_types: ["m.space"],
126145
},
@@ -176,7 +195,7 @@ export class SlidingSyncManager {
176195
list = {
177196
ranges: [[0, 20]],
178197
sort: [
179-
"by_highlight_count", "by_notification_count", "by_recency",
198+
"by_notification_level", "by_recency",
180199
],
181200
timeline_limit: 1, // most recent message display: though this seems to only be needed for favourites?
182201
required_state: [
@@ -187,6 +206,16 @@ export class SlidingSyncManager {
187206
[EventType.RoomCreate, ""], // for isSpaceRoom checks
188207
[EventType.RoomMember, this.client.getUserId()], // lets the client calculate that we are in fact in the room
189208
],
209+
include_old_rooms: {
210+
timeline_limit: 0,
211+
required_state: [
212+
[EventType.RoomCreate, ""],
213+
[EventType.RoomTombstone, ""], // lets JS SDK hide rooms which are dead
214+
[EventType.SpaceChild, "*"], // all space children
215+
[EventType.SpaceParent, "*"], // all space parents
216+
[EventType.RoomMember, this.client.getUserId()!], // lets the client calculate that we are in fact in the room
217+
],
218+
},
190219
};
191220
list = Object.assign(list, updateArgs);
192221
} else {

src/components/views/rooms/RoomSublist.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
570570
const slidingList = SlidingSyncManager.instance.slidingSync.getList(slidingSyncIndex);
571571
isAlphabetical = slidingList.sort[0] === "by_name";
572572
isUnreadFirst = (
573-
slidingList.sort[0] === "by_highlight_count" ||
574-
slidingList.sort[0] === "by_notification_count"
573+
slidingList.sort[0] === "by_notification_level"
575574
);
576575
}
577576

src/hooks/useSlidingSyncRoomSearch.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export const useSlidingSyncRoomSearch = () => {
5252
ranges: [[0, limit]],
5353
filters: {
5454
room_name_like: term,
55-
is_tombstoned: false,
5655
},
5756
});
5857
const rooms = [];

src/stores/room-list/RoomListStore.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import SettingsStore from "../../settings/SettingsStore";
2424
import { DefaultTagID, OrderedDefaultTagIDs, RoomUpdateCause, TagID } from "./models";
2525
import { IListOrderingMap, ITagMap, ITagSortingMap, ListAlgorithm, SortAlgorithm } from "./algorithms/models";
2626
import { ActionPayload } from "../../dispatcher/payloads";
27-
import defaultDispatcher from "../../dispatcher/dispatcher";
27+
import defaultDispatcher, { MatrixDispatcher } from "../../dispatcher/dispatcher";
2828
import { readReceiptChangeIsFor } from "../../utils/read-receipts";
2929
import { FILTER_CHANGED, IFilterCondition } from "./filters/IFilterCondition";
3030
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
@@ -65,8 +65,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
6565
this.emit(LISTS_UPDATE_EVENT);
6666
});
6767

68-
constructor() {
69-
super(defaultDispatcher);
68+
constructor(dis: MatrixDispatcher) {
69+
super(dis);
7070
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
7171
this.algorithm.start();
7272
}
@@ -613,11 +613,11 @@ export default class RoomListStore {
613613
if (!RoomListStore.internalInstance) {
614614
if (SettingsStore.getValue("feature_sliding_sync")) {
615615
logger.info("using SlidingRoomListStoreClass");
616-
const instance = new SlidingRoomListStoreClass();
616+
const instance = new SlidingRoomListStoreClass(defaultDispatcher, SdkContextClass.instance);
617617
instance.start();
618618
RoomListStore.internalInstance = instance;
619619
} else {
620-
const instance = new RoomListStoreClass();
620+
const instance = new RoomListStoreClass(defaultDispatcher);
621621
instance.start();
622622
RoomListStore.internalInstance = instance;
623623
}

src/stores/room-list/SlidingRoomListStore.ts

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ import { MSC3575Filter, SlidingSyncEvent } from "matrix-js-sdk/src/sliding-sync"
2121
import { RoomUpdateCause, TagID, OrderedDefaultTagIDs, DefaultTagID } from "./models";
2222
import { ITagMap, ListAlgorithm, SortAlgorithm } from "./algorithms/models";
2323
import { ActionPayload } from "../../dispatcher/payloads";
24-
import defaultDispatcher from "../../dispatcher/dispatcher";
24+
import { MatrixDispatcher } from "../../dispatcher/dispatcher";
2525
import { IFilterCondition } from "./filters/IFilterCondition";
2626
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
2727
import { RoomListStore as Interface, RoomListStoreEvent } from "./Interface";
28-
import { SlidingSyncManager } from "../../SlidingSyncManager";
29-
import SpaceStore from "../spaces/SpaceStore";
3028
import { MetaSpace, SpaceKey, UPDATE_SELECTED_SPACE } from "../spaces";
3129
import { LISTS_LOADING_EVENT } from "./RoomListStore";
3230
import { UPDATE_EVENT } from "../AsyncStore";
@@ -38,7 +36,7 @@ interface IState {
3836

3937
export const SlidingSyncSortToFilter: Record<SortAlgorithm, string[]> = {
4038
[SortAlgorithm.Alphabetic]: ["by_name", "by_recency"],
41-
[SortAlgorithm.Recent]: ["by_highlight_count", "by_notification_count", "by_recency"],
39+
[SortAlgorithm.Recent]: ["by_notification_level", "by_recency"],
4240
[SortAlgorithm.Manual]: ["by_recency"],
4341
};
4442

@@ -48,21 +46,18 @@ const filterConditions: Record<TagID, MSC3575Filter> = {
4846
},
4947
[DefaultTagID.Favourite]: {
5048
tags: ["m.favourite"],
51-
is_tombstoned: false,
5249
},
5350
// TODO https://github.com/vector-im/element-web/issues/23207
5451
// DefaultTagID.SavedItems,
5552
[DefaultTagID.DM]: {
5653
is_dm: true,
5754
is_invite: false,
58-
is_tombstoned: false,
5955
// If a DM has a Favourite & Low Prio tag then it'll be shown in those lists instead
6056
not_tags: ["m.favourite", "m.lowpriority"],
6157
},
6258
[DefaultTagID.Untagged]: {
6359
is_dm: false,
6460
is_invite: false,
65-
is_tombstoned: false,
6661
not_room_types: ["m.space"],
6762
not_tags: ["m.favourite", "m.lowpriority"],
6863
// spaces filter added dynamically
@@ -71,7 +66,6 @@ const filterConditions: Record<TagID, MSC3575Filter> = {
7166
tags: ["m.lowpriority"],
7267
// If a room has both Favourite & Low Prio tags then it'll be shown under Favourites
7368
not_tags: ["m.favourite"],
74-
is_tombstoned: false,
7569
},
7670
// TODO https://github.com/vector-im/element-web/issues/23207
7771
// DefaultTagID.ServerNotice,
@@ -87,25 +81,25 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
8781
private counts: Record<TagID, number> = {};
8882
private stickyRoomId: string | null;
8983

90-
public constructor() {
91-
super(defaultDispatcher);
84+
public constructor(dis: MatrixDispatcher, private readonly context: SdkContextClass) {
85+
super(dis);
9286
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
9387
}
9488

9589
public async setTagSorting(tagId: TagID, sort: SortAlgorithm) {
9690
logger.info("SlidingRoomListStore.setTagSorting ", tagId, sort);
9791
this.tagIdToSortAlgo[tagId] = sort;
98-
const slidingSyncIndex = SlidingSyncManager.instance.getOrAllocateListIndex(tagId);
92+
const slidingSyncIndex = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
9993
switch (sort) {
10094
case SortAlgorithm.Alphabetic:
101-
await SlidingSyncManager.instance.ensureListRegistered(
95+
await this.context.slidingSyncManager.ensureListRegistered(
10296
slidingSyncIndex, {
10397
sort: SlidingSyncSortToFilter[SortAlgorithm.Alphabetic],
10498
},
10599
);
106100
break;
107101
case SortAlgorithm.Recent:
108-
await SlidingSyncManager.instance.ensureListRegistered(
102+
await this.context.slidingSyncManager.ensureListRegistered(
109103
slidingSyncIndex, {
110104
sort: SlidingSyncSortToFilter[SortAlgorithm.Recent],
111105
},
@@ -174,10 +168,13 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
174168
// check all lists for each tag we know about and see if the room is there
175169
const tags: TagID[] = [];
176170
for (const tagId in this.tagIdToSortAlgo) {
177-
const index = SlidingSyncManager.instance.getOrAllocateListIndex(tagId);
178-
const { roomIndexToRoomId } = SlidingSyncManager.instance.slidingSync.getListData(index);
179-
for (const roomIndex in roomIndexToRoomId) {
180-
const roomId = roomIndexToRoomId[roomIndex];
171+
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
172+
const listData = this.context.slidingSyncManager.slidingSync.getListData(index);
173+
if (!listData) {
174+
continue;
175+
}
176+
for (const roomIndex in listData.roomIndexToRoomId) {
177+
const roomId = listData.roomIndexToRoomId[roomIndex];
181178
if (roomId === room.roomId) {
182179
tags.push(tagId);
183180
break;
@@ -207,7 +204,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
207204

208205
// this room will not move due to it being viewed: it is sticky. This can be null to indicate
209206
// no sticky room if you aren't viewing a room.
210-
this.stickyRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
207+
this.stickyRoomId = this.context.roomViewStore.getRoomId();
211208
let stickyRoomNewIndex = -1;
212209
const stickyRoomOldIndex = (tagMap[tagId] || []).findIndex((room) => {
213210
return room.roomId === this.stickyRoomId;
@@ -264,7 +261,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
264261
}
265262

266263
private onSlidingSyncListUpdate(listIndex: number, joinCount: number, roomIndexToRoomId: Record<number, string>) {
267-
const tagId = SlidingSyncManager.instance.listIdForIndex(listIndex);
264+
const tagId = this.context.slidingSyncManager.listIdForIndex(listIndex);
268265
this.counts[tagId]= joinCount;
269266
this.refreshOrderedLists(tagId, roomIndexToRoomId);
270267
// let the UI update
@@ -273,7 +270,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
273270

274271
private onRoomViewStoreUpdated() {
275272
// we only care about this to know when the user has clicked on a room to set the stickiness value
276-
if (SdkContextClass.instance.roomViewStore.getRoomId() === this.stickyRoomId) {
273+
if (this.context.roomViewStore.getRoomId() === this.stickyRoomId) {
277274
return;
278275
}
279276

@@ -296,14 +293,17 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
296293
if (room) {
297294
// resort it based on the slidingSync view of the list. This may cause this old sticky
298295
// room to cease to exist.
299-
const index = SlidingSyncManager.instance.getOrAllocateListIndex(tagId);
300-
const { roomIndexToRoomId } = SlidingSyncManager.instance.slidingSync.getListData(index);
301-
this.refreshOrderedLists(tagId, roomIndexToRoomId);
296+
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
297+
const listData = this.context.slidingSyncManager.slidingSync.getListData(index);
298+
if (!listData) {
299+
continue;
300+
}
301+
this.refreshOrderedLists(tagId, listData.roomIndexToRoomId);
302302
hasUpdatedAnyList = true;
303303
}
304304
}
305305
// in the event we didn't call refreshOrderedLists, it helps to still remember the sticky room ID.
306-
this.stickyRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
306+
this.stickyRoomId = this.context.roomViewStore.getRoomId();
307307

308308
if (hasUpdatedAnyList) {
309309
this.emit(LISTS_UPDATE_EVENT);
@@ -313,11 +313,11 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
313313
protected async onReady(): Promise<any> {
314314
logger.info("SlidingRoomListStore.onReady");
315315
// permanent listeners: never get destroyed. Could be an issue if we want to test this in isolation.
316-
SlidingSyncManager.instance.slidingSync.on(SlidingSyncEvent.List, this.onSlidingSyncListUpdate.bind(this));
317-
SdkContextClass.instance.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdated.bind(this));
318-
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated.bind(this));
319-
if (SpaceStore.instance.activeSpace) {
320-
this.onSelectedSpaceUpdated(SpaceStore.instance.activeSpace, false);
316+
this.context.slidingSyncManager.slidingSync.on(SlidingSyncEvent.List, this.onSlidingSyncListUpdate.bind(this));
317+
this.context.roomViewStore.addListener(UPDATE_EVENT, this.onRoomViewStoreUpdated.bind(this));
318+
this.context.spaceStore.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated.bind(this));
319+
if (this.context.spaceStore.activeSpace) {
320+
this.onSelectedSpaceUpdated(this.context.spaceStore.activeSpace, false);
321321
}
322322

323323
// sliding sync has an initial response for spaces. Now request all the lists.
@@ -332,8 +332,8 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
332332
const sort = SortAlgorithm.Recent; // default to recency sort, TODO: read from config
333333
this.tagIdToSortAlgo[tagId] = sort;
334334
this.emit(LISTS_LOADING_EVENT, tagId, true);
335-
const index = SlidingSyncManager.instance.getOrAllocateListIndex(tagId);
336-
SlidingSyncManager.instance.ensureListRegistered(index, {
335+
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
336+
this.context.slidingSyncManager.ensureListRegistered(index, {
337337
filters: filter,
338338
sort: SlidingSyncSortToFilter[sort],
339339
}).then(() => {
@@ -350,9 +350,18 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
350350
const oldSpace = filters.spaces?.[0];
351351
filters.spaces = (activeSpace && activeSpace != MetaSpace.Home) ? [activeSpace] : undefined;
352352
if (oldSpace !== activeSpace) {
353+
// include subspaces in this list
354+
this.context.spaceStore.traverseSpace(activeSpace, (roomId: string) => {
355+
if (roomId === activeSpace) {
356+
return;
357+
}
358+
filters.spaces.push(roomId); // add subspace
359+
}, false);
360+
353361
this.emit(LISTS_LOADING_EVENT, tagId, true);
354-
SlidingSyncManager.instance.ensureListRegistered(
355-
SlidingSyncManager.instance.getOrAllocateListIndex(tagId),
362+
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
363+
this.context.slidingSyncManager.ensureListRegistered(
364+
index,
356365
{
357366
filters: filters,
358367
},

0 commit comments

Comments
 (0)