Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

When joining room in sub-space join the parents too #11011

Merged
merged 11 commits into from
Jun 1, 2023
20 changes: 13 additions & 7 deletions src/components/structures/SpaceHierarchy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { IHierarchyRelation, IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces";
import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import { ClientEvent, MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix";
import classNames from "classnames";
import { sortBy, uniqBy } from "lodash";
import { GuestAccess, HistoryVisibility } from "matrix-js-sdk/src/@types/partials";
Expand Down Expand Up @@ -101,7 +101,7 @@ const Tile: React.FC<ITileProps> = ({
children,
}) => {
const cli = useContext(MatrixClientContext);
const [joinedRoom, setJoinedRoom] = useState<Room | undefined>(() => {
const joinedRoom = useTypedEventEmitterState(cli, ClientEvent.Room, () => {
const cliRoom = cli?.getRoom(room.room_id);
return cliRoom?.getMyMembership() === "join" ? cliRoom : undefined;
});
Expand All @@ -128,7 +128,6 @@ const Tile: React.FC<ITileProps> = ({
ev.stopPropagation();
onJoinRoomClick()
.then(() => awaitRoomDownSync(cli, room.room_id))
.then(setJoinedRoom)
.finally(() => {
setBusy(false);
});
Expand Down Expand Up @@ -429,7 +428,7 @@ interface IHierarchyLevelProps {
parents: Set<string>;
selectedMap?: Map<string, Set<string>>;
onViewRoomClick(roomId: string, roomType?: RoomType): void;
onJoinRoomClick(roomId: string): Promise<unknown>;
onJoinRoomClick(roomId: string, parents: Set<string>): Promise<unknown>;
onToggleClick?(parentId: string, childId: string): void;
}

Expand Down Expand Up @@ -511,7 +510,7 @@ export const HierarchyLevel: React.FC<IHierarchyLevelProps> = ({
suggested={hierarchy.isSuggested(root.room_id, room.room_id)}
selected={selectedMap?.get(root.room_id)?.has(room.room_id)}
onViewRoomClick={() => onViewRoomClick(room.room_id, room.room_type as RoomType)}
onJoinRoomClick={() => onJoinRoomClick(room.room_id)}
onJoinRoomClick={() => onJoinRoomClick(room.room_id, newParents)}
hasPermissions={hasPermissions}
onToggleClick={onToggleClick ? () => onToggleClick(root.room_id, room.room_id) : undefined}
/>
Expand All @@ -532,7 +531,7 @@ export const HierarchyLevel: React.FC<IHierarchyLevelProps> = ({
suggested={hierarchy.isSuggested(root.room_id, space.room_id)}
selected={selectedMap?.get(root.room_id)?.has(space.room_id)}
onViewRoomClick={() => onViewRoomClick(space.room_id, RoomType.Space)}
onJoinRoomClick={() => onJoinRoomClick(space.room_id)}
onJoinRoomClick={() => onJoinRoomClick(space.room_id, newParents)}
hasPermissions={hasPermissions}
onToggleClick={onToggleClick ? () => onToggleClick(root.room_id, space.room_id) : undefined}
>
Expand Down Expand Up @@ -839,7 +838,14 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
selectedMap={selected}
onToggleClick={hasPermissions ? onToggleClick : undefined}
onViewRoomClick={(roomId, roomType) => showRoom(cli, hierarchy, roomId, roomType)}
onJoinRoomClick={(roomId) => joinRoom(cli, hierarchy, roomId)}
onJoinRoomClick={async (roomId, parents) => {
for (const parent of parents) {
if (cli.getRoom(parent)?.getMyMembership() !== "join") {
await joinRoom(cli, hierarchy, parent);
}
}
await joinRoom(cli, hierarchy, roomId);
}}
/>
</>
);
Expand Down
87 changes: 64 additions & 23 deletions test/components/structures/SpaceHierarchy-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import React from "react";
import { mocked } from "jest-mock";
import { render } from "@testing-library/react";
import { fireEvent, render } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomHierarchy } from "matrix-js-sdk/src/room-hierarchy";
Expand Down Expand Up @@ -167,13 +167,21 @@ describe("SpaceHierarchy", () => {
} as unknown as DMRoomMap;
jest.spyOn(DMRoomMap, "shared").mockReturnValue(dmRoomMap);

const root = mkStubRoom("room-id-1", "Room 1", client);
const room1 = mkStubRoom("room-id-2", "Room 2", client);
const room2 = mkStubRoom("room-id-3", "Room 3", client);
const root = mkStubRoom("space-id-1", "Space 1", client);
const room1 = mkStubRoom("room-id-2", "Room 1", client);
const room2 = mkStubRoom("room-id-3", "Room 2", client);
const space1 = mkStubRoom("space-id-4", "Space 2", client);
const room3 = mkStubRoom("room-id-5", "Room 3", client);
mocked(client.getRooms).mockReturnValue([root]);
mocked(client.getRoom).mockImplementation(
(roomId) => client.getRooms().find((room) => room.roomId === roomId) ?? null,
);
[room1, room2, space1, room3].forEach((r) => mocked(r.getMyMembership).mockReturnValue("leave"));

const hierarchyRoot = {
room_id: root.roomId,
num_joined_members: 1,
room_type: "m.space",
children_state: [
{
state_key: room1.roomId,
Expand All @@ -183,39 +191,72 @@ describe("SpaceHierarchy", () => {
state_key: room2.roomId,
content: { order: "2" },
},
{
state_key: space1.roomId,
content: { order: "3" },
},
],
} as IHierarchyRoom;
const hierarchyRoom1 = { room_id: room1.roomId, num_joined_members: 2 } as IHierarchyRoom;
const hierarchyRoom2 = { room_id: root.roomId, num_joined_members: 3 } as IHierarchyRoom;
const hierarchyRoom2 = { room_id: room2.roomId, num_joined_members: 3 } as IHierarchyRoom;
const hierarchyRoom3 = {
name: "Nested room",
room_id: room3.roomId,
num_joined_members: 3,
} as IHierarchyRoom;
const hierarchySpace1 = {
room_id: space1.roomId,
name: "Nested space",
num_joined_members: 1,
room_type: "m.space",
children_state: [
{
state_key: room3.roomId,
content: { order: "1" },
},
],
} as IHierarchyRoom;

const roomHierarchy = {
roomMap: new Map([
[root.roomId, hierarchyRoot],
[space1.roomId, hierarchySpace1],
[room1.roomId, hierarchyRoom1],
[room2.roomId, hierarchyRoom2],
[room3.roomId, hierarchyRoom3],
]),
isSuggested: jest.fn(),
} as unknown as RoomHierarchy;

const defaultProps = {
root: hierarchyRoot,
roomSet: new Set([hierarchyRoom1, hierarchyRoom2, hierarchySpace1, hierarchyRoom3]),
hierarchy: roomHierarchy,
parents: new Set<string>(),
selectedMap: new Map<string, Set<string>>(),
onViewRoomClick: jest.fn(),
onJoinRoomClick: jest.fn(),
onToggleClick: jest.fn(),
};
const getComponent = (props = {}): React.ReactElement => (
<MatrixClientContext.Provider value={client}>
<HierarchyLevel {...defaultProps} {...props} />;
</MatrixClientContext.Provider>
);

it("renders", () => {
const defaultProps = {
root: hierarchyRoot,
roomSet: new Set([hierarchyRoom1, hierarchyRoom2]),
hierarchy: roomHierarchy,
parents: new Set<string>(),
selectedMap: new Map<string, Set<string>>(),
onViewRoomClick: jest.fn(),
onJoinRoomClick: jest.fn(),
onToggleClick: jest.fn(),
};
const getComponent = (props = {}): React.ReactElement => (
<MatrixClientContext.Provider value={client}>
<HierarchyLevel {...defaultProps} {...props} />;
</MatrixClientContext.Provider>
);

const { container } = render(getComponent());
expect(container).toMatchSnapshot();
const { asFragment } = render(getComponent());
expect(asFragment()).toMatchSnapshot();
});

it("should join subspace when joining nested room", async () => {
const onJoinRoomClick = jest.fn().mockResolvedValue({});

const { getByText } = render(getComponent({ onJoinRoomClick }));
const button = getByText("Nested room")!.closest("li")!.querySelector(".mx_AccessibleButton_kind_primary")!;
fireEvent.click(button);

expect(onJoinRoomClick).toHaveBeenCalledWith(room3.roomId, new Set([root.roomId, space1.roomId]));
});
});
});
Loading