Remove feature_favourite_messages as it is has been abandoned for now (#11097)

* Remove `feature_favourite_messages` as it is has been abandoned for now

* i18n

* Fix test

* Remove unused css
This commit is contained in:
Michael Telatynski 2023-06-15 12:02:45 +01:00 committed by GitHub
parent 386a459b9f
commit cb2b1718ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 3 additions and 219 deletions

View file

@ -21,7 +21,6 @@ limitations under the License.
--MessageActionBar-item-hover-background: $panel-actions; --MessageActionBar-item-hover-background: $panel-actions;
--MessageActionBar-item-hover-borderRadius: 6px; --MessageActionBar-item-hover-borderRadius: 6px;
--MessageActionBar-item-hover-zIndex: 1; --MessageActionBar-item-hover-zIndex: 1;
--MessageActionBar-star-button-color: #ffa534;
position: absolute; position: absolute;
visibility: hidden; visibility: hidden;
@ -118,10 +117,6 @@ limitations under the License.
color: $primary-content; color: $primary-content;
} }
&.mx_MessageActionBar_favouriteButton_fillstar {
color: var(--MessageActionBar-star-button-color);
}
&.mx_MessageActionBar_downloadButton { &.mx_MessageActionBar_downloadButton {
--MessageActionBar-icon-size: 14px; --MessageActionBar-icon-size: 14px;

View file

@ -28,7 +28,6 @@ import { Icon as EmojiIcon } from "../../../../res/img/element-icons/room/messag
import { Icon as ResendIcon } from "../../../../res/img/element-icons/retry.svg"; import { Icon as ResendIcon } from "../../../../res/img/element-icons/retry.svg";
import { Icon as ThreadIcon } from "../../../../res/img/element-icons/message/thread.svg"; import { Icon as ThreadIcon } from "../../../../res/img/element-icons/message/thread.svg";
import { Icon as TrashcanIcon } from "../../../../res/img/element-icons/trashcan.svg"; import { Icon as TrashcanIcon } from "../../../../res/img/element-icons/trashcan.svg";
import { Icon as StarIcon } from "../../../../res/img/element-icons/room/message-bar/star.svg";
import { Icon as ReplyIcon } from "../../../../res/img/element-icons/room/message-bar/reply.svg"; import { Icon as ReplyIcon } from "../../../../res/img/element-icons/room/message-bar/reply.svg";
import { Icon as ExpandMessageIcon } from "../../../../res/img/element-icons/expand-message.svg"; import { Icon as ExpandMessageIcon } from "../../../../res/img/element-icons/expand-message.svg";
import { Icon as CollapseMessageIcon } from "../../../../res/img/element-icons/collapse-message.svg"; import { Icon as CollapseMessageIcon } from "../../../../res/img/element-icons/collapse-message.svg";
@ -45,7 +44,6 @@ import Resend from "../../../Resend";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { MediaEventHelper } from "../../../utils/MediaEventHelper"; import { MediaEventHelper } from "../../../utils/MediaEventHelper";
import DownloadActionButton from "./DownloadActionButton"; import DownloadActionButton from "./DownloadActionButton";
import SettingsStore from "../../../settings/SettingsStore";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import ReplyChain from "../elements/ReplyChain"; import ReplyChain from "../elements/ReplyChain";
import ReactionPicker from "../emojipicker/ReactionPicker"; import ReactionPicker from "../emojipicker/ReactionPicker";
@ -55,7 +53,6 @@ import { Key } from "../../../Keyboard";
import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts"; import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload"; import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
import { GetRelationsForEvent } from "../rooms/EventTile"; import { GetRelationsForEvent } from "../rooms/EventTile";
import { VoiceBroadcastInfoEventType } from "../../../voice-broadcast/types"; import { VoiceBroadcastInfoEventType } from "../../../voice-broadcast/types";
import { ButtonEvent } from "../elements/AccessibleButton"; import { ButtonEvent } from "../elements/AccessibleButton";
@ -254,42 +251,6 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent }) => {
); );
}; };
interface IFavouriteButtonProp {
mxEvent: MatrixEvent;
}
const FavouriteButton: React.FC<IFavouriteButtonProp> = ({ mxEvent }) => {
const { isFavourite, toggleFavourite } = useFavouriteMessages();
const eventId = mxEvent.getId()!;
const classes = classNames("mx_MessageActionBar_iconButton mx_MessageActionBar_favouriteButton", {
mx_MessageActionBar_favouriteButton_fillstar: isFavourite(eventId),
});
const onClick = useCallback(
(e: ButtonEvent) => {
// Don't open the regular browser or our context menu on right-click
e.preventDefault();
e.stopPropagation();
toggleFavourite(eventId);
},
[toggleFavourite, eventId],
);
return (
<RovingAccessibleTooltipButton
className={classes}
title={_t("Favourite")}
onClick={onClick}
onContextMenu={onClick}
data-testid={eventId}
>
<StarIcon />
</RovingAccessibleTooltipButton>
);
};
interface IMessageActionBarProps { interface IMessageActionBarProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
reactions?: Relations | null | undefined; reactions?: Relations | null | undefined;
@ -518,9 +479,6 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
/>, />,
); );
} }
if (SettingsStore.getValue("feature_favourite_messages")) {
toolbarOpts.splice(-1, 0, <FavouriteButton key="favourite" mxEvent={this.props.mxEvent} />);
}
// XXX: Assuming that the underlying tile will be a media event if it is eligible media. // XXX: Assuming that the underlying tile will be a media event if it is eligible media.
if (MediaEventHelper.isEligible(this.props.mxEvent)) { if (MediaEventHelper.isEligible(this.props.mxEvent)) {

View file

@ -78,7 +78,6 @@ interface IState {
sublists: ITagMap; sublists: ITagMap;
currentRoomId?: string; currentRoomId?: string;
suggestedRooms: ISuggestedRoom[]; suggestedRooms: ISuggestedRoom[];
feature_favourite_messages: boolean;
} }
export const TAG_ORDER: TagID[] = [ export const TAG_ORDER: TagID[] = [
@ -443,7 +442,6 @@ const TAG_AESTHETICS: TagAestheticsMap = {
export default class RoomList extends React.PureComponent<IProps, IState> { export default class RoomList extends React.PureComponent<IProps, IState> {
private dispatcherRef?: string; private dispatcherRef?: string;
private treeRef = createRef<HTMLDivElement>(); private treeRef = createRef<HTMLDivElement>();
private favouriteMessageWatcher?: string;
public static contextType = MatrixClientContext; public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>; public context!: React.ContextType<typeof MatrixClientContext>;
@ -454,7 +452,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
this.state = { this.state = {
sublists: {}, sublists: {},
suggestedRooms: SpaceStore.instance.suggestedRooms, suggestedRooms: SpaceStore.instance.suggestedRooms,
feature_favourite_messages: SettingsStore.getValue("feature_favourite_messages"),
}; };
} }
@ -463,20 +460,12 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
SdkContextClass.instance.roomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate); SdkContextClass.instance.roomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
SpaceStore.instance.on(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms); SpaceStore.instance.on(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms);
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.updateLists);
this.favouriteMessageWatcher = SettingsStore.watchSetting(
"feature_favourite_messages",
null,
(...[, , , value]) => {
this.setState({ feature_favourite_messages: value });
},
);
this.updateLists(); // trigger the first update this.updateLists(); // trigger the first update
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
SpaceStore.instance.off(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms); SpaceStore.instance.off(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms);
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists);
if (this.favouriteMessageWatcher) SettingsStore.unwatchSetting(this.favouriteMessageWatcher);
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef); if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
SdkContextClass.instance.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate); SdkContextClass.instance.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
} }
@ -607,29 +596,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
); );
}); });
} }
private renderFavoriteMessagesList(): ReactComponentElement<typeof ExtraTile>[] {
const avatar = (
<RoomAvatar
oobData={{
name: "Favourites",
}}
width={32}
height={32}
resizeMethod="crop"
/>
);
return [
<ExtraTile
isMinimized={this.props.isMinimized}
isSelected={false}
displayName="Favourite Messages"
avatar={avatar}
onClick={() => ""}
key="favMessagesTile_key"
/>,
];
}
private renderSublists(): React.ReactElement[] { private renderSublists(): React.ReactElement[] {
// show a skeleton UI if the user is in no rooms and they are not filtering and have no suggested rooms // show a skeleton UI if the user is in no rooms and they are not filtering and have no suggested rooms
@ -641,8 +607,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
let extraTiles: ReactComponentElement<typeof ExtraTile>[] | undefined; let extraTiles: ReactComponentElement<typeof ExtraTile>[] | undefined;
if (orderedTagId === DefaultTagID.Suggested) { if (orderedTagId === DefaultTagID.Suggested) {
extraTiles = this.renderSuggestedRooms(); extraTiles = this.renderSuggestedRooms();
} else if (this.state.feature_favourite_messages && orderedTagId === DefaultTagID.SavedItems) {
extraTiles = this.renderFavoriteMessagesList();
} }
const aesthetics = TAG_AESTHETICS[orderedTagId]; const aesthetics = TAG_AESTHETICS[orderedTagId];

View file

@ -1,43 +0,0 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { useState } from "react";
const favouriteMessageIds = JSON.parse(localStorage?.getItem("io_element_favouriteMessages") ?? "[]") as string[];
export default function useFavouriteMessages(): {
toggleFavourite: (eventId: string) => void;
isFavourite: (eventId: string) => boolean;
} {
const [, setX] = useState<string[]>();
//checks if an id already exist
const isFavourite = (eventId: string): boolean => favouriteMessageIds.includes(eventId);
const toggleFavourite = (eventId: string): void => {
isFavourite(eventId)
? favouriteMessageIds.splice(favouriteMessageIds.indexOf(eventId), 1)
: favouriteMessageIds.push(eventId);
//update the local storage
localStorage.setItem("io_element_favouriteMessages", JSON.stringify(favouriteMessageIds));
// This forces a re-render to account for changes in appearance in real-time when the favourite button is toggled
setX([]);
};
return { isFavourite, toggleFavourite };
}

View file

@ -985,11 +985,10 @@
"Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.", "Temporary implementation. Locations persist in room history.": "Temporary implementation. Locations persist in room history.",
"Dynamic room predecessors": "Dynamic room predecessors", "Dynamic room predecessors": "Dynamic room predecessors",
"Enable MSC3946 (to support late-arriving room archives)": "Enable MSC3946 (to support late-arriving room archives)", "Enable MSC3946 (to support late-arriving room archives)": "Enable MSC3946 (to support late-arriving room archives)",
"Favourite Messages": "Favourite Messages",
"Under active development.": "Under active development.",
"Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length", "Force 15s voice broadcast chunk length": "Force 15s voice broadcast chunk length",
"Enable new native OIDC flows (Under active development)": "Enable new native OIDC flows (Under active development)", "Enable new native OIDC flows (Under active development)": "Enable new native OIDC flows (Under active development)",
"Rust cryptography implementation": "Rust cryptography implementation", "Rust cryptography implementation": "Rust cryptography implementation",
"Under active development.": "Under active development.",
"Font size": "Font size", "Font size": "Font size",
"Use custom size": "Use custom size", "Use custom size": "Use custom size",
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing", "Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
@ -2390,7 +2389,6 @@
"React": "React", "React": "React",
"Reply in thread": "Reply in thread", "Reply in thread": "Reply in thread",
"Can't create a thread from an event with an existing relation": "Can't create a thread from an event with an existing relation", "Can't create a thread from an event with an existing relation": "Can't create a thread from an event with an existing relation",
"Favourite": "Favourite",
"Edit": "Edit", "Edit": "Edit",
"Reply": "Reply", "Reply": "Reply",
"Collapse quotes": "Collapse quotes", "Collapse quotes": "Collapse quotes",
@ -3246,6 +3244,7 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Forget": "Forget", "Forget": "Forget",
"Favourited": "Favourited", "Favourited": "Favourited",
"Favourite": "Favourite",
"Mentions only": "Mentions only", "Mentions only": "Mentions only",
"Copy room link": "Copy room link", "Copy room link": "Copy room link",
"Low Priority": "Low Priority", "Low Priority": "Low Priority",

View file

@ -426,14 +426,6 @@ export const SETTINGS: { [setting: string]: ISetting } = {
shouldWarn: true, shouldWarn: true,
default: false, default: false,
}, },
"feature_favourite_messages": {
isFeature: true,
labsGroup: LabGroup.Messaging,
supportedLevels: LEVELS_FEATURE,
displayName: _td("Favourite Messages"),
description: _td("Under active development."),
default: false,
},
[Features.VoiceBroadcast]: { [Features.VoiceBroadcast]: {
isFeature: true, isFeature: true,
labsGroup: LabGroup.Messaging, labsGroup: LabGroup.Messaging,

View file

@ -433,88 +433,7 @@ describe("<MessageActionBar />", () => {
}); });
}); });
describe("favourite button", () => { it.each([["React"], ["Reply"], ["Reply in thread"], ["Edit"]])(
//for multiple event usecase
const favButton = (evt: MatrixEvent) => {
return getComponent({ mxEvent: evt }).getByTestId(evt.getId()!);
};
describe("when favourite_messages feature is enabled", () => {
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockImplementation(
(setting) => setting === "feature_favourite_messages",
);
localStorageMock.clear();
});
it("renders favourite button on own actionable event", () => {
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
expect(queryByLabelText("Favourite")).toBeTruthy();
});
it("renders favourite button on other actionable events", () => {
const { queryByLabelText } = getComponent({ mxEvent: bobsMessageEvent });
expect(queryByLabelText("Favourite")).toBeTruthy();
});
it("does not render Favourite button on non-actionable event", () => {
//redacted event is not actionable
const { queryByLabelText } = getComponent({ mxEvent: redactedEvent });
expect(queryByLabelText("Favourite")).toBeFalsy();
});
it("remembers favourited state of multiple events, and handles the localStorage of the events accordingly", () => {
const alicesAction = favButton(alicesMessageEvent);
const bobsAction = favButton(bobsMessageEvent);
//default state before being clicked
expect(alicesAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(localStorageMock.getItem("io_element_favouriteMessages")).toBeNull();
//if only alice's event is fired
fireEvent.click(alicesAction);
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(localStorageMock.setItem).toHaveBeenCalledWith(
"io_element_favouriteMessages",
'["$alices_message"]',
);
//when bob's event is fired,both should be styled and stored in localStorage
fireEvent.click(bobsAction);
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(bobsAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(localStorageMock.setItem).toHaveBeenCalledWith(
"io_element_favouriteMessages",
'["$alices_message","$bobs_message"]',
);
//finally, at this point the localStorage should contain the two eventids
expect(localStorageMock.getItem("io_element_favouriteMessages")).toEqual(
'["$alices_message","$bobs_message"]',
);
//if decided to unfavourite bob's event by clicking again
fireEvent.click(bobsAction);
expect(bobsAction.classList).not.toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(alicesAction.classList).toContain("mx_MessageActionBar_favouriteButton_fillstar");
expect(localStorageMock.getItem("io_element_favouriteMessages")).toEqual('["$alices_message"]');
});
});
describe("when favourite_messages feature is disabled", () => {
it("does not render", () => {
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
expect(queryByLabelText("Favourite")).toBeFalsy();
});
});
});
it.each([["React"], ["Reply"], ["Reply in thread"], ["Favourite"], ["Edit"]])(
"does not show context menu when right-clicking", "does not show context menu when right-clicking",
(buttonLabel: string) => { (buttonLabel: string) => {
// For favourite button // For favourite button