New room list: move message preview in user settings (#30023)

* feat: move message preview settings to user settings

* test: update tests

* test(e2e): update preference screenshots

* test(e2e): update room list tests

* fix: display message preview settings only for new room list

* test(e2e): display all preference settings in screenshot

* test: update snapshot
This commit is contained in:
Florian Duros
2025-06-05 16:14:09 +02:00
committed by GitHub
parent ad71e7bdc4
commit 140afea791
11 changed files with 20 additions and 114 deletions

View File

@@ -333,10 +333,11 @@ test.describe("Room list", () => {
}); });
test("should render a message preview", { tag: "@screenshot" }, async ({ page, app, user, bot }) => { test("should render a message preview", { tag: "@screenshot" }, async ({ page, app, user, bot }) => {
const roomListView = getRoomList(page); await app.settings.openUserSettings("Preferences");
await page.getByRole("switch", { name: "Show message previews" }).click();
await app.closeDialog();
await page.getByRole("button", { name: "Room Options" }).click(); const roomListView = getRoomList(page);
await page.getByRole("menuitemcheckbox", { name: "Show message previews" }).click();
const roomId = await app.client.createRoom({ name: "activity" }); const roomId = await app.client.createRoom({ name: "activity" });

View File

@@ -21,10 +21,12 @@ test.describe("Preferences user settings tab", () => {
const locator = await app.settings.openUserSettings("Preferences"); const locator = await app.settings.openUserSettings("Preferences");
await use(locator); await use(locator);
}, },
// display message preview settings
labsFlags: ["feature_new_room_list"],
}); });
test("should be rendered properly", { tag: "@screenshot" }, async ({ app, page, user }) => { test("should be rendered properly", { tag: "@screenshot" }, async ({ app, page, user }) => {
await page.setViewportSize({ width: 1024, height: 3300 }); await page.setViewportSize({ width: 1024, height: 4000 });
const tab = await app.settings.openUserSettings("Preferences"); const tab = await app.settings.openUserSettings("Preferences");
// Assert that the top heading is rendered // Assert that the top heading is rendered
await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible(); await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 268 KiB

View File

@@ -32,7 +32,6 @@ import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { createRoom, hasCreateRoomRights } from "./utils"; import { createRoom, hasCreateRoomRights } from "./utils";
import { type SortOption, useSorter } from "./useSorter"; import { type SortOption, useSorter } from "./useSorter";
import { useMessagePreviewToggle } from "./useMessagePreviewToggle";
/** /**
* Hook to get the active space and its title. * Hook to get the active space and its title.
@@ -127,14 +126,6 @@ export interface RoomListHeaderViewState {
* The currently active sort option. * The currently active sort option.
*/ */
activeSortOption: SortOption; activeSortOption: SortOption;
/**
* Whether message previews must be shown or not.
*/
shouldShowMessagePreview: boolean;
/**
* A function to turn on/off message previews.
*/
toggleMessagePreview: () => void;
} }
/** /**
@@ -157,7 +148,6 @@ export function useRoomListHeaderViewModel(): RoomListHeaderViewState {
/* Actions */ /* Actions */
const { activeSortOption, sort } = useSorter(); const { activeSortOption, sort } = useSorter();
const { shouldShowMessagePreview, toggleMessagePreview } = useMessagePreviewToggle();
const createChatRoom = useCallback((e: Event) => { const createChatRoom = useCallback((e: Event) => {
defaultDispatcher.fire(Action.CreateChat); defaultDispatcher.fire(Action.CreateChat);
@@ -230,7 +220,5 @@ export function useRoomListHeaderViewModel(): RoomListHeaderViewState {
openSpaceSettings, openSpaceSettings,
activeSortOption, activeSortOption,
sort, sort,
shouldShowMessagePreview,
toggleMessagePreview,
}; };
} }

View File

@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
import { IconButton, Menu, MenuTitle, CheckboxMenuItem, Tooltip, RadioMenuItem } from "@vector-im/compound-web"; import { IconButton, Menu, MenuTitle, Tooltip, RadioMenuItem } from "@vector-im/compound-web";
import React, { type Ref, type JSX, useState, useCallback } from "react"; import React, { type Ref, type JSX, useState, useCallback } from "react";
import OverflowHorizontalIcon from "@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal"; import OverflowHorizontalIcon from "@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal";
@@ -63,12 +63,6 @@ export function RoomListOptionsMenu({ vm }: Props): JSX.Element {
checked={vm.activeSortOption === SortOption.AToZ} checked={vm.activeSortOption === SortOption.AToZ}
onSelect={onAtoZSelected} onSelect={onAtoZSelected}
/> />
<MenuTitle title={_t("room_list|appearance")} />
<CheckboxMenuItem
label={_t("room_list|show_message_previews")}
onSelect={vm.toggleMessagePreview}
checked={vm.shouldShowMessagePreview}
/>
</Menu> </Menu>
); );
} }

