New room list: move secondary filters into primary filters (#29972)

* feat: move secondary filters into primary filters in vm

* test: update room list view model tests

* feat: remove secondary filter menu

* test: update and remove secondary filter component tests

* feat: update i18n

* test: update remaining tests

* test(e2e): update screenshots and tests

* feat: add new cases for empty room list

* test(e2e): add more tests for empty room list for new primary filters
This commit is contained in:
Florian Duros
2025-05-20 16:44:29 +02:00
committed by GitHub
parent 69fe2ad06c
commit 5d2d4947f4
49 changed files with 215 additions and 868 deletions

View File

@@ -13,7 +13,6 @@ import RoomListStoreV3, { LISTS_UPDATE_EVENT } from "../../../../../src/stores/r
import { mkStubRoom } from "../../../../test-utils";
import { useRoomListViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { FilterKey } from "../../../../../src/stores/room-list-v3/skip-list/filters";
import { SecondaryFilters } from "../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { hasCreateRoomRights, createRoom } from "../../../../../src/components/viewmodels/roomlist/utils";
import dispatcher from "../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../src/dispatcher/actions";
@@ -66,10 +65,10 @@ describe("RoomListViewModel", () => {
it("should provide list of available filters", () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// should have 4 filters
expect(vm.current.primaryFilters).toHaveLength(4);
// should have 6 filters
expect(vm.current.primaryFilters).toHaveLength(6);
// check the order
for (const [i, name] of ["Unreads", "People", "Rooms", "Favourites"].entries()) {
for (const [i, name] of ["Unreads", "People", "Rooms", "Mentions", "Invites", "Favourites"].entries()) {
expect(vm.current.primaryFilters[i].name).toEqual(name);
expect(vm.current.primaryFilters[i].active).toEqual(false);
}
@@ -107,46 +106,6 @@ describe("RoomListViewModel", () => {
expect(vm.current.primaryFilters[j].active).toEqual(true);
});
it("should select all activity as default secondary filter", () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// By default, all activity should be the active secondary filter
expect(vm.current.activeSecondaryFilter).toEqual(SecondaryFilters.AllActivity);
});
it("should be able to filter using secondary filters", () => {
const { fn } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Let's say we toggle the mentions secondary filter
act(() => {
vm.current.activateSecondaryFilter(SecondaryFilters.MentionsOnly);
});
expect(fn).toHaveBeenCalledWith([FilterKey.MentionsFilter]);
});
it("primary filters are applied on top of secondary filers", () => {
const { fn } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Let's say we toggle the mentions secondary filter
act(() => {
vm.current.activateSecondaryFilter(SecondaryFilters.MentionsOnly);
});
// Let's say we toggle the People filter
const i = vm.current.primaryFilters.findIndex((f) => f.name === "People");
act(() => {
vm.current.primaryFilters[i].toggle();
});
// RLS call must include both these filters
expect(fn).toHaveBeenLastCalledWith(
expect.arrayContaining([FilterKey.PeopleFilter, FilterKey.MentionsFilter]),
);
});
it("should return the current active primary filter", async () => {
// Let's say that the user's preferred sorting is alphabetic
mockAndCreateRooms();
@@ -160,29 +119,6 @@ describe("RoomListViewModel", () => {
expect(vm.current.activePrimaryFilter).toEqual(vm.current.primaryFilters[i]);
});
it("should remove any active primary filters when secondary filter is changed", async () => {
const { fn } = mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Let's first toggle the People filter
const i = vm.current.primaryFilters.findIndex((f) => f.name === "People");
act(() => {
vm.current.primaryFilters[i].toggle();
});
expect(vm.current.primaryFilters[i].active).toEqual(true);
// Let's say we toggle the mentions secondary filter
act(() => {
vm.current.activateSecondaryFilter(SecondaryFilters.MentionsOnly);
});
// Primary filer should have been unapplied
expect(vm.current.primaryFilters[i].active).toEqual(false);
// RLS call must include only the secondary filter
expect(fn).toHaveBeenLastCalledWith(expect.arrayContaining([FilterKey.MentionsFilter]));
});
it("should remove all filters when active space is changed", async () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
@@ -194,58 +130,11 @@ describe("RoomListViewModel", () => {
});
expect(vm.current.primaryFilters[i].active).toEqual(true);
// Let's say we toggle the mentions secondary filter
act(() => {
vm.current.activateSecondaryFilter(SecondaryFilters.MentionsOnly);
});
expect(vm.current.activeSecondaryFilter).toEqual(SecondaryFilters.MentionsOnly);
// Simulate a space change
await act(() => SpaceStore.instance.emit(UPDATE_SELECTED_SPACE));
// Primary filer should have been unapplied
expect(vm.current.activePrimaryFilter).toEqual(undefined);
// Secondary filter should be reset to "All Activity"
expect(vm.current.activeSecondaryFilter).toEqual(SecondaryFilters.AllActivity);
});
const testcases: Array<[string, { secondary: SecondaryFilters; filterKey: FilterKey }, string]> = [
[
"Mentions only",
{ secondary: SecondaryFilters.MentionsOnly, filterKey: FilterKey.MentionsFilter },
"Unreads",
],
[
"Invites only",
{ secondary: SecondaryFilters.InvitesOnly, filterKey: FilterKey.InvitesFilter },
"Unreads",
],
[
"Invites only",
{ secondary: SecondaryFilters.InvitesOnly, filterKey: FilterKey.InvitesFilter },
"Favourites",
],
[
"Low priority",
{ secondary: SecondaryFilters.LowPriority, filterKey: FilterKey.LowPriorityFilter },
"Favourites",
],
];
describe.each(testcases)("For secondary filter: %s", (secondaryFilterName, secondary, primaryFilterName) => {
it(`should hide incompatible primary filter: ${primaryFilterName}`, () => {
mockAndCreateRooms();
const { result: vm } = renderHook(() => useRoomListViewModel());
// Apply the secondary filter
act(() => {
vm.current.activateSecondaryFilter(secondary.secondary);
});
// Incompatible primary filter must be hidden
expect(vm.current.primaryFilters.find((f) => f.name === primaryFilterName)).toBeUndefined();
});
});
});

View File

@@ -10,7 +10,6 @@ import { render, screen } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { EmptyRoomList } from "../../../../../../src/components/views/rooms/RoomListPanel/EmptyRoomList";
import { FilterKey } from "../../../../../../src/stores/room-list-v3/skip-list/filters";
@@ -22,8 +21,6 @@ describe("<EmptyRoomList />", () => {
isLoadingRooms: false,
rooms: [],
primaryFilters: [],
activateSecondaryFilter: jest.fn().mockReturnValue({}),
activeSecondaryFilter: SecondaryFilters.AllActivity,
createRoom: jest.fn(),
createChatRoom: jest.fn(),
canCreateRoom: true,
@@ -53,13 +50,17 @@ describe("<EmptyRoomList />", () => {
expect(asFragment()).toMatchSnapshot();
});
it("should display the empty state for the unread filter", async () => {
it.each([
{ key: FilterKey.UnreadFilter, name: "unread", action: "Show all chats" },
{ key: FilterKey.MentionsFilter, name: "mention", action: "See all activity" },
{ key: FilterKey.InvitesFilter, name: "invite", action: "See all activity" },
])("should display the empty state for the $name filter", async ({ key, name, action }) => {
const user = userEvent.setup();
const activePrimaryFilter = {
toggle: jest.fn(),
active: true,
name: "unread",
key: FilterKey.UnreadFilter,
name,
key,
};
const newState = {
...vm,
@@ -67,7 +68,7 @@ describe("<EmptyRoomList />", () => {
};
const { asFragment } = render(<EmptyRoomList vm={newState} />);
await user.click(screen.getByRole("button", { name: "Show all chats" }));
await user.click(screen.getByRole("button", { name: action }));
expect(activePrimaryFilter.toggle).toHaveBeenCalled();
expect(asFragment()).toMatchSnapshot();
});

View File

@@ -14,7 +14,6 @@ import { mkRoom, stubClient } from "../../../../../test-utils";
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { RoomList } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomList";
import DMRoomMap from "../../../../../../src/utils/DMRoomMap";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { Landmark, LandmarkNavigation } from "../../../../../../src/accessibility/LandmarkNavigation";
describe("<RoomList />", () => {
@@ -33,8 +32,6 @@ describe("<RoomList />", () => {
isLoadingRooms: false,
rooms,
primaryFilters: [],
activateSecondaryFilter: () => {},
activeSecondaryFilter: SecondaryFilters.AllActivity,
createRoom: jest.fn(),
createChatRoom: jest.fn(),
canCreateRoom: true,

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { render, type RenderOptions, screen } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { TooltipProvider } from "@vector-im/compound-web";
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { RoomListFilterMenu } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListFilterMenu";
function getRenderOptions(): RenderOptions {
return {
wrapper: ({ children }) => <TooltipProvider>{children}</TooltipProvider>,
};
}
describe("<RoomListFilterMenu />", () => {
let vm: RoomListViewState;
beforeEach(() => {
vm = {
isLoadingRooms: false,
rooms: [],
canCreateRoom: true,
createRoom: jest.fn(),
createChatRoom: jest.fn(),
primaryFilters: [],
activateSecondaryFilter: () => {},
activeSecondaryFilter: SecondaryFilters.AllActivity,
activeIndex: undefined,
};
});
it("should render room list filter menu button", async () => {
const { asFragment } = render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
expect(screen.getByRole("button", { name: "Filter" })).toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
});
it("opens the menu on click", async () => {
const userevent = userEvent.setup();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
expect(screen.getByRole("menu", { name: "Filter" })).toBeInTheDocument();
});
it("shows 'All activity' checked if selected", async () => {
const userevent = userEvent.setup();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "All activity" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Invites only' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.InvitesOnly;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Invites only" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Low priority' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.LowPriority;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Low priority" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("shows 'Mentions only' checked if selected", async () => {
const userevent = userEvent.setup();
vm.activeSecondaryFilter = SecondaryFilters.MentionsOnly;
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
const shouldBeSelected = screen.getByRole("menuitem", { name: "Mentions only" });
expect(shouldBeSelected).toHaveAttribute("aria-selected", "true");
expect(shouldBeSelected).toMatchSnapshot();
});
it("activates filter when item clicked", async () => {
const userevent = userEvent.setup();
vm.activateSecondaryFilter = jest.fn();
render(<RoomListFilterMenu vm={vm} />, getRenderOptions());
await userevent.click(screen.getByRole("button", { name: "Filter" }));
await userevent.click(screen.getByRole("menuitem", { name: "Invites only" }));
expect(vm.activateSecondaryFilter).toHaveBeenCalledWith(SecondaryFilters.InvitesOnly);
});
});

View File

@@ -10,7 +10,6 @@ import { render, screen } from "jest-matrix-react";
import userEvent from "@testing-library/user-event";
import { type RoomListViewState } from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { RoomListPrimaryFilters } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListPrimaryFilters";
import { FilterKey } from "../../../../../../src/stores/room-list-v3/skip-list/filters";
@@ -28,8 +27,6 @@ describe("<RoomListPrimaryFilters />", () => {
{ name: "People", active: false, toggle: jest.fn(), key: FilterKey.PeopleFilter },
{ name: "Rooms", active: true, toggle: jest.fn(), key: FilterKey.RoomsFilter },
],
activateSecondaryFilter: () => {},
activeSecondaryFilter: SecondaryFilters.AllActivity,
activeIndex: undefined,
};
});

View File

@@ -13,7 +13,6 @@ import {
type RoomListViewState,
useRoomListViewModel,
} from "../../../../../../src/components/viewmodels/roomlist/RoomListViewModel";
import { SecondaryFilters } from "../../../../../../src/components/viewmodels/roomlist/useFilteredRooms";
import { RoomListView } from "../../../../../../src/components/views/rooms/RoomListPanel/RoomListView";
import { mkRoom, stubClient } from "../../../../../test-utils";
@@ -26,8 +25,6 @@ describe("<RoomListView />", () => {
isLoadingRooms: false,
rooms: [],
primaryFilters: [],
activateSecondaryFilter: jest.fn().mockReturnValue({}),
activeSecondaryFilter: SecondaryFilters.AllActivity,
createRoom: jest.fn(),
createChatRoom: jest.fn(),
canCreateRoom: true,

View File

@@ -63,6 +63,56 @@ exports[`<EmptyRoomList /> should display empty state for filter rooms 1`] = `
</DocumentFragment>
`;
exports[`<EmptyRoomList /> should display the empty state for the invite filter 1`] = `
<DocumentFragment>
<div
class="mx_Flex mx_EmptyRoomList_GenericPlaceholder"
data-testid="empty-room-list"
style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: stretch; --mx-flex-justify: center; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
>
<span
class="mx_EmptyRoomList_GenericPlaceholder_title"
>
You don't have any unread invites
</span>
<button
class="_button_vczzf_8"
data-kind="tertiary"
data-size="lg"
role="button"
tabindex="0"
>
See all activity
</button>
</div>
</DocumentFragment>
`;
exports[`<EmptyRoomList /> should display the empty state for the mention filter 1`] = `
<DocumentFragment>
<div
class="mx_Flex mx_EmptyRoomList_GenericPlaceholder"
data-testid="empty-room-list"
style="--mx-flex-display: flex; --mx-flex-direction: column; --mx-flex-align: stretch; --mx-flex-justify: center; --mx-flex-gap: var(--cpd-space-2x); --mx-flex-wrap: nowrap;"
>
<span
class="mx_EmptyRoomList_GenericPlaceholder_title"
>
You don't have any unread mentions
</span>
<button
class="_button_vczzf_8"
data-kind="tertiary"
data-size="lg"
role="button"
tabindex="0"
>
See all activity
</button>
</div>
</DocumentFragment>
`;
exports[`<EmptyRoomList /> should display the empty state for the unread filter 1`] = `
<DocumentFragment>
<div

View File

@@ -1,208 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RoomListFilterMenu /> should render room list filter menu button 1`] = `
<DocumentFragment>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Filter"
aria-labelledby="«r2»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«r0»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
</DocumentFragment>
`;
exports[`<RoomListFilterMenu /> shows 'All activity' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m1.5 21.25 1.45-4.95a10.2 10.2 0 0 1-.712-2.1A10.2 10.2 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22q-1.125 0-2.2-.238a10.2 10.2 0 0 1-2.1-.712L2.75 22.5a.94.94 0 0 1-1-.25.94.94 0 0 1-.25-1m2.45-1.2 3.2-.95a1 1 0 0 1 .275-.062q.15-.013.275-.013.225 0 .438.038.212.036.412.137a7.4 7.4 0 0 0 1.675.6Q11.1 20 12 20q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12q0 .9.2 1.775t.6 1.675q.176.325.188.688t-.088.712z"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
All activity
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Invites only' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19 6h-2a.97.97 0 0 1-.712-.287A.97.97 0 0 1 16 5q0-.424.288-.713A.97.97 0 0 1 17 4h2V2q0-.424.288-.712A.97.97 0 0 1 20 1q.424 0 .712.288Q21 1.575 21 2v2h2q.424 0 .712.287Q24 4.576 24 5t-.288.713A.97.97 0 0 1 23 6h-2v2q0 .424-.288.713A.97.97 0 0 1 20 9a.97.97 0 0 1-.712-.287A.97.97 0 0 1 19 8z"
/>
<path
d="M22 17v-6.341A6 6 0 0 1 20 11v6H6a2 2 0 0 0-1.414.586L4 18.172V5h10c0-.701.12-1.374.341-2H4a2 2 0 0 0-2 2v15.586c0 .89 1.077 1.337 1.707.707L6 19h14a2 2 0 0 0 2-2"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Invites only
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Low priority' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4.5a1 1 0 0 1 1 1v10.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-6 6a1 1 0 0 1-1.414 0l-6-6a1 1 0 1 1 1.414-1.414L11 16.086V5.5a1 1 0 0 1 1-1"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Low priority
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;
exports[`<RoomListFilterMenu /> shows 'Mentions only' checked if selected 1`] = `
<button
aria-selected="true"
class="_item_dyt4i_8 _interactive_dyt4i_26"
data-kind="primary"
data-orientation="vertical"
data-radix-collection-item=""
role="menuitem"
tabindex="-1"
>
<svg
class="_icon_dyt4i_50"
fill="currentColor"
height="20px"
viewBox="0 0 24 24"
width="20px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4a8 8 0 1 0 0 16 1 1 0 1 1 0 2C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10v1.5a3.5 3.5 0 0 1-6.396 1.966A5 5 0 1 1 17 12v1.5a1.5 1.5 0 0 0 3 0V12a8 8 0 0 0-8-8m3 8a3 3 0 1 0-6 0 3 3 0 0 0 6 0"
/>
</svg>
<span
class="_typography_6v6n8_153 _font-body-md-medium_6v6n8_60 _label_dyt4i_34"
>
Mentions only
</span>
<svg
color="var(--cpd-color-icon-primary)"
fill="currentColor"
height="24px"
viewBox="0 0 24 24"
width="24px"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.55 17.575q-.2 0-.375-.062a.9.9 0 0 1-.325-.213L4.55 13q-.274-.274-.262-.713.012-.437.287-.712a.95.95 0 0 1 .7-.275q.425 0 .7.275L9.55 15.15l8.475-8.475q.274-.275.713-.275.437 0 .712.275.275.274.275.713 0 .437-.275.712l-9.2 9.2q-.15.15-.325.212a1.1 1.1 0 0 1-.375.063"
/>
</svg>
</button>
`;

View File

@@ -32,10 +32,10 @@ exports[`<RoomListPanel /> should not render the RoomListSearch component when U
aria-expanded="false"
aria-haspopup="menu"
aria-label="Room Options"
aria-labelledby="«rk»"
aria-labelledby="«rc»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«ri»"
id="radix-«ra»"
role="button"
style="--cpd-icon-button-size: 32px;"
tabindex="0"
@@ -136,6 +136,32 @@ exports[`<RoomListPanel /> should not render the RoomListSearch component when U
Rooms
</button>
</li>
<li
aria-selected="false"
role="option"
>
<button
aria-selected="false"
class="_chat-filter_5qdp0_8"
role="button"
tabindex="0"
>
Mentions
</button>
</li>
<li
aria-selected="false"
role="option"
>
<button
aria-selected="false"
class="_chat-filter_5qdp0_8"
role="button"
tabindex="0"
>
Invites
</button>
</li>
<li
aria-selected="false"
role="option"
@@ -150,44 +176,6 @@ exports[`<RoomListPanel /> should not render the RoomListSearch component when U
</button>
</li>
</ul>
<div
aria-label="Secondary filters"
class="mx_Flex mx_RoomListSecondaryFilters"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 4px; --mx-flex-wrap: nowrap;"
>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Filter"
aria-labelledby="«rr»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«rp»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
All activity
</div>
<div
class="mx_RoomListSkeleton"
/>
@@ -397,6 +385,32 @@ exports[`<RoomListPanel /> should render the RoomListSearch component when UICom
Rooms
</button>
</li>
<li
aria-selected="false"
role="option"
>
<button
aria-selected="false"
class="_chat-filter_5qdp0_8"
role="button"
tabindex="0"
>
Mentions
</button>
</li>
<li
aria-selected="false"
role="option"
>
<button
aria-selected="false"
class="_chat-filter_5qdp0_8"
role="button"
tabindex="0"
>
Invites
</button>
</li>
<li
aria-selected="false"
role="option"
@@ -411,44 +425,6 @@ exports[`<RoomListPanel /> should render the RoomListSearch component when UICom
</button>
</li>
</ul>
<div
aria-label="Secondary filters"
class="mx_Flex mx_RoomListSecondaryFilters"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: 4px; --mx-flex-wrap: nowrap;"
>
<button
aria-disabled="false"
aria-expanded="false"
aria-haspopup="menu"
aria-label="Filter"
aria-labelledby="«rb»"
class="_icon-button_m2erp_8"
data-state="closed"
id="radix-«r9»"
role="button"
style="--cpd-icon-button-size: 28px;"
tabindex="0"
type="button"
>
<div
class="_indicator-icon_zr2a0_17"
style="--cpd-icon-button-size: 100%;"
>
<svg
fill="currentColor"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 7a1 1 0 0 0 0 2h14a1 1 0 1 0 0-2zm3 4a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2zm2 5a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1"
/>
</svg>
</div>
</button>
All activity
</div>
<div
class="mx_RoomListSkeleton"
/>