New room list: add dial to search section (#29359)

* feat(new room list): add dial to new room list

* test(new room list): test dial button

* test(new room list): update room list test
This commit is contained in:
Florian Duros 2025-02-25 12:03:29 +01:00 committed by GitHub
parent 2e883b40eb
commit 43efd911c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 136 additions and 6 deletions

View File

@ -31,7 +31,7 @@
}
}
.mx_RoomListSearch_explore:hover {
.mx_RoomListSearch_button:hover {
svg {
fill: var(--cpd-color-icon-primary);
}

View File

@ -9,6 +9,7 @@ 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 DialPadIcon from "@vector-im/compound-design-tokens/assets/web/icons/dial-pad";
import { IS_MAC, Key } from "../../../../Keyboard";
import { _t } from "../../../../languageHandler";
@ -20,6 +21,8 @@ import { Action } from "../../../../dispatcher/actions";
import PosthogTrackers from "../../../../PosthogTrackers";
import defaultDispatcher from "../../../../dispatcher/dispatcher";
import { Flex } from "../../../utils/Flex";
import { useTypedEventEmitterState } from "../../../../hooks/useEventEmitter";
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../../LegacyCallHandler";
type RoomListSearchProps = {
/**
@ -35,6 +38,12 @@ type RoomListSearchProps = {
*/
export function RoomListSearch({ activeSpace }: RoomListSearchProps): JSX.Element {
const displayExploreButton = activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms);
// We only display the dial button if the user is can make PSTN calls
const displayDialButton = useTypedEventEmitterState(
LegacyCallHandler.instance,
LegacyCallHandlerEvent.ProtocolSupport,
() => LegacyCallHandler.instance.getSupportsPstnProtocol(),
);
return (
<Flex className="mx_RoomListSearch" role="search" gap="var(--cpd-space-2x)" align="center">
@ -50,9 +59,22 @@ export function RoomListSearch({ activeSpace }: RoomListSearchProps): JSX.Elemen
<kbd>{IS_MAC ? "⌘ K" : _t(ALTERNATE_KEY_NAME[Key.CONTROL]) + " K"}</kbd>
</Flex>
</Button>
{displayDialButton && (
<Button
className="mx_RoomListSearch_button"
kind="secondary"
size="sm"
Icon={DialPadIcon}
iconOnly={true}
aria-label={_t("left_panel|open_dial_pad")}
onClick={(ev) => {
defaultDispatcher.fire(Action.OpenDialPad);
}}
/>
)}
{displayExploreButton && (
<Button
className="mx_RoomListSearch_explore"
className="mx_RoomListSearch_button"
kind="secondary"
size="sm"
Icon={ExploreIcon}

View File

@ -15,6 +15,7 @@ import { MetaSpace } from "../../../../../../src/stores/spaces";
import { shouldShowComponent } from "../../../../../../src/customisations/helpers/UIComponents";
import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
import { Action } from "../../../../../../src/dispatcher/actions";
import LegacyCallHandler from "../../../../../../src/LegacyCallHandler";
jest.mock("../../../../../../src/customisations/helpers/UIComponents", () => ({
shouldShowComponent: jest.fn(),
@ -28,14 +29,17 @@ describe("<RoomListSearch />", () => {
beforeEach(() => {
// By default, we consider shouldShowComponent(UIComponent.ExploreRooms) should return true
mocked(shouldShowComponent).mockReturnValue(true);
jest.spyOn(LegacyCallHandler.instance, "getSupportsPstnProtocol").mockReturnValue(false);
});
it("should display all the buttons", () => {
it("should display search and explore buttons", () => {
const { asFragment } = renderComponent();
// The search and explore buttons should be displayed
expect(screen.getByRole("button", { name: "Search Ctrl K" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Explore rooms" })).toBeInTheDocument();
// The dial button should not be displayed
expect(screen.queryByRole("button", { name: "Open dial pad" })).not.toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
});
@ -58,6 +62,15 @@ describe("<RoomListSearch />", () => {
expect(asFragment()).toMatchSnapshot();
});
it("should display the dial button when the PTSN protocol is not supported", () => {
jest.spyOn(LegacyCallHandler.instance, "getSupportsPstnProtocol").mockReturnValue(true);
const { asFragment } = renderComponent();
// The dial button should be displayed
expect(screen.getByRole("button", { name: "Open dial pad" })).toBeInTheDocument();
expect(asFragment()).toMatchSnapshot();
});
it("should open the spotlight when the search button is clicked", async () => {
const fireSpy = jest.spyOn(defaultDispatcher, "fire");
const user = userEvent.setup();
@ -81,4 +94,17 @@ describe("<RoomListSearch />", () => {
// The spotlight should be opened
expect(fireSpy).toHaveBeenCalledWith(Action.ViewRoomDirectory);
});
it("should open the dial pad when the dial button is clicked", async () => {
jest.spyOn(LegacyCallHandler.instance, "getSupportsPstnProtocol").mockReturnValue(true);
const fireSpy = jest.spyOn(defaultDispatcher, "fire");
const user = userEvent.setup();
renderComponent();
// Click on the search button
await user.click(screen.getByRole("button", { name: "Open dial pad" }));
// The spotlight should be opened
expect(fireSpy).toHaveBeenCalledWith(Action.OpenDialPad);
});
});

View File

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<RoomListSearch /> should display all the buttons 1`] = `
exports[`<RoomListSearch /> should display search and explore buttons 1`] = `
<DocumentFragment>
<div
class="mx_Flex mx_RoomListSearch"
@ -38,7 +38,89 @@ exports[`<RoomListSearch /> should display all the buttons 1`] = `
</button>
<button
aria-label="Explore rooms"
class="_button_vczzf_8 mx_RoomListSearch_explore _has-icon_vczzf_57 _icon-only_vczzf_50"
class="_button_vczzf_8 mx_RoomListSearch_button _has-icon_vczzf_57 _icon-only_vczzf_50"
data-kind="secondary"
data-size="sm"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 13a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 12q0-.424.287-.713A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713 0 .424-.287.713A.97.97 0 0 1 12 13m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 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 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12t2.325 5.675T12 20m0 0q-3.35 0-5.675-2.325T4 12t2.325-5.675T12 4t5.675 2.325T20 12t-2.325 5.675T12 20m1.675-5.85q.15-.075.275-.2t.2-.275l2.925-6.25q.125-.25-.062-.437-.188-.188-.438-.063l-6.25 2.925q-.15.075-.275.2t-.2.275l-2.925 6.25q-.125.25.063.438.186.186.437.062z"
/>
</svg>
</button>
</div>
</DocumentFragment>
`;
exports[`<RoomListSearch /> should display the dial button when the PTSN protocol is not supported 1`] = `
<DocumentFragment>
<div
class="mx_Flex mx_RoomListSearch"
role="search"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-2x);"
>
<button
class="_button_vczzf_8 mx_RoomListSearch_search _has-icon_vczzf_57"
data-kind="secondary"
data-size="sm"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414zM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0"
/>
</svg>
<span
class="mx_Flex"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: start; --mx-flex-justify: space-between; --mx-flex-gap: 0;"
>
Search
<kbd>
Ctrl K
</kbd>
</span>
</button>
<button
aria-label="Open dial pad"
class="_button_vczzf_8 mx_RoomListSearch_button _has-icon_vczzf_57 _icon-only_vczzf_50"
data-kind="secondary"
data-size="sm"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
fill="currentColor"
height="20"
viewBox="0 0 24 24"
width="20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 18.6c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M6.6 2.4c-.99 0-1.8.81-1.8 1.8S5.61 6 6.6 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0 5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8M17.4 6c.99 0 1.8-.81 1.8-1.8s-.81-1.8-1.8-1.8-1.8.81-1.8 1.8.81 1.8 1.8 1.8M12 13.2c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m-5.4 0c-.99 0-1.8.81-1.8 1.8s.81 1.8 1.8 1.8 1.8-.81 1.8-1.8-.81-1.8-1.8-1.8m0-5.4c-.99 0-1.8.81-1.8 1.8S11.01 6 12 6s1.8-.81 1.8-1.8-.81-1.8-1.8-1.8"
/>
</svg>
</button>
<button
aria-label="Explore rooms"
class="_button_vczzf_8 mx_RoomListSearch_button _has-icon_vczzf_57 _icon-only_vczzf_50"
data-kind="secondary"
data-size="sm"
role="button"

View File

@ -62,7 +62,7 @@ exports[`<RoomListView /> should render the RoomListSearch component when UIComp
</button>
<button
aria-label="Explore rooms"
class="_button_vczzf_8 mx_RoomListSearch_explore _has-icon_vczzf_57 _icon-only_vczzf_50"
class="_button_vczzf_8 mx_RoomListSearch_button _has-icon_vczzf_57 _icon-only_vczzf_50"
data-kind="secondary"
data-size="sm"
role="button"