Fix space hierarchy not updating when user mutates it

This commit is contained in:
Michael Telatynski 2021-07-28 19:08:59 +01:00
parent 5d9e421de0
commit ed950875e7
5 changed files with 57 additions and 42 deletions

View file

@ -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 = ({
</React.Fragment>;
};
// mutate argument refreshToken to force a reload
export const useSpaceSummary = (cli: MatrixClient, space: Room, refreshToken?: any): [
export const useSpaceSummary = (space: Room): [
null,
ISpaceSummaryRoom[],
Map<string, Map<string, ISpaceSummaryEvent>>?,
Map<string, Set<string>>?,
Map<string, Set<string>>?,
] | [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<string, Map<string, ISpaceSummaryEvent>>();
const childParentRelations = new EnhancedMap<string, Set<string>>();
@ -354,7 +363,6 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
space,
initialText = "",
showRoom,
refreshToken,
additionalButtons,
children,
}) => {
@ -364,7 +372,7 @@ export const SpaceHierarchy: React.FC<IHierarchyProps> = ({
const [selected, setSelected] = useState(new Map<string, Set<string>>()); // Map<parentId, Set<childId>>
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;

View file

@ -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 }) =>
</div>;
};
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);
}
}}
/>
<IconizedContextMenuOption
label={_t("Add existing room")}
iconClassName="mx_RoomList_iconHash"
onClick={async (e) => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
closeMenu();
const [added] = await showAddExistingRooms(space);
if (added) {
onNewRoomAdded();
}
showAddExistingRooms(space);
}}
/>
<IconizedContextMenuOption
label={_t("Add subspace")}
iconClassName="mx_RoomList_iconPlus"
onClick={async (e) => {
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
closeMenu();
const [added] = await showCreateNewSubspace(space);
if (added) {
onNewRoomAdded();
}
showCreateNewSubspace(space);
}}
>
<BetaPill />
@ -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 = <SpaceLandingAddButton space={space} onNewRoomAdded={forceUpdate} />;
addRoomButton = <SpaceLandingAddButton space={space} />;
}
let settingsButton;
@ -470,12 +459,7 @@ const SpaceLanding = ({ space }) => {
<SpaceFeedbackPrompt />
<hr />
<SpaceHierarchy
space={space}
showRoom={showRoom}
refreshToken={refreshToken}
additionalButtons={addRoomButton}
/>
<SpaceHierarchy space={space} showRoom={showRoom} additionalButtons={addRoomButton} />
</div>;
};

View file

@ -249,7 +249,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
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;
}

View file

@ -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",
}

View file

@ -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<boolean> => {
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]>;
);
};