View File

@@ -242,12 +242,12 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
const roomListSettings = PreferencesUserSettingsTab.ROOM_LIST_SETTINGS;
const browserTimezoneLabel: string = _t("settings|preferences|default_timezone", { const browserTimezoneLabel: string = _t("settings|preferences|default_timezone", {
timezone: TimezoneHandler.shortBrowserTimezone(), timezone: TimezoneHandler.shortBrowserTimezone(),
}); });
const newRoomListEnabled = SettingsStore.getValue("feature_new_room_list");
// Always Preprend the default option // Always Preprend the default option
const timezones = this.state.timezones.map((tz) => { const timezones = this.state.timezones.map((tz) => {
return <div key={tz}>{tz}</div>; return <div key={tz}>{tz}</div>;
@@ -263,11 +263,13 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
<SpellCheckSection /> <SpellCheckSection />
</SettingsSubsection> </SettingsSubsection>
{roomListSettings.length > 0 && ( <SettingsSubsection heading={_t("settings|preferences|room_list_heading")}>
<SettingsSubsection heading={_t("settings|preferences|room_list_heading")}> {this.renderGroup(PreferencesUserSettingsTab.ROOM_LIST_SETTINGS)}
{this.renderGroup(roomListSettings)} {/* The settings is on device level where the other room list settings are on account level */}
</SettingsSubsection> {newRoomListEnabled && (
)} <SettingsFlag name="RoomList.showMessagePreview" level={SettingLevel.DEVICE} />
)}
</SettingsSubsection>
<SettingsSubsection heading={_t("common|spaces")}> <SettingsSubsection heading={_t("common|spaces")}>
{this.renderGroup(PreferencesUserSettingsTab.SPACES_SETTINGS, SettingLevel.ACCOUNT)} {this.renderGroup(PreferencesUserSettingsTab.SPACES_SETTINGS, SettingLevel.ACCOUNT)}

View File

@@ -2095,7 +2095,6 @@
"room_list": { "room_list": {
"add_room_label": "Add room", "add_room_label": "Add room",
"add_space_label": "Add space", "add_space_label": "Add space",
"appearance": "Appearance",
"breadcrumbs_empty": "No recently visited rooms", "breadcrumbs_empty": "No recently visited rooms",
"breadcrumbs_label": "Recently visited rooms", "breadcrumbs_label": "Recently visited rooms",
"empty": { "empty": {
@@ -2154,7 +2153,6 @@
}, },
"room_options": "Room Options", "room_options": "Room Options",
"show_less": "Show less", "show_less": "Show less",
"show_message_previews": "Show message previews",
"show_n_more": { "show_n_more": {
"one": "Show %(count)s more", "one": "Show %(count)s more",
"other": "Show %(count)s more" "other": "Show %(count)s more"
@@ -2984,6 +2982,7 @@
"show_chat_effects": "Show chat effects (animations when receiving e.g. confetti)", "show_chat_effects": "Show chat effects (animations when receiving e.g. confetti)",
"show_displayname_changes": "Show display name changes", "show_displayname_changes": "Show display name changes",
"show_join_leave": "Show join/leave messages (invites/removes/bans unaffected)", "show_join_leave": "Show join/leave messages (invites/removes/bans unaffected)",
"show_message_previews": "Show message previews",
"show_nsfw_content": "Show NSFW content", "show_nsfw_content": "Show NSFW content",
"show_read_receipts": "Show read receipts sent by other users", "show_read_receipts": "Show read receipts sent by other users",
"show_redaction_placeholder": "Show a placeholder for removed messages", "show_redaction_placeholder": "Show a placeholder for removed messages",

View File

@@ -1136,6 +1136,7 @@ export const SETTINGS: Settings = {
"RoomList.showMessagePreview": { "RoomList.showMessagePreview": {
supportedLevels: [SettingLevel.DEVICE], supportedLevels: [SettingLevel.DEVICE],
default: false, default: false,
displayName: _td("settings|show_message_previews"),
}, },
"RightPanel.phasesGlobal": { "RightPanel.phasesGlobal": {
supportedLevels: [SettingLevel.DEVICE], supportedLevels: [SettingLevel.DEVICE],

View File

@@ -13,7 +13,7 @@ import { range } from "lodash";
import { useRoomListHeaderViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListHeaderViewModel"; import { useRoomListHeaderViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListHeaderViewModel";
import SpaceStore from "../../../../../src/stores/spaces/SpaceStore"; import SpaceStore from "../../../../../src/stores/spaces/SpaceStore";
import { mkStubRoom, stubClient, withClientContextRenderOptions } from "../../../../test-utils"; import { mkStubRoom, stubClient, withClientContextRenderOptions } from "../../../../test-utils";
import SettingsStore, { type CallbackFn } from "../../../../../src/settings/SettingsStore"; import SettingsStore from "../../../../../src/settings/SettingsStore";
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher"; import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions"; import { Action } from "../../../../../src/dispatcher/actions";
import { import {
@@ -24,7 +24,6 @@ import {
showSpaceSettings, showSpaceSettings,
} from "../../../../../src/utils/space"; } from "../../../../../src/utils/space";
import { createRoom, hasCreateRoomRights } from "../../../../../src/components/viewmodels/roomlist/utils"; import { createRoom, hasCreateRoomRights } from "../../../../../src/components/viewmodels/roomlist/utils";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import RoomListStoreV3 from "../../../../../src/stores/room-list-v3/RoomListStoreV3"; import RoomListStoreV3 from "../../../../../src/stores/room-list-v3/RoomListStoreV3";
import { SortOption } from "../../../../../src/components/viewmodels/roomlist/useSorter"; import { SortOption } from "../../../../../src/components/viewmodels/roomlist/useSorter";
import { SortingAlgorithm } from "../../../../../src/stores/room-list-v3/skip-list/sorters"; import { SortingAlgorithm } from "../../../../../src/stores/room-list-v3/skip-list/sorters";
@@ -238,38 +237,4 @@ describe("useRoomListHeaderViewModel", () => {
expect(vm.current.activeSortOption).toEqual(SortOption.AToZ); expect(vm.current.activeSortOption).toEqual(SortOption.AToZ);
}); });
}); });
describe("message preview toggle", () => {
it("should return shouldShowMessagePreview based on setting", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => true);
const { result: vm } = render();
expect(vm.current.shouldShowMessagePreview).toEqual(true);
});
it("should update when setting changes", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => true);
let watchFn: CallbackFn;
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, _roomId, fn) => {
if (settingName === "RoomList.showMessagePreview") watchFn = fn;
return "";
});
const { result: vm } = render();
expect(vm.current.shouldShowMessagePreview).toEqual(true);
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => false);
act(() => watchFn("RoomList.showMessagePreview", "", SettingLevel.DEVICE, false, false));
expect(vm.current.shouldShowMessagePreview).toEqual(false);
});
it("should change setting on toggle", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation(() => true);
const fn = jest.spyOn(SettingsStore, "setValue").mockImplementation(async () => {});
const { result: vm } = render();
expect(vm.current.shouldShowMessagePreview).toEqual(true);
act(() => vm.current.toggleMessagePreview());
expect(fn).toHaveBeenCalledWith("RoomList.showMessagePreview", null, "device", false);
});
});
}); });

