diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 997d86e0dc..904ada4090 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -766,6 +766,15 @@ export class RoomView extends React.Component { newState.search = undefined; } + if ( + room && + this.getMainSplitContentType(room) !== MainSplitContentType.Timeline && + newState.initialEventId !== this.state.initialEventId + ) { + // Ensure the right panel timeline is open to show the linked event + this.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline }, true, room.roomId); + } + this.setState(newState as IRoomState); // At this point, newState.roomId could be null (e.g. the alias might not // have been resolved yet) so anything called here must handle this case. diff --git a/test/unit-tests/components/structures/RoomView-test.tsx b/test/unit-tests/components/structures/RoomView-test.tsx index 58a26ab73e..1abdd91f20 100644 --- a/test/unit-tests/components/structures/RoomView-test.tsx +++ b/test/unit-tests/components/structures/RoomView-test.tsx @@ -22,32 +22,32 @@ import { RoomStateEvent, SearchResult, } from "matrix-js-sdk/src/matrix"; -import { type CryptoApi, UserVerificationStatus, CryptoEvent } from "matrix-js-sdk/src/crypto-api"; +import { type CryptoApi, CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { - fireEvent, - render, - screen, - type RenderResult, - waitForElementToBeRemoved, - waitFor, act, cleanup, + fireEvent, + render, + type RenderResult, + screen, + waitFor, + waitForElementToBeRemoved, } from "jest-matrix-react"; import userEvent from "@testing-library/user-event"; import { - stubClient, - mockPlatformPeg, - unmockPlatformPeg, + createTestClient, + emitPromise, + filterConsole, flushPromises, mkEvent, - setupAsyncStoreWithClient, - filterConsole, mkRoomMemberJoinEvent, mkThirdPartyInviteEvent, - emitPromise, - createTestClient, + mockPlatformPeg, + setupAsyncStoreWithClient, + stubClient, + unmockPlatformPeg, untilDispatch, } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; @@ -628,6 +628,26 @@ describe("RoomView", () => { const { asFragment } = await mountRoomView(); expect(asFragment()).toMatchSnapshot(); }); + + it("should open timeline card when navigating to permalink", async () => { + jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join); + await mountRoomView(); + + stores.rightPanelStore.setCard({ phase: RightPanelPhases.RoomSummary }); + + expect(stores.rightPanelStore.isOpen).toEqual(true); + expect(stores.rightPanelStore.currentCard.phase).not.toEqual(RightPanelPhases.Timeline); + + await stores.roomViewStore.viewRoom({ + action: Action.ViewRoom, + room_id: stores.roomViewStore.getRoomId()!, + event_id: "$eventId", + metricsTrigger: undefined, + }); + + expect(stores.rightPanelStore.isOpen).toEqual(true); + expect(stores.rightPanelStore.currentCard.phase).toEqual(RightPanelPhases.Timeline); + }); }); describe("for a local room", () => { diff --git a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap index 6858a9a6dd..1b0165991b 100644 --- a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap +++ b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap @@ -385,7 +385,7 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] = >