Fix proliferation when joining upgraded rooms
We have to do a bit of a dance to return the sticky room to the list so we can remove it, if needed, and ensure that we generally swap the rooms out of the list.
This commit is contained in:
parent
52b52dfec4
commit
c7a83e65f0
2 changed files with 98 additions and 19 deletions
|
@ -97,8 +97,10 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
this.algorithm.stickyRoom = null;
|
this.algorithm.stickyRoom = null;
|
||||||
} else if (activeRoomId) {
|
} else if (activeRoomId) {
|
||||||
const activeRoom = this.matrixClient.getRoom(activeRoomId);
|
const activeRoom = this.matrixClient.getRoom(activeRoomId);
|
||||||
if (!activeRoom) throw new Error(`${activeRoomId} is current in RVS but missing from client`);
|
if (!activeRoom) {
|
||||||
if (activeRoom !== this.algorithm.stickyRoom) {
|
console.warn(`${activeRoomId} is current in RVS but missing from client - clearing sticky room`);
|
||||||
|
this.algorithm.stickyRoom = null;
|
||||||
|
} else if (activeRoom !== this.algorithm.stickyRoom) {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log(`Changing sticky room to ${activeRoomId}`);
|
console.log(`Changing sticky room to ${activeRoomId}`);
|
||||||
this.algorithm.stickyRoom = activeRoom;
|
this.algorithm.stickyRoom = activeRoom;
|
||||||
|
@ -187,10 +189,13 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
console.log(`[RoomListDebug] Live timeline event ${eventPayload.event.getId()} in ${updatedRoom.roomId}`);
|
console.log(`[RoomListDebug] Live timeline event ${eventPayload.event.getId()} in ${updatedRoom.roomId}`);
|
||||||
if (eventPayload.event.getType() === 'm.room.tombstone' && eventPayload.event.getStateKey() === '') {
|
if (eventPayload.event.getType() === 'm.room.tombstone' && eventPayload.event.getStateKey() === '') {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log(`[RoomListDebug] Got tombstone event - regenerating room list`);
|
console.log(`[RoomListDebug] Got tombstone event - trying to remove now-dead room`);
|
||||||
// TODO: We could probably be smarter about this: https://github.com/vector-im/riot-web/issues/14035
|
const newRoom = this.matrixClient.getRoom(eventPayload.event.getContent()['replacement_room']);
|
||||||
await this.regenerateAllLists();
|
if (newRoom) {
|
||||||
return; // don't pass the update down - we will have already handled it in the regen
|
// If we have the new room, then the new room check will have seen the predecessor
|
||||||
|
// and did the required updates, so do nothing here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await this.handleRoomUpdate(updatedRoom, RoomUpdateCause.Timeline);
|
await this.handleRoomUpdate(updatedRoom, RoomUpdateCause.Timeline);
|
||||||
};
|
};
|
||||||
|
@ -245,7 +250,29 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
if (membershipPayload.oldMembership !== "join" && membershipPayload.membership === "join") {
|
if (membershipPayload.oldMembership !== "join" && membershipPayload.membership === "join") {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log(`[RoomListDebug] Handling new room ${membershipPayload.room.roomId}`);
|
console.log(`[RoomListDebug] Handling new room ${membershipPayload.room.roomId}`);
|
||||||
await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
|
|
||||||
|
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
|
||||||
|
// the dead room in the list.
|
||||||
|
const createEvent = membershipPayload.room.currentState.getStateEvents("m.room.create", "");
|
||||||
|
if (createEvent && createEvent.getContent()['predecessor']) {
|
||||||
|
console.log(`[RoomListDebug] Room has a predecessor`);
|
||||||
|
const prevRoom = this.matrixClient.getRoom(createEvent.getContent()['predecessor']['room_id']);
|
||||||
|
if (prevRoom) {
|
||||||
|
const isSticky = this.algorithm.stickyRoom === prevRoom;
|
||||||
|
if (isSticky) {
|
||||||
|
console.log(`[RoomListDebug] Clearing sticky room due to room upgrade`);
|
||||||
|
await this.algorithm.setStickyRoomAsync(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we hit the algorithm instead of our handleRoomUpdate() function to
|
||||||
|
// avoid redundant updates.
|
||||||
|
console.log(`[RoomListDebug] Removing previous room from room list`);
|
||||||
|
await this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[RoomListDebug] Adding new room to room list`);
|
||||||
|
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +280,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
if (membershipPayload.oldMembership !== membershipPayload.membership) {
|
if (membershipPayload.oldMembership !== membershipPayload.membership) {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log(`[RoomListDebug] Handling membership change in ${membershipPayload.room.roomId}`);
|
console.log(`[RoomListDebug] Handling membership change in ${membershipPayload.room.roomId}`);
|
||||||
await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange);
|
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import {
|
||||||
SortAlgorithm
|
SortAlgorithm
|
||||||
} from "./models";
|
} from "./models";
|
||||||
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "../filters/IFilterCondition";
|
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "../filters/IFilterCondition";
|
||||||
import { EffectiveMembership, splitRoomsByMembership } from "../membership";
|
import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } from "../membership";
|
||||||
import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm";
|
import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm";
|
||||||
import { getListAlgorithmInstance } from "./list-ordering";
|
import { getListAlgorithmInstance } from "./list-ordering";
|
||||||
|
|
||||||
|
@ -99,6 +99,14 @@ export class Algorithm extends EventEmitter {
|
||||||
return this._cachedRooms;
|
return this._cachedRooms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Awaitable version of the sticky room setter.
|
||||||
|
* @param val The new room to sticky.
|
||||||
|
*/
|
||||||
|
public async setStickyRoomAsync(val: Room) {
|
||||||
|
await this.updateStickyRoom(val);
|
||||||
|
}
|
||||||
|
|
||||||
public getTagSorting(tagId: TagID): SortAlgorithm {
|
public getTagSorting(tagId: TagID): SortAlgorithm {
|
||||||
return this.sortAlgorithms[tagId];
|
return this.sortAlgorithms[tagId];
|
||||||
}
|
}
|
||||||
|
@ -160,10 +168,13 @@ export class Algorithm extends EventEmitter {
|
||||||
// It's possible to have no selected room. In that case, clear the sticky room
|
// It's possible to have no selected room. In that case, clear the sticky room
|
||||||
if (!val) {
|
if (!val) {
|
||||||
if (this._stickyRoom) {
|
if (this._stickyRoom) {
|
||||||
|
const stickyRoom = this._stickyRoom.room;
|
||||||
|
this._stickyRoom = null; // clear before we go to update the algorithm
|
||||||
|
|
||||||
// Lie to the algorithm and re-add the room to the algorithm
|
// Lie to the algorithm and re-add the room to the algorithm
|
||||||
await this.handleRoomUpdate(this._stickyRoom.room, RoomUpdateCause.NewRoom);
|
await this.handleRoomUpdate(stickyRoom, RoomUpdateCause.NewRoom);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this._stickyRoom = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +300,8 @@ export class Algorithm extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected recalculateFilteredRoomsForTag(tagId: TagID): void {
|
protected recalculateFilteredRoomsForTag(tagId: TagID): void {
|
||||||
|
if (!this.hasFilters) return; // don't bother doing work if there's nothing to do
|
||||||
|
|
||||||
console.log(`Recalculating filtered rooms for ${tagId}`);
|
console.log(`Recalculating filtered rooms for ${tagId}`);
|
||||||
delete this.filteredRooms[tagId];
|
delete this.filteredRooms[tagId];
|
||||||
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
|
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
|
||||||
|
@ -458,14 +471,7 @@ export class Algorithm extends EventEmitter {
|
||||||
|
|
||||||
// Now process all the joined rooms. This is a bit more complicated
|
// Now process all the joined rooms. This is a bit more complicated
|
||||||
for (const room of memberships[EffectiveMembership.Join]) {
|
for (const room of memberships[EffectiveMembership.Join]) {
|
||||||
let tags = Object.keys(room.tags || {});
|
const tags = this.getTagsOfJoinedRoom(room);
|
||||||
|
|
||||||
if (tags.length === 0) {
|
|
||||||
// Check to see if it's a DM if it isn't anything else
|
|
||||||
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
|
|
||||||
tags = [DefaultTagID.DM];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let inTag = false;
|
let inTag = false;
|
||||||
if (tags.length > 0) {
|
if (tags.length > 0) {
|
||||||
|
@ -496,6 +502,39 @@ export class Algorithm extends EventEmitter {
|
||||||
this.updateTagsFromCache();
|
this.updateTagsFromCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTagsForRoom(room: Room): TagID[] {
|
||||||
|
// XXX: This duplicates a lot of logic from setKnownRooms above, but has a slightly
|
||||||
|
// different use case and therefore different performance curve
|
||||||
|
|
||||||
|
const tags: TagID[] = [];
|
||||||
|
|
||||||
|
const membership = getEffectiveMembership(room.getMyMembership());
|
||||||
|
if (membership === EffectiveMembership.Invite) {
|
||||||
|
tags.push(DefaultTagID.Invite);
|
||||||
|
} else if (membership === EffectiveMembership.Leave) {
|
||||||
|
tags.push(DefaultTagID.Archived);
|
||||||
|
} else {
|
||||||
|
tags.push(...this.getTagsOfJoinedRoom(room));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tags.length) tags.push(DefaultTagID.Untagged);
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTagsOfJoinedRoom(room: Room): TagID[] {
|
||||||
|
let tags = Object.keys(room.tags || {});
|
||||||
|
|
||||||
|
if (tags.length === 0) {
|
||||||
|
// Check to see if it's a DM if it isn't anything else
|
||||||
|
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
|
||||||
|
tags = [DefaultTagID.DM];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the roomsToTags map
|
* Updates the roomsToTags map
|
||||||
*/
|
*/
|
||||||
|
@ -566,6 +605,19 @@ export class Algorithm extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cause === RoomUpdateCause.NewRoom && !this.roomIdsToTags[room.roomId]) {
|
||||||
|
console.log(`[RoomListDebug] Updating tags for new room ${room.roomId} (${room.name})`);
|
||||||
|
|
||||||
|
// Get the tags for the room and populate the cache
|
||||||
|
const roomTags = this.getTagsForRoom(room).filter(t => !isNullOrUndefined(this.cachedRooms[t]));
|
||||||
|
|
||||||
|
// "This should never happen" condition - we specify DefaultTagID.Untagged in getTagsForRoom(),
|
||||||
|
// which means we should *always* have a tag to go off of.
|
||||||
|
if (!roomTags.length) throw new Error(`Tags cannot be determined for ${room.roomId}`);
|
||||||
|
|
||||||
|
this.roomIdsToTags[room.roomId] = roomTags;
|
||||||
|
}
|
||||||
|
|
||||||
let tags = this.roomIdsToTags[room.roomId];
|
let tags = this.roomIdsToTags[room.roomId];
|
||||||
if (!tags) {
|
if (!tags) {
|
||||||
console.warn(`No tags known for "${room.name}" (${room.roomId})`);
|
console.warn(`No tags known for "${room.name}" (${room.roomId})`);
|
||||||
|
|
Loading…
Reference in a new issue