diff --git a/.eslintrc.js b/.eslintrc.js index a1fe472db2..10e8238a77 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -46,6 +46,7 @@ module.exports = { "import/no-duplicates": ["error"], // Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell. + // Ban compound-design-tokens raw svg imports in favour of their React component counterparts "no-restricted-imports": [ "error", { @@ -150,6 +151,10 @@ module.exports = { message: "This regex doesn't actually test for emoji. See the docs at https://emojibase.dev/docs/regex/ and prefer our own EMOJI_REGEX from HtmlUtils.", }, + { + group: ["@vector-im/compound-design-tokens/icons/*"], + message: "Please use @vector-im/compound-design-tokens/assets/web/icons/* instead", + }, ], }, ], diff --git a/package.json b/package.json index 2df1926c8a..f658bf04b6 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ }, "dependencies": { "@babel/runtime": "^7.12.5", - "@matrix-org/analytics-events": "^0.25.0", + "@matrix-org/analytics-events": "^0.26.0", "@matrix-org/emojibase-bindings": "^1.1.2", "@matrix-org/matrix-wysiwyg": "2.37.9", "@matrix-org/react-sdk-module-api": "^2.4.0", diff --git a/playwright/snapshots/crypto/crypto.spec.ts/RoomSummaryCard-with-verified-e2ee-linux.png b/playwright/snapshots/crypto/crypto.spec.ts/RoomSummaryCard-with-verified-e2ee-linux.png index a8813b601d..3e68415017 100644 Binary files a/playwright/snapshots/crypto/crypto.spec.ts/RoomSummaryCard-with-verified-e2ee-linux.png and b/playwright/snapshots/crypto/crypto.spec.ts/RoomSummaryCard-with-verified-e2ee-linux.png differ diff --git a/playwright/snapshots/permalinks/permalinks.spec.ts/permalink-rendering-linux.png b/playwright/snapshots/permalinks/permalinks.spec.ts/permalink-rendering-linux.png index 2214206cab..198e4dfe08 100644 Binary files a/playwright/snapshots/permalinks/permalinks.spec.ts/permalink-rendering-linux.png and b/playwright/snapshots/permalinks/permalinks.spec.ts/permalink-rendering-linux.png differ diff --git a/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-messages-list-empty-linux.png b/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-messages-list-empty-linux.png index 38285305f6..16c694de95 100644 Binary files a/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-messages-list-empty-linux.png and b/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-messages-list-empty-linux.png differ diff --git a/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-bubble-layout-linux.png b/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-bubble-layout-linux.png index d35ec837b1..9a38579e21 100644 Binary files a/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-bubble-layout-linux.png and b/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-bubble-layout-linux.png differ diff --git a/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-group-layout-linux.png b/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-group-layout-linux.png index 0dfeb20b6a..f5bc02ef1e 100644 Binary files a/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-group-layout-linux.png and b/playwright/snapshots/polls/polls.spec.ts/ThreadView-with-a-poll-on-group-layout-linux.png differ diff --git a/playwright/snapshots/right-panel/file-panel.spec.ts/empty-linux.png b/playwright/snapshots/right-panel/file-panel.spec.ts/empty-linux.png index 178acd1828..9edd65a633 100644 Binary files a/playwright/snapshots/right-panel/file-panel.spec.ts/empty-linux.png and b/playwright/snapshots/right-panel/file-panel.spec.ts/empty-linux.png differ diff --git a/playwright/snapshots/right-panel/file-panel.spec.ts/file-tiles-list-linux.png b/playwright/snapshots/right-panel/file-panel.spec.ts/file-tiles-list-linux.png index c5bf1e7d6a..0593b44155 100644 Binary files a/playwright/snapshots/right-panel/file-panel.spec.ts/file-tiles-list-linux.png and b/playwright/snapshots/right-panel/file-panel.spec.ts/file-tiles-list-linux.png differ diff --git a/playwright/snapshots/right-panel/notification-panel.spec.ts/empty-linux.png b/playwright/snapshots/right-panel/notification-panel.spec.ts/empty-linux.png index b80b57fe4b..26481bfe5d 100644 Binary files a/playwright/snapshots/right-panel/notification-panel.spec.ts/empty-linux.png and b/playwright/snapshots/right-panel/notification-panel.spec.ts/empty-linux.png differ diff --git a/playwright/snapshots/right-panel/right-panel.spec.ts/with-name-and-address-linux.png b/playwright/snapshots/right-panel/right-panel.spec.ts/with-name-and-address-linux.png index 68f31135c5..4e3c67393b 100644 Binary files a/playwright/snapshots/right-panel/right-panel.spec.ts/with-name-and-address-linux.png and b/playwright/snapshots/right-panel/right-panel.spec.ts/with-name-and-address-linux.png differ diff --git a/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png b/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png index 32950f4dde..4652833628 100644 Binary files a/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png and b/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png differ diff --git a/playwright/snapshots/timeline/timeline.spec.ts/highlighted-search-results-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/highlighted-search-results-linux.png index 347c7a5477..008ebc82e3 100644 Binary files a/playwright/snapshots/timeline/timeline.spec.ts/highlighted-search-results-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/highlighted-search-results-linux.png differ diff --git a/playwright/snapshots/timeline/timeline.spec.ts/search-aux-panel-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/search-aux-panel-linux.png index fe96a9e6be..b50f176222 100644 Binary files a/playwright/snapshots/timeline/timeline.spec.ts/search-aux-panel-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/search-aux-panel-linux.png differ diff --git a/playwright/snapshots/timeline/timeline.spec.ts/search-results-with-TextualEvent-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/search-results-with-TextualEvent-linux.png index c1d762d512..cf489b1836 100644 Binary files a/playwright/snapshots/timeline/timeline.spec.ts/search-results-with-TextualEvent-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/search-results-with-TextualEvent-linux.png differ diff --git a/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png b/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png index 6e4df5c776..0612fe1ba7 100644 Binary files a/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png and b/playwright/snapshots/user-view/user-view.spec.ts/user-info-linux.png differ diff --git a/res/css/views/rooms/_MessageComposerFormatBar.pcss b/res/css/views/rooms/_MessageComposerFormatBar.pcss index 318bfe6547..36bfe477d7 100644 --- a/res/css/views/rooms/_MessageComposerFormatBar.pcss +++ b/res/css/views/rooms/_MessageComposerFormatBar.pcss @@ -55,6 +55,7 @@ Please see LICENSE files in the repository root for full details. width: 100%; mask-repeat: no-repeat; mask-position: center; + mask-size: 20px; background-color: var(--cpd-color-icon-secondary); } @@ -84,7 +85,6 @@ Please see LICENSE files in the repository root for full details. .mx_MessageComposerFormatBar_buttonIconInsertLink::after { mask-image: url("@vector-im/compound-design-tokens/icons/link.svg"); - mask-size: 18px; } } diff --git a/src/components/structures/MainSplit.tsx b/src/components/structures/MainSplit.tsx index 282ec69e18..54aa220354 100644 --- a/src/components/structures/MainSplit.tsx +++ b/src/components/structures/MainSplit.tsx @@ -10,8 +10,10 @@ Please see LICENSE files in the repository root for full details. import React, { ReactNode } from "react"; import { NumberSize, Resizable } from "re-resizable"; import { Direction } from "re-resizable/lib/resizer"; +import { WebPanelResize } from "@matrix-org/analytics-events/types/typescript/WebPanelResize"; import ResizeNotifier from "../../utils/ResizeNotifier"; +import { PosthogAnalytics } from "../../PosthogAnalytics.ts"; interface IProps { resizeNotifier: ResizeNotifier; @@ -26,14 +28,16 @@ interface IProps { */ sizeKey?: string; /** - * The size to use for the panel component if one isn't persisted in storage. Defaults to 350. + * The size to use for the panel component if one isn't persisted in storage. Defaults to 320. */ defaultSize: number; + + analyticsRoomType: WebPanelResize["roomType"]; } export default class MainSplit extends React.Component { public static defaultProps = { - defaultSize: 350, + defaultSize: 320, }; private onResizeStart = (): void => { @@ -58,11 +62,16 @@ export default class MainSplit extends React.Component { elementRef: HTMLElement, delta: NumberSize, ): void => { + const newSize = this.loadSidePanelSize().width + delta.width; this.props.resizeNotifier.stopResizing(); - window.localStorage.setItem( - this.sizeSettingStorageKey, - (this.loadSidePanelSize().width + delta.width).toString(), - ); + window.localStorage.setItem(this.sizeSettingStorageKey, newSize.toString()); + + PosthogAnalytics.instance.trackEvent({ + eventName: "WebPanelResize", + panel: "right", + roomType: this.props.analyticsRoomType, + size: newSize, + }); }; private loadSidePanelSize(): { height: string | number; width: number } { diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 5448e609ec..2ac6c8d01b 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -269,7 +269,7 @@ export default class RoomStatusBar extends React.PureComponent {
- +
{_t("room|status_bar|server_connectivity_lost_title")} diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index ba30a3445d..958c93bebc 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ -import React, { ChangeEvent, createRef, ReactElement, ReactNode, RefObject, useContext } from "react"; +import React, { ChangeEvent, ComponentProps, createRef, ReactElement, ReactNode, RefObject, useContext } from "react"; import classNames from "classnames"; import { IRecommendedVersion, @@ -54,7 +54,7 @@ import WidgetEchoStore from "../../stores/WidgetEchoStore"; import SettingsStore from "../../settings/SettingsStore"; import { Layout } from "../../settings/enums/Layout"; import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; -import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext"; +import RoomContext, { TimelineRenderingType, MainSplitContentType } from "../../contexts/RoomContext"; import { E2EStatus, shieldStatusForRoom } from "../../utils/ShieldUtils"; import { Action } from "../../dispatcher/actions"; import { IMatrixClientCreds } from "../../MatrixClientPeg"; @@ -152,13 +152,8 @@ interface IRoomProps { onRegistered?(credentials: IMatrixClientCreds): void; } -// This defines the content of the mainSplit. -// If the mainSplit does not contain the Timeline, the chat is shown in the right panel. -export enum MainSplitContentType { - Timeline, - MaximisedWidget, - Call, -} +export { MainSplitContentType }; + export interface IRoomState { room?: Room; virtualRoom?: Room; @@ -191,11 +186,6 @@ export interface IRoomState { showApps: boolean; isPeeking: boolean; showRightPanel: boolean; - /** - * Whether the right panel shown is either of ThreadPanel or ThreadView. - * Always false when `showRightPanel` is false. - */ - threadRightPanel: boolean; // error object, as from the matrix client/server API // If we failed to load information about the room, // store the error here. @@ -234,7 +224,7 @@ export interface IRoomState { e2eStatus?: E2EStatus; rejecting?: boolean; hasPinnedWidgets?: boolean; - mainSplitContentType?: MainSplitContentType; + mainSplitContentType: MainSplitContentType; // whether or not a spaces context switch brought us here, // if it did we don't want the room to be marked as read as soon as it is loaded. wasContextSwitch?: boolean; @@ -399,7 +389,6 @@ export class RoomView extends React.Component { showApps: false, isPeeking: false, showRightPanel: false, - threadRightPanel: false, joining: false, showTopUnreadMessagesBar: false, statusBarVisible: false, @@ -626,11 +615,6 @@ 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, promptAskToJoin: this.context.roomViewStore.promptAskToJoin(), viewRoomOpts: this.context.roomViewStore.getViewRoomOpts(), @@ -1033,11 +1017,6 @@ export class RoomView extends React.Component { const { roomId } = this.state; this.setState({ showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false, - threadRightPanel: roomId - ? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes( - this.context.rightPanelStore.currentCardForRoom(roomId).phase!, - ) - : false, }); }; @@ -2531,6 +2510,17 @@ export class RoomView extends React.Component { } const mainSplitContentClasses = classNames("mx_RoomView_body", mainSplitContentClassName); + let sizeKey: string | undefined; + let defaultSize: number | undefined; + let analyticsRoomType: ComponentProps["analyticsRoomType"] = "other_room"; + if (this.state.mainSplitContentType !== MainSplitContentType.Timeline) { + // Override defaults for video rooms where more space is needed for the chat timeline + sizeKey = "wide"; + defaultSize = 420; + analyticsRoomType = + this.state.mainSplitContentType === MainSplitContentType.Call ? "video_room" : "maximised_widget"; + } + return (
@@ -2541,10 +2531,9 @@ export class RoomView extends React.Component {
{ return (
- + {this.renderBody()} diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index 4647c24b26..635115877e 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -87,7 +87,12 @@ export default class UserView extends React.Component { /> ); return ( - + ); diff --git a/src/components/views/messages/PinnedMessageBadge.tsx b/src/components/views/messages/PinnedMessageBadge.tsx index ab2ceb30f2..e1d9411a9e 100644 --- a/src/components/views/messages/PinnedMessageBadge.tsx +++ b/src/components/views/messages/PinnedMessageBadge.tsx @@ -17,7 +17,7 @@ import { _t } from "../../../languageHandler.tsx"; export function PinnedMessageBadge(): JSX.Element { return (
- + {_t("room|pinned_message_badge")}
); diff --git a/src/components/views/rooms/PinnedMessageBanner.tsx b/src/components/views/rooms/PinnedMessageBanner.tsx index 2a9fe4e942..6360870dbf 100644 --- a/src/components/views/rooms/PinnedMessageBanner.tsx +++ b/src/components/views/rooms/PinnedMessageBanner.tsx @@ -92,7 +92,7 @@ export function PinnedMessageBanner({ room, permalinkCreator }: PinnedMessageBan >
- + {!isSinglePinnedEvent && (
{_t( diff --git a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx index e130498b52..801a6050c3 100644 --- a/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx +++ b/src/components/views/spaces/threads-activity-centre/ThreadsActivityCentreButton.tsx @@ -7,7 +7,7 @@ */ import React, { ComponentProps, forwardRef } from "react"; -import { Icon } from "@vector-im/compound-design-tokens/icons/threads-solid.svg"; +import ThreadsSolidIcon from "@vector-im/compound-design-tokens/assets/web/icons/threads-solid"; import classNames from "classnames"; import { IconButton, Text, Tooltip } from "@vector-im/compound-web"; @@ -51,7 +51,7 @@ export const ThreadsActivityCentreButton = forwardRef <> - + {/* This is dirty, but we need to add the label to the indicator icon */} {displayLabel && ( ", () => { const resizeNotifier = new ResizeNotifier(); @@ -21,18 +22,33 @@ describe("", () => { ); const panel =
Right panel
; + beforeEach(() => { + localStorage.clear(); + }); + 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"); + // Assert it matches the default width of 320 + expect(container.querySelector(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("320px"); }); it("respects defaultSize prop", () => { const { asFragment, container } = render( - , + , ); expect(asFragment()).toMatchSnapshot(); // Assert it matches the default width of 350 @@ -48,8 +64,36 @@ describe("", () => { panel={panel} sizeKey="thread" defaultSize={400} + analyticsRoomType="other_room" />, ); expect(container.querySelector(".mx_RightPanel_ResizeWrapper")!.style.width).toBe("333px"); }); + + it("should report to analytics on resize stop", () => { + const { container } = render( + , + ); + + const spy = jest.spyOn(PosthogAnalytics.instance, "trackEvent"); + + const handle = container.querySelector(".mx_ResizeHandle--horizontal")!; + fireEvent.mouseDown(handle); + fireEvent.mouseMove(handle, { clientX: 0 }); + fireEvent.mouseUp(handle); + + expect(spy).toHaveBeenCalledWith({ + eventName: "WebPanelResize", + panel: "right", + roomType: "other_room", + size: 400, + }); + }); }); diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx index e1dad1cb9d..1e11272c56 100644 --- a/test/components/structures/RoomView-test.tsx +++ b/test/components/structures/RoomView-test.tsx @@ -311,6 +311,12 @@ describe("RoomView", () => { expect(stores.rightPanelStore.isOpen).toEqual(true); expect(stores.rightPanelStore.currentCard.phase).toEqual(RightPanelPhases.Timeline); }); + + it("should render joined video room view", async () => { + jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join); + const { asFragment } = await mountRoomView(); + expect(asFragment()).toMatchSnapshot(); + }); }); describe("for a local room", () => { diff --git a/test/components/structures/__snapshots__/MainSplit-test.tsx.snap b/test/components/structures/__snapshots__/MainSplit-test.tsx.snap index d6cd201594..94f5b23604 100644 --- a/test/components/structures/__snapshots__/MainSplit-test.tsx.snap +++ b/test/components/structures/__snapshots__/MainSplit-test.tsx.snap @@ -14,7 +14,7 @@ exports[` renders 1`] = `
Right panel diff --git a/test/components/structures/__snapshots__/RoomView-test.tsx.snap b/test/components/structures/__snapshots__/RoomView-test.tsx.snap index 25740fbd0b..14036bb9b9 100644 --- a/test/components/structures/__snapshots__/RoomView-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomView-test.tsx.snap @@ -61,7 +61,17 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1 class="_indicator-icon_133tf_26" style="--cpd-icon-button-size: 100%;" > -
+ + +
@@ -234,7 +274,17 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`] class="_indicator-icon_133tf_26" style="--cpd-icon-button-size: 100%;" > -
+ + +
@@ -492,7 +572,17 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] = class="_indicator-icon_133tf_26" style="--cpd-icon-button-size: 100%;" > -
+ + +
@@ -827,7 +947,17 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t class="_indicator-icon_133tf_26" style="--cpd-icon-button-size: 100%;" > -
+ + +
@@ -1125,3 +1285,352 @@ exports[`RoomView should show error view if failed to look up room alias 1`] = `
`; + +exports[`RoomView video rooms should render joined video room view 1`] = ` + +
+