Respect tombstones in locally known rooms for Space children
This commit is contained in:
parent
b86d646fa7
commit
fa800796c7
2 changed files with 61 additions and 13 deletions
|
@ -15,17 +15,17 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {
|
import React, {
|
||||||
|
Dispatch,
|
||||||
|
KeyboardEvent,
|
||||||
|
KeyboardEventHandler,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
|
SetStateAction,
|
||||||
useCallback,
|
useCallback,
|
||||||
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
KeyboardEvent,
|
|
||||||
KeyboardEventHandler,
|
|
||||||
useContext,
|
|
||||||
SetStateAction,
|
|
||||||
Dispatch,
|
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
|
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
|
||||||
|
@ -33,7 +33,8 @@ import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
|
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { sortBy } from "lodash";
|
import { sortBy, uniqBy } from "lodash";
|
||||||
|
import { GuestAccess, HistoryVisibility } from "matrix-js-sdk/src/@types/partials";
|
||||||
|
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
|
@ -48,7 +49,7 @@ import { mediaFromMxc } from "../../customisations/Media";
|
||||||
import InfoTooltip from "../views/elements/InfoTooltip";
|
import InfoTooltip from "../views/elements/InfoTooltip";
|
||||||
import TextWithTooltip from "../views/elements/TextWithTooltip";
|
import TextWithTooltip from "../views/elements/TextWithTooltip";
|
||||||
import { useStateToggle } from "../../hooks/useStateToggle";
|
import { useStateToggle } from "../../hooks/useStateToggle";
|
||||||
import { getChildOrder } from "../../stores/SpaceStore";
|
import SpaceStore, { getChildOrder } from "../../stores/SpaceStore";
|
||||||
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
||||||
import { linkifyElement } from "../../HtmlUtils";
|
import { linkifyElement } from "../../HtmlUtils";
|
||||||
import { useDispatcher } from "../../hooks/useDispatcher";
|
import { useDispatcher } from "../../hooks/useDispatcher";
|
||||||
|
@ -333,6 +334,29 @@ interface IHierarchyLevelProps {
|
||||||
onToggleClick?(parentId: string, childId: string): void;
|
onToggleClick?(parentId: string, childId: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom, upgradedRoomMap: Map<string, string>): IHierarchyRoom => {
|
||||||
|
const cliRoom = cli.getRoom(SpaceStore.instance.findMostUpgradedVersion(room.room_id, upgradedRoomMap));
|
||||||
|
if (cliRoom) {
|
||||||
|
return {
|
||||||
|
...room,
|
||||||
|
room_id: cliRoom.roomId,
|
||||||
|
room_type: cliRoom.getType(),
|
||||||
|
name: cliRoom.name,
|
||||||
|
topic: cliRoom.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent().topic,
|
||||||
|
avatar_url: cliRoom.getMxcAvatarUrl(),
|
||||||
|
canonical_alias: cliRoom.getCanonicalAlias(),
|
||||||
|
aliases: cliRoom.getAltAliases(),
|
||||||
|
world_readable: cliRoom.currentState.getStateEvents(EventType.RoomHistoryVisibility, "")?.getContent()
|
||||||
|
.history_visibility === HistoryVisibility.WorldReadable,
|
||||||
|
guest_can_join: cliRoom.currentState.getStateEvents(EventType.RoomGuestAccess, "")?.getContent()
|
||||||
|
.guest_access === GuestAccess.CanJoin,
|
||||||
|
num_joined_members: cliRoom.getJoinedMemberCount(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return room;
|
||||||
|
};
|
||||||
|
|
||||||
export const HierarchyLevel = ({
|
export const HierarchyLevel = ({
|
||||||
root,
|
root,
|
||||||
roomSet,
|
roomSet,
|
||||||
|
@ -350,10 +374,11 @@ export const HierarchyLevel = ({
|
||||||
return getChildOrder(ev.content.order, ev.origin_server_ts, ev.state_key);
|
return getChildOrder(ev.content.order, ev.origin_server_ts, ev.state_key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const upgradedRoomMap = new Map<string, string>();
|
||||||
const [subspaces, childRooms] = sortedChildren.reduce((result, ev: IHierarchyRelation) => {
|
const [subspaces, childRooms] = sortedChildren.reduce((result, ev: IHierarchyRelation) => {
|
||||||
const room = hierarchy.roomMap.get(ev.state_key);
|
const room = hierarchy.roomMap.get(ev.state_key);
|
||||||
if (room && roomSet.has(room)) {
|
if (room && roomSet.has(room)) {
|
||||||
result[room.room_type === RoomType.Space ? 0 : 1].push(room);
|
result[room.room_type === RoomType.Space ? 0 : 1].push(toLocalRoom(cli, room, upgradedRoomMap));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, [[] as IHierarchyRoom[], [] as IHierarchyRoom[]]);
|
}, [[] as IHierarchyRoom[], [] as IHierarchyRoom[]]);
|
||||||
|
@ -361,7 +386,7 @@ export const HierarchyLevel = ({
|
||||||
const newParents = new Set(parents).add(root.room_id);
|
const newParents = new Set(parents).add(root.room_id);
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{
|
{
|
||||||
childRooms.map(room => (
|
uniqBy(childRooms, "room_id").map(room => (
|
||||||
<Tile
|
<Tile
|
||||||
key={room.room_id}
|
key={room.room_id}
|
||||||
room={room}
|
room={room}
|
||||||
|
|
|
@ -283,7 +283,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
const createTs = childRoom?.currentState.getStateEvents(EventType.RoomCreate, "")?.getTs();
|
const createTs = childRoom?.currentState.getStateEvents(EventType.RoomCreate, "")?.getTs();
|
||||||
return getChildOrder(ev.getContent().order, createTs, roomId);
|
return getChildOrder(ev.getContent().order, createTs, roomId);
|
||||||
}).map(ev => {
|
}).map(ev => {
|
||||||
return this.matrixClient.getRoom(ev.getStateKey());
|
return this.matrixClient.getRoom(this.findMostUpgradedVersion(ev.getStateKey()));
|
||||||
}).filter(room => {
|
}).filter(room => {
|
||||||
return room?.getMyMembership() === "join" || room?.getMyMembership() === "invite";
|
return room?.getMyMembership() === "join" || room?.getMyMembership() === "invite";
|
||||||
}) || [];
|
}) || [];
|
||||||
|
@ -452,6 +452,28 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
this.onRoomsUpdate();
|
this.onRoomsUpdate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Utility to walk tombstones and find the most updated variant of the given room,
|
||||||
|
// takes a Map to enable caching of the responses given the recursive nature of the function.
|
||||||
|
public findMostUpgradedVersion(
|
||||||
|
roomId: string,
|
||||||
|
upgradedRoomMap?: Map<string, string>,
|
||||||
|
seen= new Set<string>(),
|
||||||
|
): string {
|
||||||
|
if (seen.has(roomId)) return roomId;
|
||||||
|
if (upgradedRoomMap?.has(roomId)) return upgradedRoomMap.get(roomId);
|
||||||
|
const room = this.matrixClient.getRoom(roomId);
|
||||||
|
const tombstone = room?.currentState.getStateEvents(EventType.RoomTombstone, "");
|
||||||
|
const replacementRoom = tombstone?.getContent().replacement_room;
|
||||||
|
if (replacementRoom && this.matrixClient.getRoom(replacementRoom)?.getMyMembership() === "join") {
|
||||||
|
seen.add(roomId);
|
||||||
|
const result = this.findMostUpgradedVersion(replacementRoom, upgradedRoomMap);
|
||||||
|
upgradedRoomMap?.set(roomId, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
upgradedRoomMap?.set(roomId, roomId);
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
private onRoomsUpdate = throttle(() => {
|
private onRoomsUpdate = throttle(() => {
|
||||||
// TODO resolve some updates as deltas
|
// TODO resolve some updates as deltas
|
||||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
const visibleRooms = this.matrixClient.getVisibleRooms();
|
||||||
|
@ -479,6 +501,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const upgradedRoomMap = new Map<string, string>();
|
||||||
this.rootSpaces.forEach(s => {
|
this.rootSpaces.forEach(s => {
|
||||||
// traverse each space tree in DFS to build up the supersets as you go up,
|
// traverse each space tree in DFS to build up the supersets as you go up,
|
||||||
// reusing results from like subtrees.
|
// reusing results from like subtrees.
|
||||||
|
@ -491,7 +514,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const [childSpaces, childRooms] = partitionSpacesAndRooms(this.getChildren(spaceId));
|
const [childSpaces, childRooms] = partitionSpacesAndRooms(this.getChildren(spaceId));
|
||||||
const roomIds = new Set(childRooms.map(r => r.roomId));
|
const roomIds = new Set(childRooms.map(r => this.findMostUpgradedVersion(r.roomId, upgradedRoomMap)));
|
||||||
const space = this.matrixClient?.getRoom(spaceId);
|
const space = this.matrixClient?.getRoom(spaceId);
|
||||||
|
|
||||||
// Add relevant DMs
|
// Add relevant DMs
|
||||||
|
@ -505,11 +528,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||||
const newPath = new Set(parentPath).add(spaceId);
|
const newPath = new Set(parentPath).add(spaceId);
|
||||||
childSpaces.forEach(childSpace => {
|
childSpaces.forEach(childSpace => {
|
||||||
fn(childSpace.roomId, newPath)?.forEach(roomId => {
|
fn(childSpace.roomId, newPath)?.forEach(roomId => {
|
||||||
roomIds.add(roomId);
|
roomIds.add(this.findMostUpgradedVersion(roomId, upgradedRoomMap));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
hiddenChildren.get(spaceId)?.forEach(roomId => {
|
hiddenChildren.get(spaceId)?.forEach(roomId => {
|
||||||
roomIds.add(roomId);
|
roomIds.add(this.findMostUpgradedVersion(roomId, upgradedRoomMap));
|
||||||
});
|
});
|
||||||
this.spaceFilteredRooms.set(spaceId, roomIds);
|
this.spaceFilteredRooms.set(spaceId, roomIds);
|
||||||
return roomIds;
|
return roomIds;
|
||||||
|
|
Loading…
Reference in a new issue