View File

@@ -32,8 +32,6 @@ describe("<RoomListHeaderView />", () => {
canAccessSpaceSettings: true, canAccessSpaceSettings: true,
sort: jest.fn(), sort: jest.fn(),
activeSortOption: SortOption.Activity, activeSortOption: SortOption.Activity,
shouldShowMessagePreview: false,
toggleMessagePreview: jest.fn(),
createRoom: jest.fn(), createRoom: jest.fn(),
createVideoRoom: jest.fn(), createVideoRoom: jest.fn(),
createChatRoom: jest.fn(), createChatRoom: jest.fn(),

View File

@@ -91,48 +91,4 @@ describe("<RoomListOptionsMenu />", () => {
expect(vm.sort).toHaveBeenCalledWith("Recency"); expect(vm.sort).toHaveBeenCalledWith("Recency");
}); });
it("should show message previews disabled", async () => {
const user = userEvent.setup();
const vm = {
shouldShowMessagePreview: false,
} as unknown as RoomListHeaderViewState;
render(<RoomListOptionsMenu vm={vm} />);
await user.click(screen.getByRole("button", { name: "Room Options" }));
expect(screen.getByRole("menuitemcheckbox", { name: "Show message previews" })).not.toBeChecked();
});
it("should show message previews enabled", async () => {
const user = userEvent.setup();
const vm = {
shouldShowMessagePreview: true,
} as unknown as RoomListHeaderViewState;
render(<RoomListOptionsMenu vm={vm} />);
await user.click(screen.getByRole("button", { name: "Room Options" }));
expect(screen.getByRole("menuitemcheckbox", { name: "Show message previews" })).toBeChecked();
});
it("should toggle message previews", async () => {
const user = userEvent.setup();
const vm = {
toggleMessagePreview: jest.fn(),
} as unknown as RoomListHeaderViewState;
render(<RoomListOptionsMenu vm={vm} />);
await user.click(screen.getByRole("button", { name: "Room Options" }));
await user.click(screen.getByRole("menuitemcheckbox", { name: "Show message previews" }));
expect(vm.toggleMessagePreview).toHaveBeenCalled();
});
}); });