Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/shared-components/src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@
}
},
"room_list": {
"appearance": "Appearance",
"open_space_menu": "Open space menu",
"room_options": "Room Options",
"show_message_previews": "Show message previews",
"sort": "Sort",
"sort_type": {
"activity": "Activity",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const RoomListHeaderViewWrapper = ({
inviteInSpace,
openSpacePreferences,
sort,
toggleMessagePreview,
...rest
}: RoomListHeaderProps): JSX.Element => {
const vm = useMockedViewModel(rest, {
Expand All @@ -39,6 +40,7 @@ const RoomListHeaderViewWrapper = ({
inviteInSpace,
sort,
openSpacePreferences,
toggleMessagePreview,
});
return <RoomListHeaderView vm={vm} />;
};
Expand All @@ -57,6 +59,7 @@ export default {
inviteInSpace: fn(),
sort: fn(),
openSpacePreferences: fn(),
toggleMessagePreview: fn(),
},
parameters: {
design: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export interface RoomListHeaderViewSnapshot {
* The currently active sort option.
*/
activeSortOption: SortOption;
/**
* Whether message previews are enabled in the room list.
*/
isMessagePreviewEnabled: boolean;
}

export interface RoomListHeaderViewActions {
Expand Down Expand Up @@ -91,6 +95,10 @@ export interface RoomListHeaderViewActions {
* Change the sort order of the room-list.
*/
sort: (option: SortOption) => void;
/**
* Toggle message preview display in the room list.
*/
toggleMessagePreview: () => void;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,17 @@ describe("<OptionMenuView />", () => {

expect(vm.sort).toHaveBeenCalledWith("recent");
});

it("should toggle message preview", async () => {
const user = userEvent.setup();

const vm = new MockedViewModel({ ...defaultSnapshot, isMessagePreviewEnabled: true });
render(<OptionMenuView vm={vm} />);

await user.click(screen.getByRole("button", { name: "Room Options" }));
expect(screen.getByRole("menuitemcheckbox", { name: "Show message previews" })).toBeChecked();

await user.click(screen.getByRole("menuitemcheckbox", { name: "Show message previews" }));
expect(vm.toggleMessagePreview).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

import { IconButton, Menu, MenuTitle, RadioMenuItem } from "@vector-im/compound-web";
import { CheckboxMenuItem, IconButton, Menu, MenuTitle, RadioMenuItem } from "@vector-im/compound-web";
import React, { type JSX, useState } from "react";
import OverflowHorizontalIcon from "@vector-im/compound-design-tokens/assets/web/icons/overflow-horizontal";

Expand Down Expand Up @@ -33,7 +33,7 @@ interface OptionMenuViewProps {
export function OptionMenuView({ vm }: OptionMenuViewProps): JSX.Element {
const { translate: _t } = useI18n();
const [open, setOpen] = useState(false);
const { activeSortOption } = useViewModel(vm);
const { activeSortOption, isMessagePreviewEnabled } = useViewModel(vm);

return (
<Menu
Expand Down Expand Up @@ -65,6 +65,12 @@ export function OptionMenuView({ vm }: OptionMenuViewProps): JSX.Element {
checked={activeSortOption === "alphabetical"}
onSelect={() => vm.sort("alphabetical")}
/>
<MenuTitle title={_t("room_list|appearance")} />
<CheckboxMenuItem
label={_t("room_list|show_message_previews")}
onSelect={vm.toggleMessagePreview}
checked={isMessagePreviewEnabled}
/>
</Menu>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class MockedViewModel extends MockViewModel<RoomListHeaderViewSnapshot> i
public inviteInSpace = jest.fn();
public sort = jest.fn();
public openSpacePreferences = jest.fn();
public toggleMessagePreview = jest.fn();
}

export const defaultSnapshot: RoomListHeaderViewSnapshot = {
Expand All @@ -31,4 +32,5 @@ export const defaultSnapshot: RoomListHeaderViewSnapshot = {
canInviteInSpace: true,
canAccessSpaceSettings: true,
activeSortOption: "recent",
isMessagePreviewEnabled: true,
};
34 changes: 27 additions & 7 deletions playwright/e2e/left-panel/room-list-panel/room-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import { type Page } from "@playwright/test";

import { expect, test } from "../../../element-web-test";
import { type Bot } from "../../../pages/bot";
import { type ElementAppPage } from "../../../pages/ElementAppPage";

test.describe("Room list", () => {
test.use({
Expand Down Expand Up @@ -392,13 +394,8 @@ test.describe("Room list", () => {
await expect(room).toMatchScreenshot("room-list-item-mention.png");
});

test("should render a message preview", { tag: "@screenshot" }, async ({ page, app, user, bot }) => {
await app.settings.openUserSettings("Preferences");
await page.getByRole("switch", { name: "Show message previews" }).click();
await app.closeDialog();

async function checkMessagePreview(page: Page, app: ElementAppPage, bot: Bot) {
const roomListView = getRoomList(page);

const roomId = await app.client.createRoom({ name: "activity" });

// focus the user menu to avoid to have hover decoration
Expand All @@ -411,7 +408,30 @@ test.describe("Room list", () => {
const room = roomListView.getByRole("option", { name: "activity" });
await expect(room.getByText("I am a robot. Beep.")).toBeVisible();
await expect(room).toMatchScreenshot("room-list-item-message-preview.png");
});
}

test(
"should render a message preview when enable in settings",
{ tag: "@screenshot" },
async ({ page, app, user, bot }) => {
await app.settings.openUserSettings("Preferences");
await page.getByRole("switch", { name: "Show message previews" }).click();
await app.closeDialog();

await checkMessagePreview(page, app, bot);
},
);

test(
"should render a message preview when enabled in header",
{ tag: "@screenshot" },
async ({ page, app, user, bot }) => {
await page.getByRole("button", { name: "Room Options" }).click();
await page.getByRole("menuitemcheckbox", { name: "Show message previews" }).click();

await checkMessagePreview(page, app, bot);
},
);

test("should render an activity decoration", { tag: "@screenshot" }, async ({ page, app, user, bot }) => {
const roomListView = getRoomList(page);
Expand Down
14 changes: 13 additions & 1 deletion src/viewmodels/room-list/RoomListHeaderViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ import { createRoom, hasCreateRoomRights } from "../../components/viewmodels/roo
import SettingsStore from "../../settings/SettingsStore";
import RoomListStoreV3 from "../../stores/room-list-v3/RoomListStoreV3";
import { SortingAlgorithm } from "../../stores/room-list-v3/skip-list/sorters";
import { SettingLevel } from "../../settings/SettingLevel";

export interface Props {
/**
* The Matrix client instance.
*/
matrixClient: MatrixClient;
/**
* The space store instance.
*/
spaceStore: SpaceStoreClass;
}

Expand Down Expand Up @@ -170,6 +174,12 @@ export class RoomListHeaderViewModel
RoomListStoreV3.instance.resort(sortingAlgorithm);
this.snapshot.merge({ activeSortOption: option });
};

public toggleMessagePreview = (): void => {
const isMessagePreviewEnabled = SettingsStore.getValue("RoomList.showMessagePreview");
SettingsStore.setValue("RoomList.showMessagePreview", null, SettingLevel.DEVICE, !isMessagePreviewEnabled);
this.snapshot.merge({ isMessagePreviewEnabled });
};
}

/**
Expand All @@ -182,9 +192,11 @@ function getInitialSnapshot(spaceStore: SpaceStoreClass, matrixClient: MatrixCli
const sortingAlgorithm = SettingsStore.getValue("RoomList.preferredSorting");
const activeSortOption =
sortingAlgorithm === SortingAlgorithm.Recency ? ("recent" as const) : ("alphabetical" as const);
const isMessagePreviewEnabled = SettingsStore.getValue("RoomList.showMessagePreview");

return {
activeSortOption,
isMessagePreviewEnabled,
...computeHeaderSpaceState(spaceStore, matrixClient),
};
}
Expand Down Expand Up @@ -216,7 +228,7 @@ function getCanCreateVideoRoom(canCreateRoom: boolean): boolean {
function computeHeaderSpaceState(
spaceStore: SpaceStoreClass,
matrixClient: MatrixClient,
): Omit<RoomListHeaderViewSnapshot, "activeSortOption"> {
): Omit<RoomListHeaderViewSnapshot, "activeSortOption" | "isMessagePreviewEnabled"> {
const activeSpace = spaceStore.activeSpaceRoom;
const title = getHeaderTitle(spaceStore);

Expand Down
25 changes: 25 additions & 0 deletions test/viewmodels/room-list/RoomListHeaderViewModel-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ describe("RoomListHeaderViewModel", () => {
vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
expect(vm.getSnapshot().canAccessSpaceSettings).toBe(false);
});

it("should show message preview when RoomList.showMessagePreview is enabled", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
if (settingName === "RoomList.showMessagePreview") return true;
return false;
});

vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
expect(vm.getSnapshot().isMessagePreviewEnabled).toBe(true);
});
});

describe("event listeners", () => {
Expand Down Expand Up @@ -268,5 +278,20 @@ describe("RoomListHeaderViewModel", () => {

expect(resortSpy).toHaveBeenCalledWith(expectedAlgorithm);
});

it("should toggle message preview from enabled to disabled", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
if (settingName === "RoomList.showMessagePreview") return true;
return false;
});
const setValueSpy = jest.spyOn(SettingsStore, "setValue").mockImplementation(jest.fn());

vm = new RoomListHeaderViewModel({ matrixClient, spaceStore: SpaceStore.instance });
expect(vm.getSnapshot().isMessagePreviewEnabled).toBe(true);

vm.toggleMessagePreview();

expect(setValueSpy).toHaveBeenCalledWith("RoomList.showMessagePreview", null, expect.anything(), false);
});
});
});
Loading