From 7236e48765c1464d7a4ec864f6ff663ac9d78d7c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 15 Jun 2023 12:57:58 +0100 Subject: [PATCH] Allow maintaining a different right panel width for thread panels (#11064) * Move Room context threadId our of RoomView state * Allow maintaining a different right panel width for thread panels * Fix types * Fix types * Add tests * Increase coverage * Increase coverage * Add comments * Update src/components/structures/MainSplit.tsx Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- src/components/structures/MainSplit.tsx | 33 +++++++++- src/components/structures/RoomView.tsx | 29 ++++++++- src/contexts/RoomContext.ts | 7 ++- test/components/structures/MainSplit-test.tsx | 63 +++++++++++++++++++ test/components/structures/RoomView-test.tsx | 1 + .../__snapshots__/MainSplit-test.tsx.snap | 61 ++++++++++++++++++ .../views/rooms/SendMessageComposer-test.tsx | 1 + test/test-utils/room.ts | 1 + test/test-utils/test-utils.ts | 1 + 9 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 test/components/structures/MainSplit-test.tsx create mode 100644 test/components/structures/__snapshots__/MainSplit-test.tsx.snap diff --git a/src/components/structures/MainSplit.tsx b/src/components/structures/MainSplit.tsx index ab29cd2b397..64b2e5c04fd 100644 --- a/src/components/structures/MainSplit.tsx +++ b/src/components/structures/MainSplit.tsx @@ -26,9 +26,24 @@ interface IProps { collapsedRhs?: boolean; panel?: JSX.Element; children: ReactNode; + /** + * A unique identifier for this panel split. + * + * This is appended to the key used to store the panel size in localStorage, allowing the widths of different + * panels to be stored. + */ + sizeKey?: string; + /** + * The size to use for the panel component if one isn't persisted in storage. Defaults to 350. + */ + defaultSize: number; } export default class MainSplit extends React.Component { + public static defaultProps = { + defaultSize: 350, + }; + private onResizeStart = (): void => { this.props.resizeNotifier.startResizing(); }; @@ -37,6 +52,14 @@ export default class MainSplit extends React.Component { this.props.resizeNotifier.notifyRightHandleResized(); }; + private get sizeSettingStorageKey(): string { + let key = "mx_rhs_size"; + if (!!this.props.sizeKey) { + key += `_${this.props.sizeKey}`; + } + return key; + } + private onResizeStop = ( event: MouseEvent | TouchEvent, direction: Direction, @@ -44,14 +67,17 @@ export default class MainSplit extends React.Component { delta: NumberSize, ): void => { this.props.resizeNotifier.stopResizing(); - window.localStorage.setItem("mx_rhs_size", (this.loadSidePanelSize().width + delta.width).toString()); + window.localStorage.setItem( + this.sizeSettingStorageKey, + (this.loadSidePanelSize().width + delta.width).toString(), + ); }; private loadSidePanelSize(): { height: string | number; width: number } { - let rhsSize = parseInt(window.localStorage.getItem("mx_rhs_size")!, 10); + let rhsSize = parseInt(window.localStorage.getItem(this.sizeSettingStorageKey)!, 10); if (isNaN(rhsSize)) { - rhsSize = 350; + rhsSize = this.props.defaultSize; } return { @@ -70,6 +96,7 @@ export default class MainSplit extends React.Component { if (hasResizer) { children = ( { showApps: false, isPeeking: false, showRightPanel: false, + threadRightPanel: false, joining: false, showTopUnreadMessagesBar: false, statusBarVisible: false, @@ -623,6 +628,11 @@ export class RoomView extends React.Component { mainSplitContentType: room ? this.getMainSplitContentType(room) : undefined, initialEventId: undefined, // default to clearing this, will get set later in the method if needed showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false, + threadRightPanel: roomId + ? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes( + this.context.rightPanelStore.currentCardForRoom(roomId).phase!, + ) + : false, activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null, }; @@ -1011,8 +1021,14 @@ export class RoomView extends React.Component { } private onRightPanelStoreUpdate = (): void => { + const { roomId } = this.state; this.setState({ - showRightPanel: this.state.roomId ? this.context.rightPanelStore.isOpenForRoom(this.state.roomId) : false, + showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false, + threadRightPanel: roomId + ? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes( + this.context.rightPanelStore.currentCardForRoom(roomId).phase!, + ) + : false, }); }; @@ -2439,7 +2455,14 @@ export class RoomView extends React.Component { viewingCall={viewingCall} activeCall={this.state.activeCall} /> - +
({ +const RoomContext = createContext< + IRoomState & { + threadId?: string; + } +>({ roomLoading: true, peekLoading: false, shouldPeek: true, @@ -39,6 +43,7 @@ const RoomContext = createContext({ showApps: false, isPeeking: false, showRightPanel: true, + threadRightPanel: false, joining: false, showTopUnreadMessagesBar: false, statusBarVisible: false, diff --git a/test/components/structures/MainSplit-test.tsx b/test/components/structures/MainSplit-test.tsx new file mode 100644 index 00000000000..f32a0720701 --- /dev/null +++ b/test/components/structures/MainSplit-test.tsx @@ -0,0 +1,63 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { render } from "@testing-library/react"; + +import MainSplit from "../../../src/components/structures/MainSplit"; +import ResizeNotifier from "../../../src/utils/ResizeNotifier"; + +describe("", () => { + const resizeNotifier = new ResizeNotifier(); + const children = ( +
+ ChildFooBar +
+ ); + const panel =
Right panel
; + + it("renders", () => { + const { asFragment, container } = render( + , + ); + expect(asFragment()).toMatchSnapshot(); + // Assert it matches the default width of 350 + expect(container.querySelector(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("350px"); + }); + + it("respects defaultSize prop", () => { + const { asFragment, container } = render( + , + ); + expect(asFragment()).toMatchSnapshot(); + // Assert it matches the default width of 350 + expect(container.querySelector(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("500px"); + }); + + it("prefers size stashed in LocalStorage to the defaultSize prop", () => { + localStorage.setItem("mx_rhs_size_thread", "333"); + const { container } = render( + , + ); + expect(container.querySelector(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("333px"); + }); +}); diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx index fadeb5c2c2e..61b987585b7 100644 --- a/test/components/structures/RoomView-test.tsx +++ b/test/components/structures/RoomView-test.tsx @@ -225,6 +225,7 @@ describe("RoomView", () => { }); it("updates url preview visibility on encryption state change", async () => { + room.getMyMembership = jest.fn().mockReturnValue("join"); // we should be starting unencrypted expect(cli.isCryptoEnabled()).toEqual(false); expect(cli.isRoomEncrypted(room.roomId)).toEqual(false); diff --git a/test/components/structures/__snapshots__/MainSplit-test.tsx.snap b/test/components/structures/__snapshots__/MainSplit-test.tsx.snap new file mode 100644 index 00000000000..d6cd2015941 --- /dev/null +++ b/test/components/structures/__snapshots__/MainSplit-test.tsx.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders 1`] = ` + +
+
+ Child + + Foo + + Bar +
+
+
+ Right panel +
+
+
+
+
+
+ +`; + +exports[` respects defaultSize prop 1`] = ` + +
+
+ Child + + Foo + + Bar +
+
+
+ Right panel +
+
+
+
+
+
+ +`; diff --git a/test/components/views/rooms/SendMessageComposer-test.tsx b/test/components/views/rooms/SendMessageComposer-test.tsx index 0d392c97c2a..bf9fb0e1851 100644 --- a/test/components/views/rooms/SendMessageComposer-test.tsx +++ b/test/components/views/rooms/SendMessageComposer-test.tsx @@ -57,6 +57,7 @@ describe("", () => { showApps: false, isPeeking: false, showRightPanel: true, + threadRightPanel: false, joining: false, atEndOfLiveTimeline: true, showTopUnreadMessagesBar: false, diff --git a/test/test-utils/room.ts b/test/test-utils/room.ts index 501afb947dc..2b5491dc789 100644 --- a/test/test-utils/room.ts +++ b/test/test-utils/room.ts @@ -61,6 +61,7 @@ export function getRoomContext(room: Room, override: Partial): IRoom showApps: false, isPeeking: false, showRightPanel: true, + threadRightPanel: false, joining: false, atEndOfLiveTimeline: true, showTopUnreadMessagesBar: false, diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 6eea4114d23..811290be17d 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -237,6 +237,7 @@ export function createTestClient(): MatrixClient { searchUserDirectory: jest.fn().mockResolvedValue({ limited: false, results: [] }), setDeviceVerified: jest.fn(), joinRoom: jest.fn(), + getSyncStateData: jest.fn(), } as unknown as MatrixClient; client.reEmitter = new ReEmitter(client);