Pass the dynamic predecessor feature flag when listing rooms (#10068)
This commit is contained in:
parent
41c8ab5e59
commit
add23e4d5d
2 changed files with 127 additions and 5 deletions
|
@ -56,6 +56,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
|
||||||
public static TEST_MODE = false;
|
public static TEST_MODE = false;
|
||||||
|
|
||||||
private initialListsGenerated = false;
|
private initialListsGenerated = false;
|
||||||
|
private msc3946ProcessDynamicPredecessor: boolean;
|
||||||
|
private msc3946SettingWatcherRef: string;
|
||||||
private algorithm = new Algorithm();
|
private algorithm = new Algorithm();
|
||||||
private prefilterConditions: IFilterCondition[] = [];
|
private prefilterConditions: IFilterCondition[] = [];
|
||||||
private updateFn = new MarkedExecution(() => {
|
private updateFn = new MarkedExecution(() => {
|
||||||
|
@ -69,6 +71,20 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
|
||||||
super(dis);
|
super(dis);
|
||||||
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
|
this.setMaxListeners(20); // RoomList + LeftPanel + 8xRoomSubList + spares
|
||||||
this.algorithm.start();
|
this.algorithm.start();
|
||||||
|
|
||||||
|
this.msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
|
||||||
|
this.msc3946SettingWatcherRef = SettingsStore.watchSetting(
|
||||||
|
"feature_dynamic_room_predecessors",
|
||||||
|
null,
|
||||||
|
(_settingName, _roomId, _level, _newValAtLevel, newVal) => {
|
||||||
|
this.msc3946ProcessDynamicPredecessor = newVal;
|
||||||
|
this.regenerateAllLists({ trigger: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount(): void {
|
||||||
|
SettingsStore.unwatchSetting(this.msc3946SettingWatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupWatchers(): void {
|
private setupWatchers(): void {
|
||||||
|
@ -286,7 +302,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
|
||||||
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
|
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
|
||||||
// the dead room in the list.
|
// the dead room in the list.
|
||||||
const roomState: RoomState = membershipPayload.room.currentState;
|
const roomState: RoomState = membershipPayload.room.currentState;
|
||||||
const predecessor = roomState.findPredecessor(SettingsStore.getValue("feature_dynamic_room_predecessors"));
|
const predecessor = roomState.findPredecessor(this.msc3946ProcessDynamicPredecessor);
|
||||||
if (predecessor) {
|
if (predecessor) {
|
||||||
const prevRoom = this.matrixClient.getRoom(predecessor.roomId);
|
const prevRoom = this.matrixClient.getRoom(predecessor.roomId);
|
||||||
if (prevRoom) {
|
if (prevRoom) {
|
||||||
|
@ -496,7 +512,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
|
||||||
private getPlausibleRooms(): Room[] {
|
private getPlausibleRooms(): Room[] {
|
||||||
if (!this.matrixClient) return [];
|
if (!this.matrixClient) return [];
|
||||||
|
|
||||||
let rooms = this.matrixClient.getVisibleRooms().filter((r) => VisibilityProvider.instance.isRoomVisible(r));
|
let rooms = this.matrixClient.getVisibleRooms(this.msc3946ProcessDynamicPredecessor);
|
||||||
|
rooms = rooms.filter((r) => VisibilityProvider.instance.isRoomVisible(r));
|
||||||
|
|
||||||
if (this.prefilterConditions.length > 0) {
|
if (this.prefilterConditions.length > 0) {
|
||||||
rooms = rooms.filter((r) => {
|
rooms = rooms.filter((r) => {
|
||||||
|
|
|
@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EventType, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { EventType, MatrixEvent, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { MatrixDispatcher } from "../../../src/dispatcher/dispatcher";
|
import { MatrixDispatcher } from "../../../src/dispatcher/dispatcher";
|
||||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
|
import SettingsStore, { CallbackFn } from "../../../src/settings/SettingsStore";
|
||||||
import { ListAlgorithm, SortAlgorithm } from "../../../src/stores/room-list/algorithms/models";
|
import { ListAlgorithm, SortAlgorithm } from "../../../src/stores/room-list/algorithms/models";
|
||||||
import { OrderedDefaultTagIDs, RoomUpdateCause } from "../../../src/stores/room-list/models";
|
import { OrderedDefaultTagIDs, RoomUpdateCause } from "../../../src/stores/room-list/models";
|
||||||
import RoomListStore, { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
|
import RoomListStore, { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
|
||||||
|
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
||||||
import { stubClient, upsertRoomStateEvents } from "../../test-utils";
|
import { stubClient, upsertRoomStateEvents } from "../../test-utils";
|
||||||
|
|
||||||
describe("RoomListStore", () => {
|
describe("RoomListStore", () => {
|
||||||
|
@ -62,7 +64,9 @@ describe("RoomListStore", () => {
|
||||||
upsertRoomStateEvents(roomWithPredecessorEvent, [predecessor]);
|
upsertRoomStateEvents(roomWithPredecessorEvent, [predecessor]);
|
||||||
const roomWithCreatePredecessor = new Room(newRoomId, client, userId, {});
|
const roomWithCreatePredecessor = new Room(newRoomId, client, userId, {});
|
||||||
upsertRoomStateEvents(roomWithCreatePredecessor, [createWithPredecessor]);
|
upsertRoomStateEvents(roomWithCreatePredecessor, [createWithPredecessor]);
|
||||||
const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {});
|
const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {
|
||||||
|
pendingEventOrdering: PendingEventOrdering.Detached,
|
||||||
|
});
|
||||||
upsertRoomStateEvents(roomNoPredecessor, [createNoPredecessor]);
|
upsertRoomStateEvents(roomNoPredecessor, [createNoPredecessor]);
|
||||||
const oldRoom = new Room(oldRoomId, client, userId, {});
|
const oldRoom = new Room(oldRoomId, client, userId, {});
|
||||||
client.getRoom = jest.fn().mockImplementation((roomId) => {
|
client.getRoom = jest.fn().mockImplementation((roomId) => {
|
||||||
|
@ -138,6 +142,93 @@ describe("RoomListStore", () => {
|
||||||
expect(handleRoomUpdate).toHaveBeenCalledTimes(1);
|
expect(handleRoomUpdate).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Lists all rooms that the client says are visible", () => {
|
||||||
|
// Given 3 rooms that are visible according to the client
|
||||||
|
const room1 = new Room("!r1:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
|
||||||
|
const room2 = new Room("!r2:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
|
||||||
|
const room3 = new Room("!r3:e.com", client, userId, { pendingEventOrdering: PendingEventOrdering.Detached });
|
||||||
|
room1.updateMyMembership("join");
|
||||||
|
room2.updateMyMembership("join");
|
||||||
|
room3.updateMyMembership("join");
|
||||||
|
DMRoomMap.makeShared();
|
||||||
|
const { store } = createStore();
|
||||||
|
client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]);
|
||||||
|
|
||||||
|
// When we make the list of rooms
|
||||||
|
store.regenerateAllLists({ trigger: false });
|
||||||
|
|
||||||
|
// Then the list contains all 3
|
||||||
|
expect(store.orderedLists).toMatchObject({
|
||||||
|
"im.vector.fake.recent": [room1, room2, room3],
|
||||||
|
});
|
||||||
|
|
||||||
|
// We asked not to use MSC3946 when we asked the client for the visible rooms
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Watches the feature flag setting", () => {
|
||||||
|
jest.spyOn(SettingsStore, "watchSetting").mockReturnValue("dyn_pred_ref");
|
||||||
|
jest.spyOn(SettingsStore, "unwatchSetting");
|
||||||
|
|
||||||
|
// When we create a store
|
||||||
|
const { store } = createStore();
|
||||||
|
|
||||||
|
// Then we watch the feature flag
|
||||||
|
expect(SettingsStore.watchSetting).toHaveBeenCalledWith(
|
||||||
|
"feature_dynamic_room_predecessors",
|
||||||
|
null,
|
||||||
|
expect.any(Function),
|
||||||
|
);
|
||||||
|
|
||||||
|
// And when we unmount it
|
||||||
|
store.componentWillUnmount();
|
||||||
|
|
||||||
|
// Then we unwatch it.
|
||||||
|
expect(SettingsStore.unwatchSetting).toHaveBeenCalledWith("dyn_pred_ref");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Regenerates all lists when the feature flag is set", () => {
|
||||||
|
// Given a store allowing us to spy on any use of SettingsStore
|
||||||
|
let featureFlagValue = false;
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => featureFlagValue);
|
||||||
|
|
||||||
|
let watchCallback: CallbackFn | undefined;
|
||||||
|
jest.spyOn(SettingsStore, "watchSetting").mockImplementation(
|
||||||
|
(_settingName: string, _roomId: string | null, callbackFn: CallbackFn) => {
|
||||||
|
watchCallback = callbackFn;
|
||||||
|
return "dyn_pred_ref";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
jest.spyOn(SettingsStore, "unwatchSetting");
|
||||||
|
|
||||||
|
const { store } = createStore();
|
||||||
|
client.getVisibleRooms = jest.fn().mockReturnValue([]);
|
||||||
|
// Sanity: no calculation has happened yet
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
// When we calculate for the first time
|
||||||
|
store.regenerateAllLists({ trigger: false });
|
||||||
|
|
||||||
|
// Then we use the current feature flag value (false)
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
// But when we update the feature flag
|
||||||
|
featureFlagValue = true;
|
||||||
|
watchCallback(
|
||||||
|
"feature_dynamic_room_predecessors",
|
||||||
|
"",
|
||||||
|
SettingLevel.DEFAULT,
|
||||||
|
featureFlagValue,
|
||||||
|
featureFlagValue,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Then we recalculate and passed the updated value (true)
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
describe("When feature_dynamic_room_predecessors = true", () => {
|
describe("When feature_dynamic_room_predecessors = true", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
@ -168,5 +259,19 @@ describe("RoomListStore", () => {
|
||||||
// And the new room is added
|
// And the new room is added
|
||||||
expect(handleRoomUpdate).toHaveBeenCalledWith(roomWithPredecessorEvent, RoomUpdateCause.NewRoom);
|
expect(handleRoomUpdate).toHaveBeenCalledWith(roomWithPredecessorEvent, RoomUpdateCause.NewRoom);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Passes the feature flag on to the client when asking for visible rooms", () => {
|
||||||
|
// Given a store that we can ask for a room list
|
||||||
|
DMRoomMap.makeShared();
|
||||||
|
const { store } = createStore();
|
||||||
|
client.getVisibleRooms = jest.fn().mockReturnValue([]);
|
||||||
|
|
||||||
|
// When we make the list of rooms
|
||||||
|
store.regenerateAllLists({ trigger: false });
|
||||||
|
|
||||||
|
// We asked to use MSC3946 when we asked the client for the visible rooms
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue