Respect tombstones in locally known rooms for Space children
							parent
							
								
									b86d646fa7
								
							
						
					
					
						commit
						fa800796c7
					
				|  | @ -15,17 +15,17 @@ limitations under the License. | |||
| */ | ||||
| 
 | ||||
| import React, { | ||||
|     Dispatch, | ||||
|     KeyboardEvent, | ||||
|     KeyboardEventHandler, | ||||
|     ReactNode, | ||||
|     SetStateAction, | ||||
|     useCallback, | ||||
|     useContext, | ||||
|     useEffect, | ||||
|     useMemo, | ||||
|     useRef, | ||||
|     useState, | ||||
|     KeyboardEvent, | ||||
|     KeyboardEventHandler, | ||||
|     useContext, | ||||
|     SetStateAction, | ||||
|     Dispatch, | ||||
| } from "react"; | ||||
| import { Room } from "matrix-js-sdk/src/models/room"; | ||||
| 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 { MatrixClient } from "matrix-js-sdk/src/matrix"; | ||||
| 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 defaultDispatcher from "../../dispatcher/dispatcher"; | ||||
|  | @ -48,7 +49,7 @@ import { mediaFromMxc } from "../../customisations/Media"; | |||
| import InfoTooltip from "../views/elements/InfoTooltip"; | ||||
| import TextWithTooltip from "../views/elements/TextWithTooltip"; | ||||
| import { useStateToggle } from "../../hooks/useStateToggle"; | ||||
| import { getChildOrder } from "../../stores/SpaceStore"; | ||||
| import SpaceStore, { getChildOrder } from "../../stores/SpaceStore"; | ||||
| import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; | ||||
| import { linkifyElement } from "../../HtmlUtils"; | ||||
| import { useDispatcher } from "../../hooks/useDispatcher"; | ||||
|  | @ -333,6 +334,29 @@ interface IHierarchyLevelProps { | |||
|     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 = ({ | ||||
|     root, | ||||
|     roomSet, | ||||
|  | @ -350,10 +374,11 @@ export const HierarchyLevel = ({ | |||
|         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 room = hierarchy.roomMap.get(ev.state_key); | ||||
|         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; | ||||
|     }, [[] as IHierarchyRoom[], [] as IHierarchyRoom[]]); | ||||
|  | @ -361,7 +386,7 @@ export const HierarchyLevel = ({ | |||
|     const newParents = new Set(parents).add(root.room_id); | ||||
|     return <React.Fragment> | ||||
|         { | ||||
|             childRooms.map(room => ( | ||||
|             uniqBy(childRooms, "room_id").map(room => ( | ||||
|                 <Tile | ||||
|                     key={room.room_id} | ||||
|                     room={room} | ||||
|  |  | |||
|  | @ -283,7 +283,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> { | |||
|             const createTs = childRoom?.currentState.getStateEvents(EventType.RoomCreate, "")?.getTs(); | ||||
|             return getChildOrder(ev.getContent().order, createTs, roomId); | ||||
|         }).map(ev => { | ||||
|             return this.matrixClient.getRoom(ev.getStateKey()); | ||||
|             return this.matrixClient.getRoom(this.findMostUpgradedVersion(ev.getStateKey())); | ||||
|         }).filter(room => { | ||||
|             return room?.getMyMembership() === "join" || room?.getMyMembership() === "invite"; | ||||
|         }) || []; | ||||
|  | @ -452,6 +452,28 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> { | |||
|         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(() => { | ||||
|         // TODO resolve some updates as deltas
 | ||||
|         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 => { | ||||
|             // traverse each space tree in DFS to build up the supersets as you go up,
 | ||||
|             // reusing results from like subtrees.
 | ||||
|  | @ -491,7 +514,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> { | |||
|                 } | ||||
| 
 | ||||
|                 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); | ||||
| 
 | ||||
|                 // Add relevant DMs
 | ||||
|  | @ -505,11 +528,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> { | |||
|                 const newPath = new Set(parentPath).add(spaceId); | ||||
|                 childSpaces.forEach(childSpace => { | ||||
|                     fn(childSpace.roomId, newPath)?.forEach(roomId => { | ||||
|                         roomIds.add(roomId); | ||||
|                         roomIds.add(this.findMostUpgradedVersion(roomId, upgradedRoomMap)); | ||||
|                     }); | ||||
|                 }); | ||||
|                 hiddenChildren.get(spaceId)?.forEach(roomId => { | ||||
|                     roomIds.add(roomId); | ||||
|                     roomIds.add(this.findMostUpgradedVersion(roomId, upgradedRoomMap)); | ||||
|                 }); | ||||
|                 this.spaceFilteredRooms.set(spaceId, roomIds); | ||||
|                 return roomIds; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Michael Telatynski
						Michael Telatynski