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

Commit add23e4

Browse files
authored
Pass the dynamic predecessor feature flag when listing rooms (#10068)
1 parent 41c8ab5 commit add23e4

File tree

2 files changed

+127
-5
lines changed

2 files changed

+127
-5
lines changed

Diff for: src/stores/room-list/RoomListStore.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
5656
public static TEST_MODE = false;
5757

5858
private initialListsGenerated = false;
59+
private msc3946ProcessDynamicPredecessor: boolean;
60+
private msc3946SettingWatcherRef: string;
5961
private algorithm = new Algorithm();
6062
private prefilterConditions: IFilterCondition[] = [];
6163
private updateFn = new MarkedExecution(() => {
@@ -69,6 +71,20 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
6971
super(dis);
7072
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
7173
this.algorithm.start();
74+
75+
this.msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
76+
this.msc3946SettingWatcherRef = SettingsStore.watchSetting(
77+
"feature_dynamic_room_predecessors",
78+
null,
79+
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
80+
this.msc3946ProcessDynamicPredecessor = newVal;
81+
this.regenerateAllLists({ trigger: true });
82+
},
83+
);
84+
}
85+
86+
public componentWillUnmount(): void {
87+
SettingsStore.unwatchSetting(this.msc3946SettingWatcherRef);
7288
}
7389

7490
private setupWatchers(): void {
@@ -286,7 +302,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
286302
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
287303
// the dead room in the list.
288304
const roomState: RoomState = membershipPayload.room.currentState;
289-
const predecessor = roomState.findPredecessor(SettingsStore.getValue("feature_dynamic_room_predecessors"));
305+
const predecessor = roomState.findPredecessor(this.msc3946ProcessDynamicPredecessor);
290306
if (predecessor) {
291307
const prevRoom = this.matrixClient.getRoom(predecessor.roomId);
292308
if (prevRoom) {
@@ -496,7 +512,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
496512
private getPlausibleRooms(): Room[] {
497513
if (!this.matrixClient) return [];
498514

499-
let rooms = this.matrixClient.getVisibleRooms().filter((r) => VisibilityProvider.instance.isRoomVisible(r));
515+
let rooms = this.matrixClient.getVisibleRooms(this.msc3946ProcessDynamicPredecessor);
516+
rooms = rooms.filter((r) => VisibilityProvider.instance.isRoomVisible(r));
500517

501518
if (this.prefilterConditions.length > 0) {
502519
rooms = rooms.filter((r) => {

Diff for: test/stores/room-list/RoomListStore-test.ts

+108-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import { EventType, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
17+
import { EventType, MatrixEvent, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
1818

1919
import { MatrixDispatcher } from "../../../src/dispatcher/dispatcher";
20-
import SettingsStore from "../../../src/settings/SettingsStore";
20+
import { SettingLevel } from "../../../src/settings/SettingLevel";
21+
import SettingsStore, { CallbackFn } from "../../../src/settings/SettingsStore";
2122
import { ListAlgorithm, SortAlgorithm } from "../../../src/stores/room-list/algorithms/models";
2223
import { OrderedDefaultTagIDs, RoomUpdateCause } from "../../../src/stores/room-list/models";
2324
import RoomListStore, { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
25+
import DMRoomMap from "../../../src/utils/DMRoomMap";
2426
import { stubClient, upsertRoomStateEvents } from "../../test-utils";
2527

2628
describe("RoomListStore", () => {
@@ -62,7 +64,9 @@ describe("RoomListStore", () => {
6264
upsertRoomStateEvents(roomWithPredecessorEvent, [predecessor]);
6365
const roomWithCreatePredecessor = new Room(newRoomId, client, userId, {});
6466
upsertRoomStateEvents(roomWithCreatePredecessor, [createWithPredecessor]);
65-
const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {});
67+
const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {
68+
pendingEventOrdering: PendingEventOrdering.Detached,
69+
});
6670
upsertRoomStateEvents(roomNoPredecessor, [createNoPredecessor]);
6771
const oldRoom = new Room(oldRoomId, client, userId, {});
6872
client.getRoom = jest.fn().mockImplementation((roomId) => {
@@ -138,6 +142,93 @@ describe("RoomListStore", () => {
138142
expect(handleRoomUpdate).toHaveBeenCalledTimes(1);
139143
});
140144

145+
it("Lists all rooms that the client says are visible", () => {
146+
// Given 3 rooms that are visible according to the client
147+
const room1 = new Room("!r1:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
148+
const room2 = new Room("!r2:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
149+
const room3 = new Room("!r3:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
150+
room1.updateMyMembership("join");
151+
room2.updateMyMembership("join");
152+
room3.updateMyMembership("join");
153+
DMRoomMap.makeShared();
154+
const { store } = createStore();
155+
client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]);
156+
157+
// When we make the list of rooms
158+
store.regenerateAllLists({ trigger: false });
159+
160+
// Then the list contains all 3
161+
expect(store.orderedLists).toMatchObject({
162+
"im.vector.fake.recent": [room1, room2, room3],
163+
});
164+
165+
// We asked not to use MSC3946 when we asked the client for the visible rooms
166+
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
167+
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
168+
});
169+
170+
it("Watches the feature flag setting", () => {
171+
jest.spyOn(SettingsStore, "watchSetting").mockReturnValue("dyn_pred_ref");
172+
jest.spyOn(SettingsStore, "unwatchSetting");
173+
174+
// When we create a store
175+
const { store } = createStore();
176+
177+
// Then we watch the feature flag
178+
expect(SettingsStore.watchSetting).toHaveBeenCalledWith(
179+
"feature_dynamic_room_predecessors",
180+
null,
181+
expect.any(Function),
182+
);
183+
184+
// And when we unmount it
185+
store.componentWillUnmount();
186+
187+
// Then we unwatch it.
188+
expect(SettingsStore.unwatchSetting).toHaveBeenCalledWith("dyn_pred_ref");
189+
});
190+
191+
it("Regenerates all lists when the feature flag is set", () => {
192+
// Given a store allowing us to spy on any use of SettingsStore
193+
let featureFlagValue = false;
194+
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => featureFlagValue);
195+
196+
let watchCallback: CallbackFn | undefined;
197+
jest.spyOn(SettingsStore, "watchSetting").mockImplementation(
198+
(_settingName: string, _roomId: string | null, callbackFn: CallbackFn) => {
199+
watchCallback = callbackFn;
200+
return "dyn_pred_ref";
201+
},
202+
);
203+
jest.spyOn(SettingsStore, "unwatchSetting");
204+
205+
const { store } = createStore();
206+
client.getVisibleRooms = jest.fn().mockReturnValue([]);
207+
// Sanity: no calculation has happened yet
208+
expect(client.getVisibleRooms).toHaveBeenCalledTimes(0);
209+
210+
// When we calculate for the first time
211+
store.regenerateAllLists({ trigger: false });
212+
213+
// Then we use the current feature flag value (false)
214+
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
215+
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
216+
217+
// But when we update the feature flag
218+
featureFlagValue = true;
219+
watchCallback(
220+
"feature_dynamic_room_predecessors",
221+
"",
222+
SettingLevel.DEFAULT,
223+
featureFlagValue,
224+
featureFlagValue,
225+
);
226+
227+
// Then we recalculate and passed the updated value (true)
228+
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
229+
expect(client.getVisibleRooms).toHaveBeenCalledTimes(2);
230+
});
231+
141232
describe("When feature_dynamic_room_predecessors = true", () => {
142233
beforeEach(() => {
143234
jest.spyOn(SettingsStore, "getValue").mockImplementation(
@@ -168,5 +259,19 @@ describe("RoomListStore", () => {
168259
// And the new room is added
169260
expect(handleRoomUpdate).toHaveBeenCalledWith(roomWithPredecessorEvent, RoomUpdateCause.NewRoom);
170261
});
262+
263+
it("Passes the feature flag on to the client when asking for visible rooms", () => {
264+
// Given a store that we can ask for a room list
265+
DMRoomMap.makeShared();
266+
const { store } = createStore();
267+
client.getVisibleRooms = jest.fn().mockReturnValue([]);
268+
269+
// When we make the list of rooms
270+
store.regenerateAllLists({ trigger: false });
271+
272+
// We asked to use MSC3946 when we asked the client for the visible rooms
273+
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
274+
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
275+
});
171276
});
172277
});

0 commit comments

Comments
 (0)