Support dynamic room predecessors in SpaceStore (#10332)
This commit is contained in:
parent
01d7b795ab
commit
acb7dd84ac
2 changed files with 136 additions and 9 deletions
|
@ -144,6 +144,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// The following properties are set by onReady as they live in account_data
|
// The following properties are set by onReady as they live in account_data
|
||||||
private _allRoomsInHome = false;
|
private _allRoomsInHome = false;
|
||||||
private _enabledMetaSpaces: MetaSpace[] = [];
|
private _enabledMetaSpaces: MetaSpace[] = [];
|
||||||
|
/** Whether the feature flag is set for MSC3946 */
|
||||||
|
private _msc3946ProcessDynamicPredecessor: boolean = SettingsStore.getValue("feature_dynamic_room_predecessors");
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super(defaultDispatcher, {});
|
super(defaultDispatcher, {});
|
||||||
|
@ -151,6 +153,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
SettingsStore.monitorSetting("Spaces.allRoomsInHome", null);
|
SettingsStore.monitorSetting("Spaces.allRoomsInHome", null);
|
||||||
SettingsStore.monitorSetting("Spaces.enabledMetaSpaces", null);
|
SettingsStore.monitorSetting("Spaces.enabledMetaSpaces", null);
|
||||||
SettingsStore.monitorSetting("Spaces.showPeopleInSpace", null);
|
SettingsStore.monitorSetting("Spaces.showPeopleInSpace", null);
|
||||||
|
SettingsStore.monitorSetting("feature_dynamic_room_predecessors", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get invitedSpaces(): Room[] {
|
public get invitedSpaces(): Room[] {
|
||||||
|
@ -352,7 +355,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
return getChildOrder(ev.getContent().order, ev.getTs(), ev.getStateKey()!);
|
return getChildOrder(ev.getContent().order, ev.getTs(), ev.getStateKey()!);
|
||||||
})
|
})
|
||||||
.map((ev) => {
|
.map((ev) => {
|
||||||
const history = this.matrixClient.getRoomUpgradeHistory(ev.getStateKey()!, true);
|
const history = this.matrixClient.getRoomUpgradeHistory(
|
||||||
|
ev.getStateKey()!,
|
||||||
|
true,
|
||||||
|
this._msc3946ProcessDynamicPredecessor,
|
||||||
|
);
|
||||||
return history[history.length - 1];
|
return history[history.length - 1];
|
||||||
})
|
})
|
||||||
.filter((room) => {
|
.filter((room) => {
|
||||||
|
@ -450,7 +457,9 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
useCache = true,
|
useCache = true,
|
||||||
): Set<string> => {
|
): Set<string> => {
|
||||||
if (space === MetaSpace.Home && this.allRoomsInHome) {
|
if (space === MetaSpace.Home && this.allRoomsInHome) {
|
||||||
return new Set(this.matrixClient.getVisibleRooms().map((r) => r.roomId));
|
return new Set(
|
||||||
|
this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).map((r) => r.roomId),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// meta spaces never have descendants
|
// meta spaces never have descendants
|
||||||
|
@ -539,7 +548,9 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuildSpaceHierarchy = (): void => {
|
private rebuildSpaceHierarchy = (): void => {
|
||||||
const visibleSpaces = this.matrixClient.getVisibleRooms().filter((r) => r.isSpaceRoom());
|
const visibleSpaces = this.matrixClient
|
||||||
|
.getVisibleRooms(this._msc3946ProcessDynamicPredecessor)
|
||||||
|
.filter((r) => r.isSpaceRoom());
|
||||||
const [joinedSpaces, invitedSpaces] = visibleSpaces.reduce(
|
const [joinedSpaces, invitedSpaces] = visibleSpaces.reduce(
|
||||||
([joined, invited], s) => {
|
([joined, invited], s) => {
|
||||||
switch (getEffectiveMembership(s.getMyMembership())) {
|
switch (getEffectiveMembership(s.getMyMembership())) {
|
||||||
|
@ -573,7 +584,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private rebuildParentMap = (): void => {
|
private rebuildParentMap = (): void => {
|
||||||
const joinedSpaces = this.matrixClient.getVisibleRooms().filter((r) => {
|
const joinedSpaces = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor).filter((r) => {
|
||||||
return r.isSpaceRoom() && r.getMyMembership() === "join";
|
return r.isSpaceRoom() && r.getMyMembership() === "join";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -595,7 +606,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
} else {
|
} else {
|
||||||
const rooms = new Set(
|
const rooms = new Set(
|
||||||
this.matrixClient
|
this.matrixClient
|
||||||
.getVisibleRooms()
|
.getVisibleRooms(this._msc3946ProcessDynamicPredecessor)
|
||||||
.filter(this.showInHomeSpace)
|
.filter(this.showInHomeSpace)
|
||||||
.map((r) => r.roomId),
|
.map((r) => r.roomId),
|
||||||
);
|
);
|
||||||
|
@ -609,7 +620,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
|
|
||||||
private rebuildMetaSpaces = (): void => {
|
private rebuildMetaSpaces = (): void => {
|
||||||
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
if (enabledMetaSpaces.has(MetaSpace.Home)) {
|
if (enabledMetaSpaces.has(MetaSpace.Home)) {
|
||||||
this.rebuildHomeSpace();
|
this.rebuildHomeSpace();
|
||||||
|
@ -643,7 +654,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
|
|
||||||
private updateNotificationStates = (spaces?: SpaceKey[]): void => {
|
private updateNotificationStates = (spaces?: SpaceKey[]): void => {
|
||||||
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
let dmBadgeSpace: MetaSpace | undefined;
|
let dmBadgeSpace: MetaSpace | undefined;
|
||||||
// only show badges on dms on the most relevant space if such exists
|
// only show badges on dms on the most relevant space if such exists
|
||||||
|
@ -729,7 +740,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onRoomsUpdate = (): void => {
|
private onRoomsUpdate = (): void => {
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
const visibleRooms = this.matrixClient.getVisibleRooms(this._msc3946ProcessDynamicPredecessor);
|
||||||
|
|
||||||
const prevRoomsBySpace = this.roomIdsBySpace;
|
const prevRoomsBySpace = this.roomIdsBySpace;
|
||||||
const prevUsersBySpace = this.userIdsBySpace;
|
const prevUsersBySpace = this.userIdsBySpace;
|
||||||
|
@ -792,7 +803,9 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
// Expand room IDs to all known versions of the given rooms
|
// Expand room IDs to all known versions of the given rooms
|
||||||
const expandedRoomIds = new Set(
|
const expandedRoomIds = new Set(
|
||||||
Array.from(roomIds).flatMap((roomId) => {
|
Array.from(roomIds).flatMap((roomId) => {
|
||||||
return this.matrixClient.getRoomUpgradeHistory(roomId, true).map((r) => r.roomId);
|
return this.matrixClient
|
||||||
|
.getRoomUpgradeHistory(roomId, true, this._msc3946ProcessDynamicPredecessor)
|
||||||
|
.map((r) => r.roomId);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1275,6 +1288,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.updateNotificationStates([payload.roomId]);
|
this.updateNotificationStates([payload.roomId]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "feature_dynamic_room_predecessors":
|
||||||
|
this._msc3946ProcessDynamicPredecessor = SettingsStore.getValue(
|
||||||
|
"feature_dynamic_room_predecessors",
|
||||||
|
);
|
||||||
|
this.rebuildSpaceHierarchy();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1355,6 +1375,15 @@ export default class SpaceStore {
|
||||||
public static get instance(): SpaceStoreClass {
|
public static get instance(): SpaceStoreClass {
|
||||||
return SpaceStore.internalInstance;
|
return SpaceStore.internalInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal for test only
|
||||||
|
*/
|
||||||
|
public static testInstance(): SpaceStoreClass {
|
||||||
|
const store = new SpaceStoreClass();
|
||||||
|
store.start();
|
||||||
|
return store;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.mxSpaceStore = SpaceStore.instance;
|
window.mxSpaceStore = SpaceStore.instance;
|
||||||
|
|
|
@ -1331,4 +1331,102 @@ describe("SpaceStore", () => {
|
||||||
expect(metaSpaces).toEqual(store.enabledMetaSpaces);
|
expect(metaSpaces).toEqual(store.enabledMetaSpaces);
|
||||||
removeListener();
|
removeListener();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("when feature_dynamic_room_predecessors is not enabled", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(settingName) => settingName === "Spaces.allRoomsInHome",
|
||||||
|
);
|
||||||
|
// @ts-ignore calling a private function
|
||||||
|
SpaceStore.instance.onAction({
|
||||||
|
action: Action.SettingUpdated,
|
||||||
|
settingName: "feature_dynamic_room_predecessors",
|
||||||
|
roomId: null,
|
||||||
|
level: SettingLevel.ACCOUNT,
|
||||||
|
newValueAtLevel: SettingLevel.ACCOUNT,
|
||||||
|
newValue: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes that value in calls to getVisibleRooms and getRoomUpgradeHistory during startup", async () => {
|
||||||
|
// When we create an instance, which calls onReady and rebuildSpaceHierarchy
|
||||||
|
mkSpace("!dynspace:example.com", [mkRoom("!dynroom:example.com").roomId]);
|
||||||
|
await run();
|
||||||
|
|
||||||
|
// Then we pass through the correct value of the feature flag to
|
||||||
|
// everywhere that needs it.
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith();
|
||||||
|
expect(client.getRoomUpgradeHistory).toHaveBeenCalledWith(expect.anything(), expect.anything(), false);
|
||||||
|
expect(client.getRoomUpgradeHistory).not.toHaveBeenCalledWith(expect.anything(), expect.anything(), true);
|
||||||
|
expect(client.getRoomUpgradeHistory).not.toHaveBeenCalledWith(expect.anything(), expect.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes that value in calls to getVisibleRooms during getSpaceFilteredRoomIds", () => {
|
||||||
|
// Given a store
|
||||||
|
const store = SpaceStore.testInstance();
|
||||||
|
|
||||||
|
// When we ask for filtered room ids
|
||||||
|
store.getSpaceFilteredRoomIds(MetaSpace.Home);
|
||||||
|
|
||||||
|
// Then we pass the correct feature flag
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when feature_dynamic_room_predecessors is enabled", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||||
|
(settingName) =>
|
||||||
|
settingName === "Spaces.allRoomsInHome" || settingName === "feature_dynamic_room_predecessors",
|
||||||
|
);
|
||||||
|
// @ts-ignore calling a private function
|
||||||
|
SpaceStore.instance.onAction({
|
||||||
|
action: Action.SettingUpdated,
|
||||||
|
settingName: "feature_dynamic_room_predecessors",
|
||||||
|
roomId: null,
|
||||||
|
level: SettingLevel.ACCOUNT,
|
||||||
|
newValueAtLevel: SettingLevel.ACCOUNT,
|
||||||
|
newValue: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes that value in calls to getVisibleRooms and getRoomUpgradeHistory during startup", async () => {
|
||||||
|
// When we create an instance, which calls onReady and rebuildSpaceHierarchy
|
||||||
|
mkSpace("!dynspace:example.com", [mkRoom("!dynroom:example.com").roomId]);
|
||||||
|
await run();
|
||||||
|
|
||||||
|
// Then we pass through the correct value of the feature flag to
|
||||||
|
// everywhere that needs it.
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith();
|
||||||
|
expect(client.getRoomUpgradeHistory).toHaveBeenCalledWith(expect.anything(), expect.anything(), true);
|
||||||
|
expect(client.getRoomUpgradeHistory).not.toHaveBeenCalledWith(expect.anything(), expect.anything(), false);
|
||||||
|
expect(client.getRoomUpgradeHistory).not.toHaveBeenCalledWith(expect.anything(), expect.anything());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes that value in calls to getVisibleRooms during getSpaceFilteredRoomIds", () => {
|
||||||
|
// Given a store
|
||||||
|
const store = SpaceStore.testInstance();
|
||||||
|
// When we ask for filtered room ids
|
||||||
|
store.getSpaceFilteredRoomIds(MetaSpace.Home);
|
||||||
|
|
||||||
|
// Then we pass the correct feature flag
|
||||||
|
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith(false);
|
||||||
|
expect(client.getVisibleRooms).not.toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue