diff --git a/cypress/e2e/right-panel/notification-panel.spec.ts b/cypress/e2e/right-panel/notification-panel.spec.ts index 4068285070..75a80abaf3 100644 --- a/cypress/e2e/right-panel/notification-panel.spec.ts +++ b/cypress/e2e/right-panel/notification-panel.spec.ts @@ -38,6 +38,7 @@ describe("NotificationPanel", () => { }); it("should render empty state", () => { + cy.enableLabsFeature("feature_notifications"); cy.viewRoomByName(ROOM_NAME); cy.findByRole("button", { name: "Notifications" }).click(); diff --git a/cypress/e2e/room/room-header.spec.ts b/cypress/e2e/room/room-header.spec.ts index 835fb2bb3e..d92d505167 100644 --- a/cypress/e2e/room/room-header.spec.ts +++ b/cypress/e2e/room/room-header.spec.ts @@ -36,6 +36,7 @@ describe("Room Header", () => { }); it("should render default buttons properly", () => { + cy.enableLabsFeature("feature_notifications"); cy.createRoom({ name: "Test Room" }).viewRoomByName("Test Room"); cy.get(".mx_LegacyRoomHeader").within(() => { @@ -79,6 +80,7 @@ describe("Room Header", () => { }); it("should render a very long room name without collapsing the buttons", () => { + cy.enableLabsFeature("feature_notifications"); const LONG_ROOM_NAME = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + @@ -109,6 +111,7 @@ describe("Room Header", () => { }); it("should have buttons highlighted by being clicked", () => { + cy.enableLabsFeature("feature_notifications"); cy.createRoom({ name: "Test Room" }).viewRoomByName("Test Room"); cy.get(".mx_LegacyRoomHeader").within(() => { @@ -142,6 +145,7 @@ describe("Room Header", () => { }; it("should render buttons for room options, beta pill, invite, chat, and room info", () => { + cy.enableLabsFeature("feature_notifications"); createVideoRoom(); cy.get(".mx_LegacyRoomHeader").within(() => { diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx index 0fe075332a..dbdd2f10b5 100644 --- a/src/components/views/right_panel/HeaderButtons.tsx +++ b/src/components/views/right_panel/HeaderButtons.tsx @@ -25,6 +25,7 @@ import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { NotificationColor } from "../../../stores/notifications/NotificationColor"; +import SettingsStore from "../../../settings/SettingsStore"; export enum HeaderKind { Room = "room", @@ -35,6 +36,7 @@ interface IState { phase: RightPanelPhases | null; threadNotificationColor: NotificationColor; globalNotificationColor: NotificationColor; + notificationsEnabled?: boolean; } interface IProps {} @@ -42,6 +44,7 @@ interface IProps {} export default abstract class HeaderButtons<P = {}> extends React.Component<IProps & P, IState> { private unmounted = false; private dispatcherRef?: string = undefined; + private readonly watcherRef: string; public constructor(props: IProps & P, kind: HeaderKind) { super(props); @@ -52,7 +55,11 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro phase: rps.currentCard.phase, threadNotificationColor: NotificationColor.None, globalNotificationColor: NotificationColor.None, + notificationsEnabled: SettingsStore.getValue("feature_notifications"), }; + this.watcherRef = SettingsStore.watchSetting("feature_notifications", null, (...[, , , value]) => + this.setState({ notificationsEnabled: value }), + ); } public componentDidMount(): void { @@ -63,6 +70,7 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro this.unmounted = true; RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate); if (this.dispatcherRef) dis.unregister(this.dispatcherRef); + if (this.watcherRef) SettingsStore.unwatchSetting(this.watcherRef); } public isPhase(phases: string | string[]): boolean { diff --git a/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx b/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx index 43c3fcb762..fddb9fd106 100644 --- a/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx +++ b/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx @@ -282,21 +282,23 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons<IProps> { <UnreadIndicator color={this.state.threadNotificationColor} /> </HeaderButton>, ); - rightPanelPhaseButtons.set( - RightPanelPhases.NotificationPanel, - <HeaderButton - key="notifsButton" - name="notifsButton" - title={_t("Notifications")} - isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)} - onClick={this.onNotificationsClicked} - isUnread={this.globalNotificationState.color === NotificationColor.Red} - > - {this.globalNotificationState.color === NotificationColor.Red ? ( - <UnreadIndicator color={this.globalNotificationState.color} /> - ) : null} - </HeaderButton>, - ); + if (this.state.notificationsEnabled) { + rightPanelPhaseButtons.set( + RightPanelPhases.NotificationPanel, + <HeaderButton + key="notifsButton" + name="notifsButton" + title={_t("Notifications")} + isHighlighted={this.isPhase(RightPanelPhases.NotificationPanel)} + onClick={this.onNotificationsClicked} + isUnread={this.globalNotificationState.color === NotificationColor.Red} + > + {this.globalNotificationState.color === NotificationColor.Red ? ( + <UnreadIndicator color={this.globalNotificationState.color} /> + ) : null} + </HeaderButton>, + ); + } rightPanelPhaseButtons.set( RightPanelPhases.RoomSummary, <HeaderButton diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx index 56f2af3a22..552d43f982 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -100,6 +100,8 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element { }, [room, directRoomsList]); const e2eStatus = useEncryptionStatus(client, room); + const notificationsEnabled = useFeatureEnabled("feature_notifications"); + return ( <Flex as="header" @@ -202,18 +204,20 @@ export default function RoomHeader({ room }: { room: Room }): JSX.Element { <ThreadsIcon /> </IconButton> </Tooltip> - <Tooltip label={_t("Notifications")}> - <IconButton - indicator={notificationColorToIndicator(globalNotificationState.color)} - onClick={(evt) => { - evt.stopPropagation(); - RightPanelStore.instance.showOrHidePanel(RightPanelPhases.NotificationPanel); - }} - title={_t("Notifications")} - > - <NotificationsIcon /> - </IconButton> - </Tooltip> + {notificationsEnabled && ( + <Tooltip label={_t("Notifications")}> + <IconButton + indicator={notificationColorToIndicator(globalNotificationState.color)} + onClick={(evt) => { + evt.stopPropagation(); + RightPanelStore.instance.showOrHidePanel(RightPanelPhases.NotificationPanel); + }} + title={_t("Notifications")} + > + <NotificationsIcon /> + </IconButton> + </Tooltip> + )} </Flex> {!isDirectMessage && ( <BodyText diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f4dc88b1b1..b034564029 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1161,7 +1161,9 @@ "rust_crypto": "Rust cryptography implementation", "hidebold": "Hide notification dot (only display counters badges)", "ask_to_join": "Enable ask to join", - "new_room_decoration_ui": "New room header & details interface", + "new_room_decoration_ui": "Under active development, new room header & details interface", + "notifications": "Enable the notifications panel in the room header", + "unrealiable_e2e": "Unreliable in encrypted rooms", "beta_feature": "This is a beta feature", "click_for_info": "Click for more info", "leave_beta_reload": "Leaving the beta will reload %(brand)s.", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index c5f4165331..1aabc71e77 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -547,6 +547,14 @@ export const SETTINGS: { [setting: string]: ISetting } = { default: false, controller: new ReloadOnChangeController(), }, + "feature_notifications": { + isFeature: true, + labsGroup: LabGroup.Messaging, + displayName: _td("labs|notifications"), + description: _td("labs|unrealiable_e2e"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "useCompactLayout": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, displayName: _td("Use a more compact 'Modern' layout"), diff --git a/test/components/views/right_panel/__snapshots__/LegacyRoomHeaderButtons-test.tsx.snap b/test/components/views/right_panel/__snapshots__/LegacyRoomHeaderButtons-test.tsx.snap index bd706048be..6dbe9ed2e3 100644 --- a/test/components/views/right_panel/__snapshots__/LegacyRoomHeaderButtons-test.tsx.snap +++ b/test/components/views/right_panel/__snapshots__/LegacyRoomHeaderButtons-test.tsx.snap @@ -17,13 +17,6 @@ exports[`LegacyRoomHeaderButtons-test.tsx should render 1`] = ` role="button" tabindex="0" /> - <div - aria-current="false" - aria-label="Notifications" - class="mx_AccessibleButton mx_LegacyRoomHeader_button mx_RightPanel_notifsButton" - role="button" - tabindex="0" - /> <div aria-current="false" aria-label="Room info" diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index 64f805bca2..cdecd493b3 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -200,6 +200,10 @@ describe("RoomHeader", () => { }); it("opens the notifications panel", async () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => { + if (name === "feature_notifications") return true; + }); + const { container } = render( <RoomHeader room={room} />, withClientContextRenderOptions(MatrixClientPeg.get()!), diff --git a/test/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap b/test/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap index f8acfdfe0e..60f42b919d 100644 --- a/test/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap +++ b/test/components/views/rooms/__snapshots__/RoomHeader-test.tsx.snap @@ -60,14 +60,6 @@ exports[`RoomHeader does not show the face pile for DMs 1`] = ` > <div /> </button> - <button - class="_icon-button_1segd_17" - data-state="closed" - style="--cpd-icon-button-size: 32px;" - title="Notifications" - > - <div /> - </button> </nav> </header> </DocumentFragment>