diff --git a/playwright/snapshots/invite/invite-dialog.spec.ts/send-your-first-message-view-linux.png b/playwright/snapshots/invite/invite-dialog.spec.ts/send-your-first-message-view-linux.png
index ec2d8d5443e..36ba4b247d8 100644
Binary files a/playwright/snapshots/invite/invite-dialog.spec.ts/send-your-first-message-view-linux.png and b/playwright/snapshots/invite/invite-dialog.spec.ts/send-your-first-message-view-linux.png differ
diff --git a/src/components/views/rooms/RoomHeader/RoomHeader.tsx b/src/components/views/rooms/RoomHeader/RoomHeader.tsx
index 8c162216ba9..cdc0a1b8a77 100644
--- a/src/components/views/rooms/RoomHeader/RoomHeader.tsx
+++ b/src/components/views/rooms/RoomHeader/RoomHeader.tsx
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { type JSX, useCallback, useMemo, useState } from "react";
-import { Body as BodyText, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
+import { Text, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
import VideoCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
import VoiceCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/voice-call-solid";
import CloseCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/close";
@@ -54,22 +54,15 @@ import { RoomSettingsTab } from "../../dialogs/RoomSettingsDialog.tsx";
import { useScopedRoomContext } from "../../../../contexts/ScopedRoomContext.tsx";
import { ToggleableIcon } from "./toggle/ToggleableIcon.tsx";
import { CurrentRightPanelPhaseContextProvider } from "../../../../contexts/CurrentRightPanelPhaseContext.tsx";
-import { type LocalRoom } from "../../../../models/LocalRoom.ts";
+import { LocalRoom } from "../../../../models/LocalRoom.ts";
-export default function RoomHeader({
+function RoomHeaderButtons({
room,
additionalButtons,
- oobData,
}: {
- room: Room | LocalRoom;
+ room: Room;
additionalButtons?: ViewRoomOpts["buttons"];
- oobData?: IOOBData;
}): JSX.Element {
- const client = useMatrixClientContext();
-
- const roomName = useRoomName(room);
- const joinRule = useRoomState(room, (state) => state.getJoinRule());
-
const members = useRoomMembers(room, 2500);
const memberCount = useRoomMemberCount(room, { throttleWait: 2500, includeInvited: true });
@@ -101,12 +94,9 @@ export default function RoomHeader({
const dmMember = useDmMember(room);
const isDirectMessage = !!dmMember;
- const e2eStatus = useEncryptionStatus(client, room);
const notificationsEnabled = useFeatureEnabled("feature_notifications");
- const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
-
const videoClick = useCallback(
(ev: React.MouseEvent) => videoCallClick(ev, callOptions[0]),
[callOptions, videoCallClick],
@@ -242,7 +232,118 @@ export default function RoomHeader({
isVideoRoom ||
roomContext.mainSplitContentType === MainSplitContentType.MaximisedWidget ||
roomContext.mainSplitContentType === MainSplitContentType.Call;
+ return (
+ <>
+ {additionalButtons?.map((props) => {
+ const label = props.label();
+
+ return (
+
+ {
+ event.stopPropagation();
+ props.onClick();
+ }}
+ >
+ {typeof props.icon === "function" ? props.icon() : props.icon}
+
+
+ );
+ })}
+
+ {isViewingCall && }
+ {hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
+ joinCallButton
+ ) : (
+ <>
+ {!isVideoRoom && videoCallButton}
+ {!useElementCallExclusively && !isVideoRoom && voiceCallButton}
+ >
+ )}
+
+ {showChatButton && }
+
+
+ {
+ evt.stopPropagation();
+ RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
+ PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
+ }}
+ aria-label={_t("common|threads")}
+ >
+
+
+
+ {notificationsEnabled && (
+
+ {
+ evt.stopPropagation();
+ RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
+ }}
+ aria-label={_t("notifications|enable_prompt_toast_title")}
+ >
+
+
+
+ )}
+
+
+ {
+ evt.stopPropagation();
+ RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
+ }}
+ aria-label={_t("right_panel|room_summary_card|title")}
+ >
+
+
+
+
+ {!isDirectMessage && (
+
+ {
+ RightPanelStore.instance.showOrHidePhase(RightPanelPhases.MemberList);
+ e.stopPropagation();
+ }}
+ aria-label={_t("common|n_members", { count: memberCount })}
+ >
+ {formatCount(memberCount)}
+
+
+ )}
+ >
+ );
+}
+
+export default function RoomHeader({
+ room,
+ additionalButtons,
+ oobData,
+}: {
+ room: Room | LocalRoom;
+ additionalButtons?: ViewRoomOpts["buttons"];
+ oobData?: IOOBData;
+}): JSX.Element {
+ const client = useMatrixClientContext();
+ const roomName = useRoomName(room);
+ const joinRule = useRoomState(room, (state) => state.getJoinRule());
+ const dmMember = useDmMember(room);
+ const isDirectMessage = !!dmMember;
+ const e2eStatus = useEncryptionStatus(client, room);
+ const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
const onAvatarClick = (): void => {
defaultDispatcher.dispatch({
action: "open_room_settings",
@@ -256,23 +357,29 @@ export default function RoomHeader({
{/* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */}
+ {/* Disable on-click actions until the room is created */}
+ {/* Disable on-click actions until the room is created */}
-
- {additionalButtons?.map((props) => {
- const label = props.label();
-
- return (
-
- {
- event.stopPropagation();
- props.onClick();
- }}
- >
- {typeof props.icon === "function" ? props.icon() : props.icon}
-
-
- );
- })}
-
- {isViewingCall && }
-
- {hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
- joinCallButton
- ) : (
- <>
- {!isVideoRoom && videoCallButton}
- {!useElementCallExclusively && !isVideoRoom && voiceCallButton}
- >
- )}
-
- {showChatButton && }
-
-
- {
- evt.stopPropagation();
- RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
- PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
- }}
- aria-label={_t("common|threads")}
- >
-
-
-
- {notificationsEnabled && (
-
- {
- evt.stopPropagation();
- RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
- }}
- aria-label={_t("notifications|enable_prompt_toast_title")}
- >
-
-
-
- )}
-
-
- {
- evt.stopPropagation();
- RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
- }}
- aria-label={_t("right_panel|room_summary_card|title")}
- >
-
-
-
-
- {!isDirectMessage && (
-
- {
- RightPanelStore.instance.showOrHidePhase(RightPanelPhases.MemberList);
- e.stopPropagation();
- }}
- aria-label={_t("common|n_members", { count: memberCount })}
- >
- {formatCount(memberCount)}
-
-
+ {/* If the room is local-only then we don't want to show any additional buttons, as it won't work */}
+ {room instanceof LocalRoom === false && (
+
)}
{askToJoinEnabled && }
diff --git a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
index d8ffc523084..77a8440bb69 100644
--- a/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
+++ b/test/unit-tests/components/structures/__snapshots__/RoomView-test.tsx.snap
@@ -9,19 +9,18 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1
class="flex mx_RoomHeader light-panel"
style="--mx-flex-display: flex; --mx-flex-direction: row; --mx-flex-align: center; --mx-flex-justify: start; --mx-flex-gap: var(--cpd-space-3x); --mx-flex-wrap: nowrap;"
>
-
+
-
-
-
-
+
-
-
-