From 59852773ad41ea3be479ba9f6bfbdad1dd159d69 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Mon, 16 Sep 2024 16:51:59 +0200 Subject: [PATCH] Unlabs feature pinning (#22) --- src/TextForEvent.tsx | 1 - src/components/structures/RightPanel.tsx | 3 +- src/components/structures/RoomView.tsx | 10 +- .../structures/grouper/MainGrouper.tsx | 3 +- .../views/context_menus/RoomContextMenu.tsx | 6 +- .../right_panel/LegacyRoomHeaderButtons.tsx | 22 ++- .../views/right_panel/RoomSummaryCard.tsx | 25 ++-- .../tabs/room/RolesRoomSettingsTab.tsx | 4 +- src/i18n/strings/en_EN.json | 1 - src/settings/Settings.tsx | 8 -- src/utils/PinningUtils.ts | 2 - test/TextForEvent-test.ts | 5 - .../context_menus/MessageContextMenu-test.tsx | 16 --- .../right_panel/RoomSummaryCard-test.tsx | 12 +- .../RoomSummaryCard-test.tsx.snap | 132 ++++++++++++++++++ .../views/rooms/PinnedEventTile-test.tsx | 3 - test/submit-rageshake-test.ts | 4 +- test/utils/PinningUtils-test.ts | 8 -- 18 files changed, 166 insertions(+), 99 deletions(-) diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index 1ee7088945..1ffae62aea 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -561,7 +561,6 @@ const onPinnedMessagesClick = (): void => { }; function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: boolean): (() => Renderable) | null { - if (!SettingsStore.getValue("feature_pinning")) return null; const senderName = getSenderName(event); const roomId = event.getRoomId()!; diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 1cfc57e4fb..d4014f6aa0 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -17,7 +17,6 @@ import RightPanelStore from "../../stores/right-panel/RightPanelStore"; import MatrixClientContext from "../../contexts/MatrixClientContext"; import RoomSummaryCard from "../views/right_panel/RoomSummaryCard"; import WidgetCard from "../views/right_panel/WidgetCard"; -import SettingsStore from "../../settings/SettingsStore"; import MemberList from "../views/rooms/MemberList"; import UserInfo from "../views/right_panel/UserInfo"; import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo"; @@ -220,7 +219,7 @@ export default class RightPanel extends React.Component { break; case RightPanelPhases.PinnedMessages: - if (!!this.props.room && SettingsStore.getValue("feature_pinning")) { + if (!!this.props.room) { card = ( { ); - const isPinningEnabled = SettingsStore.getValue("feature_pinning"); - let pinnedMessageBanner; - if (isPinningEnabled) { - pinnedMessageBanner = ( - - ); - } + const pinnedMessageBanner = ( + + ); let messageComposer; const showComposer = diff --git a/src/components/structures/grouper/MainGrouper.tsx b/src/components/structures/grouper/MainGrouper.tsx index 2a7baab3a2..72fd3fcdf0 100644 --- a/src/components/structures/grouper/MainGrouper.tsx +++ b/src/components/structures/grouper/MainGrouper.tsx @@ -18,7 +18,6 @@ import DateSeparator from "../../views/messages/DateSeparator"; import HistoryTile from "../../views/rooms/HistoryTile"; import EventListSummary from "../../views/elements/EventListSummary"; import { SeparatorKind } from "../../views/messages/TimelineSeparator"; -import SettingsStore from "../../../settings/SettingsStore"; const groupedStateEvents = [ EventType.RoomMember, @@ -91,7 +90,7 @@ export class MainGrouper extends BaseGrouper { return; } - if (ev.getType() === EventType.RoomPinnedEvents && !SettingsStore.getValue("feature_pinning")) { + if (ev.getType() === EventType.RoomPinnedEvents) { // If pinned messages are disabled, don't show the summary return; } diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx index bc10e88074..694aba0ef5 100644 --- a/src/components/views/context_menus/RoomContextMenu.tsx +++ b/src/components/views/context_menus/RoomContextMenu.tsx @@ -26,7 +26,6 @@ import { EchoChamber } from "../../../stores/local-echo/EchoChamber"; import { RoomNotifState } from "../../../RoomNotifs"; import Modal from "../../../Modal"; import ExportDialog from "../dialogs/ExportDialog"; -import { useFeatureEnabled } from "../../../hooks/useSettings"; import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases"; import { RoomSettingsTab } from "../dialogs/RoomSettingsDialog"; import { useEventEmitterState } from "../../../hooks/useEventEmitter"; @@ -261,11 +260,10 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => { ); } - const pinningEnabled = useFeatureEnabled("feature_pinning"); - const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length; + const pinCount = usePinnedEvents(room).length; let pinsOption: JSX.Element | undefined; - if (pinningEnabled && !isVideoRoom) { + if (!isVideoRoom) { pinsOption = ( { diff --git a/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx b/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx index 1a5d0d1dcc..85b173c40c 100644 --- a/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx +++ b/src/components/views/right_panel/LegacyRoomHeaderButtons.tsx @@ -21,7 +21,6 @@ import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePha import { ActionPayload } from "../../../dispatcher/payloads"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import { showThreadPanel } from "../../../dispatcher/dispatch-actions/threads"; -import SettingsStore from "../../../settings/SettingsStore"; import { RoomNotificationStateStore, UPDATE_STATUS_INDICATOR, @@ -245,17 +244,16 @@ export default class LegacyRoomHeaderButtons extends HeaderButtons { const rightPanelPhaseButtons: Map = new Map(); - if (SettingsStore.getValue("feature_pinning")) { - rightPanelPhaseButtons.set( - RightPanelPhases.PinnedMessages, - , - ); - } + rightPanelPhaseButtons.set( + RightPanelPhases.PinnedMessages, + , + ); + rightPanelPhaseButtons.set( RightPanelPhases.Timeline, = ({ ); - const pinningEnabled = useFeatureEnabled("feature_pinning"); - const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length; + const pinCount = usePinnedEvents(room).length; const roomTags = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () => RoomListStore.instance.getTagsForRoom(room), @@ -382,17 +380,16 @@ const RoomSummaryCard: React.FC = ({ {!isVideoRoom && ( <> - {pinningEnabled && ( - - - {pinCount} - - - )} + + + {pinCount} + + + )} diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx index eebd0b194f..ec8a2b8718 100644 --- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx @@ -267,15 +267,13 @@ export default class RolesRoomSettingsTab extends React.Component { [EventType.RoomServerAcl]: _td("room_settings|permissions|m.room.server_acl"), [EventType.Reaction]: _td("room_settings|permissions|m.reaction"), [EventType.RoomRedaction]: _td("room_settings|permissions|m.room.redaction"), + [EventType.RoomPinnedEvents]: _td("room_settings|permissions|m.room.pinned_events"), // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) "im.vector.modular.widgets": isSpaceRoom ? null : _td("room_settings|permissions|m.widget"), [VoiceBroadcastInfoEventType]: _td("room_settings|permissions|io.element.voice_broadcast_info"), }; - if (SettingsStore.getValue("feature_pinning")) { - plEventsToLabels[EventType.RoomPinnedEvents] = _td("room_settings|permissions|m.room.pinned_events"); - } // MSC3401: Native Group VoIP signaling if (SettingsStore.getValue("feature_group_calls")) { plEventsToLabels[ElementCall.CALL_EVENT_TYPE.name] = _td("room_settings|permissions|m.call"); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8580b6c13b..cc051ac0cf 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1468,7 +1468,6 @@ "notifications": "Enable the notifications panel in the room header", "oidc_native_flow": "OIDC native authentication", "oidc_native_flow_description": "⚠ WARNING: Experimental. Use OIDC native authentication when supported by the server.", - "pinning": "Message Pinning", "release_announcement": "Release announcement", "render_reaction_images": "Render custom images in reactions", "render_reaction_images_description": "Sometimes referred to as \"custom emojis\".", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 5733c6e353..2fadb53dde 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -275,14 +275,6 @@ export const SETTINGS: { [setting: string]: ISetting } = { supportedLevelsAreOrdered: true, default: false, }, - "feature_pinning": { - isFeature: true, - labsGroup: LabGroup.Messaging, - displayName: _td("labs|pinning"), - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED, - supportedLevelsAreOrdered: true, - default: true, - }, "feature_wysiwyg_composer": { isFeature: true, labsGroup: LabGroup.Messaging, diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts index dfc71b134a..806e59b014 100644 --- a/src/utils/PinningUtils.ts +++ b/src/utils/PinningUtils.ts @@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details. import { MatrixEvent, EventType, M_POLL_START, MatrixClient, EventTimeline, Room } from "matrix-js-sdk/src/matrix"; import { isContentActionable } from "./EventUtils"; -import SettingsStore from "../settings/SettingsStore"; import { ReadPinsEventId } from "../components/views/right_panel/types"; export default class PinningUtils { @@ -70,7 +69,6 @@ export default class PinningUtils { * @private */ private static canPinOrUnpin(matrixClient: MatrixClient, mxEvent: MatrixEvent): boolean { - if (!SettingsStore.getValue("feature_pinning")) return false; if (!isContentActionable(mxEvent)) return false; const room = matrixClient.getRoom(mxEvent.getRoomId()); diff --git a/test/TextForEvent-test.ts b/test/TextForEvent-test.ts index e709e66cff..66f4345a8d 100644 --- a/test/TextForEvent-test.ts +++ b/test/TextForEvent-test.ts @@ -65,11 +65,6 @@ describe("TextForEvent", () => { }); describe("TextForPinnedEvent", () => { - beforeAll(() => { - // enable feature_pinning setting - (SettingsStore.getValue as jest.Mock).mockImplementation((feature) => feature === "feature_pinning"); - }); - it("mentions message when a single message was pinned, with no previously pinned messages", () => { const event = mockPinnedEvent(["message-1"]); const plainText = textForEvent(event, mockClient); diff --git a/test/components/views/context_menus/MessageContextMenu-test.tsx b/test/components/views/context_menus/MessageContextMenu-test.tsx index fe0d5037b9..b2763c1085 100644 --- a/test/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/components/views/context_menus/MessageContextMenu-test.tsx @@ -116,22 +116,6 @@ describe("MessageContextMenu", () => { expect(screen.queryByRole("menuitem", { name: "Pin" })).toBeFalsy(); }); - it("does not show pin option when pinning feature is disabled", () => { - const eventContent = createMessageEventContent("hello"); - const pinnableEvent = new MatrixEvent({ - type: EventType.RoomMessage, - content: eventContent, - room_id: roomId, - }); - - // disable pinning feature - jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); - - createMenu(pinnableEvent, { rightClick: true }, {}, undefined, room); - - expect(screen.queryByRole("menuitem", { name: "Pin" })).toBeFalsy(); - }); - it("shows pin option when pinning feature is enabled", () => { const eventContent = createMessageEventContent("hello"); const pinnableEvent = new MatrixEvent({ diff --git a/test/components/views/right_panel/RoomSummaryCard-test.tsx b/test/components/views/right_panel/RoomSummaryCard-test.tsx index 9a5b12c717..2e230c6352 100644 --- a/test/components/views/right_panel/RoomSummaryCard-test.tsx +++ b/test/components/views/right_panel/RoomSummaryCard-test.tsx @@ -259,8 +259,7 @@ describe("", () => { }); describe("pinning", () => { - it("renders pins options when pinning feature is enabled", () => { - mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_pinning"); + it("renders pins options", () => { const { getByText } = getComponent(); expect(getByText("Pinned messages")).toBeInTheDocument(); @@ -291,9 +290,7 @@ describe("", () => { describe("video rooms", () => { it("does not render irrelevant options for element video room", () => { jest.spyOn(room, "isElementVideoRoom").mockReturnValue(true); - mocked(settingsHooks.useFeatureEnabled).mockImplementation( - (feature) => feature === "feature_video_rooms" || feature === "feature_pinning", - ); + mocked(settingsHooks.useFeatureEnabled).mockImplementation((feature) => feature === "feature_video_rooms"); const { queryByText } = getComponent(); // options not rendered @@ -305,10 +302,7 @@ describe("", () => { it("does not render irrelevant options for element call room", () => { jest.spyOn(room, "isCallRoom").mockReturnValue(true); mocked(settingsHooks.useFeatureEnabled).mockImplementation( - (feature) => - feature === "feature_element_call_video_rooms" || - feature === "feature_video_rooms" || - feature === "feature_pinning", + (feature) => feature === "feature_element_call_video_rooms" || feature === "feature_video_rooms", ); const { queryByText } = getComponent(); diff --git a/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap b/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap index f04669e877..26a7b88eda 100644 --- a/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap +++ b/test/components/views/right_panel/__snapshots__/RoomSummaryCard-test.tsx.snap @@ -186,6 +186,50 @@ exports[` has button to edit topic 1`] = ` data-orientation="horizontal" role="separator" /> +