-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
* feat(new room list): move `RoomListView` to its own folder and add styling * feat(new room list): add search section * test(new room list): add tests for `RoomListSearch` * test(new room list): add tests for `RoomListView` * test(e2e): add method to close notification toast to `ElementAppPage` * test(e2e): add tests for the search section * test(e2e): add tests for the room list view * refactor: use Flex component * fix: loop icon size in search button * refactor: remove `focus_room_filter` listener
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* 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 { type Page } from "@playwright/test"; | ||
|
||
import { test, expect } from "../../../element-web-test"; | ||
|
||
test.describe("Search section of the room list", () => { | ||
test.use({ | ||
labsFlags: ["feature_new_room_list"], | ||
}); | ||
|
||
/** | ||
* Get the search section of the room list | ||
* @param page | ||
*/ | ||
function getSearchSection(page: Page) { | ||
return page.getByRole("search"); | ||
} | ||
|
||
test.beforeEach(async ({ page, app, user }) => { | ||
// The notification toast is displayed above the search section | ||
await app.closeNotificationToast(); | ||
}); | ||
|
||
test("should render the search section", { tag: "@screenshot" }, async ({ page, app, user }) => { | ||
const searchSection = getSearchSection(page); | ||
// exact=false to ignore the shortcut which is related to the OS | ||
await expect(searchSection.getByRole("button", { name: "Search", exact: false })).toBeVisible(); | ||
await expect(searchSection).toMatchScreenshot("search-section.png"); | ||
}); | ||
|
||
test("should open the spotlight when the search button is clicked", async ({ page, app, user }) => { | ||
const searchSection = getSearchSection(page); | ||
await searchSection.getByRole("button", { name: "Search", exact: false }).click(); | ||
// The spotlight should be displayed | ||
await expect(page.getByRole("dialog", { name: "Search Dialog" })).toBeVisible(); | ||
}); | ||
|
||
test("should open the room directory when the search button is clicked", async ({ page, app, user }) => { | ||
const searchSection = getSearchSection(page); | ||
await searchSection.getByRole("button", { name: "Explore rooms" }).click(); | ||
const dialog = page.getByRole("dialog", { name: "Search Dialog" }); | ||
// The room directory should be displayed | ||
await expect(dialog).toBeVisible(); | ||
// The public room filter should be displayed | ||
await expect(dialog.getByText("Public rooms")).toBeVisible(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* 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 { type Page } from "@playwright/test"; | ||
|
||
import { test, expect } from "../../../element-web-test"; | ||
|
||
test.describe("Search section of the room list", () => { | ||
test.use({ | ||
labsFlags: ["feature_new_room_list"], | ||
}); | ||
|
||
/** | ||
* Get the room list view | ||
* @param page | ||
*/ | ||
function getRoomListView(page: Page) { | ||
return page.getByTestId("room-list-view"); | ||
} | ||
|
||
test.beforeEach(async ({ page, app, user }) => { | ||
// The notification toast is displayed above the search section | ||
await app.closeNotificationToast(); | ||
}); | ||
|
||
test("should render the room list view", { tag: "@screenshot" }, async ({ page, app, user }) => { | ||
const roomListView = getRoomListView(page); | ||
await expect(roomListView).toMatchScreenshot("room-list-view.png"); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,13 +25,9 @@ test.describe("Security user settings tab", () => { | |
}, | ||
}); | ||
|
||
test.beforeEach(async ({ page, user }) => { | ||
test.beforeEach(async ({ page, app, user }) => { | ||
Check failure on line 28 in playwright/e2e/settings/security-user-settings-tab.spec.ts
|
||
// Dismiss "Notification" toast | ||
await page | ||
.locator(".mx_Toast_toast", { hasText: "Notifications" }) | ||
.getByRole("button", { name: "Dismiss" }) | ||
.click(); | ||
|
||
await app.closeNotificationToast(); | ||
await page.locator(".mx_Toast_buttons").getByRole("button", { name: "Yes" }).click(); // Allow analytics | ||
}); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -202,4 +202,15 @@ export class ElementAppPage { | |
} | ||
return this.page.locator(`id=${labelledById ?? describedById}`); | ||
} | ||
|
||
/** | ||
* Close the notification toast | ||
*/ | ||
public closeNotificationToast(): Promise<void> { | ||
// Dismiss "Notification" toast | ||
return this.page | ||
.locator(".mx_Toast_toast", { hasText: "Notifications" }) | ||
.getByRole("button", { name: "Dismiss" }) | ||
.click(); | ||
Check failure on line 214 in playwright/pages/ElementAppPage.ts
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
.mx_RoomListSearch { | ||
/* From figma, this should be aligned with the room header */ | ||
height: 64px; | ||
box-sizing: border-box; | ||
border-bottom: 1px solid var(--cpd-color-bg-subtle-primary); | ||
padding: 0 var(--cpd-space-3x); | ||
|
||
svg { | ||
fill: var(--cpd-color-icon-secondary); | ||
} | ||
|
||
.mx_RoomListSearch_search { | ||
/* The search button should take all the remaining space */ | ||
flex: 1; | ||
font: var(--cpd-font-body-md-regular); | ||
color: var(--cpd-color-text-secondary); | ||
|
||
span { | ||
flex: 1; | ||
|
||
kbd { | ||
font-family: inherit; | ||
} | ||
} | ||
} | ||
|
||
.mx_RoomListSearch_explore:hover { | ||
svg { | ||
fill: var(--cpd-color-icon-primary); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
.mx_RoomListView { | ||
background-color: var(--cpd-color-bg-canvas-default); | ||
height: 100%; | ||
border-right: 1px solid var(--cpd-color-bg-subtle-primary); | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* 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, { type JSX } from "react"; | ||
import { Button } from "@vector-im/compound-web"; | ||
import ExploreIcon from "@vector-im/compound-design-tokens/assets/web/icons/explore"; | ||
import SearchIcon from "@vector-im/compound-design-tokens/assets/web/icons/search"; | ||
|
||
import { IS_MAC, Key } from "../../../../Keyboard"; | ||
import { _t } from "../../../../languageHandler"; | ||
import { ALTERNATE_KEY_NAME } from "../../../../accessibility/KeyboardShortcuts"; | ||
import { shouldShowComponent } from "../../../../customisations/helpers/UIComponents"; | ||
import { UIComponent } from "../../../../settings/UIFeature"; | ||
import { MetaSpace } from "../../../../stores/spaces"; | ||
import { Action } from "../../../../dispatcher/actions"; | ||
import PosthogTrackers from "../../../../PosthogTrackers"; | ||
import defaultDispatcher from "../../../../dispatcher/dispatcher"; | ||
import { Flex } from "../../../utils/Flex"; | ||
|
||
type RoomListSearchProps = { | ||
/** | ||
* Current active space | ||
* The explore button is only displayed in the Home meta space | ||
*/ | ||
activeSpace: string; | ||
}; | ||
|
||
/** | ||
* A search component to be displayed at the top of the room list | ||
* The `Explore` button is displayed only in the Home meta space and when UIComponent.ExploreRooms is enabled. | ||
*/ | ||
export function RoomListSearch({ activeSpace }: RoomListSearchProps): JSX.Element { | ||
const displayExploreButton = activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms); | ||
|
||
return ( | ||
<Flex className="mx_RoomListSearch" role="search" gap="var(--cpd-space-2x)" align="center"> | ||
<Button | ||
className="mx_RoomListSearch_search" | ||
kind="secondary" | ||
size="sm" | ||
Icon={SearchIcon} | ||
onClick={() => defaultDispatcher.fire(Action.OpenSpotlight)} | ||
> | ||
<Flex as="span" justify="space-between"> | ||
{_t("action|search")} | ||
<kbd>{IS_MAC ? "⌘ K" : _t(ALTERNATE_KEY_NAME[Key.CONTROL]) + " K"}</kbd> | ||
</Flex> | ||
</Button> | ||
{displayExploreButton && ( | ||
<Button | ||
className="mx_RoomListSearch_explore" | ||
kind="secondary" | ||
size="sm" | ||
Icon={ExploreIcon} | ||
iconOnly={true} | ||
aria-label={_t("action|explore_rooms")} | ||
onClick={(ev) => { | ||
defaultDispatcher.fire(Action.ViewRoomDirectory); | ||
PosthogTrackers.trackInteraction("WebLeftPanelExploreRoomsButton", ev); | ||
}} | ||
/> | ||
)} | ||
</Flex> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
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 { shouldShowComponent } from "../../../../customisations/helpers/UIComponents"; | ||
import { UIComponent } from "../../../../settings/UIFeature"; | ||
import { RoomListSearch } from "./RoomListSearch"; | ||
|
||
type RoomListViewProps = { | ||
/** | ||
* Current active space | ||
* See {@link RoomListSearch} | ||
*/ | ||
activeSpace: string; | ||
}; | ||
|
||
/** | ||
* A view component for the room list. | ||
*/ | ||
export const RoomListView: React.FC<RoomListViewProps> = ({ activeSpace }) => { | ||
const displayRoomSearch = shouldShowComponent(UIComponent.FilterContainer); | ||
|
||
return ( | ||
<div className="mx_RoomListView" data-testid="room-list-view"> | ||
{displayRoomSearch && <RoomListSearch activeSpace={activeSpace} />} | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
export { RoomListView } from "./RoomListView"; |