From ed950875e7d3cf8f38cf8b787f4376c08d34a173 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 28 Jul 2021 19:08:59 +0100 Subject: [PATCH] Fix space hierarchy not updating when user mutates it --- .../structures/SpaceRoomDirectory.tsx | 20 +++++++--- src/components/structures/SpaceRoomView.tsx | 32 ++++----------- .../dialogs/AddExistingToSpaceDialog.tsx | 2 +- src/dispatcher/actions.ts | 5 +++ src/utils/space.tsx | 40 ++++++++++++++----- 5 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 038c1df514..610ac5e103 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -44,11 +44,13 @@ import { getChildOrder } from "../../stores/SpaceStore"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; import { linkifyElement } from "../../HtmlUtils"; import { getDisplayAliasForAliasSet } from "../../Rooms"; +import { useDispatcher } from "../../hooks/useDispatcher"; +import defaultDispatcher from "../../dispatcher/dispatcher"; +import { Action } from "../../dispatcher/actions"; interface IHierarchyProps { space: Room; initialText?: string; - refreshToken?: any; additionalButtons?: ReactNode; showRoom(room: ISpaceSummaryRoom, viaServers?: string[], autoJoin?: boolean): void; } @@ -315,18 +317,25 @@ export const HierarchyLevel = ({ ; }; -// mutate argument refreshToken to force a reload -export const useSpaceSummary = (cli: MatrixClient, space: Room, refreshToken?: any): [ +export const useSpaceSummary = (space: Room): [ null, ISpaceSummaryRoom[], Map>?, Map>?, Map>?, ] | [Error] => { + // crude temporary refresh token approach until we have pagination and rework the data flow here + const [refreshToken, setRefreshToken] = useState(0); + useDispatcher(defaultDispatcher, (payload => { + if (payload.action === Action.UpdateSpaceHierarchy) { + setRefreshToken(t => t + 1); + } + })); + // TODO pagination return useAsyncMemo(async () => { try { - const data = await cli.getSpaceSummary(space.roomId); + const data = await space.client.getSpaceSummary(space.roomId); const parentChildRelations = new EnhancedMap>(); const childParentRelations = new EnhancedMap>(); @@ -354,7 +363,6 @@ export const SpaceHierarchy: React.FC = ({ space, initialText = "", showRoom, - refreshToken, additionalButtons, children, }) => { @@ -364,7 +372,7 @@ export const SpaceHierarchy: React.FC = ({ const [selected, setSelected] = useState(new Map>()); // Map> - const [summaryError, rooms, parentChildMap, viaMap, childParentMap] = useSpaceSummary(cli, space, refreshToken); + const [summaryError, rooms, parentChildMap, viaMap, childParentMap] = useSpaceSummary(space); const roomsMap = useMemo(() => { if (!rooms) return null; diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index cf5cad1651..5829578cd2 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -56,7 +56,6 @@ import { } from "../../utils/space"; import { showRoom, SpaceHierarchy } from "./SpaceRoomDirectory"; import MemberAvatar from "../views/avatars/MemberAvatar"; -import { useStateToggle } from "../../hooks/useStateToggle"; import SpaceStore from "../../stores/SpaceStore"; import FacePile from "../views/elements/FacePile"; import { @@ -318,7 +317,7 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) => ; }; -const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { +const SpaceLandingAddButton = ({ space }) => { const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); let contextMenu; @@ -342,36 +341,28 @@ const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { closeMenu(); if (await showCreateNewRoom(space)) { - onNewRoomAdded(); + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); } }} /> { + onClick={(e) => { e.preventDefault(); e.stopPropagation(); closeMenu(); - - const [added] = await showAddExistingRooms(space); - if (added) { - onNewRoomAdded(); - } + showAddExistingRooms(space); }} /> { + onClick={(e) => { e.preventDefault(); e.stopPropagation(); closeMenu(); - - const [added] = await showCreateNewSubspace(space); - if (added) { - onNewRoomAdded(); - } + showCreateNewSubspace(space); }} > @@ -416,11 +407,9 @@ const SpaceLanding = ({ space }) => { const canAddRooms = myMembership === "join" && space.currentState.maySendStateEvent(EventType.SpaceChild, userId); - const [refreshToken, forceUpdate] = useStateToggle(false); - let addRoomButton; if (canAddRooms) { - addRoomButton = ; + addRoomButton = ; } let settingsButton; @@ -470,12 +459,7 @@ const SpaceLanding = ({ space }) => {
- + ; }; diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 7194f3d7e2..9b64af0c80 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -249,7 +249,7 @@ export const AddExistingToSpace: React.FC = ({ let noResults = true; if ((roomsRenderer && rooms.length > 0) || (dmsRenderer && dms.length > 0) || - (!roomsRenderer && !dmsRenderer && spacesRenderer && dms.length > 0) // only count spaces when alone + (!roomsRenderer && !dmsRenderer && spacesRenderer && spaces.length > 0) // only count spaces when alone ) { noResults = false; } diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 5732428201..06cbbba46c 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -193,4 +193,9 @@ export enum Action { * Switches space. Should be used with SwitchSpacePayload. */ SwitchSpace = "switch_space", + + /** + * Signals to the visible space hierarchy that a change has occurred an that it should refresh. + */ + UpdateSpaceHierarchy = "update_space_hierarchy", } diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 1e8a6fbeaf..e705b4eee4 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -30,6 +30,9 @@ import InfoDialog from "../components/views/dialogs/InfoDialog"; import { showRoomInviteDialog } from "../RoomInvite"; import CreateSubspaceDialog from "../components/views/dialogs/CreateSubspaceDialog"; import AddExistingSubspaceDialog from "../components/views/dialogs/AddExistingSubspaceDialog"; +import defaultDispatcher from "../dispatcher/dispatcher"; +import RoomViewStore from "../stores/RoomViewStore"; +import { Action } from "../dispatcher/actions"; export const shouldShowSpaceSettings = (space: Room) => { const userId = space.client.getUserId(); @@ -56,8 +59,8 @@ export const showSpaceSettings = (space: Room) => { }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); }; -export const showAddExistingRooms = async (space: Room): Promise<[boolean]> => { - return Modal.createTrackedDialog( +export const showAddExistingRooms = (space: Room): void => { + Modal.createTrackedDialog( "Space Landing", "Add Existing", AddExistingToSpaceDialog, @@ -65,12 +68,17 @@ export const showAddExistingRooms = async (space: Room): Promise<[boolean]> => { onCreateRoomClick: () => showCreateNewRoom(space), onAddSubspaceClick: () => showAddExistingSubspace(space), space, + onFinished: (added: boolean) => { + if (added && RoomViewStore.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } + }, }, "mx_AddExistingToSpaceDialog_wrapper", - ).finished as Promise<[boolean]>; + ); }; -export const showCreateNewRoom = async (space: Room) => { +export const showCreateNewRoom = async (space: Room): Promise => { const modal = Modal.createTrackedDialog<[boolean, IOpts]>( "Space Landing", "Create Room", @@ -87,7 +95,7 @@ export const showCreateNewRoom = async (space: Room) => { return shouldCreate; }; -export const showSpaceInvite = (space: Room, initialText = "") => { +export const showSpaceInvite = (space: Room, initialText = ""): void => { if (space.getJoinRule() === "public") { const modal = Modal.createTrackedDialog("Space Invite", "User Menu", InfoDialog, { title: _t("Invite to %(spaceName)s", { spaceName: space.name }), @@ -105,28 +113,38 @@ export const showSpaceInvite = (space: Room, initialText = "") => { } }; -export const showAddExistingSubspace = async (space: Room): Promise<[boolean]> => { - return Modal.createTrackedDialog( +export const showAddExistingSubspace = (space: Room): void => { + Modal.createTrackedDialog( "Space Landing", "Create Subspace", AddExistingSubspaceDialog, { space, onCreateSubspaceClick: () => showCreateNewSubspace(space), + onFinished: (added: boolean) => { + if (added && RoomViewStore.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } + }, }, "mx_AddExistingToSpaceDialog_wrapper", - ).finished as Promise<[boolean]>; + ); }; -export const showCreateNewSubspace = async (space: Room): Promise<[boolean]> => { - return Modal.createTrackedDialog( +export const showCreateNewSubspace = (space: Room): void => { + Modal.createTrackedDialog( "Space Landing", "Create Subspace", CreateSubspaceDialog, { space, onAddExistingSpaceClick: () => showAddExistingSubspace(space), + onFinished: (added: boolean) => { + if (added && RoomViewStore.getRoomId() === space.roomId) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } + }, }, "mx_CreateSubspaceDialog_wrapper", - ).finished as Promise<[boolean]>; + ); };