Add RoomKnocksBar to RoomHeader (#12077)
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>pull/28788/head^2
parent
2c714e2d9c
commit
def4b728d0
|
@ -51,6 +51,7 @@ import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import { Linkify, topicToHtml } from "../../../HtmlUtils";
|
import { Linkify, topicToHtml } from "../../../HtmlUtils";
|
||||||
import PosthogTrackers from "../../../PosthogTrackers";
|
import PosthogTrackers from "../../../PosthogTrackers";
|
||||||
import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton";
|
import { VideoRoomChatButton } from "./RoomHeader/VideoRoomChatButton";
|
||||||
|
import { RoomKnocksBar } from "./RoomKnocksBar";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper to transform a notification color to the what the Compound Icon Button
|
* A helper to transform a notification color to the what the Compound Icon Button
|
||||||
|
@ -115,165 +116,170 @@ export default function RoomHeader({
|
||||||
[roomTopic?.html, roomTopic?.text],
|
[roomTopic?.html, roomTopic?.text],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
|
<>
|
||||||
<button
|
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
|
||||||
aria-label={_t("right_panel|room_summary_card|title")}
|
<button
|
||||||
tabIndex={0}
|
aria-label={_t("right_panel|room_summary_card|title")}
|
||||||
onClick={() => {
|
tabIndex={0}
|
||||||
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomSummary);
|
onClick={() => {
|
||||||
}}
|
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomSummary);
|
||||||
className="mx_RoomHeader_infoWrapper"
|
}}
|
||||||
>
|
className="mx_RoomHeader_infoWrapper"
|
||||||
<RoomAvatar room={room} size="40px" />
|
>
|
||||||
<Box flex="1" className="mx_RoomHeader_info">
|
<RoomAvatar room={room} size="40px" />
|
||||||
<BodyText
|
<Box flex="1" className="mx_RoomHeader_info">
|
||||||
as="div"
|
|
||||||
size="lg"
|
|
||||||
weight="semibold"
|
|
||||||
dir="auto"
|
|
||||||
role="heading"
|
|
||||||
aria-level={1}
|
|
||||||
className="mx_RoomHeader_heading"
|
|
||||||
>
|
|
||||||
<span className="mx_RoomHeader_truncated mx_lineClamp">{roomName}</span>
|
|
||||||
|
|
||||||
{!isDirectMessage && roomState.getJoinRule() === JoinRule.Public && (
|
|
||||||
<Tooltip label={_t("common|public_room")} side="right">
|
|
||||||
<PublicIcon
|
|
||||||
width="16px"
|
|
||||||
height="16px"
|
|
||||||
className="mx_RoomHeader_icon text-secondary"
|
|
||||||
aria-label={_t("common|public_room")}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isDirectMessage && e2eStatus === E2EStatus.Verified && (
|
|
||||||
<Tooltip label={_t("common|verified")} side="right">
|
|
||||||
<VerifiedIcon
|
|
||||||
width="16px"
|
|
||||||
height="16px"
|
|
||||||
className="mx_RoomHeader_icon mx_Verified"
|
|
||||||
aria-label={_t("common|verified")}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isDirectMessage && e2eStatus === E2EStatus.Warning && (
|
|
||||||
<Tooltip label={_t("room|header_untrusted_label")} side="right">
|
|
||||||
<ErrorIcon
|
|
||||||
width="16px"
|
|
||||||
height="16px"
|
|
||||||
className="mx_RoomHeader_icon mx_Untrusted"
|
|
||||||
aria-label={_t("room|header_untrusted_label")}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</BodyText>
|
|
||||||
{roomTopic && (
|
|
||||||
<BodyText
|
<BodyText
|
||||||
as="div"
|
as="div"
|
||||||
size="sm"
|
size="lg"
|
||||||
className="mx_RoomHeader_topic mx_RoomHeader_truncated mx_lineClamp"
|
weight="semibold"
|
||||||
|
dir="auto"
|
||||||
|
role="heading"
|
||||||
|
aria-level={1}
|
||||||
|
className="mx_RoomHeader_heading"
|
||||||
>
|
>
|
||||||
<Linkify>{roomTopicBody}</Linkify>
|
<span className="mx_RoomHeader_truncated mx_lineClamp">{roomName}</span>
|
||||||
</BodyText>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</button>
|
|
||||||
<Flex align="center" gap="var(--cpd-space-2x)">
|
|
||||||
{additionalButtons?.map((props) => {
|
|
||||||
const label = props.label();
|
|
||||||
|
|
||||||
return (
|
{!isDirectMessage && roomState.getJoinRule() === JoinRule.Public && (
|
||||||
<Tooltip label={label} key={props.id}>
|
<Tooltip label={_t("common|public_room")} side="right">
|
||||||
<IconButton
|
<PublicIcon
|
||||||
aria-label={label}
|
width="16px"
|
||||||
onClick={(event) => {
|
height="16px"
|
||||||
event.stopPropagation();
|
className="mx_RoomHeader_icon text-secondary"
|
||||||
props.onClick();
|
aria-label={_t("common|public_room")}
|
||||||
}}
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isDirectMessage && e2eStatus === E2EStatus.Verified && (
|
||||||
|
<Tooltip label={_t("common|verified")} side="right">
|
||||||
|
<VerifiedIcon
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
className="mx_RoomHeader_icon mx_Verified"
|
||||||
|
aria-label={_t("common|verified")}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isDirectMessage && e2eStatus === E2EStatus.Warning && (
|
||||||
|
<Tooltip label={_t("room|header_untrusted_label")} side="right">
|
||||||
|
<ErrorIcon
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
className="mx_RoomHeader_icon mx_Untrusted"
|
||||||
|
aria-label={_t("room|header_untrusted_label")}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</BodyText>
|
||||||
|
{roomTopic && (
|
||||||
|
<BodyText
|
||||||
|
as="div"
|
||||||
|
size="sm"
|
||||||
|
className="mx_RoomHeader_topic mx_RoomHeader_truncated mx_lineClamp"
|
||||||
>
|
>
|
||||||
{typeof props.icon === "function" ? props.icon() : props.icon}
|
<Linkify>{roomTopicBody}</Linkify>
|
||||||
|
</BodyText>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</button>
|
||||||
|
<Flex align="center" gap="var(--cpd-space-2x)">
|
||||||
|
{additionalButtons?.map((props) => {
|
||||||
|
const label = props.label();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip label={label} key={props.id}>
|
||||||
|
<IconButton
|
||||||
|
aria-label={label}
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
props.onClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{typeof props.icon === "function" ? props.icon() : props.icon}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Tooltip label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}>
|
||||||
|
<IconButton
|
||||||
|
disabled={!!videoCallDisabledReason}
|
||||||
|
aria-label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}
|
||||||
|
onClick={videoCallClick}
|
||||||
|
>
|
||||||
|
<VideoCallIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
{!useElementCallExclusively && (
|
||||||
|
<Tooltip label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}>
|
||||||
|
<IconButton
|
||||||
|
disabled={!!voiceCallDisabledReason}
|
||||||
|
aria-label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}
|
||||||
|
onClick={voiceCallClick}
|
||||||
|
>
|
||||||
|
<VoiceCallIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
)}
|
||||||
})}
|
|
||||||
<Tooltip label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}>
|
|
||||||
<IconButton
|
|
||||||
disabled={!!videoCallDisabledReason}
|
|
||||||
aria-label={!videoCallDisabledReason ? _t("voip|video_call") : videoCallDisabledReason!}
|
|
||||||
onClick={videoCallClick}
|
|
||||||
>
|
|
||||||
<VideoCallIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
{!useElementCallExclusively && (
|
|
||||||
<Tooltip label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}>
|
|
||||||
<IconButton
|
|
||||||
disabled={!!voiceCallDisabledReason}
|
|
||||||
aria-label={!voiceCallDisabledReason ? _t("voip|voice_call") : voiceCallDisabledReason!}
|
|
||||||
onClick={voiceCallClick}
|
|
||||||
>
|
|
||||||
<VoiceCallIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Renders nothing when room is not a video room */}
|
{/* Renders nothing when room is not a video room */}
|
||||||
<VideoRoomChatButton room={room} />
|
<VideoRoomChatButton room={room} />
|
||||||
|
|
||||||
<Tooltip label={_t("common|threads")}>
|
<Tooltip label={_t("common|threads")}>
|
||||||
<IconButton
|
|
||||||
indicator={notificationColorToIndicator(threadNotifications)}
|
|
||||||
onClick={(evt) => {
|
|
||||||
evt.stopPropagation();
|
|
||||||
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.ThreadPanel);
|
|
||||||
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
|
|
||||||
}}
|
|
||||||
aria-label={_t("common|threads")}
|
|
||||||
>
|
|
||||||
<ThreadsIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
{notificationsEnabled && (
|
|
||||||
<Tooltip label={_t("notifications|enable_prompt_toast_title")}>
|
|
||||||
<IconButton
|
<IconButton
|
||||||
indicator={notificationColorToIndicator(globalNotificationState.color)}
|
indicator={notificationColorToIndicator(threadNotifications)}
|
||||||
onClick={(evt) => {
|
onClick={(evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.NotificationPanel);
|
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.ThreadPanel);
|
||||||
|
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
|
||||||
}}
|
}}
|
||||||
aria-label={_t("notifications|enable_prompt_toast_title")}
|
aria-label={_t("common|threads")}
|
||||||
>
|
>
|
||||||
<NotificationsIcon />
|
<ThreadsIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
{notificationsEnabled && (
|
||||||
|
<Tooltip label={_t("notifications|enable_prompt_toast_title")}>
|
||||||
|
<IconButton
|
||||||
|
indicator={notificationColorToIndicator(globalNotificationState.color)}
|
||||||
|
onClick={(evt) => {
|
||||||
|
evt.stopPropagation();
|
||||||
|
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.NotificationPanel);
|
||||||
|
}}
|
||||||
|
aria-label={_t("notifications|enable_prompt_toast_title")}
|
||||||
|
>
|
||||||
|
<NotificationsIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
{!isDirectMessage && (
|
||||||
|
<BodyText
|
||||||
|
as="div"
|
||||||
|
size="sm"
|
||||||
|
weight="medium"
|
||||||
|
aria-label={_t("common|n_members", { count: memberCount })}
|
||||||
|
onClick={(e: React.MouseEvent) => {
|
||||||
|
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomMemberList);
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FacePile
|
||||||
|
className="mx_RoomHeader_members"
|
||||||
|
members={members.slice(0, 3)}
|
||||||
|
size="20px"
|
||||||
|
overflow={false}
|
||||||
|
viewUserOnClick={false}
|
||||||
|
>
|
||||||
|
{formatCount(memberCount)}
|
||||||
|
</FacePile>
|
||||||
|
</BodyText>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
{!isDirectMessage && (
|
{askToJoinEnabled && <RoomKnocksBar room={room} />}
|
||||||
<BodyText
|
</>
|
||||||
as="div"
|
|
||||||
size="sm"
|
|
||||||
weight="medium"
|
|
||||||
aria-label={_t("common|n_members", { count: memberCount })}
|
|
||||||
onClick={(e: React.MouseEvent) => {
|
|
||||||
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.RoomMemberList);
|
|
||||||
e.stopPropagation();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FacePile
|
|
||||||
className="mx_RoomHeader_members"
|
|
||||||
members={members.slice(0, 3)}
|
|
||||||
size="20px"
|
|
||||||
overflow={false}
|
|
||||||
viewUserOnClick={false}
|
|
||||||
>
|
|
||||||
{formatCount(memberCount)}
|
|
||||||
</FacePile>
|
|
||||||
</BodyText>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,15 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
import { CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
||||||
import { EventType, JoinRule, MatrixClient, MatrixEvent, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
|
import {
|
||||||
|
EventType,
|
||||||
|
JoinRule,
|
||||||
|
MatrixClient,
|
||||||
|
MatrixEvent,
|
||||||
|
PendingEventOrdering,
|
||||||
|
Room,
|
||||||
|
RoomMember,
|
||||||
|
} from "matrix-js-sdk/src/matrix";
|
||||||
import {
|
import {
|
||||||
createEvent,
|
createEvent,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
|
@ -562,6 +570,25 @@ describe("RoomHeader", () => {
|
||||||
expect(callback).toHaveBeenCalled();
|
expect(callback).toHaveBeenCalled();
|
||||||
expect(event.stopPropagation).toHaveBeenCalled();
|
expect(event.stopPropagation).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("ask to join disabled", () => {
|
||||||
|
it("does not render the RoomKnocksBar", () => {
|
||||||
|
render(<RoomHeader room={room} />, withClientContextRenderOptions(MatrixClientPeg.get()!));
|
||||||
|
expect(screen.queryByRole("heading", { name: "Asking to join" })).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("ask to join enabled", () => {
|
||||||
|
it("does render the RoomKnocksBar", () => {
|
||||||
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((feature) => feature === "feature_ask_to_join");
|
||||||
|
jest.spyOn(room, "canInvite").mockReturnValue(true);
|
||||||
|
jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock);
|
||||||
|
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([new RoomMember(room.roomId, "@foo")]);
|
||||||
|
|
||||||
|
render(<RoomHeader room={room} />, withClientContextRenderOptions(MatrixClientPeg.get()!));
|
||||||
|
expect(screen.getByRole("heading", { name: "Asking to join" })).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue