You've already forked element-web
mirror of
https://github.com/element-hq/element-web.git
synced 2025-08-09 14:42:51 +03:00
Add low priority avatar decoration to room tile (#30065)
* Add avatar decoration for low priority rooms * Write tests * Remove unnecesasry step in test * Make the vm expose which decoration to render * Fix jest test * Fix broken e2e test
This commit is contained in:
@@ -255,6 +255,28 @@ test.describe("Room list", () => {
|
|||||||
await expect(publicRoom).toMatchScreenshot("room-list-item-public.png");
|
await expect(publicRoom).toMatchScreenshot("room-list-item-public.png");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should be a low priority room", { tag: "@screenshot" }, async ({ page, app, user }) => {
|
||||||
|
// @ts-ignore Visibility enum is not accessible
|
||||||
|
await app.client.createRoom({ name: "low priority room", visibility: "public" });
|
||||||
|
const roomListView = getRoomList(page);
|
||||||
|
const publicRoom = roomListView.getByRole("gridcell", { name: "low priority room" });
|
||||||
|
|
||||||
|
// Make room low priority
|
||||||
|
await publicRoom.hover();
|
||||||
|
const roomItemMenu = publicRoom.getByRole("button", { name: "More Options" });
|
||||||
|
await roomItemMenu.click();
|
||||||
|
await page.getByRole("menuitemcheckbox", { name: "Low priority" }).click();
|
||||||
|
|
||||||
|
// Should have low priority decoration
|
||||||
|
await expect(publicRoom.locator(".mx_RoomAvatarView_icon")).toHaveAccessibleName(
|
||||||
|
"This is a low priority room",
|
||||||
|
);
|
||||||
|
|
||||||
|
// focus the user menu to avoid to have hover decoration
|
||||||
|
await page.getByRole("button", { name: "User menu" }).focus();
|
||||||
|
await expect(publicRoom).toMatchScreenshot("room-list-item-low-priority.png");
|
||||||
|
});
|
||||||
|
|
||||||
test("should be a video room", { tag: "@screenshot" }, async ({ page, app, user }) => {
|
test("should be a video room", { tag: "@screenshot" }, async ({ page, app, user }) => {
|
||||||
await page.getByTestId("room-list-panel").getByRole("button", { name: "Add" }).click();
|
await page.getByTestId("room-list-panel").getByRole("button", { name: "Add" }).click();
|
||||||
await page.getByRole("menuitem", { name: "New video room" }).click();
|
await page.getByRole("menuitem", { name: "New video room" }).click();
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
@@ -10,26 +10,26 @@ import { useEffect, useState } from "react";
|
|||||||
|
|
||||||
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
|
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import { useDmMember, usePresence, type Presence } from "../../views/avatars/WithPresenceIndicator";
|
import { useDmMember, usePresence, type Presence } from "../../views/avatars/WithPresenceIndicator";
|
||||||
|
import { DefaultTagID } from "../../../stores/room-list/models";
|
||||||
|
|
||||||
|
export enum AvatarBadgeDecoration {
|
||||||
|
LowPriority = "LowPriority",
|
||||||
|
VideoRoom = "VideoRoom",
|
||||||
|
PublicRoom = "PublicRoom",
|
||||||
|
Presence = "Presence",
|
||||||
|
}
|
||||||
|
|
||||||
export interface RoomAvatarViewState {
|
export interface RoomAvatarViewState {
|
||||||
/**
|
|
||||||
* Whether the room avatar has a decoration.
|
|
||||||
* A decoration can be a public or a video call icon or an indicator of presence.
|
|
||||||
*/
|
|
||||||
hasDecoration: boolean;
|
|
||||||
/**
|
|
||||||
* Whether the room is public.
|
|
||||||
*/
|
|
||||||
isPublic: boolean;
|
|
||||||
/**
|
|
||||||
* Whether the room is a video room.
|
|
||||||
*/
|
|
||||||
isVideoRoom: boolean;
|
|
||||||
/**
|
/**
|
||||||
* The presence of the user in the DM room.
|
* The presence of the user in the DM room.
|
||||||
* If null, the user is not in a DM room or presence is not enabled.
|
* If null, the user is not in a DM room or presence is not enabled.
|
||||||
*/
|
*/
|
||||||
presence: Presence | null;
|
presence: Presence | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The decoration that should be rendered.
|
||||||
|
*/
|
||||||
|
badgeDecoration?: AvatarBadgeDecoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,10 +41,20 @@ export function useRoomAvatarViewModel(room: Room): RoomAvatarViewState {
|
|||||||
const roomMember = useDmMember(room);
|
const roomMember = useDmMember(room);
|
||||||
const presence = usePresence(room, roomMember);
|
const presence = usePresence(room, roomMember);
|
||||||
const isPublic = useIsPublic(room);
|
const isPublic = useIsPublic(room);
|
||||||
|
const isLowPriority = !!room.tags[DefaultTagID.LowPriority];
|
||||||
|
|
||||||
const hasDecoration = isPublic || isVideoRoom || presence !== null;
|
let badgeDecoration: AvatarBadgeDecoration | undefined;
|
||||||
|
if (isLowPriority) {
|
||||||
|
badgeDecoration = AvatarBadgeDecoration.LowPriority;
|
||||||
|
} else if (isVideoRoom) {
|
||||||
|
badgeDecoration = AvatarBadgeDecoration.VideoRoom;
|
||||||
|
} else if (isPublic) {
|
||||||
|
badgeDecoration = AvatarBadgeDecoration.PublicRoom;
|
||||||
|
} else if (presence) {
|
||||||
|
badgeDecoration = AvatarBadgeDecoration.Presence;
|
||||||
|
}
|
||||||
|
|
||||||
return { hasDecoration, isPublic, isVideoRoom, presence };
|
return { badgeDecoration, presence };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -9,13 +9,14 @@ import React, { type JSX } from "react";
|
|||||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||||
import PublicIcon from "@vector-im/compound-design-tokens/assets/web/icons/public";
|
import PublicIcon from "@vector-im/compound-design-tokens/assets/web/icons/public";
|
||||||
import VideoIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
|
import VideoIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
|
||||||
|
import ArrowDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/arrow-down";
|
||||||
import OnlineOrUnavailableIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-solid-8x8";
|
import OnlineOrUnavailableIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-solid-8x8";
|
||||||
import OfflineIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-outline-8x8";
|
import OfflineIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-outline-8x8";
|
||||||
import BusyIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-strikethrough-8x8";
|
import BusyIcon from "@vector-im/compound-design-tokens/assets/web/icons/presence-strikethrough-8x8";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import RoomAvatar from "./RoomAvatar";
|
import RoomAvatar from "./RoomAvatar";
|
||||||
import { useRoomAvatarViewModel } from "../../viewmodels/avatars/RoomAvatarViewModel";
|
import { AvatarBadgeDecoration, useRoomAvatarViewModel } from "../../viewmodels/avatars/RoomAvatarViewModel";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { Presence } from "./WithPresenceIndicator";
|
import { Presence } from "./WithPresenceIndicator";
|
||||||
|
|
||||||
@@ -33,41 +34,21 @@ interface RoomAvatarViewProps {
|
|||||||
export function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
|
export function RoomAvatarView({ room }: RoomAvatarViewProps): JSX.Element {
|
||||||
const vm = useRoomAvatarViewModel(room);
|
const vm = useRoomAvatarViewModel(room);
|
||||||
// No decoration, we just show the avatar
|
// No decoration, we just show the avatar
|
||||||
if (!vm.hasDecoration) return <RoomAvatar size="32px" room={room} />;
|
if (!vm.badgeDecoration) return <RoomAvatar size="32px" room={room} />;
|
||||||
|
|
||||||
|
const icon = getAvatarDecoration(vm.badgeDecoration, vm.presence);
|
||||||
|
|
||||||
|
// Presence indicator and video/public icons don't have the same size
|
||||||
|
// We use different masks
|
||||||
|
const maskClass =
|
||||||
|
vm.badgeDecoration === AvatarBadgeDecoration.Presence
|
||||||
|
? "mx_RoomAvatarView_RoomAvatar_presence"
|
||||||
|
: "mx_RoomAvatarView_RoomAvatar_icon";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomAvatarView">
|
<div className="mx_RoomAvatarView">
|
||||||
<RoomAvatar
|
<RoomAvatar className={classNames("mx_RoomAvatarView_RoomAvatar", maskClass)} size="32px" room={room} />
|
||||||
className={classNames("mx_RoomAvatarView_RoomAvatar", {
|
{icon}
|
||||||
// Presence indicator and video/public icons don't have the same size
|
|
||||||
// We use different masks
|
|
||||||
mx_RoomAvatarView_RoomAvatar_icon: vm.isVideoRoom || vm.isPublic,
|
|
||||||
mx_RoomAvatarView_RoomAvatar_presence: Boolean(vm.presence),
|
|
||||||
})}
|
|
||||||
size="32px"
|
|
||||||
room={room}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* If the room is a public video room, we prefer to display only the video icon */}
|
|
||||||
{vm.isPublic && !vm.isVideoRoom && (
|
|
||||||
<PublicIcon
|
|
||||||
width="16px"
|
|
||||||
height="16px"
|
|
||||||
className="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
aria-label={_t("room|header|room_is_public")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{vm.isVideoRoom && (
|
|
||||||
<VideoIcon
|
|
||||||
width="16px"
|
|
||||||
height="16px"
|
|
||||||
className="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
aria-label={_t("room|video_room")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{vm.presence && <PresenceDecoration presence={vm.presence} />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -126,3 +107,39 @@ function PresenceDecoration({ presence }: PresenceDecorationProps): JSX.Element
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAvatarDecoration(decoration: AvatarBadgeDecoration, presence: Presence | null): React.ReactNode {
|
||||||
|
if (decoration === AvatarBadgeDecoration.LowPriority) {
|
||||||
|
return (
|
||||||
|
<ArrowDownIcon
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
className="mx_RoomAvatarView_icon"
|
||||||
|
color="var(--cpd-color-icon-tertiary)"
|
||||||
|
aria-label={_t("room|room_is_low_priority")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (decoration === AvatarBadgeDecoration.VideoRoom) {
|
||||||
|
return (
|
||||||
|
<VideoIcon
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
className="mx_RoomAvatarView_icon"
|
||||||
|
color="var(--cpd-color-icon-tertiary)"
|
||||||
|
aria-label={_t("room|video_room")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (decoration === AvatarBadgeDecoration.PublicRoom) {
|
||||||
|
return (
|
||||||
|
<PublicIcon
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
className="mx_RoomAvatarView_icon"
|
||||||
|
color="var(--cpd-color-icon-tertiary)"
|
||||||
|
aria-label={_t("room|header|room_is_public")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (decoration === AvatarBadgeDecoration.Presence) {
|
||||||
|
return <PresenceDecoration presence={presence!} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -2047,6 +2047,7 @@
|
|||||||
"read_topic": "Click to read topic",
|
"read_topic": "Click to read topic",
|
||||||
"rejecting": "Rejecting invite…",
|
"rejecting": "Rejecting invite…",
|
||||||
"rejoin_button": "Re-join",
|
"rejoin_button": "Re-join",
|
||||||
|
"room_is_low_priority": "This is a low priority room",
|
||||||
"search": {
|
"search": {
|
||||||
"all_rooms_button": "Search all rooms",
|
"all_rooms_button": "Search all rooms",
|
||||||
"placeholder": "Search messages…",
|
"placeholder": "Search messages…",
|
||||||
|
@@ -8,10 +8,14 @@
|
|||||||
import { renderHook, waitFor } from "jest-matrix-react";
|
import { renderHook, waitFor } from "jest-matrix-react";
|
||||||
import { JoinRule, type MatrixClient, type Room, RoomMember, User } from "matrix-js-sdk/src/matrix";
|
import { JoinRule, type MatrixClient, type Room, RoomMember, User } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { useRoomAvatarViewModel } from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
import {
|
||||||
|
AvatarBadgeDecoration,
|
||||||
|
useRoomAvatarViewModel,
|
||||||
|
} from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
||||||
import { createTestClient, mkStubRoom } from "../../../../test-utils";
|
import { createTestClient, mkStubRoom } from "../../../../test-utils";
|
||||||
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
||||||
import * as PresenceIndicatorModule from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
import * as PresenceIndicatorModule from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
||||||
|
import { DefaultTagID } from "../../../../../src/stores/room-list/models";
|
||||||
|
|
||||||
jest.mock("../../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
|
jest.mock("../../../../../src/utils/room/getJoinedNonFunctionalMembers", () => ({
|
||||||
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([]),
|
getJoinedNonFunctionalMembers: jest.fn().mockReturnValue([]),
|
||||||
@@ -32,35 +36,61 @@ describe("RoomAvatarViewModel", () => {
|
|||||||
jest.spyOn(PresenceIndicatorModule, "usePresence").mockReturnValue(null);
|
jest.spyOn(PresenceIndicatorModule, "usePresence").mockReturnValue(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should has hasDecoration to false", async () => {
|
it("should have badgeDecoration set to LowPriority", () => {
|
||||||
|
room.tags[DefaultTagID.LowPriority] = {};
|
||||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||||
expect(vm.current.hasDecoration).toBe(false);
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.LowPriority);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should has isVideoRoom set to true", () => {
|
it("should have badgeDecoration set to VideoRoom", () => {
|
||||||
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
||||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||||
expect(vm.current.isVideoRoom).toBe(true);
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.VideoRoom);
|
||||||
expect(vm.current.hasDecoration).toBe(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should has isPublic set to true", () => {
|
it("should have badgeDecoration set to PublicRoom", () => {
|
||||||
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Public);
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||||
|
|
||||||
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
const { result: vm } = renderHook(() => useRoomAvatarViewModel(room));
|
||||||
expect(vm.current.isPublic).toBe(true);
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom);
|
||||||
expect(vm.current.hasDecoration).toBe(true);
|
});
|
||||||
|
|
||||||
|
it("should set badgeDecoration based on priority", () => {
|
||||||
|
// 1. Presence has the least priority
|
||||||
|
const user = User.createUser("userId", matrixClient);
|
||||||
|
const roomMember = new RoomMember(room.roomId, "userId");
|
||||||
|
roomMember.user = user;
|
||||||
|
jest.spyOn(PresenceIndicatorModule, "useDmMember").mockReturnValue(roomMember);
|
||||||
|
jest.spyOn(PresenceIndicatorModule, "usePresence").mockReturnValue(PresenceIndicatorModule.Presence.Online);
|
||||||
|
|
||||||
|
const { result: vm1 } = renderHook(() => useRoomAvatarViewModel(room));
|
||||||
|
expect(vm1.current.badgeDecoration).toBe(AvatarBadgeDecoration.Presence);
|
||||||
|
|
||||||
|
// 2. With presence and public room, presence takes precedence
|
||||||
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||||
|
// Render again, it's easier than mocking the event emitter.
|
||||||
|
const { result: vm, rerender } = renderHook(() => useRoomAvatarViewModel(room));
|
||||||
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom);
|
||||||
|
|
||||||
|
// 3. With presence, public-room and video room, video room takes precedence
|
||||||
|
jest.spyOn(room, "isCallRoom").mockReturnValue(true);
|
||||||
|
rerender(room);
|
||||||
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.VideoRoom);
|
||||||
|
|
||||||
|
// 4. With presence, public room, video room and low priority, low priority takes precedence
|
||||||
|
room.tags[DefaultTagID.LowPriority] = {};
|
||||||
|
rerender(room);
|
||||||
|
expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.LowPriority);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should recompute isPublic when room changed", async () => {
|
it("should recompute isPublic when room changed", async () => {
|
||||||
const { result: vm, rerender } = renderHook((props) => useRoomAvatarViewModel(props), { initialProps: room });
|
const { result: vm, rerender } = renderHook((props) => useRoomAvatarViewModel(props), { initialProps: room });
|
||||||
expect(vm.current.isPublic).toBe(false);
|
expect(vm.current.badgeDecoration).not.toBe(AvatarBadgeDecoration.PublicRoom);
|
||||||
|
|
||||||
const publicRoom = mkStubRoom("roomId2", "roomName2", matrixClient);
|
const publicRoom = mkStubRoom("roomId2", "roomName2", matrixClient);
|
||||||
jest.spyOn(publicRoom, "getJoinRule").mockReturnValue(JoinRule.Public);
|
jest.spyOn(publicRoom, "getJoinRule").mockReturnValue(JoinRule.Public);
|
||||||
rerender(publicRoom);
|
rerender(publicRoom);
|
||||||
|
|
||||||
await waitFor(() => expect(vm.current.isPublic).toBe(true));
|
await waitFor(() => expect(vm.current.badgeDecoration).toBe(AvatarBadgeDecoration.PublicRoom));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return presence", async () => {
|
it("should return presence", async () => {
|
||||||
|
@@ -12,6 +12,7 @@ import { mocked } from "jest-mock";
|
|||||||
import { RoomAvatarView } from "../../../../../src/components/views/avatars/RoomAvatarView";
|
import { RoomAvatarView } from "../../../../../src/components/views/avatars/RoomAvatarView";
|
||||||
import { mkStubRoom, stubClient } from "../../../../test-utils";
|
import { mkStubRoom, stubClient } from "../../../../test-utils";
|
||||||
import {
|
import {
|
||||||
|
AvatarBadgeDecoration,
|
||||||
type RoomAvatarViewState,
|
type RoomAvatarViewState,
|
||||||
useRoomAvatarViewModel,
|
useRoomAvatarViewModel,
|
||||||
} from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
} from "../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel";
|
||||||
@@ -19,6 +20,7 @@ import DMRoomMap from "../../../../../src/utils/DMRoomMap";
|
|||||||
import { Presence } from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
import { Presence } from "../../../../../src/components/views/avatars/WithPresenceIndicator";
|
||||||
|
|
||||||
jest.mock("../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel", () => ({
|
jest.mock("../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel", () => ({
|
||||||
|
...jest.requireActual("../../../../../src/components/viewmodels/avatars/RoomAvatarViewModel"),
|
||||||
useRoomAvatarViewModel: jest.fn(),
|
useRoomAvatarViewModel: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -33,9 +35,7 @@ describe("<RoomAvatarView />", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
defaultValue = {
|
defaultValue = {
|
||||||
hasDecoration: true,
|
badgeDecoration: undefined,
|
||||||
isPublic: true,
|
|
||||||
isVideoRoom: true,
|
|
||||||
presence: null,
|
presence: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,13 +43,27 @@ describe("<RoomAvatarView />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not render a decoration", () => {
|
it("should not render a decoration", () => {
|
||||||
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue, hasDecoration: false });
|
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue });
|
||||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should render a low priority room decoration", () => {
|
||||||
|
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||||
|
...defaultValue,
|
||||||
|
badgeDecoration: AvatarBadgeDecoration.LowPriority,
|
||||||
|
});
|
||||||
|
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||||
|
|
||||||
|
expect(screen.getByLabelText("This is a low priority room")).toBeInTheDocument();
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it("should render a video room decoration", () => {
|
it("should render a video room decoration", () => {
|
||||||
mocked(useRoomAvatarViewModel).mockReturnValue({ ...defaultValue, hasDecoration: true, isVideoRoom: true });
|
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||||
|
...defaultValue,
|
||||||
|
badgeDecoration: AvatarBadgeDecoration.VideoRoom,
|
||||||
|
});
|
||||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||||
|
|
||||||
expect(screen.getByLabelText("This room is a video room")).toBeInTheDocument();
|
expect(screen.getByLabelText("This room is a video room")).toBeInTheDocument();
|
||||||
@@ -59,9 +73,7 @@ describe("<RoomAvatarView />", () => {
|
|||||||
it("should render a public room decoration", () => {
|
it("should render a public room decoration", () => {
|
||||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||||
...defaultValue,
|
...defaultValue,
|
||||||
hasDecoration: true,
|
badgeDecoration: AvatarBadgeDecoration.PublicRoom,
|
||||||
isPublic: true,
|
|
||||||
isVideoRoom: false,
|
|
||||||
});
|
});
|
||||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||||
|
|
||||||
@@ -69,19 +81,6 @@ describe("<RoomAvatarView />", () => {
|
|||||||
expect(asFragment()).toMatchSnapshot();
|
expect(asFragment()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not render a public room decoration if the room is a video room", () => {
|
|
||||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
|
||||||
...defaultValue,
|
|
||||||
hasDecoration: true,
|
|
||||||
isPublic: true,
|
|
||||||
isVideoRoom: true,
|
|
||||||
});
|
|
||||||
render(<RoomAvatarView room={room} />);
|
|
||||||
|
|
||||||
expect(screen.getByLabelText("This room is a video room")).toBeInTheDocument();
|
|
||||||
expect(screen.queryByLabelText("This room is public")).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
{ presence: Presence.Online, label: "Online" },
|
{ presence: Presence.Online, label: "Online" },
|
||||||
{ presence: Presence.Offline, label: "Offline" },
|
{ presence: Presence.Offline, label: "Offline" },
|
||||||
@@ -90,7 +89,7 @@ describe("<RoomAvatarView />", () => {
|
|||||||
])("should render the $presence presence", ({ presence, label }) => {
|
])("should render the $presence presence", ({ presence, label }) => {
|
||||||
mocked(useRoomAvatarViewModel).mockReturnValue({
|
mocked(useRoomAvatarViewModel).mockReturnValue({
|
||||||
...defaultValue,
|
...defaultValue,
|
||||||
hasDecoration: true,
|
badgeDecoration: AvatarBadgeDecoration.Presence,
|
||||||
presence,
|
presence,
|
||||||
});
|
});
|
||||||
const { asFragment } = render(<RoomAvatarView room={room} />);
|
const { asFragment } = render(<RoomAvatarView room={room} />);
|
||||||
|
@@ -24,6 +24,48 @@ exports[`<RoomAvatarView /> should not render a decoration 1`] = `
|
|||||||
</DocumentFragment>
|
</DocumentFragment>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`<RoomAvatarView /> should render a low priority room decoration 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mx_RoomAvatarView"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="Avatar"
|
||||||
|
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon"
|
||||||
|
data-color="1"
|
||||||
|
data-testid="avatar-img"
|
||||||
|
data-type="round"
|
||||||
|
style="--cpd-avatar-size: 32px;"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
class="_image_1qbcf_41"
|
||||||
|
data-type="round"
|
||||||
|
height="32px"
|
||||||
|
loading="lazy"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
src="http://this.is.a.url/avatar.url/room.png"
|
||||||
|
width="32px"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
aria-label="This is a low priority room"
|
||||||
|
class="mx_RoomAvatarView_icon"
|
||||||
|
color="var(--cpd-color-icon-tertiary)"
|
||||||
|
fill="currentColor"
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
width="16px"
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`<RoomAvatarView /> should render a public room decoration 1`] = `
|
exports[`<RoomAvatarView /> should render a public room decoration 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
<div
|
||||||
@@ -115,7 +157,7 @@ exports[`<RoomAvatarView /> should render the AWAY presence 1`] = `
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="Avatar"
|
aria-label="Avatar"
|
||||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||||
data-color="1"
|
data-color="1"
|
||||||
data-testid="avatar-img"
|
data-testid="avatar-img"
|
||||||
data-type="round"
|
data-type="round"
|
||||||
@@ -132,20 +174,6 @@ exports[`<RoomAvatarView /> should render the AWAY presence 1`] = `
|
|||||||
width="32px"
|
width="32px"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<svg
|
|
||||||
aria-label="This room is a video room"
|
|
||||||
class="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
fill="currentColor"
|
|
||||||
height="16px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16px"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
<svg
|
||||||
aria-label="Away"
|
aria-label="Away"
|
||||||
class="mx_RoomAvatarView_PresenceDecoration"
|
class="mx_RoomAvatarView_PresenceDecoration"
|
||||||
@@ -184,7 +212,7 @@ exports[`<RoomAvatarView /> should render the BUSY presence 1`] = `
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="Avatar"
|
aria-label="Avatar"
|
||||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||||
data-color="1"
|
data-color="1"
|
||||||
data-testid="avatar-img"
|
data-testid="avatar-img"
|
||||||
data-type="round"
|
data-type="round"
|
||||||
@@ -201,20 +229,6 @@ exports[`<RoomAvatarView /> should render the BUSY presence 1`] = `
|
|||||||
width="32px"
|
width="32px"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<svg
|
|
||||||
aria-label="This room is a video room"
|
|
||||||
class="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
fill="currentColor"
|
|
||||||
height="16px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16px"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
<svg
|
||||||
aria-label="Busy"
|
aria-label="Busy"
|
||||||
class="mx_RoomAvatarView_PresenceDecoration"
|
class="mx_RoomAvatarView_PresenceDecoration"
|
||||||
@@ -255,7 +269,7 @@ exports[`<RoomAvatarView /> should render the OFFLINE presence 1`] = `
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="Avatar"
|
aria-label="Avatar"
|
||||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||||
data-color="1"
|
data-color="1"
|
||||||
data-testid="avatar-img"
|
data-testid="avatar-img"
|
||||||
data-type="round"
|
data-type="round"
|
||||||
@@ -272,20 +286,6 @@ exports[`<RoomAvatarView /> should render the OFFLINE presence 1`] = `
|
|||||||
width="32px"
|
width="32px"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<svg
|
|
||||||
aria-label="This room is a video room"
|
|
||||||
class="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
fill="currentColor"
|
|
||||||
height="16px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16px"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
<svg
|
||||||
aria-label="Offline"
|
aria-label="Offline"
|
||||||
class="mx_RoomAvatarView_PresenceDecoration"
|
class="mx_RoomAvatarView_PresenceDecoration"
|
||||||
@@ -326,7 +326,7 @@ exports[`<RoomAvatarView /> should render the ONLINE presence 1`] = `
|
|||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="Avatar"
|
aria-label="Avatar"
|
||||||
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_icon mx_RoomAvatarView_RoomAvatar_presence"
|
class="_avatar_1qbcf_8 mx_BaseAvatar mx_RoomAvatarView_RoomAvatar mx_RoomAvatarView_RoomAvatar_presence"
|
||||||
data-color="1"
|
data-color="1"
|
||||||
data-testid="avatar-img"
|
data-testid="avatar-img"
|
||||||
data-type="round"
|
data-type="round"
|
||||||
@@ -343,20 +343,6 @@ exports[`<RoomAvatarView /> should render the ONLINE presence 1`] = `
|
|||||||
width="32px"
|
width="32px"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<svg
|
|
||||||
aria-label="This room is a video room"
|
|
||||||
class="mx_RoomAvatarView_icon"
|
|
||||||
color="var(--cpd-color-icon-tertiary)"
|
|
||||||
fill="currentColor"
|
|
||||||
height="16px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="16px"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6 4h10a2 2 0 0 1 2 2v4.286l3.35-2.871a1 1 0 0 1 1.65.76v7.65a1 1 0 0 1-1.65.76L18 13.715V18a2 2 0 0 1-2 2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<svg
|
<svg
|
||||||
aria-label="Online"
|
aria-label="Online"
|
||||||
class="mx_RoomAvatarView_PresenceDecoration"
|
class="mx_RoomAvatarView_PresenceDecoration"
|
||||||
|
Reference in New Issue
Block a user