Remove threads labs flag and the ability to disable threads (#9878)

This commit is contained in:
Germain 2023-02-20 14:46:07 +00:00 committed by GitHub
parent a09e105c23
commit 8c22584f64
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 197 additions and 501 deletions

View file

@ -1,5 +1,5 @@
/*
Copyright 2016 - 2022 The Matrix.org Foundation C.I.C.
Copyright 2016 - 2023 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.
@ -75,7 +75,6 @@ export function shouldFormContinuation(
prevEvent: MatrixEvent | null,
mxEvent: MatrixEvent,
showHiddenEvents: boolean,
threadsEnabled: boolean,
timelineRenderingType?: TimelineRenderingType,
): boolean {
if (timelineRenderingType === TimelineRenderingType.ThreadsList) return false;
@ -105,7 +104,6 @@ export function shouldFormContinuation(
// Thread summaries in the main timeline should break up a continuation on both sides
if (
threadsEnabled &&
(hasThreadSummary(mxEvent) || hasThreadSummary(prevEvent)) &&
timelineRenderingType !== TimelineRenderingType.Thread
) {
@ -259,7 +257,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
private readReceiptsByUserId: Record<string, IReadReceiptForUser> = {};
private readonly _showHiddenEvents: boolean;
private readonly threadsEnabled: boolean;
private isMounted = false;
private readMarkerNode = createRef<HTMLLIElement>();
@ -287,7 +284,6 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// and we check this in a hot code path. This is also cached in our
// RoomContext, however we still need a fallback for roomless MessagePanels.
this._showHiddenEvents = SettingsStore.getValue("showHiddenEventsInTimeline");
this.threadsEnabled = SettingsStore.getValue("feature_threadenabled");
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
"showTypingNotifications",
@ -464,7 +460,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// TODO: Implement granular (per-room) hide options
public shouldShowEvent(mxEv: MatrixEvent, forceHideEvents = false): boolean {
if (this.props.hideThreadedMessages && this.threadsEnabled && this.props.room) {
if (this.props.hideThreadedMessages && this.props.room) {
const { shouldLiveInRoom } = this.props.room.eventShouldLiveIn(mxEv, this.props.events);
if (!shouldLiveInRoom) {
return false;
@ -720,25 +716,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
willWantDateSeparator ||
mxEv.getSender() !== nextEv.getSender() ||
getEventDisplayInfo(nextEv, this.showHiddenEvents).isInfoMessage ||
!shouldFormContinuation(
mxEv,
nextEv,
this.showHiddenEvents,
this.threadsEnabled,
this.context.timelineRenderingType,
);
!shouldFormContinuation(mxEv, nextEv, this.showHiddenEvents, this.context.timelineRenderingType);
}
// is this a continuation of the previous message?
const continuation =
!wantsDateSeparator &&
shouldFormContinuation(
prevEvent,
mxEv,
this.showHiddenEvents,
this.threadsEnabled,
this.context.timelineRenderingType,
);
shouldFormContinuation(prevEvent, mxEv, this.showHiddenEvents, this.context.timelineRenderingType);
const eventId = mxEv.getId();
const highlight = eventId === this.props.highlightedEventId;

View file

@ -1,5 +1,5 @@
/*
Copyright 2015 - 2022 The Matrix.org Foundation C.I.C.
Copyright 2015 - 2023 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.
@ -34,7 +34,6 @@ import ResizeNotifier from "../../utils/ResizeNotifier";
import MatrixClientContext from "../../contexts/MatrixClientContext";
import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks";
import RoomContext from "../../contexts/RoomContext";
import SettingsStore from "../../settings/SettingsStore";
const DEBUG = false;
let debuglog = function (msg: string): void {};
@ -100,23 +99,19 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
return b.length - a.length;
});
if (SettingsStore.getValue("feature_threadenabled")) {
// Process all thread roots returned in this batch of search results
// XXX: This won't work for results coming from Seshat which won't include the bundled relationship
for (const result of results.results) {
for (const event of result.context.getTimeline()) {
const bundledRelationship =
event.getServerAggregatedRelation<IThreadBundledRelationship>(
THREAD_RELATION_TYPE.name,
);
if (!bundledRelationship || event.getThread()) continue;
const room = client.getRoom(event.getRoomId());
const thread = room?.findThreadForEvent(event);
if (thread) {
event.setThread(thread);
} else {
room?.createThread(event.getId()!, event, [], true);
}
for (const result of results.results) {
for (const event of result.context.getTimeline()) {
const bundledRelationship =
event.getServerAggregatedRelation<IThreadBundledRelationship>(
THREAD_RELATION_TYPE.name,
);
if (!bundledRelationship || event.getThread()) continue;
const room = client.getRoom(event.getRoomId());
const thread = room?.findThreadForEvent(event);
if (thread) {
event.setThread(thread);
} else {
room?.createThread(event.getId()!, event, [], true);
}
}
}

View file

@ -2,7 +2,7 @@
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018, 2019 New Vector Ltd
Copyright 2019 - 2022 The Matrix.org Foundation C.I.C.
Copyright 2019 - 2023 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.
@ -1194,7 +1194,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
CHAT_EFFECTS.forEach((effect) => {
if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) {
// For initial threads launch, chat effects are disabled see #19731
if (!SettingsStore.getValue("feature_threadenabled") || !ev.isRelation(THREAD_RELATION_TYPE.name)) {
if (!ev.isRelation(THREAD_RELATION_TYPE.name)) {
dis.dispatch({ action: `effects.${effect.command}` });
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2016 - 2022 The Matrix.org Foundation C.I.C.
Copyright 2016 - 2023 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.
@ -1689,8 +1689,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
/* Threads do not have server side support for read receipts and the concept
is very tied to the main room timeline, we are forcing the timeline to
send read receipts for threaded events */
const isThreadTimeline = this.context.timelineRenderingType === TimelineRenderingType.Thread;
if (SettingsStore.getValue("feature_threadenabled") && isThreadTimeline) {
if (this.context.timelineRenderingType === TimelineRenderingType.Thread) {
return 0;
}
const index = this.state.events.findIndex((ev) => ev.getId() === evId);

View file

@ -1,6 +1,6 @@
/*
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2015 - 2022 The Matrix.org Foundation C.I.C.
Copyright 2015 - 2023 The Matrix.org Foundation C.I.C.
Copyright 2021 - 2022 Šimon Brandner <simon.bra.ag@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
@ -56,7 +56,6 @@ import { getForwardableEvent } from "../../../events/forward/getForwardableEvent
import { getShareableLocationEvent } from "../../../events/location/getShareableLocationEvent";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import { CardContext } from "../right_panel/context";
import { UserTab } from "../dialogs/UserTab";
interface IReplyInThreadButton {
mxEvent: MatrixEvent;
@ -71,12 +70,7 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent, closeMen
if (Boolean(relationType) && relationType !== RelationType.Thread) return null;
const onClick = (): void => {
if (!SettingsStore.getValue("feature_threadenabled")) {
dis.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Labs,
});
} else if (mxEvent.getThread() && !mxEvent.isThreadRoot) {
if (mxEvent.getThread() && !mxEvent.isThreadRoot) {
dis.dispatch<ShowThreadPayload>({
action: Action.ShowThread,
rootEvent: mxEvent.getThread().rootEvent,
@ -639,7 +633,6 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
rightClick &&
contentActionable &&
canSendMessages &&
SettingsStore.getValue("feature_threadenabled") &&
Thread.hasServerSideSupport &&
timelineRenderingType !== TimelineRenderingType.Thread
) {

View file

@ -1,7 +1,7 @@
/*
Copyright 2019 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Copyright 2019 - 2023 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.
@ -20,7 +20,6 @@ import React, { ReactElement, useCallback, useContext, useEffect } from "react";
import { EventStatus, MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
import classNames from "classnames";
import { MsgType, RelationType } from "matrix-js-sdk/src/@types/event";
import { Thread } from "matrix-js-sdk/src/models/thread";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { Icon as ContextMenuIcon } from "../../../../res/img/element-icons/context-menu.svg";
@ -54,7 +53,6 @@ import { CardContext } from "../right_panel/context";
import { shouldDisplayReply } from "../../../utils/Reply";
import { Key } from "../../../Keyboard";
import { ALTERNATE_KEY_NAME } from "../../../accessibility/KeyboardShortcuts";
import { UserTab } from "../dialogs/UserTab";
import { Action } from "../../../dispatcher/actions";
import { ShowThreadPayload } from "../../../dispatcher/payloads/ShowThreadPayload";
import useFavouriteMessages from "../../../hooks/useFavouriteMessages";
@ -204,24 +202,13 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent }) => {
const relationType = mxEvent?.getRelation()?.rel_type;
const hasARelation = !!relationType && relationType !== RelationType.Thread;
const threadsEnabled = SettingsStore.getValue("feature_threadenabled");
if (!threadsEnabled && !Thread.hasServerSideSupport) {
// hide the prompt if the user would only have degraded mode
return null;
}
const onClick = (e: React.MouseEvent): void => {
// Don't open the regular browser or our context menu on right-click
e.preventDefault();
e.stopPropagation();
if (!SettingsStore.getValue("feature_threadenabled")) {
dis.dispatch({
action: Action.ViewUserSettings,
initialTabId: UserTab.Labs,
});
} else if (mxEvent.getThread() && !mxEvent.isThreadRoot) {
if (mxEvent.getThread() && !mxEvent.isThreadRoot) {
defaultDispatcher.dispatch<ShowThreadPayload>({
action: Action.ShowThread,
rootEvent: mxEvent.getThread().rootEvent,
@ -250,13 +237,6 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent }) => {
? _t("Reply in thread")
: _t("Can't create a thread from an event with an existing relation")}
</div>
{!hasARelation && (
<div className="mx_Tooltip_sub">
{SettingsStore.getValue("feature_threadenabled")
? _t("Beta feature")
: _t("Beta feature. Click to learn more.")}
</div>
)}
</>
}
title={
@ -548,7 +528,6 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
);
}
} else if (
SettingsStore.getValue("feature_threadenabled") &&
// Show thread icon even for deleted messages, but only within main timeline
this.context.timelineRenderingType === TimelineRenderingType.Room &&
this.props.mxEvent.getThread()

View file

@ -3,7 +3,7 @@ Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd
Copyright 2018 New Vector Ltd
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Copyright 2019 - 2023 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.
@ -294,19 +294,17 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
);
rightPanelPhaseButtons.set(
RightPanelPhases.ThreadPanel,
SettingsStore.getValue("feature_threadenabled") ? (
<HeaderButton
key={RightPanelPhases.ThreadPanel}
name="threadsButton"
data-testid="threadsButton"
title={_t("Threads")}
onClick={this.onThreadsPanelClicked}
isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)}
isUnread={this.state.threadNotificationColor > 0}
>
<UnreadIndicator color={this.state.threadNotificationColor} />
</HeaderButton>
) : null,
<HeaderButton
key={RightPanelPhases.ThreadPanel}
name="threadsButton"
data-testid="threadsButton"
title={_t("Threads")}
onClick={this.onThreadsPanelClicked}
isHighlighted={this.isPhase(RoomHeaderButtons.THREAD_PHASES)}
isUnread={this.state.threadNotificationColor > 0}
>
<UnreadIndicator color={this.state.threadNotificationColor} />
</HeaderButton>,
);
rightPanelPhaseButtons.set(
RightPanelPhases.NotificationPanel,

View file

@ -57,7 +57,6 @@ import { IReadReceiptInfo } from "./ReadReceiptMarker";
import MessageActionBar from "../messages/MessageActionBar";
import ReactionsRow from "../messages/ReactionsRow";
import { getEventDisplayInfo } from "../../../utils/EventRenderingUtils";
import SettingsStore from "../../../settings/SettingsStore";
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
@ -381,9 +380,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
}
}
if (SettingsStore.getValue("feature_threadenabled")) {
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
}
this.props.mxEvent.on(ThreadEvent.Update, this.updateThread);
client.decryptEventIfNeeded(this.props.mxEvent);
@ -420,9 +417,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
if (this.props.showReactions) {
this.props.mxEvent.removeListener(MatrixEventEvent.RelationsCreated, this.onReactionsCreated);
}
if (SettingsStore.getValue("feature_threadenabled")) {
this.props.mxEvent.off(ThreadEvent.Update, this.updateThread);
}
this.props.mxEvent.off(ThreadEvent.Update, this.updateThread);
}
public componentDidUpdate(prevProps: Readonly<EventTileProps>, prevState: Readonly<IState>): void {
@ -450,10 +445,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
};
private get thread(): Thread | null {
if (!SettingsStore.getValue("feature_threadenabled")) {
return null;
}
let thread = this.props.mxEvent.getThread();
/**
* Accessing the threads value through the room due to a race condition

View file

@ -1,6 +1,6 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019 - 2023 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.
@ -68,7 +68,6 @@ export default class SearchResultTile extends React.Component<IProps> {
const layout = SettingsStore.getValue("layout");
const isTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
const alwaysShowTimestamps = SettingsStore.getValue("alwaysShowTimestamps");
const threadsEnabled = SettingsStore.getValue("feature_threadenabled");
for (let j = 0; j < timeline.length; j++) {
const mxEv = timeline[j];
@ -85,13 +84,7 @@ export default class SearchResultTile extends React.Component<IProps> {
const continuation =
prevEv &&
!wantsDateSeparator(prevEv.getDate() || undefined, mxEv.getDate() || undefined) &&
shouldFormContinuation(
prevEv,
mxEv,
this.context?.showHiddenEvents,
threadsEnabled,
TimelineRenderingType.Search,
);
shouldFormContinuation(prevEv, mxEv, this.context?.showHiddenEvents, TimelineRenderingType.Search);
let lastInSection = true;
const nextEv = timeline[j + 1];
@ -107,7 +100,6 @@ export default class SearchResultTile extends React.Component<IProps> {
mxEv,
nextEv,
this.context?.showHiddenEvents,
threadsEnabled,
TimelineRenderingType.Search,
);
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
Copyright 2019 - 2023 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.
@ -443,7 +443,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
// For initial threads launch, chat effects are disabled
// see #19731
const isNotThread = this.props.relation?.rel_type !== THREAD_RELATION_TYPE.name;
if (!SettingsStore.getValue("feature_threadenabled") || isNotThread) {
if (isNotThread) {
dis.dispatch({ action: `effects.${effect.command}` });
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Copyright 2022 - 2023 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.
@ -112,7 +112,7 @@ export async function sendMessage(
// For initial threads launch, chat effects are disabled
// see #19731
const isNotThread = relation?.rel_type !== THREAD_RELATION_TYPE.name;
if (!SettingsStore.getValue("feature_threadenabled") || isNotThread) {
if (isNotThread) {
dis.dispatch({ action: `effects.${effect.command}` });
}
}