From 6868478044e8eb4eccfa15b279d9193499907891 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 8 Jul 2021 11:30:56 +0200 Subject: [PATCH 01/51] Add threaded messaging feature flag --- src/i18n/strings/en_EN.json | 1 + src/settings/Settings.tsx | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bbf6954435..eb82c1b533 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -808,6 +808,7 @@ "Render LaTeX maths in messages": "Render LaTeX maths in messages", "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.", "Message Pinning": "Message Pinning", + "Threaded messaging": "Threaded messaging", "Custom user status messages": "Custom user status messages", "Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)", "Render simple counters in room header": "Render simple counters in room header", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 1751eddb2c..2224d1bbd5 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -239,6 +239,12 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_FEATURE, default: false, }, + "feature_threading": { + isFeature: true, + displayName: _td("Threaded messaging"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "feature_custom_status": { isFeature: true, displayName: _td("Custom user status messages"), From cf3117bd57ee298fa84cc0b0dea6eba7804abc4a Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 8 Jul 2021 11:55:31 +0200 Subject: [PATCH 02/51] Migrate ViewSourceEvent to TypeScript --- ...ViewSourceEvent.js => ViewSourceEvent.tsx} | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) rename src/components/views/messages/{ViewSourceEvent.js => ViewSourceEvent.tsx} (85%) diff --git a/src/components/views/messages/ViewSourceEvent.js b/src/components/views/messages/ViewSourceEvent.tsx similarity index 85% rename from src/components/views/messages/ViewSourceEvent.js rename to src/components/views/messages/ViewSourceEvent.tsx index 62454fef1a..d8b558c4a1 100644 --- a/src/components/views/messages/ViewSourceEvent.js +++ b/src/components/views/messages/ViewSourceEvent.tsx @@ -15,27 +15,29 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { MatrixEvent } from '../../../../../matrix-js-sdk/src'; + +interface IProps { + mxEvent: MatrixEvent; +} + +interface IState { + expanded: boolean; +} @replaceableComponent("views.messages.ViewSourceEvent") -export default class ViewSourceEvent extends React.PureComponent { - static propTypes = { - /* the MatrixEvent to show */ - mxEvent: PropTypes.object.isRequired, - }; - - constructor(props) { +export default class ViewSourceEvent extends React.PureComponent { + constructor(props: IProps) { super(props); - this.state = { expanded: false, }; } - componentDidMount() { + public componentDidMount(): void { const { mxEvent } = this.props; const client = MatrixClientPeg.get(); @@ -46,15 +48,15 @@ export default class ViewSourceEvent extends React.PureComponent { } } - onToggle = (ev) => { + private onToggle = (ev: React.MouseEvent): void => { ev.preventDefault(); const { expanded } = this.state; this.setState({ expanded: !expanded, }); - } + }; - render() { + public render(): React.ReactNode { const { mxEvent } = this.props; const { expanded } = this.state; From d9718027892e0932ebf84ab10652c5d616e79f7b Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 10 Aug 2021 14:30:12 +0200 Subject: [PATCH 03/51] Create ThreadView phase in RightPanel --- res/css/views/messages/_MessageActionBar.scss | 4 + src/components/structures/RightPanel.tsx | 9 ++ src/components/structures/ThreadView.tsx | 90 +++++++++++++++++++ .../views/messages/MessageActionBar.js | 33 +++++-- src/i18n/strings/en_EN.json | 1 + src/stores/RightPanelStorePhases.ts | 3 + 6 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 src/components/structures/ThreadView.tsx diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 69f3c672b7..509ded8ee8 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -92,6 +92,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/message-bar/reply.svg'); } +.mx_MessageActionBar_threadButton::after { + mask-image: url('$(res)/img/element-icons/room/files.svg'); +} + .mx_MessageActionBar_editButton::after { mask-image: url('$(res)/img/element-icons/room/message-bar/edit.svg'); } diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 95d70e913a..f2bd7db0f3 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -45,6 +45,7 @@ import GroupRoomInfo from "../views/groups/GroupRoomInfo"; import UserInfo from "../views/right_panel/UserInfo"; import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo"; import FilePanel from "./FilePanel"; +import ThreadView from "./ThreadView"; import NotificationPanel from "./NotificationPanel"; import ResizeNotifier from "../../utils/ResizeNotifier"; import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard"; @@ -309,6 +310,14 @@ export default class RightPanel extends React.Component { panel = ; break; + case RightPanelPhases.ThreadView: + panel = ; + break; + case RightPanelPhases.RoomSummary: panel = ; break; diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx new file mode 100644 index 0000000000..8b196cb4f0 --- /dev/null +++ b/src/components/structures/ThreadView.tsx @@ -0,0 +1,90 @@ +/* +Copyright 2016 OpenMarket Ltd +Copyright 2019 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 React from 'react'; +import { MatrixEvent } from 'matrix-js-sdk/src'; + +import BaseCard from "../views/right_panel/BaseCard"; +import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { MatrixClientPeg } from '../../MatrixClientPeg'; + +import ResizeNotifier from '../../utils/ResizeNotifier'; +import EventTile from '../views/rooms/EventTile'; +import MessageComposer from '../views/rooms/MessageComposer'; + +interface IProps { + roomId: string; + onClose: () => void; + resizeNotifier: ResizeNotifier; + mxEvent: MatrixEvent; +} + +interface IState { +} + +/* + * Component which shows the filtered file using a TimelinePanel + */ +@replaceableComponent("structures.ThreadView") +class ThreadView extends React.Component { + state = {}; + + public componentDidMount(): void {} + + public componentWillUnmount(): void {} + + public renderEventTile(event: MatrixEvent): JSX.Element { + return ; + } + + public render() { + const client = MatrixClientPeg.get(); + const room = client.getRoom(this.props.roomId); + const thread = room.getThread(this.props.mxEvent.getId()); + return ( + + { this.renderEventTile(this.props.mxEvent) } + + { thread && ( + thread.eventTimeline.map((event: MatrixEvent) => { + return this.renderEventTile(event); + }) + ) } + + + + ); + } +} + +export default ThreadView; diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 7fe0eca697..25f3dc740f 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -23,6 +23,8 @@ import { EventStatus } from 'matrix-js-sdk/src/models/event'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; +import { Action } from '../../../dispatcher/actions'; +import { RightPanelPhases } from '../../../stores/RightPanelStorePhases'; import { aboveLeftOf, ContextMenu, ContextMenuTooltipButton, useContextMenu } from '../../structures/ContextMenu'; import { isContentActionable, canEditContent } from '../../../utils/EventUtils'; import RoomContext from "../../../contexts/RoomContext"; @@ -170,6 +172,17 @@ export default class MessageActionBar extends React.PureComponent { }); }; + onThreadClick = () => { + dis.dispatch({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.ThreadView, + allowClose: false, + refireParams: { + event: this.props.mxEvent, + } + }); + } + onEditClick = (ev) => { dis.dispatch({ action: 'edit_event', @@ -254,12 +267,20 @@ export default class MessageActionBar extends React.PureComponent { // The only catch is we do the reply button first so that we can make sure the react // button is the very first button without having to do length checks for `splice()`. if (this.context.canReply) { - toolbarOpts.splice(0, 0, ); + toolbarOpts.splice(0, 0, <> + + + ); } if (this.context.canReact) { toolbarOpts.splice(0, 0, Date: Tue, 17 Aug 2021 10:38:09 +0100 Subject: [PATCH 04/51] Adapt threading UI to new backend --- src/components/structures/RightPanel.tsx | 13 ++- src/components/structures/RoomView.tsx | 5 +- src/components/structures/ThreadPanel.tsx | 106 ++++++++++++++++++ src/components/structures/ThreadView.tsx | 22 +++- .../views/right_panel/RoomSummaryCard.tsx | 10 ++ src/i18n/strings/en_EN.json | 1 + src/stores/RightPanelStorePhases.ts | 1 + 7 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 src/components/structures/ThreadPanel.tsx diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index f2bd7db0f3..85d3013a58 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -46,17 +46,20 @@ import UserInfo from "../views/right_panel/UserInfo"; import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo"; import FilePanel from "./FilePanel"; import ThreadView from "./ThreadView"; +import ThreadPanel from "./ThreadPanel"; import NotificationPanel from "./NotificationPanel"; import ResizeNotifier from "../../utils/ResizeNotifier"; import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard"; import { throttle } from 'lodash'; import SpaceStore from "../../stores/SpaceStore"; +import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; interface IProps { room?: Room; // if showing panels for a given room, this is set groupId?: string; // if showing panels for a given group, this is set user?: User; // used if we know the user ahead of opening the panel resizeNotifier: ResizeNotifier; + permalinkCreator?: RoomPermalinkCreator; } interface IState { @@ -315,7 +318,15 @@ export default class RightPanel extends React.Component { roomId={roomId} resizeNotifier={this.props.resizeNotifier} onClose={this.onClose} - mxEvent={this.state.event} />; + mxEvent={this.state.event} + permalinkCreator={this.props.permalinkCreator} />; + break; + + case RightPanelPhases.ThreadPanel: + panel = ; break; case RightPanelPhases.RoomSummary: diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 474b99262d..baf557ee18 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2052,7 +2052,10 @@ export default class RoomView extends React.Component { const showRightPanel = this.state.room && this.state.showRightPanel; const rightPanel = showRightPanel - ? + ? : null; const timelineClasses = classNames("mx_RoomView_timeline", { diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx new file mode 100644 index 0000000000..c99246ccda --- /dev/null +++ b/src/components/structures/ThreadPanel.tsx @@ -0,0 +1,106 @@ +/* +Copyright 2016 OpenMarket Ltd +Copyright 2019 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 React from 'react'; +import { MatrixEvent, Room } from 'matrix-js-sdk/src'; + +import BaseCard from "../views/right_panel/BaseCard"; +import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { MatrixClientPeg } from '../../MatrixClientPeg'; + +import ResizeNotifier from '../../utils/ResizeNotifier'; +import EventTile from '../views/rooms/EventTile'; +import { Thread } from '../../../../matrix-js-sdk/src/models/thread'; + +interface IProps { + roomId: string; + onClose: () => void; + resizeNotifier: ResizeNotifier; +} + +interface IState { + threads?: Thread[]; +} + +/* + * Component which shows the filtered file using a TimelinePanel + */ +@replaceableComponent("structures.ThreadView") +class ThreadView extends React.Component { + private room: Room; + + constructor(props: IProps) { + super(props); + this.room = MatrixClientPeg.get().getRoom(this.props.roomId); + } + + public componentDidMount(): void { + this.room.on("Thread.update", this.onThreadEventReceived); + this.room.on("Thread.ready", this.onThreadEventReceived); + this.updateThreads(() => { + this.state.threads.forEach(thread => { + if (!thread.ready) { + thread.fetchReplyChain(); + } + }); + }); + } + + public componentWillUnmount(): void { + this.room.removeListener("Thread.update", this.onThreadEventReceived); + this.room.removeListener("Thread.ready", this.onThreadEventReceived); + } + + public onThreadEventReceived = () => this.updateThreads(); + + public updateThreads = (callback?: () => void): void => { + this.setState({ + threads: this.room.getThreads(), + }, callback); + }; + + public renderEventTile(event: MatrixEvent): JSX.Element { + return ; + } + + public render() { + return ( + + { + this.state?.threads.map((thread: Thread) => { + if (thread.ready) { + return this.renderEventTile(thread.rootEvent); + } + }) + } + + ); + } +} + +export default ThreadView; diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 8b196cb4f0..0f9d499884 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -26,12 +26,14 @@ import { MatrixClientPeg } from '../../MatrixClientPeg'; import ResizeNotifier from '../../utils/ResizeNotifier'; import EventTile from '../views/rooms/EventTile'; import MessageComposer from '../views/rooms/MessageComposer'; +import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; interface IProps { roomId: string; onClose: () => void; resizeNotifier: ResizeNotifier; mxEvent: MatrixEvent; + permalinkCreator?: RoomPermalinkCreator; } interface IState { @@ -44,9 +46,18 @@ interface IState { class ThreadView extends React.Component { state = {}; - public componentDidMount(): void {} + public componentDidMount(): void { + // this.props.mxEvent.getThread().on("Thread.update", this.updateThread); + this.props.mxEvent.getThread().once("Thread.ready", this.updateThread); + } - public componentWillUnmount(): void {} + public componentWillUnmount(): void { + this.props.mxEvent.getThread().removeListener("Thread.update", this.updateThread); + } + + updateThread = () => { + this.forceUpdate(); + }; public renderEventTile(event: MatrixEvent): JSX.Element { return { } public render() { - const client = MatrixClientPeg.get(); - const room = client.getRoom(this.props.roomId); - const thread = room.getThread(this.props.mxEvent.getId()); + const thread = this.props.mxEvent.getThread(); + const room = MatrixClientPeg.get().getRoom(this.props.roomId); return ( { room={room} resizeNotifier={this.props.resizeNotifier} replyToEvent={this.props.mxEvent} - permalinkCreator={null} + permalinkCreator={this.props.permalinkCreator} /> ); diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 047448d925..eb3d7499f4 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -220,6 +220,13 @@ const onRoomFilesClick = () => { }); }; +const onRoomThreadsClick = () => { + defaultDispatcher.dispatch({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.ThreadPanel, + }); +}; + const onRoomSettingsClick = () => { defaultDispatcher.dispatch({ action: "open_room_settings" }); }; @@ -273,6 +280,9 @@ const RoomSummaryCard: React.FC = ({ room, onClose }) => { + diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ca55f45619..ec28be664b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1790,6 +1790,7 @@ "%(count)s people|other": "%(count)s people", "%(count)s people|one": "%(count)s person", "Show files": "Show files", + "Show threads": "Show threads", "Share room": "Share room", "Room settings": "Room settings", "Trusted": "Trusted", diff --git a/src/stores/RightPanelStorePhases.ts b/src/stores/RightPanelStorePhases.ts index 8f41b17e47..96a585b676 100644 --- a/src/stores/RightPanelStorePhases.ts +++ b/src/stores/RightPanelStorePhases.ts @@ -40,6 +40,7 @@ export enum RightPanelPhases { // Thread stuff ThreadView = "ThreadView", + ThreadPanel = "ThreadPanel", } // These are the phases that are safe to persist (the ones that don't require additional From d1dbfbd014094554a6d3e25e37a5ff33708708f1 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 17 Aug 2021 11:10:02 +0100 Subject: [PATCH 05/51] hide thread events from the timeline --- res/css/views/rooms/_EventTile.scss | 30 +++++++++++++++ res/img/element-icons/message/thread.svg | 4 ++ src/components/structures/MessagePanel.tsx | 7 ++++ src/components/structures/ThreadView.tsx | 29 +++++++++----- src/components/structures/TimelinePanel.tsx | 4 ++ src/components/views/rooms/EventTile.tsx | 38 +++++++++++++++++++ .../views/rooms/MessageComposer.tsx | 9 ++++- 7 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 res/img/element-icons/message/thread.svg diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 1c9d8e87d9..1adfc0cde3 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -670,3 +670,33 @@ $hover-select-border: 4px; margin-right: 0; } } + + +.mx_ThreadView { + + display: flex; + flex-direction: column; + + .mx_ThreadView_List { + flex: 1; + overflow: scroll; + } + + .mx_EventTile_roomName { + display: none; + } + + .mx_EventTile_line { + padding-left: 0 !important; + order: 10 !important; + } + .mx_EventTile { + width: 100%; + display: flex; + flex-direction: column; + border-bottom: 1px solid #888; + margin-top: 0; + padding-bottom: 5px; + margin-bottom: 5px; + } +} diff --git a/res/img/element-icons/message/thread.svg b/res/img/element-icons/message/thread.svg new file mode 100644 index 0000000000..b4a7cc0066 --- /dev/null +++ b/res/img/element-icons/message/thread.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 1691d90651..15275328a6 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -173,6 +173,8 @@ interface IProps { onUnfillRequest?(backwards: boolean, scrollToken: string): void; getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations; + + hideThreadedMessages?: boolean; } interface IState { @@ -443,6 +445,11 @@ export default class MessagePanel extends React.Component { // Always show highlighted event if (this.props.highlightedEventId === mxEv.getId()) return true; + const threadingEnabled = SettingsStore.getValue("feature_threading"); + if (threadingEnabled && mxEv.replyEventId && this.props.hideThreadedMessages === true) { + return false; + } + return !shouldHideEvent(mxEv, this.context); } diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 0f9d499884..f34be87c95 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -24,9 +24,11 @@ import { replaceableComponent } from "../../utils/replaceableComponent"; import { MatrixClientPeg } from '../../MatrixClientPeg'; import ResizeNotifier from '../../utils/ResizeNotifier'; -import EventTile from '../views/rooms/EventTile'; +import EventTile, { TileShape } from '../views/rooms/EventTile'; import MessageComposer from '../views/rooms/MessageComposer'; import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; +import { Layout } from '../../settings/Layout'; +import TimelinePanel from './TimelinePanel'; interface IProps { roomId: string; @@ -37,6 +39,7 @@ interface IProps { } interface IState { + replyToEvent?: MatrixEvent; } /* @@ -65,6 +68,7 @@ class ThreadView extends React.Component { mxEvent={event} enableFlair={false} showReadReceipts={false} + tileShape={TileShape.FileGrid} as="div" />; } @@ -77,19 +81,24 @@ class ThreadView extends React.Component { className="mx_ThreadView" onClose={this.props.onClose} previousPhase={RightPanelPhases.RoomSummary} + withoutScrollContainer={true} > - { this.renderEventTile(this.props.mxEvent) } - - { thread && ( - thread.eventTimeline.map((event: MatrixEvent) => { - return this.renderEventTile(event); - }) - ) } - + empty} + alwaysShowTimestamps={true} + layout={Layout.Group} + hideThreadedMessages={false} + /> diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index f62676a4fc..e5fa6967dc 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -126,6 +126,8 @@ interface IProps { // callback which is called when we wish to paginate the timeline window. onPaginationRequest?(timelineWindow: TimelineWindow, direction: string, size: number): Promise; + + hideThreadedMessages?: boolean; } interface IState { @@ -214,6 +216,7 @@ class TimelinePanel extends React.Component { timelineCap: Number.MAX_VALUE, className: 'mx_RoomView_messagePanel', sendReadReceiptOnLoad: true, + hideThreadedMessages: true, }; private lastRRSentEventId: string = undefined; @@ -1511,6 +1514,7 @@ class TimelinePanel extends React.Component { showReactions={this.props.showReactions} layout={this.props.layout} enableFlair={SettingsStore.getValue(UIFeature.Flair)} + hideThreadedMessages={this.props.hideThreadedMessages} /> ); } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 884d004551..30355e55bf 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -55,6 +55,7 @@ import ReadReceiptMarker from "./ReadReceiptMarker"; import MessageActionBar from "../messages/MessageActionBar"; import ReactionsRow from '../messages/ReactionsRow'; import { getEventDisplayInfo } from '../../../utils/EventUtils'; +import { RightPanelPhases } from "../../../stores/RightPanelStorePhases"; const eventTileTypes = { [EventType.RoomMessage]: 'messages.MessageEvent', @@ -299,6 +300,9 @@ interface IProps { // whether or not to display the sender hideSender?: boolean; + + // whether or not to display thread info + showThreadInfo?: boolean; } interface IState { @@ -451,6 +455,7 @@ export default class EventTile extends React.Component { client.on("Room.receipt", this.onRoomReceipt); this.isListeningForReceipts = true; } + this.props.mxEvent.on("Thread.update", this.forceUpdate); } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event @@ -491,6 +496,38 @@ export default class EventTile extends React.Component { } } + private renderThreadInfo(): React.ReactNode { + const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); + const thread = room.getThread(this.props.mxEvent.getId()); + if (!thread || this.props.showThreadInfo === false) { + return null; + } + + const avatars = Array.from(thread.participants).map((mxId: string) => { + const member = room.getMember(mxId); + return ; + }); + + return ( +
{ + dis.dispatch({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.ThreadView, + refireParams: { + event: this.props.mxEvent, + }, + }); + }} + > + + { avatars } + + { thread.length } { thread.length === 1 ? 'reply' : 'replies' } +
+ ); + } + private onRoomReceipt = (ev, room) => { // ignore events for other rooms const tileRoom = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); @@ -1167,6 +1204,7 @@ export default class EventTile extends React.Component { { keyRequestInfo } { actionBar } { this.props.layout === Layout.IRC && (reactionsRow) } + { this.renderThreadInfo() } { this.props.layout !== Layout.IRC && (reactionsRow) } { msgOption } diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 8455e9aa11..bd53c9566a 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -183,6 +183,7 @@ interface IProps { resizeNotifier: ResizeNotifier; permalinkCreator: RoomPermalinkCreator; replyToEvent?: MatrixEvent; + showReplyPreview?: boolean; e2eStatus?: E2EStatus; } @@ -201,6 +202,10 @@ export default class MessageComposer extends React.Component { private messageComposerInput: SendMessageComposer; private voiceRecordingButton: VoiceRecordComposerTile; + static defaultProps = { + showReplyPreview: true, + }; + constructor(props) { super(props); VoiceRecordingStore.instance.on(UPDATE_EVENT, this.onVoiceStoreUpdate); @@ -454,7 +459,9 @@ export default class MessageComposer extends React.Component {
{ recordingTooltip }
- + { this.props.showReplyPreview && ( + + ) }
{ controls }
From 95f4513bd21506665646dd5bfca230add77398f6 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 17 Aug 2021 17:42:47 +0100 Subject: [PATCH 06/51] Make UI respond to thread events --- res/css/views/messages/_MessageActionBar.scss | 4 ++-- .../views/right_panel/_RoomSummaryCard.scss | 4 ++++ src/components/structures/MessagePanel.tsx | 1 + src/components/structures/ThreadPanel.tsx | 7 ------ src/components/structures/ThreadView.tsx | 23 +++++++++++++++---- .../views/right_panel/RoomSummaryCard.tsx | 2 +- src/components/views/rooms/EventTile.tsx | 20 +++++++++++++--- 7 files changed, 44 insertions(+), 17 deletions(-) diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 509ded8ee8..3e5ab87ca9 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -89,11 +89,11 @@ limitations under the License. } .mx_MessageActionBar_replyButton::after { - mask-image: url('$(res)/img/element-icons/room/message-bar/reply.svg'); + mask-image: url('$(res)/img/element-icons/room/files.svg'); } .mx_MessageActionBar_threadButton::after { - mask-image: url('$(res)/img/element-icons/room/files.svg'); + mask-image: url('$(res)/img/element-icons/message/thread.svg'); } .mx_MessageActionBar_editButton::after { diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss index dc7804d072..d93e593679 100644 --- a/res/css/views/right_panel/_RoomSummaryCard.scss +++ b/res/css/views/right_panel/_RoomSummaryCard.scss @@ -232,6 +232,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/files.svg'); } +.mx_RoomSummaryCard_icon_threads::before { + mask-image: url('$(res)/img/element-icons/message/thread.svg'); +} + .mx_RoomSummaryCard_icon_share::before { mask-image: url('$(res)/img/element-icons/room/share.svg'); } diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 15275328a6..fd716041c2 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -267,6 +267,7 @@ export default class MessagePanel extends React.Component { componentDidMount() { this.calculateRoomMembersCount(); this.props.room?.on("RoomState.members", this.calculateRoomMembersCount); + this.props.room?.getThreads().forEach(thread => thread.fetchReplyChain()); this.isMounted = true; } diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index c99246ccda..f0b85e9723 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -52,13 +52,6 @@ class ThreadView extends React.Component { public componentDidMount(): void { this.room.on("Thread.update", this.onThreadEventReceived); this.room.on("Thread.ready", this.onThreadEventReceived); - this.updateThreads(() => { - this.state.threads.forEach(thread => { - if (!thread.ready) { - thread.fetchReplyChain(); - } - }); - }); } public componentWillUnmount(): void { diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index f34be87c95..7767e5929e 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -29,6 +29,7 @@ import MessageComposer from '../views/rooms/MessageComposer'; import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; import { Layout } from '../../settings/Layout'; import TimelinePanel from './TimelinePanel'; +import { Thread } from '../../../../matrix-js-sdk/src/models/thread'; interface IProps { roomId: string; @@ -40,6 +41,7 @@ interface IProps { interface IState { replyToEvent?: MatrixEvent; + thread?: Thread; } /* @@ -50,16 +52,29 @@ class ThreadView extends React.Component { state = {}; public componentDidMount(): void { - // this.props.mxEvent.getThread().on("Thread.update", this.updateThread); - this.props.mxEvent.getThread().once("Thread.ready", this.updateThread); + this.setupThread(); } public componentWillUnmount(): void { - this.props.mxEvent.getThread().removeListener("Thread.update", this.updateThread); + if (this.state.thread) { + this.state.thread.removeListener("Thread.update", this.updateThread); + this.state.thread.removeListener("Thread.ready", this.updateThread); + } } + setupThread = () => { + const thread = this.props.mxEvent.getThread(); + if (thread) { + thread.on("Thread.update", this.updateThread); + thread.once("Thread.ready", this.updateThread); + this.updateThread(); + } + }; + updateThread = () => { - this.forceUpdate(); + this.setState({ + thread: this.props.mxEvent.getThread(), + }); }; public renderEventTile(event: MatrixEvent): JSX.Element { diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index eb3d7499f4..a09fabc06d 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -280,7 +280,7 @@ const RoomSummaryCard: React.FC = ({ room, onClose }) => { - - + { SettingsStore.getValue("experimentalThreadSupport") && ( + + ) } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 6f807f66d6..74d9fc5ca6 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -57,6 +57,7 @@ import ReactionsRow from '../messages/ReactionsRow'; import { getEventDisplayInfo } from '../../../utils/EventUtils'; import { RightPanelPhases } from "../../../stores/RightPanelStorePhases"; import { Thread } from '../../../../../matrix-js-sdk/src/models/thread'; +import SettingsStore from "../../../settings/SettingsStore"; const eventTileTypes = { [EventType.RoomMessage]: 'messages.MessageEvent', @@ -461,8 +462,10 @@ export default class EventTile extends React.Component { this.isListeningForReceipts = true; } - this.props.mxEvent.once("Thread.ready", this.updateThread); - this.props.mxEvent.on("Thread.update", this.updateThread); + if (SettingsStore.getValue("experimentalThreadSupport")) { + this.props.mxEvent.once("Thread.ready", this.updateThread); + this.props.mxEvent.on("Thread.update", this.updateThread); + } } private updateThread = (thread) => { @@ -511,6 +514,10 @@ export default class EventTile extends React.Component { } private renderThreadInfo(): React.ReactNode { + if (!SettingsStore.getValue("experimentalThreadSupport")) { + return null; + } + const thread = this.state.thread; const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); if (!thread || this.props.showThreadInfo === false) { From 30a762944af85a7134e3a4829d2f95ab53001d6c Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 20 Aug 2021 12:11:04 +0100 Subject: [PATCH 09/51] Implement a very low fidelity UI for threads --- res/css/views/rooms/_EventTile.scss | 25 ++++++++++++++++++- res/css/views/rooms/_MessageComposer.scss | 14 +++++++++++ src/components/structures/ThreadView.tsx | 1 + .../views/rooms/MessageComposer.tsx | 12 +++++++-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 4dd91eb7f2..4b48ec971b 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -681,6 +681,30 @@ $hover-select-border: 4px; display: flex; flex-direction: column; + .mx_ScrollPanel { + margin-top: 20px; + .mx_RoomView_MessageList { + padding: 0; + } + } + + .mx_EventTile_senderDetails { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 6px; + a { + flex: 1; + min-width: none; + max-width: 100%; + display: flex; + align-items: center; + .mx_SenderProfile { + flex: 1; + } + } + } + .mx_ThreadView_List { flex: 1; overflow: scroll; @@ -698,7 +722,6 @@ $hover-select-border: 4px; width: 100%; display: flex; flex-direction: column; - border-bottom: 1px solid #888; margin-top: 0; padding-bottom: 5px; margin-bottom: 5px; diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 5e2eff4047..b2747f7a9b 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -340,3 +340,17 @@ limitations under the License. height: 50px; } } + +/** + * Unstable compact mode + */ + +.mx_MessageComposer.mx_MessageComposer--compact { + margin-right: 0; + .mx_MessageComposer_wrapper { + padding: 0; + } + .mx_MessageComposer_button:last-child { + margin-right: 0; + } +} diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 7767e5929e..5d07b7feaa 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -115,6 +115,7 @@ class ThreadView extends React.Component { replyToEvent={thread?.replyToEvent} showReplyPreview={false} permalinkCreator={this.props.permalinkCreator} + compact={true} /> ); diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index bd53c9566a..fbf3b58570 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -185,6 +185,7 @@ interface IProps { replyToEvent?: MatrixEvent; showReplyPreview?: boolean; e2eStatus?: E2EStatus; + compact?: boolean; } interface IState { @@ -204,6 +205,7 @@ export default class MessageComposer extends React.Component { static defaultProps = { showReplyPreview: true, + compact: false, }; constructor(props) { @@ -367,7 +369,7 @@ export default class MessageComposer extends React.Component { render() { const controls = [ - this.state.me ? : null, + this.state.me && !this.props.compact ? : null, this.props.e2eStatus ? : null, @@ -455,8 +457,14 @@ export default class MessageComposer extends React.Component { />; } + const classes = classNames({ + "mx_MessageComposer": true, + "mx_GroupLayout": true, + "mx_MessageComposer--compact": this.props.compact, + }); + return ( -
+
{ recordingTooltip }
{ this.props.showReplyPreview && ( From 9facb0d963afa4932f5b48ff3f20aa7128bef30a Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 23 Aug 2021 14:44:44 +0100 Subject: [PATCH 10/51] Polish UI --- res/css/views/messages/_MessageActionBar.scss | 2 +- res/css/views/rooms/_EventTile.scss | 4 + src/components/structures/ThreadView.tsx | 88 +++++++++++++------ src/components/views/rooms/EventTile.tsx | 3 +- 4 files changed, 67 insertions(+), 30 deletions(-) diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 3e5ab87ca9..c2f3c2ebca 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -89,7 +89,7 @@ limitations under the License. } .mx_MessageActionBar_replyButton::after { - mask-image: url('$(res)/img/element-icons/room/files.svg'); + mask-image: url('$(res)/img/element-icons/room/message-bar/reply.svg'); } .mx_MessageActionBar_threadButton::after { diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 4b48ec971b..1bf62d3fb1 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -676,6 +676,10 @@ $hover-select-border: 4px; } +.mx_ThreadInfo:hover { + cursor: pointer; +} + .mx_ThreadView { display: flex; diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 5d07b7feaa..cac4054dfb 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -30,6 +30,8 @@ import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; import { Layout } from '../../settings/Layout'; import TimelinePanel from './TimelinePanel'; import { Thread } from '../../../../matrix-js-sdk/src/models/thread'; +import dis from "../../dispatcher/dispatcher"; +import { ActionPayload } from '../../dispatcher/payloads'; interface IProps { roomId: string; @@ -49,32 +51,61 @@ interface IState { */ @replaceableComponent("structures.ThreadView") class ThreadView extends React.Component { - state = {}; + private dispatcherRef: string; + + constructor(props: IProps) { + super(props); + this.state = {}; + } public componentDidMount(): void { - this.setupThread(); + this.setupThread(this.props.mxEvent); + this.dispatcherRef = dis.register(this.onAction); } public componentWillUnmount(): void { + this.teardownThread(); + dis.unregister(this.dispatcherRef); + } + + public componentDidUpdate(prevProps) { + if (prevProps.mxEvent !== this.props.mxEvent) { + this.teardownThread(); + this.setupThread(this.props.mxEvent); + } + } + + private onAction = (payload: ActionPayload): void => { + if (payload.phase == RightPanelPhases.ThreadView && payload.event) { + if (payload.event !== this.props.mxEvent) { + this.teardownThread(); + this.setupThread(payload.event); + } + } + }; + + setupThread = (mxEv: MatrixEvent) => { + const thread = mxEv.getThread(); + if (thread) { + thread.on("Thread.update", this.updateThread); + thread.once("Thread.ready", this.updateThread); + this.updateThread(thread); + } + }; + + teardownThread = () => { if (this.state.thread) { this.state.thread.removeListener("Thread.update", this.updateThread); this.state.thread.removeListener("Thread.ready", this.updateThread); } - } - - setupThread = () => { - const thread = this.props.mxEvent.getThread(); - if (thread) { - thread.on("Thread.update", this.updateThread); - thread.once("Thread.ready", this.updateThread); - this.updateThread(); - } }; - updateThread = () => { - this.setState({ - thread: this.props.mxEvent.getThread(), - }); + updateThread = (thread?: Thread) => { + if (thread) { + this.setState({ thread }); + } else { + this.forceUpdate(); + } }; public renderEventTile(event: MatrixEvent): JSX.Element { @@ -89,7 +120,6 @@ class ThreadView extends React.Component { } public render() { - const thread = this.props.mxEvent.getThread(); const room = MatrixClientPeg.get().getRoom(this.props.roomId); return ( { previousPhase={RightPanelPhases.RoomSummary} withoutScrollContainer={true} > - empty
} - alwaysShowTimestamps={true} - layout={Layout.Group} - hideThreadedMessages={false} - /> + { this.state.thread && ( + empty
} + alwaysShowTimestamps={true} + layout={Layout.Group} + hideThreadedMessages={false} + /> + ) } { return (
{ dis.dispatch({ action: Action.SetRightPanelPhase, @@ -544,7 +545,7 @@ export default class EventTile extends React.Component { { avatars } - { thread.length } { thread.length === 1 ? 'reply' : 'replies' } + { thread.length - 1 } { thread.length === 2 ? 'reply' : 'replies' }
); } From ef51a46d247b1ed673532632ac1cfaf5445c46ec Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 23 Aug 2021 14:55:14 +0100 Subject: [PATCH 11/51] Fix linting --- src/components/views/messages/MessageActionBar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 29212449d1..83e063ab8c 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -180,7 +180,7 @@ export default class MessageActionBar extends React.PureComponent { allowClose: false, refireParams: { event: this.props.mxEvent, - } + }, }); } @@ -282,7 +282,7 @@ export default class MessageActionBar extends React.PureComponent { onClick={this.onThreadClick} key="thread" /> - )} + ) } ); } if (this.context.canReact) { From 34da07f1f9f314b21441e5cf4f2568a00d38f283 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 23 Aug 2021 17:31:23 +0100 Subject: [PATCH 12/51] Pass room to ThreadView over roomId --- src/components/structures/RightPanel.tsx | 2 +- src/components/structures/ThreadPanel.tsx | 2 +- src/components/structures/ThreadView.tsx | 18 +++++++++++++----- src/components/views/rooms/EventTile.tsx | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 85d3013a58..67634c63d2 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -315,7 +315,7 @@ export default class RightPanel extends React.Component { case RightPanelPhases.ThreadView: panel = void; resizeNotifier: ResizeNotifier; mxEvent: MatrixEvent; @@ -73,6 +75,13 @@ class ThreadView extends React.Component { this.teardownThread(); this.setupThread(this.props.mxEvent); } + + if (prevProps.room !== this.props.room) { + dis.dispatch({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.RoomSummary, + }); + } } private onAction = (payload: ActionPayload): void => { @@ -120,7 +129,6 @@ class ThreadView extends React.Component { } public render() { - const room = MatrixClientPeg.get().getRoom(this.props.roomId); return ( { /> ) } Date: Tue, 24 Aug 2021 09:09:28 +0100 Subject: [PATCH 13/51] PR feedback --- .stylelintrc.js | 1 + res/css/views/rooms/_EventTile.scss | 6 ++++-- res/css/views/rooms/_MessageComposer.scss | 2 ++ src/MatrixClientPeg.ts | 2 +- src/components/structures/MessagePanel.tsx | 7 ++++--- src/components/structures/ThreadPanel.tsx | 18 ++++++------------ src/components/structures/ThreadView.tsx | 19 ++++++------------- .../views/messages/MessageActionBar.js | 2 +- .../views/right_panel/RoomSummaryCard.tsx | 2 +- src/components/views/rooms/EventTile.tsx | 4 ++-- src/settings/Settings.tsx | 2 +- 11 files changed, 29 insertions(+), 36 deletions(-) diff --git a/.stylelintrc.js b/.stylelintrc.js index 0e6de7000f..c044b19a63 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -17,6 +17,7 @@ module.exports = { "selector-list-comma-newline-after": null, "at-rule-no-unknown": null, "no-descending-specificity": null, + "no-empty-first-line": true, "scss/at-rule-no-unknown": [true, { // https://github.com/vector-im/element-web/issues/10544 "ignoreAtRules": ["define-mixin"], diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 1bf62d3fb1..0e77f20c49 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -643,6 +643,7 @@ $hover-select-border: 4px; // Remove some of the default tile padding so that the error is centered margin-right: 0; + .mx_EventTile_line { padding-left: 0; margin-right: 0; @@ -675,18 +676,17 @@ $hover-select-border: 4px; } } - .mx_ThreadInfo:hover { cursor: pointer; } .mx_ThreadView { - display: flex; flex-direction: column; .mx_ScrollPanel { margin-top: 20px; + .mx_RoomView_MessageList { padding: 0; } @@ -703,6 +703,7 @@ $hover-select-border: 4px; max-width: 100%; display: flex; align-items: center; + .mx_SenderProfile { flex: 1; } @@ -722,6 +723,7 @@ $hover-select-border: 4px; padding-left: 0 !important; order: 10 !important; } + .mx_EventTile { width: 100%; display: flex; diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index b2747f7a9b..54c250fc2e 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -347,9 +347,11 @@ limitations under the License. .mx_MessageComposer.mx_MessageComposer--compact { margin-right: 0; + .mx_MessageComposer_wrapper { padding: 0; } + .mx_MessageComposer_button:last-child { margin-right: 0; } diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index d3382a2b5e..7d0ff560b7 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -213,7 +213,7 @@ class MatrixClientPegClass implements IMatrixClientPeg { opts.pendingEventOrdering = PendingEventOrdering.Detached; opts.lazyLoadMembers = true; opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours - opts.experimentalThreadSupport = SettingsStore.getValue("experimentalThreadSupport"); + opts.experimentalThreadSupport = SettingsStore.getValue("feature_thread"); // Connect the matrix client to the dispatcher and setting handlers MatrixActionCreators.start(this.matrixClient); diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 49fb50814c..8bf1f5bd5f 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -267,7 +267,7 @@ export default class MessagePanel extends React.Component { componentDidMount() { this.calculateRoomMembersCount(); this.props.room?.on("RoomState.members", this.calculateRoomMembersCount); - if (SettingsStore.getValue("experimentalThreadSupport")) { + if (SettingsStore.getValue("feature_thread")) { this.props.room?.getThreads().forEach(thread => thread.fetchReplyChain()); } this.isMounted = true; @@ -448,8 +448,9 @@ export default class MessagePanel extends React.Component { // Always show highlighted event if (this.props.highlightedEventId === mxEv.getId()) return true; - const threadingEnabled = SettingsStore.getValue("experimentalThreadSupport"); - if (threadingEnabled && mxEv.replyEventId && this.props.hideThreadedMessages === true) { + if (mxEv.replyEventId + && this.props.hideThreadedMessages + && SettingsStore.getValue("feature_thread")) { return false; } diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 9259dbe13b..047e527f34 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -1,6 +1,5 @@ /* -Copyright 2016 OpenMarket Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2021 New Vector Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,11 +36,8 @@ interface IState { threads?: Thread[]; } -/* - * Component which shows the filtered file using a TimelinePanel - */ @replaceableComponent("structures.ThreadView") -class ThreadView extends React.Component { +export default class ThreadPanel extends React.Component { private room: Room; constructor(props: IProps) { @@ -59,15 +55,15 @@ class ThreadView extends React.Component { this.room.removeListener("Thread.ready", this.onThreadEventReceived); } - public onThreadEventReceived = () => this.updateThreads(); + private onThreadEventReceived = () => this.updateThreads(); - public updateThreads = (callback?: () => void): void => { + private updateThreads = (callback?: () => void): void => { this.setState({ threads: this.room.getThreads(), }, callback); }; - public renderEventTile(event: MatrixEvent): JSX.Element { + private renderEventTile(event: MatrixEvent): JSX.Element { return { />; } - public render() { + public render(): JSX.Element { return ( { ); } } - -export default ThreadView; diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 38b1c8dc08..03609c66d0 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -1,6 +1,5 @@ /* -Copyright 2016 OpenMarket Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2021 New Vector Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +21,6 @@ import { Thread } from 'matrix-js-sdk/src/models/thread'; import BaseCard from "../views/right_panel/BaseCard"; import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; import { replaceableComponent } from "../../utils/replaceableComponent"; -import { MatrixClientPeg } from '../../MatrixClientPeg'; import ResizeNotifier from '../../utils/ResizeNotifier'; import EventTile, { TileShape } from '../views/rooms/EventTile'; @@ -48,11 +46,8 @@ interface IState { thread?: Thread; } -/* - * Component which shows the filtered file using a TimelinePanel - */ @replaceableComponent("structures.ThreadView") -class ThreadView extends React.Component { +export default class ThreadView extends React.Component { private dispatcherRef: string; constructor(props: IProps) { @@ -93,7 +88,7 @@ class ThreadView extends React.Component { } }; - setupThread = (mxEv: MatrixEvent) => { + private setupThread = (mxEv: MatrixEvent) => { const thread = mxEv.getThread(); if (thread) { thread.on("Thread.update", this.updateThread); @@ -102,14 +97,14 @@ class ThreadView extends React.Component { } }; - teardownThread = () => { + private teardownThread = () => { if (this.state.thread) { this.state.thread.removeListener("Thread.update", this.updateThread); this.state.thread.removeListener("Thread.ready", this.updateThread); } }; - updateThread = (thread?: Thread) => { + private updateThread = (thread?: Thread) => { if (thread) { this.setState({ thread }); } else { @@ -128,7 +123,7 @@ class ThreadView extends React.Component { />; } - public render() { + public render(): JSX.Element { return ( { ); } } - -export default ThreadView; diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 83e063ab8c..cb8ea7a50d 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -275,7 +275,7 @@ export default class MessageActionBar extends React.PureComponent { onClick={this.onReplyClick} key="reply" /> - { SettingsStore.getValue("experimentalThreadSupport") && ( + { SettingsStore.getValue("feature_thread") && ( = ({ room, onClose }) => { - { SettingsStore.getValue("experimentalThreadSupport") && ( + { SettingsStore.getValue("feature_thread") && ( diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 638bef5061..935a349b10 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -462,7 +462,7 @@ export default class EventTile extends React.Component { this.isListeningForReceipts = true; } - if (SettingsStore.getValue("experimentalThreadSupport")) { + if (SettingsStore.getValue("feature_thread")) { this.props.mxEvent.once("Thread.ready", this.updateThread); this.props.mxEvent.on("Thread.update", this.updateThread); } @@ -514,7 +514,7 @@ export default class EventTile extends React.Component { } private renderThreadInfo(): React.ReactNode { - if (!SettingsStore.getValue("experimentalThreadSupport")) { + if (!SettingsStore.getValue("feature_thread")) { return null; } diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 6496231679..2dba4cf55d 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -211,7 +211,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_FEATURE, default: false, }, - "experimentalThreadSupport": { + "feature_thread": { isFeature: true, // Requires a reload as we change an option flag on the `js-sdk` // And the entire sync history needs to be parsed again From d4a4ac56801b46b56132fcc776e7ebf5c95b58ad Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 24 Aug 2021 17:09:26 +0100 Subject: [PATCH 14/51] Upgrade matrix-js-sdk to 12.4.0-rc.1 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e0883f5556..92953212e1 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "12.4.0-rc.1", "matrix-widget-api": "^0.1.0-beta.15", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 256fee5277..74883d7059 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5801,9 +5801,10 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "12.3.1" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/3216d7e5a7a333212b00d4d7578e29a9f0e247d8" +matrix-js-sdk@12.4.0-rc.1: + version "12.4.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.0-rc.1.tgz#6eee9f159bcc5dd968346a9ce5c7b7427636f57c" + integrity sha512-6AGIEJvgWlNYyzxPj/V13s9JUg8zsiJ9Hyj6yTpDahufkAUT5yhpFzdPNNRaLlVxHox5HlwJJBdyNQtML727Og== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 920bd82b66a38050557664bb84c8c571f2256a60 Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Tue, 24 Aug 2021 18:22:06 +0200 Subject: [PATCH 15/51] Fix resizer for detaching --- src/resizer/resizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resizer/resizer.ts b/src/resizer/resizer.ts index 19af425b8b..0db13e1af5 100644 --- a/src/resizer/resizer.ts +++ b/src/resizer/resizer.ts @@ -84,7 +84,7 @@ export default class Resizer { } public detach() { - const attachment = this?.config?.handler.parentElement ?? this.container; + const attachment = this?.config?.handler?.parentElement ?? this.container; attachment.removeEventListener("mousedown", this.onMouseDown, false); window.removeEventListener("resize", this.onResize); } From ea081d49257c7b98789a21c2e171339f1b3a222f Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 24 Aug 2021 17:30:43 +0100 Subject: [PATCH 16/51] Prepare changelog for v3.29.0-rc.1 --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f71c1414c..f2ef4e9433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +Changes in [3.29.0-rc.1](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0-rc.1) (2021-08-24) +============================================================================================================= + +## ✨ Features + * Add a warning on E2EE rooms if you try to make them public ([\#5698](https://github.com/matrix-org/matrix-react-sdk/pull/5698)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Allow pagination of the space hierarchy and use new APIs ([\#6507](https://github.com/matrix-org/matrix-react-sdk/pull/6507)). Fixes vector-im/element-web#18089 and vector-im/element-web#18427. + * Improve emoji in composer ([\#6650](https://github.com/matrix-org/matrix-react-sdk/pull/6650)). Fixes vector-im/element-web#18593 and vector-im/element-web#18593. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Allow playback of replied-to voice message ([\#6629](https://github.com/matrix-org/matrix-react-sdk/pull/6629)). Fixes vector-im/element-web#18599 and vector-im/element-web#18599. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Format autocomplete suggestions vertically ([\#6620](https://github.com/matrix-org/matrix-react-sdk/pull/6620)). Fixes vector-im/element-web#17574 and vector-im/element-web#17574. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Remember last `MemberList` search query per-room ([\#6640](https://github.com/matrix-org/matrix-react-sdk/pull/6640)). Fixes vector-im/element-web#18613 and vector-im/element-web#18613. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Sentry rageshakes ([\#6597](https://github.com/matrix-org/matrix-react-sdk/pull/6597)). Fixes vector-im/element-web#11111 and vector-im/element-web#11111. Contributed by [novocaine](https://github.com/novocaine). + * Autocomplete has been updated to match modern accessibility standards. Navigate via up/down arrows rather than Tab. Enter or Tab to confirm a suggestion. This should be familiar to Slack & Discord users. You can now use Tab to navigate around the application and do more without touching your mouse. No more accidentally sending half of people's names because the completion didn't fire on Enter! ([\#5659](https://github.com/matrix-org/matrix-react-sdk/pull/5659)). Fixes vector-im/element-web#4872, vector-im/element-web#11071, vector-im/element-web#17171, vector-im/element-web#15646 vector-im/element-web#4872 and vector-im/element-web#4872. + * Add new call tile states ([\#6610](https://github.com/matrix-org/matrix-react-sdk/pull/6610)). Fixes vector-im/element-web#18521 and vector-im/element-web#18521. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Left align call tiles ([\#6609](https://github.com/matrix-org/matrix-react-sdk/pull/6609)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Make loading encrypted images look snappier ([\#6590](https://github.com/matrix-org/matrix-react-sdk/pull/6590)). Fixes vector-im/element-web#17878 and vector-im/element-web#17862. Contributed by [Palid](https://github.com/Palid). + * Offer a way to create a space based on existing community ([\#6543](https://github.com/matrix-org/matrix-react-sdk/pull/6543)). Fixes vector-im/element-web#18092. + * Accessibility improvements in and around Spaces ([\#6569](https://github.com/matrix-org/matrix-react-sdk/pull/6569)). Fixes vector-im/element-web#18094 and vector-im/element-web#18094. + +## 🐛 Bug Fixes + * Fix images not rendering when sent from other clients. ([\#6661](https://github.com/matrix-org/matrix-react-sdk/pull/6661)). Fixes vector-im/element-web#18702 and vector-im/element-web#18702. + * Fix autocomplete scrollbar and make the autocomplete a little smaller ([\#6655](https://github.com/matrix-org/matrix-react-sdk/pull/6655)). Fixes vector-im/element-web#18682 and vector-im/element-web#18682. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix replies on the bubble layout ([\#6451](https://github.com/matrix-org/matrix-react-sdk/pull/6451)). Fixes vector-im/element-web#18184. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Show "Enable encryption in settings" only when the user can do that ([\#6646](https://github.com/matrix-org/matrix-react-sdk/pull/6646)). Fixes vector-im/element-web#18646 and vector-im/element-web#18646. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix cross signing setup from settings screen ([\#6633](https://github.com/matrix-org/matrix-react-sdk/pull/6633)). Fixes vector-im/element-web#17761 and vector-im/element-web#17761. + * Fix call tiles on the bubble layout ([\#6647](https://github.com/matrix-org/matrix-react-sdk/pull/6647)). Fixes vector-im/element-web#18648 and vector-im/element-web#18648. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix error on accessing encrypted media without encryption keys ([\#6625](https://github.com/matrix-org/matrix-react-sdk/pull/6625)). Contributed by [Palid](https://github.com/Palid). + * Fix jitsi widget sometimes being permanently stuck in the bottom-right corner ([\#6632](https://github.com/matrix-org/matrix-react-sdk/pull/6632)). Fixes vector-im/element-web#17226 and vector-im/element-web#17226. Contributed by [Palid](https://github.com/Palid). + * Fix FilePanel pagination in E2EE rooms ([\#6630](https://github.com/matrix-org/matrix-react-sdk/pull/6630)). Fixes vector-im/element-web#18415 and vector-im/element-web#18415. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix call tile buttons ([\#6624](https://github.com/matrix-org/matrix-react-sdk/pull/6624)). Fixes vector-im/element-web#18565 and vector-im/element-web#18565. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix vertical call tile spacing issues ([\#6621](https://github.com/matrix-org/matrix-react-sdk/pull/6621)). Fixes vector-im/element-web#18558 and vector-im/element-web#18558. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix long display names in call tiles ([\#6618](https://github.com/matrix-org/matrix-react-sdk/pull/6618)). Fixes vector-im/element-web#18562 and vector-im/element-web#18562. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Avoid access token overflow ([\#6616](https://github.com/matrix-org/matrix-react-sdk/pull/6616)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Properly handle media errors ([\#6615](https://github.com/matrix-org/matrix-react-sdk/pull/6615)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix glare related regressions ([\#6614](https://github.com/matrix-org/matrix-react-sdk/pull/6614)). Fixes vector-im/element-web#18538 and vector-im/element-web#18538. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix long display names in call toasts ([\#6617](https://github.com/matrix-org/matrix-react-sdk/pull/6617)). Fixes vector-im/element-web#18557 and vector-im/element-web#18557. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix PiP of held calls ([\#6611](https://github.com/matrix-org/matrix-react-sdk/pull/6611)). Fixes vector-im/element-web#18539 and vector-im/element-web#18539. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix call tile behaviour on narrow layouts ([\#6556](https://github.com/matrix-org/matrix-react-sdk/pull/6556)). Fixes vector-im/element-web#18398. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix video call persisting when widget removed ([\#6608](https://github.com/matrix-org/matrix-react-sdk/pull/6608)). Fixes vector-im/element-web#15703 and vector-im/element-web#15703. + * Fix toast colors ([\#6606](https://github.com/matrix-org/matrix-react-sdk/pull/6606)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Remove tiny scrollbar dot from code blocks ([\#6596](https://github.com/matrix-org/matrix-react-sdk/pull/6596)). Fixes vector-im/element-web#18474. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Improve handling of pills in the composer ([\#6353](https://github.com/matrix-org/matrix-react-sdk/pull/6353)). Fixes vector-im/element-web#10134 vector-im/element-web#10896 and vector-im/element-web#15037. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + Changes in [3.28.1](https://github.com/vector-im/element-desktop/releases/tag/v3.28.1) (2021-08-17) =================================================================================================== From b58f7fea5745deac0e6c206bd0045f8fe7930b28 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 24 Aug 2021 17:30:44 +0100 Subject: [PATCH 17/51] v3.29.0-rc.1 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 92953212e1..8ba3c6bce9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.28.1", + "version": "3.29.0-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -25,7 +25,7 @@ "bin": { "reskindex": "scripts/reskindex.js" }, - "main": "./src/index.js", + "main": "./lib/index.js", "matrix_src_main": "./src/index.js", "matrix_lib_main": "./lib/index.js", "matrix_lib_typings": "./lib/index.d.ts", @@ -207,5 +207,6 @@ "coverageReporters": [ "text" ] - } + }, + "typings": "./lib/index.d.ts" } From b5f377d5438771e14db524e9fc88c9cb508d8317 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 24 Aug 2021 17:43:23 +0100 Subject: [PATCH 18/51] Fix import breaking types in release mode --- src/sentry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry.ts b/src/sentry.ts index 59152f66f2..206ff9811b 100644 --- a/src/sentry.ts +++ b/src/sentry.ts @@ -19,7 +19,7 @@ import PlatformPeg from "./PlatformPeg"; import SdkConfig from "./SdkConfig"; import { MatrixClientPeg } from "./MatrixClientPeg"; import SettingsStore from "./settings/SettingsStore"; -import { MatrixClient } from "matrix-js-sdk"; +import { MatrixClient } from "matrix-js-sdk/src/client"; /* eslint-disable camelcase */ From 798da0f5fac43b4bf5429230cfee5459eb4b3873 Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Thu, 19 Aug 2021 19:00:31 +0200 Subject: [PATCH 19/51] Improve layering for chat Currently we have a lot of unnecessary layers being created in the app, which is extremely problematic on Windows when using Chrome, as it deoptimises fonts rendering due to layers mismatch; chrome's algorithm can't figure out if the layers won't resize or overlap so it creates a lot of additional layers, which has a side effect of turning off sub-pixel antialiasing on Windows. This is a first step to improve the layering in the entire app. --- res/css/structures/_LeftPanel.scss | 2 ++ res/css/structures/_RoomView.scss | 3 ++- res/css/structures/_ScrollPanel.scss | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index da17e5f1f9..fced77bac8 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -26,6 +26,8 @@ $roomListCollapsedWidth: 68px; .mx_LeftPanel_wrapper { display: flex; max-width: 50%; + // Contain the amount of layers rendered by constraining what actually needs re-layering via css + contain: layout paint; .mx_LeftPanel_wrapper--user { background-color: $roomlist-bg-color; diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 81ea75c442..67529878c9 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -20,6 +20,8 @@ limitations under the License. flex: 1; position: relative; justify-content: center; + // Contain the amount of layers rendered by constraining what actually needs re-layering via css + contain: strict; } .mx_RoomView { @@ -163,7 +165,6 @@ limitations under the License. flex: 1; display: flex; flex-direction: column; - contain: content; } .mx_RoomView_statusArea { diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss index 7b75c69e86..82caeae29d 100644 --- a/res/css/structures/_ScrollPanel.scss +++ b/res/css/structures/_ScrollPanel.scss @@ -15,6 +15,7 @@ limitations under the License. */ .mx_ScrollPanel { + contain: strict; .mx_RoomView_MessageList { position: relative; From 972682139e6e14bf152e37666b44cb0743e29e4c Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Tue, 24 Aug 2021 19:23:12 +0200 Subject: [PATCH 20/51] Force a new layer for backdrop panel --- res/css/structures/_BackdropPanel.scss | 2 ++ res/css/structures/_LeftPanel.scss | 2 ++ 2 files changed, 4 insertions(+) diff --git a/res/css/structures/_BackdropPanel.scss b/res/css/structures/_BackdropPanel.scss index 6c41ed7a09..482507cb15 100644 --- a/res/css/structures/_BackdropPanel.scss +++ b/res/css/structures/_BackdropPanel.scss @@ -22,6 +22,8 @@ limitations under the License. width: 100%; overflow: hidden; filter: blur(var(--lp-background-blur)); + // Force a new layer for the backdropPanel so it's better hardware supported + transform: translateZ(0); } .mx_BackdropPanel--image { diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index fced77bac8..32d50b9a80 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -26,6 +26,8 @@ $roomListCollapsedWidth: 68px; .mx_LeftPanel_wrapper { display: flex; max-width: 50%; + position: relative; + // Contain the amount of layers rendered by constraining what actually needs re-layering via css contain: layout paint; From e080b0d66c725518dd290d44ab357d59f30a3d1f Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 25 Aug 2021 11:45:42 +0100 Subject: [PATCH 21/51] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2ef4e9433..1fdcdfa96a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [3.29.0-rc.2](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0-rc.2) (2021-08-25) +============================================================================================================= + +## ✨ Features + * [Release]Increase general app performance by optimizing layers ([\#6672](https://github.com/matrix-org/matrix-react-sdk/pull/6672)). Fixes vector-im/element-web#18730 and vector-im/element-web#18730. Contributed by [Palid](https://github.com/Palid). + Changes in [3.29.0-rc.1](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0-rc.1) (2021-08-24) ============================================================================================================= From ccafcd0d3975a43ebf9692f27f8e6f8e7f9644f8 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 25 Aug 2021 11:46:07 +0100 Subject: [PATCH 22/51] v3.29.0-rc.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ba3c6bce9..bb2f3432d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.29.0-rc.1", + "version": "3.29.0-rc.2", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From bd1aa01b67b489ba831841577d7afadcd0804dad Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 26 Aug 2021 08:19:44 +0100 Subject: [PATCH 23/51] Update copyright and method accessors --- res/css/views/rooms/_EventTile.scss | 1 + src/components/structures/ThreadPanel.tsx | 2 +- src/components/structures/ThreadView.tsx | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 5648a164e4..494f14c9bd 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -697,6 +697,7 @@ $hover-select-border: 4px; align-items: center; gap: 6px; margin-bottom: 6px; + a { flex: 1; min-width: none; diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 047e527f34..a0bccfdce9 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 New Vector Ltd. +Copyright 2021 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. diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 03609c66d0..2e69d7b0f4 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 New Vector Ltd. +Copyright 2021 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 default class ThreadView extends React.Component { } }; - public renderEventTile(event: MatrixEvent): JSX.Element { + private renderEventTile(event: MatrixEvent): JSX.Element { return Date: Thu, 26 Aug 2021 08:45:00 +0100 Subject: [PATCH 24/51] Remove unused renderEventTile method --- src/components/structures/ThreadView.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 2e69d7b0f4..951c821d5c 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -112,17 +112,6 @@ export default class ThreadView extends React.Component { } }; - private renderEventTile(event: MatrixEvent): JSX.Element { - return ; - } - public render(): JSX.Element { return ( Date: Thu, 26 Aug 2021 14:55:37 +0200 Subject: [PATCH 25/51] Fix commit edit history Fix https://github.com/vector-im/element-web/issues/18742 --- res/css/structures/_ScrollPanel.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss index 82caeae29d..a668594bba 100644 --- a/res/css/structures/_ScrollPanel.scss +++ b/res/css/structures/_ScrollPanel.scss @@ -15,8 +15,6 @@ limitations under the License. */ .mx_ScrollPanel { - contain: strict; - .mx_RoomView_MessageList { position: relative; display: flex; From 54b93f44d0c7250436e4006c45dcd04c8cd2f9a0 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Thu, 26 Aug 2021 14:19:19 +0100 Subject: [PATCH 26/51] v3.29.0-rc.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb2f3432d4..26a88bd0d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.29.0-rc.2", + "version": "3.29.0-rc.3", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From a8b86da0584594606a9f8be673d7cb1aae4c9d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 26 Aug 2021 18:07:37 +0200 Subject: [PATCH 27/51] Set the new layout setting when reading it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/settings/handlers/DeviceSettingsHandler.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/settings/handlers/DeviceSettingsHandler.ts b/src/settings/handlers/DeviceSettingsHandler.ts index e4ad4cb51e..e57862a824 100644 --- a/src/settings/handlers/DeviceSettingsHandler.ts +++ b/src/settings/handlers/DeviceSettingsHandler.ts @@ -71,7 +71,13 @@ export default class DeviceSettingsHandler extends SettingsHandler { // Special case for old useIRCLayout setting if (settingName === "layout") { const settings = this.getSettings() || {}; - if (settings["useIRCLayout"]) return Layout.IRC; + if (settings["useIRCLayout"]) { + // Set the new layout setting and delete the old one so that we + // can delete this block of code after some time + settings["layout"] = Layout.IRC; + delete settings["useIRCLayout"]; + localStorage.setItem("mx_local_settings", JSON.stringify(settings)); + } return settings[settingName]; } From 289b1c5ce008d8407082caf7e74a0d2f4be0b49e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 26 Aug 2021 15:47:49 -0600 Subject: [PATCH 28/51] Always trigger the first amplitude capture from the worklet Fixes https://github.com/vector-im/element-web/issues/18587 See diff --- src/audio/RecorderWorklet.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/audio/RecorderWorklet.ts b/src/audio/RecorderWorklet.ts index 2d1bb0bcd2..73b053db93 100644 --- a/src/audio/RecorderWorklet.ts +++ b/src/audio/RecorderWorklet.ts @@ -45,7 +45,13 @@ class MxVoiceWorklet extends AudioWorkletProcessor { process(inputs, outputs, parameters) { const currentSecond = roundTimeToTargetFreq(currentTime); - if (currentSecond === this.nextAmplitudeSecond) { + // We special case the first ping because there's a fairly good chance that we'll miss the zeroth + // update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first + // time. Edge and Chrome occasionally lag behind too, but for the most part are on time. + // + // When this doesn't work properly we end up producing a waveform of nulls and no live preview + // of the recorded message. + if (currentSecond === this.nextAmplitudeSecond || this.nextAmplitudeSecond === 0) { // We're expecting exactly one mono input source, so just grab the very first frame of // samples for the analysis. const monoChan = inputs[0][0]; From 464d2b47b08393bca08da954f970e1c525607030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 27 Aug 2021 09:16:39 +0200 Subject: [PATCH 29/51] Default to Don't leave any MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/LeaveSpaceDialog.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/dialogs/LeaveSpaceDialog.tsx b/src/components/views/dialogs/LeaveSpaceDialog.tsx index 6e1e798e9d..3a8cd53945 100644 --- a/src/components/views/dialogs/LeaveSpaceDialog.tsx +++ b/src/components/views/dialogs/LeaveSpaceDialog.tsx @@ -80,7 +80,7 @@ const SpaceChildPicker = ({ filterPlaceholder, rooms, selected, onChange }) => { const LeaveRoomsPicker = ({ space, spaceChildren, roomsToLeave, setRoomsToLeave }) => { const selected = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); - const [state, setState] = useState(RoomsToLeave.All); + const [state, setState] = useState(RoomsToLeave.None); useEffect(() => { if (state === RoomsToLeave.All) { @@ -97,11 +97,11 @@ const LeaveRoomsPicker = ({ space, spaceChildren, roomsToLeave, setRoomsToLeave onChange={setState} definitions={[ { - value: RoomsToLeave.All, - label: _t("Leave all rooms and spaces"), - }, { value: RoomsToLeave.None, label: _t("Don't leave any"), + }, { + value: RoomsToLeave.All, + label: _t("Leave all rooms and spaces"), }, { value: RoomsToLeave.Specific, label: _t("Leave specific rooms and spaces"), From 0fae3ed23324e1ccb53fec16121be3b00e8dd405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 27 Aug 2021 09:22:30 +0200 Subject: [PATCH 30/51] i18n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 21859fb1aa..a3d9fd5203 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2411,8 +2411,8 @@ "Clear cache and resync": "Clear cache and resync", "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!", "Updating %(brand)s": "Updating %(brand)s", - "Leave all rooms and spaces": "Leave all rooms and spaces", "Don't leave any": "Don't leave any", + "Leave all rooms and spaces": "Leave all rooms and spaces", "Leave specific rooms and spaces": "Leave specific rooms and spaces", "Search %(spaceName)s": "Search %(spaceName)s", "You won't be able to rejoin unless you are re-invited.": "You won't be able to rejoin unless you are re-invited.", From 816f0f5e9027b91442b844f28a32cdcb0346f9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 27 Aug 2021 09:56:53 +0200 Subject: [PATCH 31/51] Avoid stacked dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/spaces/SpacePublicShare.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/spaces/SpacePublicShare.tsx b/src/components/views/spaces/SpacePublicShare.tsx index 39e5115e55..cb282d8d1f 100644 --- a/src/components/views/spaces/SpacePublicShare.tsx +++ b/src/components/views/spaces/SpacePublicShare.tsx @@ -54,8 +54,8 @@ const SpacePublicShare = ({ space, onFinished }: IProps) => { { space.canInvite(MatrixClientPeg.get()?.getUserId()) ? { - showRoomInviteDialog(space.roomId); if (onFinished) onFinished(); + showRoomInviteDialog(space.roomId); }} >

{ _t("Invite people") }

From bf3c8e56646f0c394327984339e72cd4e016f6a2 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 27 Aug 2021 10:38:01 +0100 Subject: [PATCH 32/51] Fix imports --- src/components/structures/ThreadView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 951c821d5c..a2595debc8 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -23,7 +23,7 @@ import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; import { replaceableComponent } from "../../utils/replaceableComponent"; import ResizeNotifier from '../../utils/ResizeNotifier'; -import EventTile, { TileShape } from '../views/rooms/EventTile'; +import { TileShape } from '../views/rooms/EventTile'; import MessageComposer from '../views/rooms/MessageComposer'; import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks'; import { Layout } from '../../settings/Layout'; From 9684d7263b1018d4e60ce2fa18408b98bba309dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 30 Aug 2021 10:09:57 +0200 Subject: [PATCH 33/51] Filter members on load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MemberList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx index 415d7e942b..df4f2d21fa 100644 --- a/src/components/views/rooms/MemberList.tsx +++ b/src/components/views/rooms/MemberList.tsx @@ -185,8 +185,8 @@ export default class MemberList extends React.Component { return { loading: false, members: members, - filteredJoinedMembers: this.filterMembers(members, 'join'), - filteredInvitedMembers: this.filterMembers(members, 'invite'), + filteredJoinedMembers: this.filterMembers(members, 'join', searchQuery), + filteredInvitedMembers: this.filterMembers(members, 'invite', searchQuery), canInvite: this.canInvite, // ideally we'd size this to the page height, but From ef30db41255b26d882bb1a5560a0c66eead0e9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 30 Aug 2021 10:09:57 +0200 Subject: [PATCH 34/51] Filter members on load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/rooms/MemberList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx index 415d7e942b..df4f2d21fa 100644 --- a/src/components/views/rooms/MemberList.tsx +++ b/src/components/views/rooms/MemberList.tsx @@ -185,8 +185,8 @@ export default class MemberList extends React.Component { return { loading: false, members: members, - filteredJoinedMembers: this.filterMembers(members, 'join'), - filteredInvitedMembers: this.filterMembers(members, 'invite'), + filteredJoinedMembers: this.filterMembers(members, 'join', searchQuery), + filteredInvitedMembers: this.filterMembers(members, 'invite', searchQuery), canInvite: this.canInvite, // ideally we'd size this to the page height, but From 09b40870d4f9b455b91704cca18724c743de5385 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 31 Aug 2021 13:51:17 +0100 Subject: [PATCH 35/51] Upgrade matrix-js-sdk to 12.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 26a88bd0d9..8fe928f162 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "12.4.0-rc.1", + "matrix-js-sdk": "12.4.0", "matrix-widget-api": "^0.1.0-beta.15", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 74883d7059..7fe5e3c143 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5801,10 +5801,10 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -matrix-js-sdk@12.4.0-rc.1: - version "12.4.0-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.0-rc.1.tgz#6eee9f159bcc5dd968346a9ce5c7b7427636f57c" - integrity sha512-6AGIEJvgWlNYyzxPj/V13s9JUg8zsiJ9Hyj6yTpDahufkAUT5yhpFzdPNNRaLlVxHox5HlwJJBdyNQtML727Og== +matrix-js-sdk@12.4.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.0.tgz#ff60306f9a9e39fd1ae6c7e501001f80eb779dd7" + integrity sha512-KamHmvNle4mkdErmNgVsGIL3n8/zgPe60DLVaEA2t4aSNwQLEmRS+oVpIgsO3ZrUivBvn4oc9sBqxP0OIl6kUg== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 99fdd57bd37bc3d703ce83c5bca0d00580cc4087 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 31 Aug 2021 13:52:40 +0100 Subject: [PATCH 36/51] Prepare changelog for v3.29.0 --- CHANGELOG.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fdcdfa96a..42e186220f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,8 @@ -Changes in [3.29.0-rc.2](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0-rc.2) (2021-08-25) -============================================================================================================= +Changes in [3.29.0](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0) (2021-08-31) +=================================================================================================== ## ✨ Features * [Release]Increase general app performance by optimizing layers ([\#6672](https://github.com/matrix-org/matrix-react-sdk/pull/6672)). Fixes vector-im/element-web#18730 and vector-im/element-web#18730. Contributed by [Palid](https://github.com/Palid). - -Changes in [3.29.0-rc.1](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0-rc.1) (2021-08-24) -============================================================================================================= - -## ✨ Features * Add a warning on E2EE rooms if you try to make them public ([\#5698](https://github.com/matrix-org/matrix-react-sdk/pull/5698)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). * Allow pagination of the space hierarchy and use new APIs ([\#6507](https://github.com/matrix-org/matrix-react-sdk/pull/6507)). Fixes vector-im/element-web#18089 and vector-im/element-web#18427. * Improve emoji in composer ([\#6650](https://github.com/matrix-org/matrix-react-sdk/pull/6650)). Fixes vector-im/element-web#18593 and vector-im/element-web#18593. Contributed by [SimonBrandner](https://github.com/SimonBrandner). @@ -23,6 +18,7 @@ Changes in [3.29.0-rc.1](https://github.com/vector-im/element-desktop/releases/t * Accessibility improvements in and around Spaces ([\#6569](https://github.com/matrix-org/matrix-react-sdk/pull/6569)). Fixes vector-im/element-web#18094 and vector-im/element-web#18094. ## 🐛 Bug Fixes + * [Release] Fix commit edit history ([\#6690](https://github.com/matrix-org/matrix-react-sdk/pull/6690)). Fixes vector-im/element-web#18742 and vector-im/element-web#18742. Contributed by [Palid](https://github.com/Palid). * Fix images not rendering when sent from other clients. ([\#6661](https://github.com/matrix-org/matrix-react-sdk/pull/6661)). Fixes vector-im/element-web#18702 and vector-im/element-web#18702. * Fix autocomplete scrollbar and make the autocomplete a little smaller ([\#6655](https://github.com/matrix-org/matrix-react-sdk/pull/6655)). Fixes vector-im/element-web#18682 and vector-im/element-web#18682. Contributed by [SimonBrandner](https://github.com/SimonBrandner). * Fix replies on the bubble layout ([\#6451](https://github.com/matrix-org/matrix-react-sdk/pull/6451)). Fixes vector-im/element-web#18184. Contributed by [SimonBrandner](https://github.com/SimonBrandner). From e4f27f04b9bb160483bace13d0180f43d676601d Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 31 Aug 2021 13:52:40 +0100 Subject: [PATCH 37/51] v3.29.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8fe928f162..08c057b35d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.29.0-rc.3", + "version": "3.29.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 0a09682982c8d7d9da90f2b783ddc0b537bf6dfb Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 31 Aug 2021 13:57:16 +0100 Subject: [PATCH 38/51] Resetting package fields for development --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e784fc1654..2f59ba4504 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "bin": { "reskindex": "scripts/reskindex.js" }, - "main": "./lib/index.js", + "main": "./src/index.js", "matrix_src_main": "./src/index.js", "matrix_lib_main": "./lib/index.js", "matrix_lib_typings": "./lib/index.d.ts", @@ -207,6 +207,5 @@ "coverageReporters": [ "text" ] - }, - "typings": "./lib/index.d.ts" + } } From 0cd00ae64f80184bab0a407d7949b5405675fc93 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 16:05:16 +0100 Subject: [PATCH 39/51] Remove non-functional DuckDuckGo Autocomplete Provider --- src/SlashCommands.tsx | 15 ---- src/autocomplete/Autocompleter.ts | 2 - src/autocomplete/CommandProvider.tsx | 2 +- src/autocomplete/DuckDuckGoProvider.tsx | 115 ------------------------ src/i18n/strings/en_EN.json | 5 -- 5 files changed, 1 insertion(+), 138 deletions(-) delete mode 100644 src/autocomplete/DuckDuckGoProvider.tsx diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index b4deb6d8c4..db05ffc5ce 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -245,21 +245,6 @@ export const Commands = [ }, category: CommandCategories.messages, }), - new Command({ - command: 'ddg', - args: '', - description: _td('Searches DuckDuckGo for results'), - runFn: function() { - // TODO Don't explain this away, actually show a search UI here. - Modal.createTrackedDialog('Slash Commands', '/ddg is not a command', ErrorDialog, { - title: _t('/ddg is not a command'), - description: _t('To use it, just wait for autocomplete results to load and tab through them.'), - }); - return success(); - }, - category: CommandCategories.actions, - hideCompletionAfterSpace: true, - }), new Command({ command: 'upgraderoom', args: '', diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts index acc7846510..4c9e82f290 100644 --- a/src/autocomplete/Autocompleter.ts +++ b/src/autocomplete/Autocompleter.ts @@ -20,7 +20,6 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import CommandProvider from './CommandProvider'; import CommunityProvider from './CommunityProvider'; -import DuckDuckGoProvider from './DuckDuckGoProvider'; import RoomProvider from './RoomProvider'; import UserProvider from './UserProvider'; import EmojiProvider from './EmojiProvider'; @@ -55,7 +54,6 @@ const PROVIDERS = [ EmojiProvider, NotifProvider, CommandProvider, - DuckDuckGoProvider, ]; if (SpaceStore.spacesEnabled) { diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index d0fb9919f6..143b7e4cdc 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -53,7 +53,7 @@ export default class CommandProvider extends AutocompleteProvider { // The input looks like a command with arguments, perform exact match const name = command[1].substr(1); // strip leading `/` if (CommandMap.has(name) && CommandMap.get(name).isEnabled()) { - // some commands, namely `me` and `ddg` don't suit having the usage shown whilst typing their arguments + // some commands, namely `me` don't suit having the usage shown whilst typing their arguments if (CommandMap.get(name).hideCompletionAfterSpace) return []; matches = [CommandMap.get(name)]; } diff --git a/src/autocomplete/DuckDuckGoProvider.tsx b/src/autocomplete/DuckDuckGoProvider.tsx deleted file mode 100644 index c41a91b97f..0000000000 --- a/src/autocomplete/DuckDuckGoProvider.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2016 Aviral Dasgupta -Copyright 2017 Vector Creations Ltd -Copyright 2017, 2018 New Vector Ltd - -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 React from 'react'; -import { _t } from '../languageHandler'; -import AutocompleteProvider from './AutocompleteProvider'; - -import { TextualCompletion } from './Components'; -import { ICompletion, ISelectionRange } from "./Autocompleter"; - -const DDG_REGEX = /\/ddg\s+(.+)$/g; -const REFERRER = 'vector'; - -export default class DuckDuckGoProvider extends AutocompleteProvider { - constructor() { - super(DDG_REGEX); - } - - static getQueryUri(query: string) { - return `https://api.duckduckgo.com/?q=${encodeURIComponent(query)}` - + `&format=json&no_redirect=1&no_html=1&t=${encodeURIComponent(REFERRER)}`; - } - - async getCompletions( - query: string, - selection: ISelectionRange, - force = false, - limit = -1, - ): Promise { - const { command, range } = this.getCurrentCommand(query, selection); - if (!query || !command) { - return []; - } - - const response = await fetch(DuckDuckGoProvider.getQueryUri(command[1]), { - method: 'GET', - }); - const json = await response.json(); - const maxLength = limit > -1 ? limit : json.Results.length; - const results = json.Results.slice(0, maxLength).map((result) => { - return { - completion: result.Text, - component: ( - - ), - range, - }; - }); - if (json.Answer) { - results.unshift({ - completion: json.Answer, - component: ( - - ), - range, - }); - } - if (json.RelatedTopics && json.RelatedTopics.length > 0) { - results.unshift({ - completion: json.RelatedTopics[0].Text, - component: ( - - ), - range, - }); - } - if (json.AbstractText) { - results.unshift({ - completion: json.AbstractText, - component: ( - - ), - range, - }); - } - return results; - } - - getName() { - return '🔍 ' + _t('Results from DuckDuckGo'); - } - - renderCompletions(completions: React.ReactNode[]): React.ReactNode { - return ( -
- { completions } -
- ); - } -} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a3d9fd5203..ede8694545 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -426,9 +426,6 @@ "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message": "Prepends ( ͡° ͜ʖ ͡°) to a plain-text message", "Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown", "Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as markdown", - "Searches DuckDuckGo for results": "Searches DuckDuckGo for results", - "/ddg is not a command": "/ddg is not a command", - "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", "Upgrades a room to a new version": "Upgrades a room to a new version", "You do not have the required permissions to use this command.": "You do not have the required permissions to use this command.", "Changes your display nickname": "Changes your display nickname", @@ -3002,8 +2999,6 @@ "Commands": "Commands", "Command Autocomplete": "Command Autocomplete", "Community Autocomplete": "Community Autocomplete", - "Results from DuckDuckGo": "Results from DuckDuckGo", - "DuckDuckGo Results": "DuckDuckGo Results", "Emoji": "Emoji", "Emoji Autocomplete": "Emoji Autocomplete", "Notify the whole room": "Notify the whole room", From c2a5cfb11e1cac808e208326741f56f0c6bc1cbb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 16:11:22 +0100 Subject: [PATCH 40/51] remove stale unused import --- src/SlashCommands.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index db05ffc5ce..902c82fff8 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -50,7 +50,6 @@ import CallHandler from "./CallHandler"; import { guessAndSetDMRoom } from "./Rooms"; import { upgradeRoom } from './utils/RoomUpgrade'; import UploadConfirmDialog from './components/views/dialogs/UploadConfirmDialog'; -import ErrorDialog from './components/views/dialogs/ErrorDialog'; import DevtoolsDialog from './components/views/dialogs/DevtoolsDialog'; import RoomUpgradeWarningDialog from "./components/views/dialogs/RoomUpgradeWarningDialog"; import InfoDialog from "./components/views/dialogs/InfoDialog"; From b814100b98c342af64c7aef3f153388e813ec0cc Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 16:31:10 +0100 Subject: [PATCH 41/51] Fix membership updates to Spaces not applying in real-time --- src/stores/SpaceStore.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index c08c66714b..c1e86504f4 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -678,12 +678,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient { } this.emit(room.roomId); break; + } + }; - case EventType.RoomMember: - if (room.isSpaceRoom()) { - this.onSpaceMembersChange(ev); - } - break; + // listening for m.room.member events in onRoomState above doesn't work as the Member object isn't updated by then + private onRoomStateMembers = (ev: MatrixEvent) => { + const room = this.matrixClient.getRoom(ev.getRoomId()); + if (room?.isSpaceRoom()) { + this.onSpaceMembersChange(ev); } }; @@ -743,6 +745,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.matrixClient.removeListener("Room.myMembership", this.onRoom); this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData); this.matrixClient.removeListener("RoomState.events", this.onRoomState); + this.matrixClient.removeListener("RoomState.members", this.onRoomStateMembers); this.matrixClient.removeListener("accountData", this.onAccountData); } await this.reset(); @@ -754,6 +757,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.matrixClient.on("Room.myMembership", this.onRoom); this.matrixClient.on("Room.accountData", this.onRoomAccountData); this.matrixClient.on("RoomState.events", this.onRoomState); + this.matrixClient.on("RoomState.members", this.onRoomStateMembers); this.matrixClient.on("accountData", this.onAccountData); this.matrixClient.getCapabilities().then(capabilities => { From bf4ffa965c5cf2bb720c6a8001b30333f3cd829b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 16:56:47 +0100 Subject: [PATCH 42/51] Reload suggested rooms if we see the state change down /sync --- src/stores/SpaceStore.tsx | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index c08c66714b..471e10d9d6 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -190,7 +190,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { * @param contextSwitch whether to switch the user's context, * should not be done when the space switch is done implicitly due to another event like switching room. */ - public async setActiveSpace(space: Room | null, contextSwitch = true) { + public setActiveSpace(space: Room | null, contextSwitch = true) { if (space === this.activeSpace || (space && !space.isSpaceRoom())) return; this._activeSpace = space; @@ -293,11 +293,15 @@ export class SpaceStoreClass extends AsyncStoreWithClient { } if (space) { - const suggestedRooms = await this.fetchSuggestedRooms(space); - if (this._activeSpace === space) { - this._suggestedRooms = suggestedRooms; - this.emit(SUGGESTED_ROOMS, this._suggestedRooms); - } + this.loadSuggestedRooms(space); + } + } + + private async loadSuggestedRooms(space) { + const suggestedRooms = await this.fetchSuggestedRooms(space); + if (this._activeSpace === space) { + this._suggestedRooms = suggestedRooms; + this.emit(SUGGESTED_ROOMS, this._suggestedRooms); } } @@ -666,6 +670,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient { this.onSpaceUpdate(); this.emit(room.roomId); } + + if (room === this.activeSpace && // current space + this.matrixClient.getRoom(ev.getStateKey())?.getMyMembership() !== "join" && // target not joined + ev.getPrevContent().suggested !== ev.getContent().suggested // suggested flag changed + ) { + this.loadSuggestedRooms(room); + } + break; case EventType.SpaceParent: From bbd420096b8807cdf2119c908f51b3f27dea10df Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 17:03:43 +0100 Subject: [PATCH 43/51] don't bother awaiting SpaceStore::setActiveSpace as it is no longer async --- src/stores/SpaceStore.tsx | 4 +- test/stores/SpaceStore-test.ts | 58 +++++++++++----------- test/stores/room-list/SpaceWatcher-test.ts | 22 ++++---- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index 471e10d9d6..5c921d6ad7 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -145,9 +145,9 @@ export class SpaceStoreClass extends AsyncStoreWithClient { return this._allRoomsInHome; } - public async setActiveRoomInSpace(space: Room | null): Promise { + public setActiveRoomInSpace(space: Room | null): void { if (space && !space.isSpaceRoom()) return; - if (space !== this.activeSpace) await this.setActiveSpace(space); + if (space !== this.activeSpace) this.setActiveSpace(space); if (space) { const roomId = this.getNotificationState(space.roomId).getFirstRoomWithNotifications(); diff --git a/test/stores/SpaceStore-test.ts b/test/stores/SpaceStore-test.ts index 2e823aa72b..7cfd97b234 100644 --- a/test/stores/SpaceStore-test.ts +++ b/test/stores/SpaceStore-test.ts @@ -562,7 +562,7 @@ describe("SpaceStore", () => { ]); mkSpace(space3).getMyMembership.mockReturnValue("invite"); await run(); - await store.setActiveSpace(null); + store.setActiveSpace(null); expect(store.activeSpace).toBe(null); }); afterEach(() => { @@ -570,31 +570,31 @@ describe("SpaceStore", () => { }); it("switch to home space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); fn.mockClear(); - await store.setActiveSpace(null); + store.setActiveSpace(null); expect(fn).toHaveBeenCalledWith(UPDATE_SELECTED_SPACE, null); expect(store.activeSpace).toBe(null); }); it("switch to invited space", async () => { const space = client.getRoom(space3); - await store.setActiveSpace(space); + store.setActiveSpace(space); expect(fn).toHaveBeenCalledWith(UPDATE_SELECTED_SPACE, space); expect(store.activeSpace).toBe(space); }); it("switch to top level space", async () => { const space = client.getRoom(space1); - await store.setActiveSpace(space); + store.setActiveSpace(space); expect(fn).toHaveBeenCalledWith(UPDATE_SELECTED_SPACE, space); expect(store.activeSpace).toBe(space); }); it("switch to subspace", async () => { const space = client.getRoom(space2); - await store.setActiveSpace(space); + store.setActiveSpace(space); expect(fn).toHaveBeenCalledWith(UPDATE_SELECTED_SPACE, space); expect(store.activeSpace).toBe(space); }); @@ -602,7 +602,7 @@ describe("SpaceStore", () => { it("switch to unknown space is a nop", async () => { expect(store.activeSpace).toBe(null); const space = client.getRoom(room1); // not a space - await store.setActiveSpace(space); + store.setActiveSpace(space); expect(fn).not.toHaveBeenCalledWith(UPDATE_SELECTED_SPACE, space); expect(store.activeSpace).toBe(null); }); @@ -635,59 +635,59 @@ describe("SpaceStore", () => { }; it("last viewed room in target space is the current viewed and in both spaces", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room2); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); viewRoom(room2); - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); expect(getCurrentRoom()).toBe(room2); }); it("last viewed room in target space is in the current space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room2); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); expect(getCurrentRoom()).toBe(space2); - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); expect(getCurrentRoom()).toBe(room2); }); it("last viewed room in target space is not in the current space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room1); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); viewRoom(room2); - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); expect(getCurrentRoom()).toBe(room1); }); it("last viewed room is target space is not known", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room1); localStorage.setItem(`mx_space_context_${space2}`, orphan2); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); expect(getCurrentRoom()).toBe(space2); }); it("last viewed room is target space is no longer in that space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room1); localStorage.setItem(`mx_space_context_${space2}`, room1); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); expect(getCurrentRoom()).toBe(space2); // Space home instead of room1 }); it("no last viewed room in target space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room1); - await store.setActiveSpace(client.getRoom(space2)); + store.setActiveSpace(client.getRoom(space2)); expect(getCurrentRoom()).toBe(space2); }); it("no last viewed room in home space", async () => { - await store.setActiveSpace(client.getRoom(space1)); + store.setActiveSpace(client.getRoom(space1)); viewRoom(room1); - await store.setActiveSpace(null); + store.setActiveSpace(null); expect(getCurrentRoom()).toBeNull(); // Home }); }); @@ -715,28 +715,28 @@ describe("SpaceStore", () => { it("no switch required, room is in current space", async () => { viewRoom(room1); - await store.setActiveSpace(client.getRoom(space1), false); + store.setActiveSpace(client.getRoom(space1), false); viewRoom(room2); expect(store.activeSpace).toBe(client.getRoom(space1)); }); it("switch to canonical parent space for room", async () => { viewRoom(room1); - await store.setActiveSpace(client.getRoom(space2), false); + store.setActiveSpace(client.getRoom(space2), false); viewRoom(room2); expect(store.activeSpace).toBe(client.getRoom(space2)); }); it("switch to first containing space for room", async () => { viewRoom(room2); - await store.setActiveSpace(client.getRoom(space2), false); + store.setActiveSpace(client.getRoom(space2), false); viewRoom(room3); expect(store.activeSpace).toBe(client.getRoom(space1)); }); it("switch to home for orphaned room", async () => { viewRoom(room1); - await store.setActiveSpace(client.getRoom(space1), false); + store.setActiveSpace(client.getRoom(space1), false); viewRoom(orphan1); expect(store.activeSpace).toBeNull(); }); @@ -744,7 +744,7 @@ describe("SpaceStore", () => { it("when switching rooms in the all rooms home space don't switch to related space", async () => { await setShowAllRooms(true); viewRoom(room2); - await store.setActiveSpace(null, false); + store.setActiveSpace(null, false); viewRoom(room1); expect(store.activeSpace).toBeNull(); }); diff --git a/test/stores/room-list/SpaceWatcher-test.ts b/test/stores/room-list/SpaceWatcher-test.ts index 85f79c75b6..474c279fdd 100644 --- a/test/stores/room-list/SpaceWatcher-test.ts +++ b/test/stores/room-list/SpaceWatcher-test.ts @@ -57,7 +57,7 @@ describe("SpaceWatcher", () => { beforeEach(async () => { filter = null; store.removeAllListeners(); - await store.setActiveSpace(null); + store.setActiveSpace(null); client.getVisibleRooms.mockReturnValue(rooms = []); space1 = mkSpace(space1Id); @@ -95,7 +95,7 @@ describe("SpaceWatcher", () => { await setShowAllRooms(true); new SpaceWatcher(mockRoomListStore); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space1); @@ -114,7 +114,7 @@ describe("SpaceWatcher", () => { await setShowAllRooms(false); new SpaceWatcher(mockRoomListStore); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space1); @@ -124,22 +124,22 @@ describe("SpaceWatcher", () => { await setShowAllRooms(true); new SpaceWatcher(mockRoomListStore); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space1); - await SpaceStore.instance.setActiveSpace(null); + SpaceStore.instance.setActiveSpace(null); expect(filter).toBeNull(); }); it("updates filter correctly for space -> home transition", async () => { await setShowAllRooms(false); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); new SpaceWatcher(mockRoomListStore); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space1); - await SpaceStore.instance.setActiveSpace(null); + SpaceStore.instance.setActiveSpace(null); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(null); @@ -147,12 +147,12 @@ describe("SpaceWatcher", () => { it("updates filter correctly for space -> space transition", async () => { await setShowAllRooms(false); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); new SpaceWatcher(mockRoomListStore); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space1); - await SpaceStore.instance.setActiveSpace(space2); + SpaceStore.instance.setActiveSpace(space2); expect(filter).toBeInstanceOf(SpaceFilterCondition); expect(filter["space"]).toBe(space2); @@ -160,7 +160,7 @@ describe("SpaceWatcher", () => { it("doesn't change filter when changing showAllRooms mode to true", async () => { await setShowAllRooms(false); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); new SpaceWatcher(mockRoomListStore); expect(filter).toBeInstanceOf(SpaceFilterCondition); @@ -173,7 +173,7 @@ describe("SpaceWatcher", () => { it("doesn't change filter when changing showAllRooms mode to false", async () => { await setShowAllRooms(true); - await SpaceStore.instance.setActiveSpace(space1); + SpaceStore.instance.setActiveSpace(space1); new SpaceWatcher(mockRoomListStore); expect(filter).toBeInstanceOf(SpaceFilterCondition); From 4ce79148cf8708708972ec6ee9830038b99d9d47 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 17:14:50 +0100 Subject: [PATCH 44/51] Clear currentRoomId when viewing home page, fixing document title --- src/components/structures/MatrixChat.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 902d2a0921..531dc9fbe9 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -1016,6 +1016,7 @@ export default class MatrixChat extends React.PureComponent { this.setStateForNewView({ view: Views.LOGGED_IN, justRegistered, + currentRoomId: null, }); this.setPage(PageTypes.HomePage); this.notifyNewScreen('home'); From e089c34db72f129e04281dcae132cf62bbbc3baa Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 17:36:10 +0100 Subject: [PATCH 45/51] Fix EmojiPicker filtering to lower case emojibase data strings --- src/components/views/emojipicker/EmojiPicker.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/views/emojipicker/EmojiPicker.tsx b/src/components/views/emojipicker/EmojiPicker.tsx index 0884db7101..9cc995a140 100644 --- a/src/components/views/emojipicker/EmojiPicker.tsx +++ b/src/components/views/emojipicker/EmojiPicker.tsx @@ -173,16 +173,16 @@ class EmojiPicker extends React.Component { }; private onChangeFilter = (filter: string) => { - filter = filter.toLowerCase(); // filter is case insensitive stored lower-case + const lcFilter = filter.toLowerCase().trim(); // filter is case insensitive for (const cat of this.categories) { let emojis; // If the new filter string includes the old filter string, we don't have to re-filter the whole dataset. - if (filter.includes(this.state.filter)) { + if (lcFilter.includes(this.state.filter)) { emojis = this.memoizedDataByCategory[cat.id]; } else { emojis = cat.id === "recent" ? this.recentlyUsed : DATA_BY_CATEGORY[cat.id]; } - emojis = emojis.filter(emoji => this.emojiMatchesFilter(emoji, filter)); + emojis = emojis.filter(emoji => this.emojiMatchesFilter(emoji, lcFilter)); this.memoizedDataByCategory[cat.id] = emojis; cat.enabled = emojis.length > 0; // The setState below doesn't re-render the header and we already have the refs for updateVisibility, so... @@ -194,9 +194,12 @@ class EmojiPicker extends React.Component { setTimeout(this.updateVisibility, 0); }; - private emojiMatchesFilter = (emoji: IEmoji, filter: string): boolean => - [emoji.annotation, ...emoji.shortcodes, emoji.emoticon, ...emoji.unicode.split(ZERO_WIDTH_JOINER)] - .some(x => x?.includes(filter)); + private emojiMatchesFilter = (emoji: IEmoji, filter: string): boolean => { + return emoji.annotation.toLowerCase().includes(filter) || + emoji.emoticon?.toLowerCase().includes(filter) || + emoji.shortcodes.some(x => x.toLowerCase().includes(filter)) || + emoji.unicode.split(ZERO_WIDTH_JOINER).includes(filter); + }; private onEnterFilter = () => { const btn = this.bodyRef.current.querySelector(".mx_EmojiPicker_item"); From 18b7a649104656799554cd50a472dd78f9d6b2ad Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 31 Aug 2021 13:17:49 -0600 Subject: [PATCH 46/51] Remove arbitrary limits from send/receive events for widgets Fixes https://github.com/vector-im/element-web/issues/17994 As per MSC change: https://github.com/matrix-org/matrix-doc/pull/2762/commits/aeadae81e2d68f76523eb61ff0ebbbd5c3202deb --- src/stores/widgets/StopGapWidgetDriver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index d473ecf3b1..c0f627b9c0 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -163,7 +163,7 @@ export class StopGapWidgetDriver extends WidgetDriver { } public async readRoomEvents(eventType: string, msgtype: string | undefined, limit: number): Promise { - limit = limit > 0 ? Math.min(limit, 25) : 25; // arbitrary choice + limit = limit > 0 ? Math.min(limit, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary const client = MatrixClientPeg.get(); const roomId = ActiveRoomObserver.activeRoomId; @@ -185,7 +185,7 @@ export class StopGapWidgetDriver extends WidgetDriver { } public async readStateEvents(eventType: string, stateKey: string | undefined, limit: number): Promise { - limit = limit > 0 ? Math.min(limit, 100) : 100; // arbitrary choice + limit = limit > 0 ? Math.min(limit, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary const client = MatrixClientPeg.get(); const roomId = ActiveRoomObserver.activeRoomId; From 855c3819c1a24f83901398b21e676b364940d74b Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 1 Sep 2021 09:52:32 +0100 Subject: [PATCH 47/51] Reset matrix-js-sdk back to develop branch --- package.json | 2 +- yarn.lock | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2f59ba4504..5c62100587 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "12.4.0", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-widget-api": "^0.1.0-beta.15", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 6dd1d269c3..4e58909563 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5791,10 +5791,9 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -matrix-js-sdk@12.4.0: +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": version "12.4.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.0.tgz#ff60306f9a9e39fd1ae6c7e501001f80eb779dd7" - integrity sha512-KamHmvNle4mkdErmNgVsGIL3n8/zgPe60DLVaEA2t4aSNwQLEmRS+oVpIgsO3ZrUivBvn4oc9sBqxP0OIl6kUg== + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/2783d162b77d6629c574f35e88bea9ae29765c34" dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 030fa17a6679d44bb0c6ea086ee20e6612e70903 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 1 Sep 2021 12:47:43 +0100 Subject: [PATCH 48/51] When creating private spaces, make the initial rooms restricted if supported --- src/components/structures/SpaceRoomView.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 767e0999c3..1ce5a53c3e 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -16,7 +16,7 @@ limitations under the License. import React, { RefObject, useContext, useRef, useState } from "react"; import { EventType } from "matrix-js-sdk/src/@types/event"; -import { Preset, JoinRule } from "matrix-js-sdk/src/@types/partials"; +import { JoinRule, Preset } from "matrix-js-sdk/src/@types/partials"; import { Room } from "matrix-js-sdk/src/models/room"; import { EventSubscription } from "fbemitter"; @@ -505,11 +505,12 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { setError(""); setBusy(true); try { + const isPublic = space.getJoinRule() === JoinRule.Public; const filteredRoomNames = roomNames.map(name => name.trim()).filter(Boolean); await Promise.all(filteredRoomNames.map(name => { return createRoom({ createOpts: { - preset: space.getJoinRule() === "public" ? Preset.PublicChat : Preset.PrivateChat, + preset: isPublic ? Preset.PublicChat : Preset.PrivateChat, name, }, spinner: false, @@ -517,6 +518,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { andView: false, inlineErrors: true, parentSpace: space, + joinRule: !isPublic ? JoinRule.Restricted : undefined, }); })); onFinished(filteredRoomNames.length > 0); From 4328ee18f523404016ee9a89530a9d9c61954d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 1 Sep 2021 15:37:59 +0200 Subject: [PATCH 49/51] Show autocomplete sections vertically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_Autocomplete.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/views/rooms/_Autocomplete.scss b/res/css/views/rooms/_Autocomplete.scss index bebe0b47c9..8d2b338d9d 100644 --- a/res/css/views/rooms/_Autocomplete.scss +++ b/res/css/views/rooms/_Autocomplete.scss @@ -10,6 +10,7 @@ max-height: 35vh; overflow: clip; display: flex; + flex-direction: column; box-shadow: 0px -16px 32px $composer-shadow-color; } From 387239864d0685cb18495db682247b594d213498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 1 Sep 2021 16:50:13 +0200 Subject: [PATCH 50/51] Add fallbackUserId MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/elements/ImageView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index 87f3dab718..7a1efb7a62 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -419,6 +419,7 @@ export default class ImageView extends React.Component { const avatar = ( Date: Wed, 1 Sep 2021 16:12:39 +0100 Subject: [PATCH 51/51] When creating subspaces properly set restricted join rule --- src/components/views/dialogs/CreateSubspaceDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/CreateSubspaceDialog.tsx b/src/components/views/dialogs/CreateSubspaceDialog.tsx index 03927c7d62..d80245918f 100644 --- a/src/components/views/dialogs/CreateSubspaceDialog.tsx +++ b/src/components/views/dialogs/CreateSubspaceDialog.tsx @@ -79,7 +79,7 @@ const CreateSubspaceDialog: React.FC = ({ space, onAddExistingSpaceClick } try { - await createSpace(name, joinRule === JoinRule.Public, alias, topic, avatar, {}, { parentSpace }); + await createSpace(name, joinRule === JoinRule.Public, alias, topic, avatar, {}, { parentSpace, joinRule }); onFinished(true); } catch (e) {