From 61a260cd405eacac4c52777bd048657a9fda3702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 18 Apr 2021 15:40:56 +0200 Subject: [PATCH 001/134] Format mxid --- res/css/views/messages/_SenderProfile.scss | 12 ++++++ .../views/messages/SenderProfile.js | 43 ++++++++++++++----- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index 655cb39489..e3a38bad6d 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -15,6 +15,18 @@ limitations under the License. */ .mx_SenderProfile_name { + display: flex; + align-items: center; + gap: 5px; +} + +.mx_SenderProfile_displayName { font-weight: 600; } +.mx_SenderProfile_mxid { + font-weight: 600; + font-family: monospace; + font-size: 1rem; + color: gray; +} diff --git a/src/components/views/messages/SenderProfile.js b/src/components/views/messages/SenderProfile.js index bd10526799..264d4ed3de 100644 --- a/src/components/views/messages/SenderProfile.js +++ b/src/components/views/messages/SenderProfile.js @@ -89,7 +89,21 @@ export default class SenderProfile extends React.Component { render() { const {mxEvent} = this.props; const colorClass = getUserNameColorClass(mxEvent.getSender()); - const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + + let disambiguate; + let displayName; + let mxid; + + const sender = mxEvent.sender; + if (sender) { + disambiguate = sender.disambiguate; + displayName = sender.rawDisplayName; + mxid = sender.userId; + } else { + disambiguate = false; + displayName = mxEvent.getSender(); + mxid = mxEvent.getSender(); + } const {msgtype} = mxEvent.getContent(); if (msgtype === 'm.emote') { @@ -108,20 +122,29 @@ export default class SenderProfile extends React.Component { />; } - const nameElem = name || ''; - - // Name + flair - const nameFlair = - - { nameElem } + const displayNameElement = ( + + { displayName || '' } - { flair } - ; + ); + + let mxidElement; + if (disambiguate) { + mxidElement = ( + + { `[${mxid || ""}]` } + + ); + } return (
- { nameFlair } +
+ { displayNameElement } + { mxidElement } + { flair } +
); From 39eb487f49718453ac152d97119f764527a67821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 20 Apr 2021 11:09:03 +0200 Subject: [PATCH 002/134] TS conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../{SenderProfile.js => SenderProfile.tsx} | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) rename src/components/views/messages/{SenderProfile.js => SenderProfile.tsx} (82%) diff --git a/src/components/views/messages/SenderProfile.js b/src/components/views/messages/SenderProfile.tsx similarity index 82% rename from src/components/views/messages/SenderProfile.js rename to src/components/views/messages/SenderProfile.tsx index 264d4ed3de..fa635eaedb 100644 --- a/src/components/views/messages/SenderProfile.js +++ b/src/components/views/messages/SenderProfile.tsx @@ -15,26 +15,37 @@ */ import React from 'react'; -import PropTypes from 'prop-types'; import Flair from '../elements/Flair.js'; import FlairStore from '../../../stores/FlairStore'; import {getUserNameColorClass} from '../../../utils/FormattingUtils'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +import MatrixEvent from "matrix-js-sdk/src/models/event"; + +interface IProps { + mxEvent: MatrixEvent; + onClick(): void; + enableFlair: boolean; +} + +interface IState { + userGroups; + relatedGroups; +} @replaceableComponent("views.messages.SenderProfile") -export default class SenderProfile extends React.Component { - static propTypes = { - mxEvent: PropTypes.object.isRequired, // event whose sender we're showing - onClick: PropTypes.func, - }; - +export default class SenderProfile extends React.Component { static contextType = MatrixClientContext; + unmounted: boolean; - state = { - userGroups: null, - relatedGroups: [], - }; + constructor(props: IProps) { + super(props) + + this.state = { + userGroups: null, + relatedGroups: [], + }; + } componentDidMount() { this.unmounted = false; @@ -89,28 +100,17 @@ export default class SenderProfile extends React.Component { render() { const {mxEvent} = this.props; const colorClass = getUserNameColorClass(mxEvent.getSender()); - - let disambiguate; - let displayName; - let mxid; - - const sender = mxEvent.sender; - if (sender) { - disambiguate = sender.disambiguate; - displayName = sender.rawDisplayName; - mxid = sender.userId; - } else { - disambiguate = false; - displayName = mxEvent.getSender(); - mxid = mxEvent.getSender(); - } const {msgtype} = mxEvent.getContent(); + const disambiguate = mxEvent.sender?.disambiguate; + const displayName = mxEvent.sender?.rawDisplayName || mxEvent.getSender() || ""; + const mxid = mxEvent.sender?.userId || mxEvent.getSender() || ""; + if (msgtype === 'm.emote') { return ; // emote message must include the name so don't duplicate it } - let flair =
; + let flair; if (this.props.enableFlair) { const displayedGroups = this._getDisplayedGroups( this.state.userGroups, this.state.relatedGroups, @@ -124,7 +124,7 @@ export default class SenderProfile extends React.Component { const displayNameElement = ( - { displayName || '' } + { displayName } ); @@ -132,7 +132,7 @@ export default class SenderProfile extends React.Component { if (disambiguate) { mxidElement = ( - { `[${mxid || ""}]` } + { `[${mxid}]` } ); } From faca498523460e59215bbe819521fcda01069729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 20 Apr 2021 11:12:16 +0200 Subject: [PATCH 003/134] Don't use gap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/messages/_SenderProfile.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index e3a38bad6d..d7763cda08 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -17,7 +17,6 @@ limitations under the License. .mx_SenderProfile_name { display: flex; align-items: center; - gap: 5px; } .mx_SenderProfile_displayName { @@ -29,4 +28,5 @@ limitations under the License. font-family: monospace; font-size: 1rem; color: gray; + margin-left: 5px; } From 4e1409dc2c7258816e51efb204a09ef608055117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 20 Apr 2021 11:40:50 +0200 Subject: [PATCH 004/134] Add private Co-authored-by: Michael Telatynski <7t3chguy@googlemail.com> --- src/components/views/messages/SenderProfile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index fa635eaedb..f0dd77f746 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -36,7 +36,7 @@ interface IState { @replaceableComponent("views.messages.SenderProfile") export default class SenderProfile extends React.Component { static contextType = MatrixClientContext; - unmounted: boolean; + private unmounted: boolean; constructor(props: IProps) { super(props) From ffcd79f4a3215c1153e50ec599a8cd18b2d1e5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 21 Apr 2021 17:34:03 +0200 Subject: [PATCH 005/134] Remove brackets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/messages/SenderProfile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index f0dd77f746..b2bfe00168 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -132,7 +132,7 @@ export default class SenderProfile extends React.Component { if (disambiguate) { mxidElement = ( - { `[${mxid}]` } + { mxid } ); } From eee1294374c568ee3e9c956b5fb3acaf537918a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 21 Apr 2021 17:37:25 +0200 Subject: [PATCH 006/134] Make both have the same baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/messages/_SenderProfile.scss | 5 ----- src/components/views/messages/SenderProfile.tsx | 8 +++----- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index d7763cda08..14e8f6583f 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -14,11 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_SenderProfile_name { - display: flex; - align-items: center; -} - .mx_SenderProfile_displayName { font-weight: 600; } diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index b2bfe00168..70040e4ef7 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -140,11 +140,9 @@ export default class SenderProfile extends React.Component { return (
-
- { displayNameElement } - { mxidElement } - { flair } -
+ { displayNameElement } + { mxidElement } + { flair }
); From 9658a760c8bd96dd91498d064e7898c5a70fe19f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 21 Apr 2021 17:41:21 +0200 Subject: [PATCH 007/134] Use timestamp color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/messages/_SenderProfile.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index 14e8f6583f..378d9e6f1a 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -22,6 +22,6 @@ limitations under the License. font-weight: 600; font-family: monospace; font-size: 1rem; - color: gray; + color: $event-timestamp-color; margin-left: 5px; } From 55365e632b524015f3dca528e18d2c593861bf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 22 Apr 2021 07:52:39 +0200 Subject: [PATCH 008/134] Use the correct selector in E2EE tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- test/end-to-end-tests/src/usecases/timeline.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/end-to-end-tests/src/usecases/timeline.js b/test/end-to-end-tests/src/usecases/timeline.js index 3889dce108..01dc618571 100644 --- a/test/end-to-end-tests/src/usecases/timeline.js +++ b/test/end-to-end-tests/src/usecases/timeline.js @@ -122,7 +122,7 @@ function getAllEventTiles(session) { } async function getMessageFromEventTile(eventTile) { - const senderElement = await eventTile.$(".mx_SenderProfile_name"); + const senderElement = await eventTile.$(".mx_SenderProfile_displayName"); const className = await (await eventTile.getProperty("className")).jsonValue(); const classNames = className.split(" "); const bodyElement = await eventTile.$(".mx_EventTile_body"); From fa534e4755df403ee23f82ecd420b94c8c184d79 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 27 Apr 2021 14:47:56 +0100 Subject: [PATCH 009/134] Add room intro warning when e2ee is not enabled --- res/css/views/rooms/_NewRoomIntro.scss | 20 ++++++++++++++++++++ src/components/views/rooms/NewRoomIntro.tsx | 20 ++++++++++++++++++++ src/i18n/strings/en_EN.json | 1 + 3 files changed, 41 insertions(+) diff --git a/res/css/views/rooms/_NewRoomIntro.scss b/res/css/views/rooms/_NewRoomIntro.scss index 9c2a428cb3..e9d80c48c9 100644 --- a/res/css/views/rooms/_NewRoomIntro.scss +++ b/res/css/views/rooms/_NewRoomIntro.scss @@ -69,4 +69,24 @@ limitations under the License. font-size: $font-15px; color: $secondary-fg-color; } + + .mx_NewRoomIntro_message:not(:first-child) { + padding-top: 1em; + margin-top: 1em; + border-top: 1px solid currentColor; + } + + .mx_NewRoomIntro_message[role=alert]::before { + --size: 25px; + content: "!"; + float: left; + border-radius: 50%; + width: var(--size); + height: var(--size); + line-height: var(--size); + text-align: center; + background: $button-danger-bg-color; + color: #fff; + margin-right: calc(var(--size) / 2); + } } diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 3f6054304d..9b003ade89 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -31,6 +31,14 @@ import dis from "../../../dispatcher/dispatcher"; import SpaceStore from "../../../stores/SpaceStore"; import {showSpaceInvite} from "../../../utils/space"; +import { privateShouldBeEncrypted } from "../../../createRoom"; + +function hasExpectedEncryptionSettings(room): boolean { + const isEncrypted: boolean = room._client.isRoomEncrypted(room.roomId); + const isPublic: boolean = room.getJoinRule() === "public"; + return isPublic || !privateShouldBeEncrypted() || isEncrypted; +} + const NewRoomIntro = () => { const cli = useContext(MatrixClientContext); const {room, roomId} = useContext(RoomContext); @@ -168,6 +176,18 @@ const NewRoomIntro = () => { return
{ body } + + { !hasExpectedEncryptionSettings(room) &&

+ {_t("Messages in this room are not end-to-end encrypted. " + + "Messages sent in an unencrypted room can be seen by the server and third parties. " + + "Learn more about encryption.", {}, + { + a: sub => {sub}, + })} + +

}
; }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c6f7a8d25e..7ea9227938 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1490,6 +1490,7 @@ "Invite to just this room": "Invite to just this room", "Add a photo, so people can easily spot your room.": "Add a photo, so people can easily spot your room.", "This is the start of .": "This is the start of .", + "Messages in this room are not end-to-end encrypted. Messages sent in an unencrypted room can be seen by the server and third parties. Learn more about encryption.": "Messages in this room are not end-to-end encrypted. Messages sent in an unencrypted room can be seen by the server and third parties. Learn more about encryption.", "No pinned messages.": "No pinned messages.", "Loading...": "Loading...", "Pinned Messages": "Pinned Messages", From b9b237fc9a531eb3d42d1203198bcb03848c86c9 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 8 May 2021 19:48:34 -0400 Subject: [PATCH 010/134] Replace forwarding UI with dialog Replaces the old forwarding UI with a dialog based on designs from https://github.com/vector-im/element-web/issues/14690. Signed-off-by: Robin Townsend --- res/css/_components.scss | 1 + res/css/views/dialogs/_ForwardDialog.scss | 115 ++++++++++ .../views/context_menus/MessageContextMenu.js | 8 +- .../views/dialogs/ForwardDialog.tsx | 213 ++++++++++++++++++ src/i18n/strings/en_EN.json | 5 + 5 files changed, 338 insertions(+), 4 deletions(-) create mode 100644 res/css/views/dialogs/_ForwardDialog.scss create mode 100644 src/components/views/dialogs/ForwardDialog.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index ec9592f3a1..ebb025d880 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -74,6 +74,7 @@ @import "./views/dialogs/_DevtoolsDialog.scss"; @import "./views/dialogs/_EditCommunityPrototypeDialog.scss"; @import "./views/dialogs/_FeedbackDialog.scss"; +@import "./views/dialogs/_ForwardDialog.scss"; @import "./views/dialogs/_GroupAddressPicker.scss"; @import "./views/dialogs/_HostSignupDialog.scss"; @import "./views/dialogs/_IncomingSasDialog.scss"; diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss new file mode 100644 index 0000000000..a3aa08d04f --- /dev/null +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -0,0 +1,115 @@ +/* +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. +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. +*/ + +.mx_ForwardDialog { + width: 520px; + color: $primary-fg-color; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + min-height: 0; + height: 80vh; + + .mx_ForwardDialog_preview { + max-height: 30%; + flex-shrink: 0; + overflow: scroll; + + div { + pointer-events: none; + } + + .mx_EventTile_msgOption { + display: none; + } + } + + .mx_ForwardList { + display: contents; + + .mx_SearchBox { + // To match the space around the title + margin: 0 0 15px 0; + flex-grow: 0; + } + + .mx_ForwardList_content { + flex-grow: 1; + } + + .mx_ForwardList_noResults { + display: block; + margin-top: 24px; + } + + .mx_ForwardList_section { + &:not(:first-child) { + margin-top: 24px; + } + + > h3 { + margin: 0; + color: $secondary-fg-color; + font-size: $font-12px; + font-weight: $font-semi-bold; + line-height: $font-15px; + } + + .mx_ForwardList_entry { + display: flex; + margin-top: 12px; + + .mx_BaseAvatar { + margin-right: 12px; + } + + .mx_ForwardList_entry_name { + font-size: $font-15px; + line-height: 30px; + flex-grow: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin-right: 12px; + } + + .mx_AccessibleButton { + &.mx_ForwardList_sending, &.mx_ForwardList_sent { + &::before { + content: ''; + display: inline-block; + background-color: $button-primary-bg-color; + mask-position: center; + mask-repeat: no-repeat; + mask-size: 14px; + width: 14px; + height: 14px; + margin-right: 5px; + } + } + + &.mx_ForwardList_sending::before { + mask-image: url('$(res)/img/element-icons/circle-sending.svg'); + } + + &.mx_ForwardList_sent::before { + mask-image: url('$(res)/img/element-icons/circle-sent.svg'); + } + } + } + } + } +} diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 35efd12c9c..e069bba975 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -154,11 +154,11 @@ export default class MessageContextMenu extends React.Component { }; onForwardClick = () => { - if (this.props.onCloseDialog) this.props.onCloseDialog(); - dis.dispatch({ - action: 'forward_event', + const ForwardDialog = sdk.getComponent("dialogs.ForwardDialog"); + Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { + cli: MatrixClientPeg.get(), event: this.props.mxEvent, - }); + }, 'mx_Dialog_forwardmessage'); this.closeMenu(); }; diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx new file mode 100644 index 0000000000..ce38a783b3 --- /dev/null +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -0,0 +1,213 @@ +/* +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. +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, {useMemo, useState, useEffect} from "react"; +import classnames from "classnames"; +import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import {Room} from "matrix-js-sdk/src/models/room"; +import {MatrixClient} from "matrix-js-sdk/src/client"; + +import {_t} from "../../../languageHandler"; +import SettingsStore from "../../../settings/SettingsStore"; +import {UIFeature} from "../../../settings/UIFeature"; +import {Layout} from "../../../settings/Layout"; +import {IDialogProps} from "./IDialogProps"; +import BaseDialog from "./BaseDialog"; +import {avatarUrlForUser} from "../../../Avatar"; +import EventTile from "../rooms/EventTile"; +import SearchBox from "../../structures/SearchBox"; +import RoomAvatar from "../avatars/RoomAvatar"; +import AccessibleButton from "../elements/AccessibleButton"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import DMRoomMap from "../../../utils/DMRoomMap"; +import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; + +const AVATAR_SIZE = 30; + +interface IProps extends IDialogProps { + cli: MatrixClient; + event: MatrixEvent; +} + +interface IEntryProps { + room: Room; + // Callback to forward the message to this room + send(): Promise; +} + +enum SendState { + CanSend, + Sending, + Sent, + Failed, +} + +const Entry: React.FC = ({ room, send }) => { + const [sendState, setSendState] = useState(SendState.CanSend); + + let label; + let className; + if (sendState === SendState.CanSend) { + label = _t("Send"); + className = "mx_ForwardList_canSend"; + } else if (sendState === SendState.Sending) { + label = _t("Sending…"); + className = "mx_ForwardList_sending"; + } else if (sendState === SendState.Sent) { + label = _t("Sent"); + className = "mx_ForwardList_sent"; + } else { + label = _t("Failed to send"); + className = "mx_ForwardList_sendFailed"; + } + + return
+ + { room.name } + { + setSendState(SendState.Sending); + try { + await send(); + setSendState(SendState.Sent); + } catch (e) { + setSendState(SendState.Failed); + } + }} + disabled={sendState !== SendState.CanSend} + > + { label } + +
; +}; + +const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { + const userId = cli.getUserId(); + const [profileInfo, setProfileInfo] = useState({}); + useEffect(() => { + cli.getProfileInfo(userId).then(info => setProfileInfo(info)); + }, [cli, userId]); + + // For the message preview we fake the sender as ourselves + const mockEvent = new MatrixEvent({ + type: "m.room.message", + sender: userId, + content: event.getContent(), + unsigned: { + age: 97, + }, + event_id: "$9999999999999999999999999999999999999999999", + room_id: "!999999999999999999:example.org", + }); + mockEvent.sender = { + name: profileInfo.displayname || userId, + userId: userId, + getAvatarUrl: (..._) => { + return avatarUrlForUser( + { avatarUrl: profileInfo.avatar_url }, + AVATAR_SIZE, AVATAR_SIZE, "crop", + ); + }, + getMxcAvatarUrl: () => profileInfo.avatar_url, + }; + + const visibleRooms = useMemo(() => sortRooms( + cli.getVisibleRooms().filter( + room => room.getMyMembership() === "join" && + !(SettingsStore.getValue("feature_spaces") && room.isSpaceRoom()), + ), + ), [cli]); + + const [query, setQuery] = useState(""); + const lcQuery = query.toLowerCase(); + + const [rooms, dms] = visibleRooms.reduce((arr, room) => { + if (room.name.toLowerCase().includes(lcQuery)) { + if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) { + arr[1].push(room); + } else { + arr[0].push(room); + } + } + return arr; + }, [[], []]); + + const previewLayout = SettingsStore.getValue("layout"); + + return +
+ +
+
+

{ _t("Forward to") }

+ + + { rooms.length > 0 ? ( +
+

{ _t("Rooms") }

+ { rooms.map(room => { + return cli.sendEvent(room.roomId, event.getType(), event.getContent())} + />; + }) } +
+ ) : undefined } + + { dms.length > 0 ? ( +
+

{ _t("Direct Messages") }

+ { dms.map(room => { + return cli.sendEvent(room.roomId, event.getType(), event.getContent())} + />; + }) } +
+ ) : null } + + { rooms.length + dms.length < 1 ? + { _t("No results") } + : undefined } +
+
+
; +}; + +export default ForwardDialog; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index dcad970300..ed49fb6b44 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2187,6 +2187,11 @@ "Report a bug": "Report a bug", "Please view existing bugs on Github first. No match? Start a new one.": "Please view existing bugs on Github first. No match? Start a new one.", "Send feedback": "Send feedback", + "Sending…": "Sending…", + "Sent": "Sent", + "Forward message": "Forward message", + "Forward to": "Forward to", + "Filter your rooms and DMs": "Filter your rooms and DMs", "Confirm abort of host creation": "Confirm abort of host creation", "Are you sure you wish to abort creation of the host? The process cannot be continued.": "Are you sure you wish to abort creation of the host? The process cannot be continued.", "Abort": "Abort", From 74925b2c6d1f7de459bb6f35bb8cf472f476ccc3 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 8 May 2021 19:51:51 -0400 Subject: [PATCH 011/134] Test ForwardDialog Signed-off-by: Robin Townsend --- .../views/dialogs/ForwardDialog-test.js | 124 ++++++++++++++++++ test/test-utils.js | 3 +- 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 test/components/views/dialogs/ForwardDialog-test.js diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js new file mode 100644 index 0000000000..cabcbb0325 --- /dev/null +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -0,0 +1,124 @@ +/* +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. +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 "../../../skinned-sdk"; + +import React from "react"; +import {configure, mount} from "enzyme"; +import Adapter from "enzyme-adapter-react-16"; +import {act} from "react-dom/test-utils"; + +import * as TestUtils from "../../../test-utils"; +import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; +import DMRoomMap from "../../../../src/utils/DMRoomMap"; +import ForwardDialog from "../../../../src/components/views/dialogs/ForwardDialog"; + +configure({ adapter: new Adapter() }); + +describe("ForwardDialog", () => { + let client; + let wrapper; + + const message = TestUtils.mkMessage({ + room: "!111111111111111111:example.org", + user: "@alice:example.org", + msg: "Hello world!", + event: true, + }); + + beforeEach(async () => { + TestUtils.stubClient(); + DMRoomMap.makeShared(); + client = MatrixClientPeg.get(); + client.getVisibleRooms = jest.fn().mockReturnValue( + ["a", "A", "b"].map(name => TestUtils.mkStubRoom(name, name)), + ); + client.getUserId = jest.fn().mockReturnValue("@bob:example.org"); + + await act(async () => { + wrapper = mount( + , + ); + // Wait one tick for our profile data to load so the state update happens within act + await new Promise(resolve => setImmediate(resolve)); + }); + }); + + it("shows a preview with us as the sender", () => { + const previewBody = wrapper.find(".mx_EventTile_body"); + expect(previewBody.text()).toBe("Hello world!"); + + // We would just test SenderProfile for the user ID, but it's stubbed + const previewAvatar = wrapper.find(".mx_EventTile_avatar .mx_BaseAvatar_image"); + expect(previewAvatar.prop("title")).toBe("@bob:example.org"); + }); + + it("filters the rooms", () => { + const roomsBefore = wrapper.find(".mx_ForwardList_entry"); + expect(roomsBefore).toHaveLength(3); + + const searchInput = wrapper.find(".mx_SearchBox input"); + searchInput.instance().value = "a"; + searchInput.simulate("change"); + + const roomsAfter = wrapper.find(".mx_ForwardList_entry"); + expect(roomsAfter).toHaveLength(2); + }); + + it("tracks message sending progress across multiple rooms", async () => { + // Make sendEvent require manual resolution so we can see the sending state + let finishSend; + let cancelSend; + client.sendEvent = jest.fn(() => new Promise((resolve, reject) => { + finishSend = resolve; + cancelSend = reject; + })); + + const firstRoom = wrapper.find(".mx_ForwardList_entry").first(); + expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Send"); + + act(() => { + firstRoom.find(".mx_AccessibleButton").simulate("click"); + }); + expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Sending…"); + + await act(async () => { + cancelSend(); + // Wait one tick for the button to realize the send failed + await new Promise(resolve => setImmediate(resolve)); + }); + expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Failed to send"); + + const secondRoom = wrapper.find(".mx_ForwardList_entry").at(1); + expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Send"); + + act(() => { + secondRoom.find(".mx_AccessibleButton").simulate("click"); + }); + expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Sending…"); + + await act(async () => { + finishSend(); + // Wait one tick for the button to realize the send succeeded + await new Promise(resolve => setImmediate(resolve)); + }); + expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Sent"); + }); +}); diff --git a/test/test-utils.js b/test/test-utils.js index 6dc02463a5..985e9f804b 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -218,7 +218,7 @@ export function mkMessage(opts) { return mkEvent(opts); } -export function mkStubRoom(roomId = null) { +export function mkStubRoom(roomId = null, name) { const stubTimeline = { getEvents: () => [] }; return { roomId, @@ -254,6 +254,7 @@ export function mkStubRoom(roomId = null) { on: jest.fn(), removeListener: jest.fn(), getDMInviter: jest.fn(), + name, getAvatarUrl: () => 'mxc://avatar.url/room.png', getMxcAvatarUrl: () => 'mxc://avatar.url/room.png', isSpaceRoom: jest.fn(() => false), From 7fa81766db34449534d265cf7c2e60069049dd5b Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 8 May 2021 20:07:51 -0400 Subject: [PATCH 012/134] Remove old forwarding code This has been replaced by ForwardDialog. Signed-off-by: Robin Townsend --- src/components/structures/RoomView.tsx | 30 +---------- src/components/views/rooms/ForwardMessage.js | 53 ------------------- src/components/views/rooms/RoomHeader.js | 9 ---- .../views/rooms/SimpleRoomHeader.js | 20 ------- src/i18n/strings/en_EN.json | 1 - src/stores/RoomViewStore.tsx | 21 -------- 6 files changed, 2 insertions(+), 132 deletions(-) delete mode 100644 src/components/views/rooms/ForwardMessage.js diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 58a87e6641..d16247e4ec 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -60,7 +60,6 @@ import ScrollPanel from "./ScrollPanel"; import TimelinePanel from "./TimelinePanel"; import ErrorBoundary from "../views/elements/ErrorBoundary"; import RoomPreviewBar from "../views/rooms/RoomPreviewBar"; -import ForwardMessage from "../views/rooms/ForwardMessage"; import SearchBar from "../views/rooms/SearchBar"; import RoomUpgradeWarningBar from "../views/rooms/RoomUpgradeWarningBar"; import PinnedEventsPanel from "../views/rooms/PinnedEventsPanel"; @@ -136,7 +135,6 @@ export interface IState { // Whether to highlight the event scrolled to isInitialEventHighlighted?: boolean; replyToEvent?: MatrixEvent; - forwardingEvent?: MatrixEvent; numUnreadMessages: number; draggingFile: boolean; searching: boolean; @@ -324,7 +322,6 @@ export default class RoomView extends React.Component { initialEventId: RoomViewStore.getInitialEventId(), isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(), replyToEvent: RoomViewStore.getQuotingEvent(), - forwardingEvent: RoomViewStore.getForwardingEvent(), // we should only peek once we have a ready client shouldPeek: this.state.matrixClientIsReady && RoomViewStore.shouldPeek(), showingPinned: SettingsStore.getValue("PinnedEvents.isOpen", roomId), @@ -1394,18 +1391,6 @@ export default class RoomView extends React.Component { dis.dispatch({ action: "open_room_settings" }); }; - private onCancelClick = () => { - console.log("updateTint from onCancelClick"); - this.updateTint(); - if (this.state.forwardingEvent) { - dis.dispatch({ - action: 'forward_event', - event: null, - }); - } - dis.fire(Action.FocusComposer); - }; - private onAppsClick = () => { dis.dispatch({ action: "appsDrawer", @@ -1856,11 +1841,7 @@ export default class RoomView extends React.Component { let aux = null; let previewBar; - let hideCancel = false; - if (this.state.forwardingEvent) { - aux = ; - } else if (this.state.searching) { - hideCancel = true; // has own cancel + if (this.state.searching) { aux = { />; } else if (showRoomUpgradeBar) { aux = ; - hideCancel = true; } else if (this.state.showingPinned) { - hideCancel = true; // has own cancel aux = ; } else if (myMembership !== "join") { // We do have a room object for this room, but we're not currently in it. @@ -1881,7 +1860,6 @@ export default class RoomView extends React.Component { inviterName = this.props.oobData.inviterName; } const invitedEmail = this.props.threepidInvite?.toEmail; - hideCancel = true; previewBar = ( { hideMessagePanel = true; } - const shouldHighlight = this.state.isInitialEventHighlighted; let highlightedEventId = null; - if (this.state.forwardingEvent) { - highlightedEventId = this.state.forwardingEvent.getId(); - } else if (shouldHighlight) { + if (this.state.isInitialEventHighlighted) { highlightedEventId = this.state.initialEventId; } @@ -2091,7 +2066,6 @@ export default class RoomView extends React.Component { onSearchClick={this.onSearchClick} onSettingsClick={this.onSettingsClick} onPinnedClick={this.onPinnedClick} - onCancelClick={(aux && !hideCancel) ? this.onCancelClick : null} onForgetClick={(myMembership === "leave") ? this.onForgetClick : null} onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null} e2eStatus={this.state.e2eStatus} diff --git a/src/components/views/rooms/ForwardMessage.js b/src/components/views/rooms/ForwardMessage.js deleted file mode 100644 index dd894c0dcf..0000000000 --- a/src/components/views/rooms/ForwardMessage.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - Copyright 2017 Vector Creations Ltd - Copyright 2017 Michael Telatynski - - 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 PropTypes from 'prop-types'; -import { _t } from '../../../languageHandler'; -import {Key} from '../../../Keyboard'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; - -@replaceableComponent("views.rooms.ForwardMessage") -export default class ForwardMessage extends React.Component { - static propTypes = { - onCancelClick: PropTypes.func.isRequired, - }; - - componentDidMount() { - document.addEventListener('keydown', this._onKeyDown); - } - - componentWillUnmount() { - document.removeEventListener('keydown', this._onKeyDown); - } - - _onKeyDown = ev => { - switch (ev.key) { - case Key.ESCAPE: - this.props.onCancelClick(); - break; - } - }; - - render() { - return ( -
-

{ _t('Please select the destination room for this message') }

-
- ); - } -} diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index f856f7f6ef..cd4f89f964 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -22,7 +22,6 @@ import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import RateLimitedFunc from '../../../ratelimitedfunc'; -import {CancelButton} from './SimpleRoomHeader'; import SettingsStore from "../../../settings/SettingsStore"; import RoomHeaderButtons from '../right_panel/RoomHeaderButtons'; import E2EIcon from './E2EIcon'; @@ -44,7 +43,6 @@ export default class RoomHeader extends React.Component { onPinnedClick: PropTypes.func, onSearchClick: PropTypes.func, onLeaveClick: PropTypes.func, - onCancelClick: PropTypes.func, e2eStatus: PropTypes.string, onAppsClick: PropTypes.func, appsShown: PropTypes.bool, @@ -54,7 +52,6 @@ export default class RoomHeader extends React.Component { static defaultProps = { editing: false, inRoom: false, - onCancelClick: null, }; componentDidMount() { @@ -120,13 +117,8 @@ export default class RoomHeader extends React.Component { render() { let searchStatus = null; - let cancelButton = null; let pinnedEventsButton = null; - if (this.props.onCancelClick) { - cancelButton = ; - } - // don't display the search count until the search completes and // gives us a valid (possibly zero) searchCount. if (this.props.searchInfo && @@ -265,7 +257,6 @@ export default class RoomHeader extends React.Component {
{ e2eIcon }
{ name } { topicElement } - { cancelButton } { rightRow }
diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index b2a66f6670..02c1e1e8a1 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -16,23 +16,9 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import AccessibleButton from '../elements/AccessibleButton'; import * as sdk from '../../../index'; -import { _t } from '../../../languageHandler'; import {replaceableComponent} from "../../../utils/replaceableComponent"; -// cancel button which is shared between room header and simple room header -export function CancelButton(props) { - const {onClick} = props; - - return ( - - {_t("Cancel")} - - ); -} - /* * A stripped-down room header used for things like the user settings * and room directory. @@ -41,18 +27,13 @@ export function CancelButton(props) { export default class SimpleRoomHeader extends React.Component { static propTypes = { title: PropTypes.string, - onCancelClick: PropTypes.func, // `src` to a TintableSvg. Optional. icon: PropTypes.string, }; render() { - let cancelButton; let icon; - if (this.props.onCancelClick) { - cancelButton = ; - } if (this.props.icon) { const TintableSvg = sdk.getComponent('elements.TintableSvg'); icon = { icon } { this.props.title } - { cancelButton } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ed49fb6b44..6f2a4e8aee 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1458,7 +1458,6 @@ "Encrypting your message...": "Encrypting your message...", "Your message was sent": "Your message was sent", "Failed to send": "Failed to send", - "Please select the destination room for this message": "Please select the destination room for this message", "Scroll to most recent messages": "Scroll to most recent messages", "Close preview": "Close preview", "and %(count)s others...|other": "and %(count)s others...", diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index fe2e0a66b2..37162c8ae7 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -53,8 +53,6 @@ const INITIAL_STATE = { // Any error that has occurred during loading roomLoadError: null, - forwardingEvent: null, - quotingEvent: null, replyingToEvent: null, @@ -149,11 +147,6 @@ class RoomViewStore extends Store { case 'on_logged_out': this.reset(); break; - case 'forward_event': - this.setState({ - forwardingEvent: payload.event, - }); - break; case 'reply_to_event': // If currently viewed room does not match the room in which we wish to reply then change rooms // this can happen when performing a search across all rooms @@ -186,7 +179,6 @@ class RoomViewStore extends Store { roomAlias: payload.room_alias, initialEventId: payload.event_id, isInitialEventHighlighted: payload.highlighted, - forwardingEvent: null, roomLoading: false, roomLoadError: null, // should peek by default @@ -206,14 +198,6 @@ class RoomViewStore extends Store { newState.replyingToEvent = payload.replyingToEvent; } - if (this.state.forwardingEvent) { - dis.dispatch({ - action: 'send_event', - room_id: newState.roomId, - event: this.state.forwardingEvent, - }); - } - this.setState(newState); if (payload.auto_join) { @@ -419,11 +403,6 @@ class RoomViewStore extends Store { return this.state.joinError; } - // The mxEvent if one is about to be forwarded - public getForwardingEvent() { - return this.state.forwardingEvent; - } - // The mxEvent if one is currently being replied to/quoted public getQuotingEvent() { return this.state.replyingToEvent; From 219c983d191d9172e3c68aa11b1765f91ac5c6cd Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sun, 9 May 2021 10:58:44 -0400 Subject: [PATCH 013/134] Use import instead of sdk.getComponent Signed-off-by: Robin Townsend --- src/components/views/context_menus/MessageContextMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index e069bba975..fc2c366b07 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -31,6 +31,7 @@ import { isContentActionable } from '../../../utils/EventUtils'; import {MenuItem} from "../../structures/ContextMenu"; import {EventType} from "matrix-js-sdk/src/@types/event"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +import ForwardDialog from "../dialogs/ForwardDialog"; export function canCancel(eventStatus) { return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT; @@ -154,7 +155,6 @@ export default class MessageContextMenu extends React.Component { }; onForwardClick = () => { - const ForwardDialog = sdk.getComponent("dialogs.ForwardDialog"); Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { cli: MatrixClientPeg.get(), event: this.props.mxEvent, From c96888c9cba48dfb1d318b2cfb89cd699c6a8529 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 00:38:01 -0400 Subject: [PATCH 014/134] Make ForwardDialog more readable Signed-off-by: Robin Townsend --- .../views/dialogs/ForwardDialog.tsx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index ce38a783b3..b1f558dfef 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -39,6 +39,7 @@ const AVATAR_SIZE = 30; interface IProps extends IDialogProps { cli: MatrixClient; + // The event to forward event: MatrixEvent; } @@ -116,7 +117,7 @@ const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { }); mockEvent.sender = { name: profileInfo.displayname || userId, - userId: userId, + userId, getAvatarUrl: (..._) => { return avatarUrlForUser( { avatarUrl: profileInfo.avatar_url }, @@ -179,28 +180,28 @@ const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { { rooms.length > 0 ? (

{ _t("Rooms") }

- { rooms.map(room => { - return + cli.sendEvent(room.roomId, event.getType(), event.getContent())} - />; - }) } + />, + ) }
) : undefined } { dms.length > 0 ? (

{ _t("Direct Messages") }

- { dms.map(room => { - return + cli.sendEvent(room.roomId, event.getType(), event.getContent())} - />; - }) } + />, + ) }
- ) : null } + ) : undefined } { rooms.length + dms.length < 1 ? { _t("No results") } From 100efb1a90c92ac6a8771787cd2564f218507550 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 00:40:54 -0400 Subject: [PATCH 015/134] Fix ForwardDialog crashing when rendering reply Signed-off-by: Robin Townsend --- src/components/views/context_menus/MessageContextMenu.js | 1 + src/components/views/dialogs/ForwardDialog.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index fc2c366b07..002542bf88 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -158,6 +158,7 @@ export default class MessageContextMenu extends React.Component { Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { cli: MatrixClientPeg.get(), event: this.props.mxEvent, + permalinkCreator: this.props.permalinkCreator, }, 'mx_Dialog_forwardmessage'); this.closeMenu(); }; diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index b1f558dfef..5cb5d68745 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -33,6 +33,7 @@ import RoomAvatar from "../avatars/RoomAvatar"; import AccessibleButton from "../elements/AccessibleButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import DMRoomMap from "../../../utils/DMRoomMap"; +import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; const AVATAR_SIZE = 30; @@ -41,6 +42,9 @@ interface IProps extends IDialogProps { cli: MatrixClient; // The event to forward event: MatrixEvent; + // We need a permalink creator for the source room to pass through to EventTile + // in case the event is a reply (even though the user can't get at the link) + permalinkCreator: RoomPermalinkCreator; } interface IEntryProps { @@ -97,7 +101,7 @@ const Entry: React.FC = ({ room, send }) => { ; }; -const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { +const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinished }) => { const userId = cli.getUserId(); const [profileInfo, setProfileInfo] = useState({}); useEffect(() => { @@ -113,7 +117,7 @@ const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { age: 97, }, event_id: "$9999999999999999999999999999999999999999999", - room_id: "!999999999999999999:example.org", + room_id: event.getRoomId(), }); mockEvent.sender = { name: profileInfo.displayname || userId, @@ -165,6 +169,7 @@ const ForwardDialog: React.FC = ({ cli, event, onFinished }) => { mxEvent={mockEvent} layout={previewLayout} enableFlair={SettingsStore.getValue(UIFeature.Flair)} + permalinkCreator={permalinkCreator} />
From eb07f1fb86de32944b8a0375beec89abdeef63d0 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 00:54:00 -0400 Subject: [PATCH 016/134] Test that ForwardDialog can render replies Previously ForwardDialog was not giving its EventTile message preview the information it needed to render a ReplyThread. This was a bit tricky to fix since we were pulling a fake event out of thin air, so this ensures it doesn't regress. Signed-off-by: Robin Townsend --- .../views/dialogs/ForwardDialog-test.js | 64 ++++++++++++++----- test/test-utils.js | 1 + 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index cabcbb0325..af325ab8f0 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -24,44 +24,51 @@ import {act} from "react-dom/test-utils"; import * as TestUtils from "../../../test-utils"; import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; +import {RoomPermalinkCreator} from "../../../../src/utils/permalinks/Permalinks"; import ForwardDialog from "../../../../src/components/views/dialogs/ForwardDialog"; configure({ adapter: new Adapter() }); describe("ForwardDialog", () => { - let client; - let wrapper; - - const message = TestUtils.mkMessage({ - room: "!111111111111111111:example.org", + const sourceRoom = "!111111111111111111:example.org"; + const defaultMessage = TestUtils.mkMessage({ + room: sourceRoom, user: "@alice:example.org", msg: "Hello world!", event: true, }); + const defaultRooms = ["a", "A", "b"].map(name => TestUtils.mkStubRoom(name, name)); - beforeEach(async () => { - TestUtils.stubClient(); - DMRoomMap.makeShared(); - client = MatrixClientPeg.get(); - client.getVisibleRooms = jest.fn().mockReturnValue( - ["a", "A", "b"].map(name => TestUtils.mkStubRoom(name, name)), - ); - client.getUserId = jest.fn().mockReturnValue("@bob:example.org"); + const mountForwardDialog = async (message = defaultMessage, rooms = defaultRooms) => { + const client = MatrixClientPeg.get(); + client.getVisibleRooms = jest.fn().mockReturnValue(rooms); + let wrapper; await act(async () => { wrapper = mount( , ); // Wait one tick for our profile data to load so the state update happens within act await new Promise(resolve => setImmediate(resolve)); }); + + return wrapper; + }; + + beforeEach(() => { + TestUtils.stubClient(); + DMRoomMap.makeShared(); + MatrixClientPeg.get().getUserId = jest.fn().mockReturnValue("@bob:example.org"); }); - it("shows a preview with us as the sender", () => { + it("shows a preview with us as the sender", async () => { + const wrapper = await mountForwardDialog(); + const previewBody = wrapper.find(".mx_EventTile_body"); expect(previewBody.text()).toBe("Hello world!"); @@ -70,7 +77,9 @@ describe("ForwardDialog", () => { expect(previewAvatar.prop("title")).toBe("@bob:example.org"); }); - it("filters the rooms", () => { + it("filters the rooms", async () => { + const wrapper = await mountForwardDialog(); + const roomsBefore = wrapper.find(".mx_ForwardList_entry"); expect(roomsBefore).toHaveLength(3); @@ -83,10 +92,12 @@ describe("ForwardDialog", () => { }); it("tracks message sending progress across multiple rooms", async () => { + const wrapper = await mountForwardDialog(); + // Make sendEvent require manual resolution so we can see the sending state let finishSend; let cancelSend; - client.sendEvent = jest.fn(() => new Promise((resolve, reject) => { + MatrixClientPeg.get().sendEvent = jest.fn(() => new Promise((resolve, reject) => { finishSend = resolve; cancelSend = reject; })); @@ -121,4 +132,25 @@ describe("ForwardDialog", () => { }); expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Sent"); }); + + it("can render replies", async () => { + const replyMessage = TestUtils.mkEvent({ + type: "m.room.message", + room: "!111111111111111111:example.org", + user: "@alice:example.org", + content: { + msgtype: "m.text", + body: "> <@bob:example.org> Hi Alice!\n\nHi Bob!", + "m.relates_to": { + "m.in_reply_to": { + event_id: "$2222222222222222222222222222222222222222222", + }, + }, + }, + event: true, + }); + + const wrapper = await mountForwardDialog(replyMessage); + expect(wrapper.find("ReplyThread")).toBeTruthy(); + }); }); diff --git a/test/test-utils.js b/test/test-utils.js index 985e9f804b..8c9c62844a 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -236,6 +236,7 @@ export function mkStubRoom(roomId = null, name) { getPendingEvents: () => [], getLiveTimeline: () => stubTimeline, getUnfilteredTimelineSet: () => null, + findEventById: () => null, getAccountData: () => null, hasMembershipState: () => null, getVersion: () => '1', From 35cf0e1c7efbd4f627e8fcc00cd8f8b96daf1b8e Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 01:02:12 -0400 Subject: [PATCH 017/134] Find components by name rather than class in ForwardDialog test It makes things shorter and more readable! Signed-off-by: Robin Townsend --- .../views/dialogs/ForwardDialog-test.js | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index af325ab8f0..f181157d09 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -80,15 +80,13 @@ describe("ForwardDialog", () => { it("filters the rooms", async () => { const wrapper = await mountForwardDialog(); - const roomsBefore = wrapper.find(".mx_ForwardList_entry"); - expect(roomsBefore).toHaveLength(3); + expect(wrapper.find("Entry")).toHaveLength(3); - const searchInput = wrapper.find(".mx_SearchBox input"); + const searchInput = wrapper.find("SearchBox input"); searchInput.instance().value = "a"; searchInput.simulate("change"); - const roomsAfter = wrapper.find(".mx_ForwardList_entry"); - expect(roomsAfter).toHaveLength(2); + expect(wrapper.find("Entry")).toHaveLength(2); }); it("tracks message sending progress across multiple rooms", async () => { @@ -102,35 +100,31 @@ describe("ForwardDialog", () => { cancelSend = reject; })); - const firstRoom = wrapper.find(".mx_ForwardList_entry").first(); - expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Send"); + const firstButton = wrapper.find("Entry AccessibleButton").first(); + expect(firstButton.text()).toBe("Send"); - act(() => { - firstRoom.find(".mx_AccessibleButton").simulate("click"); - }); - expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Sending…"); + act(() => { firstButton.simulate("click"); }); + expect(firstButton.text()).toBe("Sending…"); await act(async () => { cancelSend(); // Wait one tick for the button to realize the send failed await new Promise(resolve => setImmediate(resolve)); }); - expect(firstRoom.find(".mx_AccessibleButton").text()).toBe("Failed to send"); + expect(firstButton.text()).toBe("Failed to send"); - const secondRoom = wrapper.find(".mx_ForwardList_entry").at(1); - expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Send"); + const secondButton = wrapper.find("Entry AccessibleButton").at(1); + expect(secondButton.text()).toBe("Send"); - act(() => { - secondRoom.find(".mx_AccessibleButton").simulate("click"); - }); - expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Sending…"); + act(() => { secondButton.simulate("click"); }); + expect(secondButton.text()).toBe("Sending…"); await act(async () => { finishSend(); // Wait one tick for the button to realize the send succeeded await new Promise(resolve => setImmediate(resolve)); }); - expect(secondRoom.find(".mx_AccessibleButton").text()).toBe("Sent"); + expect(secondButton.text()).toBe("Sent"); }); it("can render replies", async () => { From 09ba74a8514fd907e758f1af24c795fa78ce8643 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 01:04:25 -0400 Subject: [PATCH 018/134] Disable forward buttons for rooms without send permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …and add a tooltip to explain why they can't accept forwarded messages. It was chosen to disable the buttons rather than hide the entries from the list, since hiding them without explanation could cause confusion. Signed-off-by: Robin Townsend --- .../views/dialogs/ForwardDialog.tsx | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 5cb5d68745..fd10a88d93 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -31,6 +31,7 @@ import EventTile from "../rooms/EventTile"; import SearchBox from "../../structures/SearchBox"; import RoomAvatar from "../avatars/RoomAvatar"; import AccessibleButton from "../elements/AccessibleButton"; +import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import DMRoomMap from "../../../utils/DMRoomMap"; import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; @@ -63,41 +64,58 @@ enum SendState { const Entry: React.FC = ({ room, send }) => { const [sendState, setSendState] = useState(SendState.CanSend); - let label; - let className; - if (sendState === SendState.CanSend) { - label = _t("Send"); - className = "mx_ForwardList_canSend"; - } else if (sendState === SendState.Sending) { - label = _t("Sending…"); - className = "mx_ForwardList_sending"; - } else if (sendState === SendState.Sent) { - label = _t("Sent"); - className = "mx_ForwardList_sent"; + let button; + if (room.maySendMessage()) { + let label; + let className; + if (sendState === SendState.CanSend) { + label = _t("Send"); + className = "mx_ForwardList_canSend"; + } else if (sendState === SendState.Sending) { + label = _t("Sending…"); + className = "mx_ForwardList_sending"; + } else if (sendState === SendState.Sent) { + label = _t("Sent"); + className = "mx_ForwardList_sent"; + } else { + label = _t("Failed to send"); + className = "mx_ForwardList_sendFailed"; + } + + button = + { + setSendState(SendState.Sending); + try { + await send(); + setSendState(SendState.Sent); + } catch (e) { + setSendState(SendState.Failed); + } + }} + disabled={sendState !== SendState.CanSend} + > + { label } + ; } else { - label = _t("Failed to send"); - className = "mx_ForwardList_sendFailed"; + button = + {}} + disabled={true} + title={_t("You do not have permission to post to this room")} + > + { _t("Send") } + ; } return
{ room.name } - { - setSendState(SendState.Sending); - try { - await send(); - setSendState(SendState.Sent); - } catch (e) { - setSendState(SendState.Failed); - } - }} - disabled={sendState !== SendState.CanSend} - > - { label } - + { button }
; }; From eb779cd3d8db279e9cf91134b1aa5bbf4326662c Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 01:07:42 -0400 Subject: [PATCH 019/134] Test that forward buttons are disabled for rooms without permission Signed-off-by: Robin Townsend --- test/components/views/dialogs/ForwardDialog-test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index f181157d09..706d47acdc 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -147,4 +147,17 @@ describe("ForwardDialog", () => { const wrapper = await mountForwardDialog(replyMessage); expect(wrapper.find("ReplyThread")).toBeTruthy(); }); + + it("disables buttons for rooms without send permissions", async () => { + const readOnlyRoom = TestUtils.mkStubRoom("a", "a"); + readOnlyRoom.maySendMessage = jest.fn().mockReturnValue(false); + const rooms = [readOnlyRoom, TestUtils.mkStubRoom("b", "b")]; + + const wrapper = await mountForwardDialog(undefined, rooms); + + const firstButton = wrapper.find("Entry AccessibleButton").first(); + expect(firstButton.prop("disabled")).toBe(true); + const secondButton = wrapper.find("Entry AccessibleButton").last(); + expect(secondButton.prop("disabled")).toBe(false); + }); }); From 5c10e1e5744e7c8b753304e4994c172f4ba493c3 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 01:16:37 -0400 Subject: [PATCH 020/134] Fix lints Signed-off-by: Robin Townsend --- test/components/views/dialogs/ForwardDialog-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index 706d47acdc..2f062a84cc 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -133,8 +133,8 @@ describe("ForwardDialog", () => { room: "!111111111111111111:example.org", user: "@alice:example.org", content: { - msgtype: "m.text", - body: "> <@bob:example.org> Hi Alice!\n\nHi Bob!", + "msgtype": "m.text", + "body": "> <@bob:example.org> Hi Alice!\n\nHi Bob!", "m.relates_to": { "m.in_reply_to": { event_id: "$2222222222222222222222222222222222222222222", From bfba2b0b6f09b7d470a6274d07053d0d854f7cd0 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 11:16:51 -0400 Subject: [PATCH 021/134] Push ForwardDialog scrollbar into the gutter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …to give more space between it and the buttons. Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index a3aa08d04f..a447b93cae 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -48,6 +48,8 @@ limitations under the License. .mx_ForwardList_content { flex-grow: 1; + // Push the scrollbar into the gutter + margin-right: -6px; } .mx_ForwardList_noResults { @@ -56,6 +58,8 @@ limitations under the License. } .mx_ForwardList_section { + margin-right: 6px; + &:not(:first-child) { margin-top: 24px; } From 503301aa89e3a8378d9e48c95b37ec19ab4d5e89 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 13:00:06 -0400 Subject: [PATCH 022/134] Make rooms in ForwardDialog clickable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …so that you can jump to a room easily once you've forwarded a message there. Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 29 ++++++---- .../views/dialogs/ForwardDialog.tsx | 53 ++++++++++++------- .../views/dialogs/ForwardDialog-test.js | 10 ++-- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index a447b93cae..30a4cfcacf 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -74,23 +74,30 @@ limitations under the License. .mx_ForwardList_entry { display: flex; + justify-content: space-between; margin-top: 12px; - .mx_BaseAvatar { + .mx_ForwardList_roomButton { + display: flex; margin-right: 12px; - } - - .mx_ForwardList_entry_name { - font-size: $font-15px; - line-height: 30px; flex-grow: 1; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - margin-right: 12px; + min-width: 0; + + .mx_BaseAvatar { + margin-right: 12px; + } + + .mx_ForwardList_entry_name { + font-size: $font-15px; + line-height: 30px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin-right: 12px; + } } - .mx_AccessibleButton { + .mx_ForwardList_sendButton { &.mx_ForwardList_sending, &.mx_ForwardList_sent { &::before { content: ''; diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index fd10a88d93..ed6973cd4a 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -21,6 +21,7 @@ import {Room} from "matrix-js-sdk/src/models/room"; import {MatrixClient} from "matrix-js-sdk/src/client"; import {_t} from "../../../languageHandler"; +import dis from "../../../dispatcher/dispatcher"; import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; import {Layout} from "../../../settings/Layout"; @@ -50,8 +51,9 @@ interface IProps extends IDialogProps { interface IEntryProps { room: Room; - // Callback to forward the message to this room - send(): Promise; + event: MatrixEvent; + cli: MatrixClient; + onFinished(success: boolean): void; } enum SendState { @@ -61,9 +63,26 @@ enum SendState { Failed, } -const Entry: React.FC = ({ room, send }) => { +const Entry: React.FC = ({ room, event, cli, onFinished }) => { const [sendState, setSendState] = useState(SendState.CanSend); + const jumpToRoom = () => { + dis.dispatch({ + action: "view_room", + room_id: room.roomId, + }); + onFinished(true); + }; + const send = async () => { + setSendState(SendState.Sending); + try { + await cli.sendEvent(room.roomId, event.getType(), event.getContent()); + setSendState(SendState.Sent); + } catch (e) { + setSendState(SendState.Failed); + } + }; + let button; if (room.maySendMessage()) { let label; @@ -85,16 +104,8 @@ const Entry: React.FC = ({ room, send }) => { button = { - setSendState(SendState.Sending); - try { - await send(); - setSendState(SendState.Sent); - } catch (e) { - setSendState(SendState.Failed); - } - }} + className={`mx_ForwardList_sendButton ${className}`} + onClick={send} disabled={sendState !== SendState.CanSend} > { label } @@ -103,7 +114,7 @@ const Entry: React.FC = ({ room, send }) => { button = {}} disabled={true} title={_t("You do not have permission to post to this room")} @@ -113,8 +124,10 @@ const Entry: React.FC = ({ room, send }) => { } return
- - { room.name } + + + { room.name } + { button }
; }; @@ -207,7 +220,9 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis cli.sendEvent(room.roomId, event.getType(), event.getContent())} + event={event} + cli={cli} + onFinished={onFinished} />, ) }
@@ -220,7 +235,9 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis cli.sendEvent(room.roomId, event.getType(), event.getContent())} + event={event} + cli={cli} + onFinished={onFinished} />, ) } diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index 2f062a84cc..331ee9d131 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -100,7 +100,7 @@ describe("ForwardDialog", () => { cancelSend = reject; })); - const firstButton = wrapper.find("Entry AccessibleButton").first(); + const firstButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first(); expect(firstButton.text()).toBe("Send"); act(() => { firstButton.simulate("click"); }); @@ -113,8 +113,8 @@ describe("ForwardDialog", () => { }); expect(firstButton.text()).toBe("Failed to send"); - const secondButton = wrapper.find("Entry AccessibleButton").at(1); - expect(secondButton.text()).toBe("Send"); + const secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").at(1); + expect(secondButton.render().text()).toBe("Send"); act(() => { secondButton.simulate("click"); }); expect(secondButton.text()).toBe("Sending…"); @@ -155,9 +155,9 @@ describe("ForwardDialog", () => { const wrapper = await mountForwardDialog(undefined, rooms); - const firstButton = wrapper.find("Entry AccessibleButton").first(); + const firstButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first(); expect(firstButton.prop("disabled")).toBe(true); - const secondButton = wrapper.find("Entry AccessibleButton").last(); + const secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").last(); expect(secondButton.prop("disabled")).toBe(false); }); }); From 7efbd2d930cc93dffdabe10f84bc320f58cf23c5 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 10 May 2021 13:57:47 -0400 Subject: [PATCH 023/134] Hide unencrypted badge from ForwardDialog preview Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 30a4cfcacf..9bd0bd2879 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -35,6 +35,12 @@ limitations under the License. .mx_EventTile_msgOption { display: none; } + + // When forwarding messages from encrypted rooms, EventTile will complain + // that our preview is unencrypted, which doesn't actually matter + .mx_EventTile_e2eIcon_unencrypted { + display: none; + } } .mx_ForwardList { From e798b36f1db8ea73c81fcc1626e1af31014c0800 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sun, 16 May 2021 08:39:22 -0400 Subject: [PATCH 024/134] Decorate forward dialog room avatars Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 2 +- src/components/views/dialogs/ForwardDialog.tsx | 4 ++-- test/test-utils.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 9bd0bd2879..2a72ea4ffb 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -89,7 +89,7 @@ limitations under the License. flex-grow: 1; min-width: 0; - .mx_BaseAvatar { + .mx_DecoratedRoomAvatar { margin-right: 12px; } diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index ed6973cd4a..1ef4841851 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -30,7 +30,7 @@ import BaseDialog from "./BaseDialog"; import {avatarUrlForUser} from "../../../Avatar"; import EventTile from "../rooms/EventTile"; import SearchBox from "../../structures/SearchBox"; -import RoomAvatar from "../avatars/RoomAvatar"; +import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import AccessibleButton from "../elements/AccessibleButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; @@ -125,7 +125,7 @@ const Entry: React.FC = ({ room, event, cli, onFinished }) => { return
- + { room.name } { button } diff --git a/test/test-utils.js b/test/test-utils.js index 8c9c62844a..a2ccf84728 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -253,6 +253,7 @@ export function mkStubRoom(roomId = null, name) { tags: {}, setBlacklistUnverifiedDevices: jest.fn(), on: jest.fn(), + off: jest.fn(), removeListener: jest.fn(), getDMInviter: jest.fn(), name, From 83224dc7b66b6d3b51d6d58568759611726b0d04 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 19 May 2021 13:32:27 -0400 Subject: [PATCH 025/134] Ensure forward list room decorations are aligned Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 2a72ea4ffb..6fcd7d881a 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -82,6 +82,7 @@ limitations under the License. display: flex; justify-content: space-between; margin-top: 12px; + height: 32px; .mx_ForwardList_roomButton { display: flex; From 6cb6c7f3d0c538ac5e0742c806849d33ec685631 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 19 May 2021 13:33:48 -0400 Subject: [PATCH 026/134] Combine forward dialog room and DM lists Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 2 +- .../views/dialogs/ForwardDialog.tsx | 46 ++++--------------- 2 files changed, 9 insertions(+), 39 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 6fcd7d881a..47ab219150 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -63,7 +63,7 @@ limitations under the License. margin-top: 24px; } - .mx_ForwardList_section { + .mx_ForwardList_results { margin-right: 6px; &:not(:first-child) { diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 1ef4841851..b7a176cfce 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -34,7 +34,6 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import AccessibleButton from "../elements/AccessibleButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import DMRoomMap from "../../../utils/DMRoomMap"; import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; @@ -162,26 +161,15 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis getMxcAvatarUrl: () => profileInfo.avatar_url, }; - const visibleRooms = useMemo(() => sortRooms( + const [query, setQuery] = useState(""); + const lcQuery = query.toLowerCase(); + + const rooms = useMemo(() => sortRooms( cli.getVisibleRooms().filter( room => room.getMyMembership() === "join" && !(SettingsStore.getValue("feature_spaces") && room.isSpaceRoom()), ), - ), [cli]); - - const [query, setQuery] = useState(""); - const lcQuery = query.toLowerCase(); - - const [rooms, dms] = visibleRooms.reduce((arr, room) => { - if (room.name.toLowerCase().includes(lcQuery)) { - if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) { - arr[1].push(room); - } else { - arr[0].push(room); - } - } - return arr; - }, [[], []]); + ), [cli]).filter(room => room.name.toLowerCase().includes(lcQuery)); const previewLayout = SettingsStore.getValue("layout"); @@ -214,8 +202,7 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis /> { rooms.length > 0 ? ( -
-

{ _t("Rooms") }

+
{ rooms.map(room => = ({ cli, event, permalinkCreator, onFinis />, ) }
- ) : undefined } - - { dms.length > 0 ? ( -
-

{ _t("Direct Messages") }

- { dms.map(room => - , - ) } -
- ) : undefined } - - { rooms.length + dms.length < 1 ? + ) : { _t("No results") } - : undefined } + }
; From 7a045021514788f67c52bf6324e9bf16fceb42cc Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Fri, 21 May 2021 12:41:29 -0400 Subject: [PATCH 027/134] Iterate on forward dialog design feedback Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 80 ++++++++++------ .../views/dialogs/ForwardDialog.tsx | 93 +++++++++++-------- .../elements/AccessibleTooltipButton.tsx | 6 +- src/i18n/strings/en_EN.json | 6 +- .../views/dialogs/ForwardDialog-test.js | 12 +-- 5 files changed, 116 insertions(+), 81 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 47ab219150..1eb37e09da 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -23,7 +23,15 @@ limitations under the License. min-height: 0; height: 80vh; - .mx_ForwardDialog_preview { + > h3 { + margin: 0 0 6px; + color: $secondary-fg-color; + font-size: $font-12px; + font-weight: $font-semi-bold; + line-height: $font-15px; + } + + > .mx_ForwardDialog_preview { max-height: 30%; flex-shrink: 0; overflow: scroll; @@ -43,7 +51,14 @@ limitations under the License. } } - .mx_ForwardList { + > hr { + width: 100%; + border: none; + border-top: 1px solid $input-border-color; + margin: 12px 0; + } + + > .mx_ForwardList { display: contents; .mx_SearchBox { @@ -54,8 +69,6 @@ limitations under the License. .mx_ForwardList_content { flex-grow: 1; - // Push the scrollbar into the gutter - margin-right: -6px; } .mx_ForwardList_noResults { @@ -64,30 +77,24 @@ limitations under the License. } .mx_ForwardList_results { - margin-right: 6px; - &:not(:first-child) { margin-top: 24px; } - > h3 { - margin: 0; - color: $secondary-fg-color; - font-size: $font-12px; - font-weight: $font-semi-bold; - line-height: $font-15px; - } - .mx_ForwardList_entry { display: flex; justify-content: space-between; - margin-top: 12px; height: 32px; + padding: 6px; + border-radius: 8px; + + &:hover { + background-color: $groupFilterPanel-bg-color; + } .mx_ForwardList_roomButton { display: flex; margin-right: 12px; - flex-grow: 1; min-width: 0; .mx_DecoratedRoomAvatar { @@ -105,26 +112,39 @@ limitations under the License. } .mx_ForwardList_sendButton { - &.mx_ForwardList_sending, &.mx_ForwardList_sent { - &::before { - content: ''; - display: inline-block; - background-color: $button-primary-bg-color; - mask-position: center; - mask-repeat: no-repeat; - mask-size: 14px; - width: 14px; - height: 14px; - margin-right: 5px; - } + position: relative; + + &:not(.mx_ForwardList_canSend) .mx_ForwardList_sendLabel { + // Hide the "Send" label while preserving button size + visibility: hidden; } - &.mx_ForwardList_sending::before { + .mx_ForwardList_sendIcon, .mx_NotificationBadge { + position: absolute; + } + + .mx_NotificationBadge { + opacity: 0.4; + } + + &.mx_ForwardList_sending .mx_ForwardList_sendIcon { + background-color: $button-primary-bg-color; mask-image: url('$(res)/img/element-icons/circle-sending.svg'); + mask-position: center; + mask-repeat: no-repeat; + mask-size: 14px; + width: 14px; + height: 14px; } - &.mx_ForwardList_sent::before { + &.mx_ForwardList_sent .mx_ForwardList_sendIcon { + background-color: $button-primary-bg-color; mask-image: url('$(res)/img/element-icons/circle-sent.svg'); + mask-position: center; + mask-repeat: no-repeat; + mask-size: 14px; + width: 14px; + height: 14px; } } } diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index b7a176cfce..3448e636d9 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -31,9 +31,11 @@ import {avatarUrlForUser} from "../../../Avatar"; import EventTile from "../rooms/EventTile"; import SearchBox from "../../structures/SearchBox"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; -import AccessibleButton from "../elements/AccessibleButton"; +import {Alignment} from '../elements/Tooltip'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState"; +import NotificationBadge from "../rooms/NotificationBadge"; import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; @@ -82,52 +84,60 @@ const Entry: React.FC = ({ room, event, cli, onFinished }) => { } }; - let button; - if (room.maySendMessage()) { - let label; - let className; - if (sendState === SendState.CanSend) { - label = _t("Send"); - className = "mx_ForwardList_canSend"; - } else if (sendState === SendState.Sending) { - label = _t("Sending…"); - className = "mx_ForwardList_sending"; - } else if (sendState === SendState.Sent) { - label = _t("Sent"); - className = "mx_ForwardList_sent"; + let className; + let disabled = false; + let title; + let icon; + if (sendState === SendState.CanSend) { + className = "mx_ForwardList_canSend"; + if (room.maySendMessage()) { + title = _t("Send"); } else { - label = _t("Failed to send"); - className = "mx_ForwardList_sendFailed"; + disabled = true; + title = _t("You do not have permission to do this"); } - - button = - - { label } - ; + } else if (sendState === SendState.Sending) { + className = "mx_ForwardList_sending"; + disabled = true; + title = _t("Sending…"); + icon =
; + } else if (sendState === SendState.Sent) { + className = "mx_ForwardList_sent"; + disabled = true; + title = _t("Sent"); + icon =
; } else { - button = - {}} - disabled={true} - title={_t("You do not have permission to post to this room")} - > - { _t("Send") } - ; + className = "mx_ForwardList_sendFailed"; + disabled = true; + title = _t("Failed to send"); + icon = ; } return
- + { room.name } - - { button } + + +
{ _t("Send") }
+ { icon } +
; }; @@ -180,6 +190,7 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis onFinished={onFinished} fixedWidth={false} > +

{ _t("Message preview") }

= ({ cli, event, permalinkCreator, onFinis permalinkCreator={permalinkCreator} />
+
-

{ _t("Forward to") }

{ @@ -28,6 +28,7 @@ interface ITooltipProps extends React.ComponentProps { tooltipClassName?: string; forceHide?: boolean; yOffset?: number; + alignment?: Alignment; } interface IState { @@ -66,13 +67,14 @@ export default class AccessibleTooltipButton extends React.PureComponent :
; return ( debug logs to help us track down the problem.": "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.", "Report a bug": "Report a bug", "Please view existing bugs on Github first. No match? Start a new one.": "Please view existing bugs on Github first. No match? Start a new one.", + "You do not have permission to do this": "You do not have permission to do this", "Sending…": "Sending…", "Sent": "Sent", + "Open link": "Open link", "Forward message": "Forward message", - "Forward to": "Forward to", - "Filter your rooms and DMs": "Filter your rooms and DMs", + "Message preview": "Message preview", + "Search for rooms or people": "Search for rooms or people", "Confirm abort of host creation": "Confirm abort of host creation", "Are you sure you wish to abort creation of the host? The process cannot be continued.": "Are you sure you wish to abort creation of the host? The process cannot be continued.", "Abort": "Abort", diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index 331ee9d131..ce62b4fa7c 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -101,30 +101,30 @@ describe("ForwardDialog", () => { })); const firstButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").first(); - expect(firstButton.text()).toBe("Send"); + expect(firstButton.render().is(".mx_ForwardList_canSend")).toBe(true); act(() => { firstButton.simulate("click"); }); - expect(firstButton.text()).toBe("Sending…"); + expect(firstButton.render().is(".mx_ForwardList_sending")).toBe(true); await act(async () => { cancelSend(); // Wait one tick for the button to realize the send failed await new Promise(resolve => setImmediate(resolve)); }); - expect(firstButton.text()).toBe("Failed to send"); + expect(firstButton.render().is(".mx_ForwardList_sendFailed")).toBe(true); const secondButton = wrapper.find("AccessibleButton.mx_ForwardList_sendButton").at(1); - expect(secondButton.render().text()).toBe("Send"); + expect(secondButton.render().is(".mx_ForwardList_canSend")).toBe(true); act(() => { secondButton.simulate("click"); }); - expect(secondButton.text()).toBe("Sending…"); + expect(secondButton.render().is(".mx_ForwardList_sending")).toBe(true); await act(async () => { finishSend(); // Wait one tick for the button to realize the send succeeded await new Promise(resolve => setImmediate(resolve)); }); - expect(secondButton.text()).toBe("Sent"); + expect(secondButton.render().is(".mx_ForwardList_sent")).toBe(true); }); it("can render replies", async () => { From cd460a2555026fe0ceaf8bb53d31af7ad6405b64 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Fri, 21 May 2021 12:59:13 -0400 Subject: [PATCH 028/134] Adjust forward dialog copy Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 3448e636d9..ff08ce43df 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -94,7 +94,7 @@ const Entry: React.FC = ({ room, event, cli, onFinished }) => { title = _t("Send"); } else { disabled = true; - title = _t("You do not have permission to do this"); + title = _t("You don't have permission to do this"); } } else if (sendState === SendState.Sending) { className = "mx_ForwardList_sending"; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ebe5f54f61..ceb48852c5 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2202,7 +2202,7 @@ "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.": "PRO TIP: If you start a bug, please submit debug logs to help us track down the problem.", "Report a bug": "Report a bug", "Please view existing bugs on Github first. No match? Start a new one.": "Please view existing bugs on Github first. No match? Start a new one.", - "You do not have permission to do this": "You do not have permission to do this", + "You don't have permission to do this": "You don't have permission to do this", "Sending…": "Sending…", "Sent": "Sent", "Open link": "Open link", From 400917623ce24f37b4eb12fda5769531f7c635c5 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 24 May 2021 08:33:28 -0400 Subject: [PATCH 029/134] Make myself the copyright holder for forward dialog code Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 2 +- src/components/views/dialogs/ForwardDialog.tsx | 2 +- test/components/views/dialogs/ForwardDialog-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 1eb37e09da..593fe12531 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -1,5 +1,5 @@ /* -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021 Robin Townsend. 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/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index ff08ce43df..66b4b49997 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021 Robin Townsend. 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/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index ce62b4fa7c..fddba1d5ae 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -1,5 +1,5 @@ /* -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021 Robin Townsend. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 6ced61b7096ed31cd00ada688495235fa61b9df8 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 24 May 2021 08:34:03 -0400 Subject: [PATCH 030/134] Use camelCase Signed-off-by: Robin Townsend --- src/components/views/context_menus/MessageContextMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 5494b0a32f..4120f7be9e 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -161,7 +161,7 @@ export default class MessageContextMenu extends React.Component { cli: MatrixClientPeg.get(), event: this.props.mxEvent, permalinkCreator: this.props.permalinkCreator, - }, 'mx_Dialog_forwardmessage'); + }, 'mx_Dialog_forwardMessage'); this.closeMenu(); }; From 121ed5eba996f41ce78c8b789278d196443e53b1 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 24 May 2021 08:51:04 -0400 Subject: [PATCH 031/134] Pass Matrix client around as matrixClient Signed-off-by: Robin Townsend --- .../views/context_menus/MessageContextMenu.js | 2 +- src/components/views/dialogs/ForwardDialog.tsx | 10 +++++----- test/components/views/dialogs/ForwardDialog-test.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 4120f7be9e..08fc5844ec 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -158,7 +158,7 @@ export default class MessageContextMenu extends React.Component { onForwardClick = () => { Modal.createTrackedDialog('Forward Message', '', ForwardDialog, { - cli: MatrixClientPeg.get(), + matrixClient: MatrixClientPeg.get(), event: this.props.mxEvent, permalinkCreator: this.props.permalinkCreator, }, 'mx_Dialog_forwardMessage'); diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 66b4b49997..3087ce51a1 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -42,7 +42,7 @@ import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/Recent const AVATAR_SIZE = 30; interface IProps extends IDialogProps { - cli: MatrixClient; + matrixClient: MatrixClient; // The event to forward event: MatrixEvent; // We need a permalink creator for the source room to pass through to EventTile @@ -53,7 +53,7 @@ interface IProps extends IDialogProps { interface IEntryProps { room: Room; event: MatrixEvent; - cli: MatrixClient; + matrixClient: MatrixClient; onFinished(success: boolean): void; } @@ -64,7 +64,7 @@ enum SendState { Failed, } -const Entry: React.FC = ({ room, event, cli, onFinished }) => { +const Entry: React.FC = ({ room, event, matrixClient: cli, onFinished }) => { const [sendState, setSendState] = useState(SendState.CanSend); const jumpToRoom = () => { @@ -141,7 +141,7 @@ const Entry: React.FC = ({ room, event, cli, onFinished }) => {
; }; -const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinished }) => { +const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCreator, onFinished }) => { const userId = cli.getUserId(); const [profileInfo, setProfileInfo] = useState({}); useEffect(() => { @@ -219,7 +219,7 @@ const ForwardDialog: React.FC = ({ cli, event, permalinkCreator, onFinis key={room.roomId} room={room} event={event} - cli={cli} + matrixClient={cli} onFinished={onFinished} />, ) } diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index fddba1d5ae..004954c713 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -47,7 +47,7 @@ describe("ForwardDialog", () => { await act(async () => { wrapper = mount( Date: Mon, 24 May 2021 08:55:08 -0400 Subject: [PATCH 032/134] Give forward dialog send buttons an accessible label Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 6 +++--- src/i18n/strings/en_EN.json | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 3087ce51a1..59475b1b51 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -99,13 +99,13 @@ const Entry: React.FC = ({ room, event, matrixClient: cli, onFinish } else if (sendState === SendState.Sending) { className = "mx_ForwardList_sending"; disabled = true; - title = _t("Sending…"); - icon =
; + title = _t("Sending"); + icon =
; } else if (sendState === SendState.Sent) { className = "mx_ForwardList_sent"; disabled = true; title = _t("Sent"); - icon =
; + icon =
; } else { className = "mx_ForwardList_sendFailed"; disabled = true; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c2c6aa9e6d..817765ca69 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2203,7 +2203,7 @@ "Report a bug": "Report a bug", "Please view existing bugs on Github first. No match? Start a new one.": "Please view existing bugs on Github first. No match? Start a new one.", "You don't have permission to do this": "You don't have permission to do this", - "Sending…": "Sending…", + "Sending": "Sending", "Sent": "Sent", "Open link": "Open link", "Forward message": "Forward message", @@ -2668,7 +2668,6 @@ "Some of your messages have not been sent": "Some of your messages have not been sent", "Delete all": "Delete all", "Retry all": "Retry all", - "Sending": "Sending", "You can select all or individual messages to retry or delete": "You can select all or individual messages to retry or delete", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", From f75fb3b3499c8a886b81d5a84e86596c5659b918 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 27 May 2021 15:51:25 +0100 Subject: [PATCH 033/134] Add footer and privacy note to the start dm dialog --- res/css/views/dialogs/_InviteDialog.scss | 61 ++++++++++++++++++- src/components/views/dialogs/InviteDialog.tsx | 58 ++++++++++++++++-- src/i18n/strings/en_EN.json | 3 + 3 files changed, 116 insertions(+), 6 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index d8ff56663a..a33871eca5 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -82,6 +82,14 @@ limitations under the License. text-transform: uppercase; } + > p { + margin: 0; + } + + > span { + color: $primary-fg-color; + } + .mx_InviteDialog_subname { margin-bottom: 10px; margin-top: -10px; // HACK: Positioning with margins is bad @@ -90,6 +98,49 @@ limitations under the License. } } +.mx_InviteDialog_footer { + border-top: 1px solid $input-border-color; + + > h3 { + margin: 8px 0; + font-size: $font-12px; + color: $muted-fg-color; + font-weight: bold; + text-transform: uppercase; + } + + .mx_InviteDialog_footer_link { + display: flex; + justify-content: space-between; + border-radius: 4px; + border: solid 1px $input-border-color; + padding: 8px; + + > a { + text-decoration: none; + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .mx_InviteDialog_footer_link_copy { + flex-shrink: 0; + cursor: pointer; + margin-left: 20px; + display: inherit; + + > div { + mask-image: url($copy-button-url); + background-color: $message-action-bar-fg-color; + margin-left: 5px; + width: 20px; + height: 20px; + background-repeat: no-repeat; + } + } +} + .mx_InviteDialog_roomTile { cursor: pointer; padding: 5px 10px; @@ -212,15 +263,21 @@ limitations under the License. .mx_InviteDialog { // Prevent the dialog from jumping around randomly when elements change. - height: 590px; + height: 600px; padding-left: 20px; // the design wants some padding on the left + display: flex; + flex-direction: column; + + .mx_InviteDialog_content { + overflow: hidden; + } } .mx_InviteDialog_userSections { margin-top: 10px; overflow-y: auto; padding-right: 45px; - height: 455px; // mx_InviteDialog's height minus some for the upper elements + height: calc(100% - 190px); // mx_InviteDialog's height minus some for the upper elements } // Right margin for the design. We could apply this to the whole dialog, but then the scrollbar diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index ec9c71ccbe..22763ceda2 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -47,6 +47,11 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import {replaceableComponent} from "../../../utils/replaceableComponent"; import {mediaFromMxc} from "../../../customisations/Media"; import {getAddressType} from "../../../UserAddress"; +import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; +import {copyPlaintext, selectText} from "../../../utils/strings"; +import * as ContextMenu from "../../structures/ContextMenu"; +import {toRightOf} from "../../structures/ContextMenu"; +import GenericTextContextMenu from "../context_menus/GenericTextContextMenu"; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ @@ -349,6 +354,7 @@ export default class InviteDialog extends React.PureComponent void; _debounceTimer: NodeJS.Timeout = null; // actually number because we're in the browser _editorRef: any = null; @@ -400,6 +406,12 @@ export default class InviteDialog extends React.PureComponent { this.setState({consultFirst: ev.target.checked}); } @@ -1232,6 +1244,25 @@ export default class InviteDialog extends React.PureComponent; } - let title; let helpText; let buttonText; let goButtonFn; - let consultSection; + let extraSection; + let footer; let keySharingWarning = ; const identityServersEnabled = SettingsStore.getValue(UIFeature.IdentityServer); @@ -1310,6 +1341,24 @@ export default class InviteDialog extends React.PureComponent + { _t("Some results may be hidden for privacy.") } +

{ _t("If you can’t see who you’re looking for, send them your invite link below.") }

+
; + const link = makeUserPermalink(MatrixClientPeg.get().getUserId()); + footer =
+

{ _t("Or send invite link") }

+ +
} else if (this.props.kind === KIND_INVITE) { const room = MatrixClientPeg.get()?.getRoom(this.props.roomId); const isSpace = SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom(); @@ -1371,7 +1420,7 @@ export default class InviteDialog extends React.PureComponent + footer =
- {consultSection} + {footer}
); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1b04ae3b89..9767d7ac76 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2246,6 +2246,9 @@ "Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).", "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", + "Some results may be hidden for privacy.": "Some results may be hidden for privacy.", + "If you can’t see who you’re looking for, send them your invite link below.": "If you can’t see who you’re looking for, send them your invite link below.", + "Or send invite link": "Or send invite link", "Unnamed Space": "Unnamed Space", "Invite to %(roomName)s": "Invite to %(roomName)s", "Invite someone using their name, email address, username (like ) or share this space.": "Invite someone using their name, email address, username (like ) or share this space.", From 2c750fcb7a3bc7317b4b8b0e6013aa3f43e584a8 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 28 May 2021 12:48:12 +0100 Subject: [PATCH 034/134] Fix overflow issue in suggestion tiles --- res/css/views/dialogs/_InviteDialog.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index a33871eca5..4016e7d2e3 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -193,6 +193,7 @@ limitations under the License. .mx_InviteDialog_roomTile_nameStack { display: inline-block; + overflow: hidden; } .mx_InviteDialog_roomTile_name { @@ -208,6 +209,13 @@ limitations under the License. margin-left: 7px; } + .mx_InviteDialog_roomTile_name, + .mx_InviteDialog_roomTile_userId { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .mx_InviteDialog_roomTile_time { text-align: right; font-size: $font-12px; From ea263937095053bf10ded22c2e0a7ec3da8e7cb5 Mon Sep 17 00:00:00 2001 From: Nique Woodhouse Date: Fri, 28 May 2021 13:00:18 +0100 Subject: [PATCH 035/134] Styling amends to accommodate the invite dialog footer --- res/css/views/dialogs/_InviteDialog.scss | 34 ++++++++++++++----- src/components/views/dialogs/InviteDialog.tsx | 4 +-- src/i18n/strings/en_EN.json | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index a33871eca5..bda576c44e 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -73,7 +73,7 @@ limitations under the License. } .mx_InviteDialog_section { - padding-bottom: 10px; + padding-bottom: 4px; h3 { font-size: $font-12px; @@ -98,11 +98,25 @@ limitations under the License. } } +.mx_InviteDialog_section_hidden_suggestions_disclaimer { + padding: 8px 0 16px 0; + font-size: $font-14px; + + > span { + color: $primary-fg-color; + font-weight: 600; + } + + > p { + margin:0; + } +} + .mx_InviteDialog_footer { border-top: 1px solid $input-border-color; > h3 { - margin: 8px 0; + margin: 12px 0; font-size: $font-12px; color: $muted-fg-color; font-weight: bold; @@ -113,7 +127,7 @@ limitations under the License. display: flex; justify-content: space-between; border-radius: 4px; - border: solid 1px $input-border-color; + border: solid 1px $light-fg-color; padding: 8px; > a { @@ -274,17 +288,21 @@ limitations under the License. } .mx_InviteDialog_userSections { - margin-top: 10px; + margin-top: 4px; overflow-y: auto; - padding-right: 45px; - height: calc(100% - 190px); // mx_InviteDialog's height minus some for the upper elements + padding: 0px 45px 4px 0px; + height: calc(100% - 175px); // mx_InviteDialog's height minus some for the upper and lower elements } + // Right margin for the design. We could apply this to the whole dialog, but then the scrollbar // for the user section gets weird. -.mx_InviteDialog_helpText, .mx_InviteDialog_addressBar { - margin-right: 45px; + margin: 8px 45px 0px 0px; +} + +.mx_InviteDialog_helpText { + margin:0px; } .mx_InviteDialog_helpText .mx_AccessibleButton_kind_link { diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 22763ceda2..081004fa74 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -1341,8 +1341,8 @@ export default class InviteDialog extends React.PureComponent - { _t("Some results may be hidden for privacy.") } + extraSection =
+ { _t("Some suggestions may be hidden for privacy.") }

{ _t("If you can’t see who you’re looking for, send them your invite link below.") }

; const link = makeUserPermalink(MatrixClientPeg.get().getUserId()); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9767d7ac76..8f5082e88a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2246,7 +2246,7 @@ "Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).", "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", - "Some results may be hidden for privacy.": "Some results may be hidden for privacy.", + "Some suggestions may be hidden for privacy.": "Some suggestions may be hidden for privacy.", "If you can’t see who you’re looking for, send them your invite link below.": "If you can’t see who you’re looking for, send them your invite link below.", "Or send invite link": "Or send invite link", "Unnamed Space": "Unnamed Space", From 36e43270ca6acd79ad5244ec83b96344fd766592 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 28 May 2021 13:08:05 +0100 Subject: [PATCH 036/134] Apply suggestions from code review --- res/css/views/dialogs/_InviteDialog.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index 0d78589db2..bae086c7d5 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -108,7 +108,7 @@ limitations under the License. } > p { - margin:0; + margin: 0; } } @@ -298,7 +298,7 @@ limitations under the License. .mx_InviteDialog_userSections { margin-top: 4px; overflow-y: auto; - padding: 0px 45px 4px 0px; + padding: 0 45px 4px 0; height: calc(100% - 175px); // mx_InviteDialog's height minus some for the upper and lower elements } @@ -306,11 +306,11 @@ limitations under the License. // Right margin for the design. We could apply this to the whole dialog, but then the scrollbar // for the user section gets weird. .mx_InviteDialog_addressBar { - margin: 8px 45px 0px 0px; + margin: 8px 45px 0 0; } .mx_InviteDialog_helpText { - margin:0px; + margin: 0; } .mx_InviteDialog_helpText .mx_AccessibleButton_kind_link { From caaef630776a07c69654393a37bd62bb56398566 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 28 May 2021 13:11:48 +0100 Subject: [PATCH 037/134] delint1 --- res/css/views/dialogs/_InviteDialog.scss | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index bae086c7d5..8c0421b989 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -17,6 +17,9 @@ limitations under the License. .mx_InviteDialog_addressBar { display: flex; flex-direction: row; + // Right margin for the design. We could apply this to the whole dialog, but then the scrollbar + // for the user section gets weird. + margin: 8px 45px 0 0; .mx_InviteDialog_editor { flex: 1; @@ -127,7 +130,7 @@ limitations under the License. display: flex; justify-content: space-between; border-radius: 4px; - border: solid 1px $light-fg-color; + border: solid 1px $light-fg-color; padding: 8px; > a { @@ -302,13 +305,6 @@ limitations under the License. height: calc(100% - 175px); // mx_InviteDialog's height minus some for the upper and lower elements } - -// Right margin for the design. We could apply this to the whole dialog, but then the scrollbar -// for the user section gets weird. -.mx_InviteDialog_addressBar { - margin: 8px 45px 0 0; -} - .mx_InviteDialog_helpText { margin: 0; } From 91b7f2551312c405257421221b4d237a3bd96682 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 28 May 2021 13:51:54 +0100 Subject: [PATCH 038/134] delint2 --- src/components/views/dialogs/InviteDialog.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 7cee61d579..ef7a31a177 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -408,9 +408,6 @@ export default class InviteDialog extends React.PureComponent Date: Sat, 29 May 2021 01:37:19 -0500 Subject: [PATCH 039/134] Don't include via when sharing room alias Signed-off-by: Aaron Raimist --- src/utils/permalinks/Permalinks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index d87c826cc2..cecd79dd53 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -149,7 +149,7 @@ export class RoomPermalinkCreator { // Prefer to use canonical alias for permalink if possible const alias = this.room.getCanonicalAlias(); if (alias) { - return getPermalinkConstructor().forRoom(alias, this._serverCandidates); + return getPermalinkConstructor().forRoom(alias); } } return getPermalinkConstructor().forRoom(this.roomId, this._serverCandidates); From ccdd2311f447111f4cf56725834ba08be78abc08 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Sat, 29 May 2021 01:38:41 -0500 Subject: [PATCH 040/134] Make "share this room" use aliases if possible Signed-off-by: Aaron Raimist --- src/utils/permalinks/Permalinks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index cecd79dd53..2f268aaa0c 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -293,16 +293,16 @@ export function makeRoomPermalink(roomId: string): string { // If the roomId isn't actually a room ID, don't try to list the servers. // Aliases are already routable, and don't need extra information. - if (roomId[0] !== '!') return getPermalinkConstructor().forRoom(roomId, []); + if (roomId[0] !== '!') return getPermalinkConstructor().forShareableRoom(roomId, []); const client = MatrixClientPeg.get(); const room = client.getRoom(roomId); if (!room) { - return getPermalinkConstructor().forRoom(roomId, []); + return getPermalinkConstructor().forShareableRoom(roomId, []); } const permalinkCreator = new RoomPermalinkCreator(room); permalinkCreator.load(); - return permalinkCreator.forRoom(); + return permalinkCreator.forShareableRoom(); } export function makeGroupPermalink(groupId: string): string { From 0c5e8ef381815725656c6619364fb54089a53137 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 1 Jun 2021 16:13:01 +0100 Subject: [PATCH 041/134] Upgrade matrix-js-sdk to 11.2.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 13047b69cf..108a61cdaf 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,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": "11.2.0-rc.1", "matrix-widget-api": "^0.1.0-beta.14", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 0ff235a660..1b07d4502b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5673,9 +5673,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 "11.1.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/acb9bc8cc5234326a7583514a8e120a4ac42eedc" +matrix-js-sdk@11.2.0-rc.1: + version "11.2.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-11.2.0-rc.1.tgz#339259d892ce08195864c1130780dd0b3d996af3" + integrity sha512-ACFONqdRqiPIj7aWf7G4f/2d0S/hfouIH6tdkFGDbizbWJCmqXRJ8EN2gmu0F3A6GGDo0+k9cqaeMf3Y1KIM8w== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From d02f462df9a3cd0a336aea733c2992abcbc07b2d Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 1 Jun 2021 16:18:25 +0100 Subject: [PATCH 042/134] Prepare changelog for v3.23.0-rc.1 --- CHANGELOG.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d9afd51d..a3abd1f32b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,101 @@ +Changes in [3.23.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.23.0-rc.1) (2021-06-01) +=============================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.22.0...v3.23.0-rc.1) + + * Upgrade to JS SDK 11.2.0-rc.1 + * Translations update from Weblate + [\#6128](https://github.com/matrix-org/matrix-react-sdk/pull/6128) + * Fix all DMs wrongly appearing in room list when `m.direct` is changed + [\#6122](https://github.com/matrix-org/matrix-react-sdk/pull/6122) + * Update way of checking for registration disabled + [\#6123](https://github.com/matrix-org/matrix-react-sdk/pull/6123) + * Fix the ability to remove avatar from a space via settings + [\#6126](https://github.com/matrix-org/matrix-react-sdk/pull/6126) + * Switch to stable endpoint/fields for MSC2858 + [\#6125](https://github.com/matrix-org/matrix-react-sdk/pull/6125) + * Clear stored editor state when canceling editing using a shortcut + [\#6117](https://github.com/matrix-org/matrix-react-sdk/pull/6117) + * Respect newlines in space topics + [\#6124](https://github.com/matrix-org/matrix-react-sdk/pull/6124) + * Add url param `defaultUsername` to prefill the login username field + [\#5674](https://github.com/matrix-org/matrix-react-sdk/pull/5674) + * Bump ws from 7.4.2 to 7.4.6 + [\#6115](https://github.com/matrix-org/matrix-react-sdk/pull/6115) + * Sticky headers repositioning without layout trashing + [\#6110](https://github.com/matrix-org/matrix-react-sdk/pull/6110) + * Handle user_busy in voip calls + [\#6112](https://github.com/matrix-org/matrix-react-sdk/pull/6112) + * Avoid showing warning modals from the invite dialog after it unmounts + [\#6105](https://github.com/matrix-org/matrix-react-sdk/pull/6105) + * Fix misleading child counts in spaces + [\#6109](https://github.com/matrix-org/matrix-react-sdk/pull/6109) + * Close creation menu when expanding space panel via expand hierarchy + [\#6090](https://github.com/matrix-org/matrix-react-sdk/pull/6090) + * Prevent having duplicates in pending room state + [\#6108](https://github.com/matrix-org/matrix-react-sdk/pull/6108) + * Update reactions row on event decryption + [\#6106](https://github.com/matrix-org/matrix-react-sdk/pull/6106) + * Destroy playback instance on voice message unmount + [\#6101](https://github.com/matrix-org/matrix-react-sdk/pull/6101) + * Fix message preview not up to date + [\#6102](https://github.com/matrix-org/matrix-react-sdk/pull/6102) + * Convert some Flow typed files to TS (round 2) + [\#6076](https://github.com/matrix-org/matrix-react-sdk/pull/6076) + * Remove unused middlePanelResized event listener + [\#6086](https://github.com/matrix-org/matrix-react-sdk/pull/6086) + * Fix accessing currentState on an invalid joinedRoom + [\#6100](https://github.com/matrix-org/matrix-react-sdk/pull/6100) + * Remove Promise allSettled polyfill as js-sdk uses it directly + [\#6097](https://github.com/matrix-org/matrix-react-sdk/pull/6097) + * Prevent DecoratedRoomAvatar to update its state for the same value + [\#6099](https://github.com/matrix-org/matrix-react-sdk/pull/6099) + * Skip generatePreview if event is not part of the live timeline + [\#6098](https://github.com/matrix-org/matrix-react-sdk/pull/6098) + * fix sticky headers when results num get displayed + [\#6095](https://github.com/matrix-org/matrix-react-sdk/pull/6095) + * Improve addEventsToTimeline performance scoping WhoIsTypingTile::setState + [\#6094](https://github.com/matrix-org/matrix-react-sdk/pull/6094) + * Safeguards to prevent layout trashing for window dimensions + [\#6092](https://github.com/matrix-org/matrix-react-sdk/pull/6092) + * Use local room state to render space hierarchy if the room is known + [\#6089](https://github.com/matrix-org/matrix-react-sdk/pull/6089) + * Add spinner in UserMenu to list pending long running actions + [\#6085](https://github.com/matrix-org/matrix-react-sdk/pull/6085) + * Stop overscroll in Firefox Nightly for macOS + [\#6093](https://github.com/matrix-org/matrix-react-sdk/pull/6093) + * Move SettingsStore watchers/monitors over to ES6 maps for performance + [\#6063](https://github.com/matrix-org/matrix-react-sdk/pull/6063) + * Bump libolm version. + [\#6080](https://github.com/matrix-org/matrix-react-sdk/pull/6080) + * Improve styling of the message action bar + [\#6066](https://github.com/matrix-org/matrix-react-sdk/pull/6066) + * Improve explore rooms when no results are found + [\#6070](https://github.com/matrix-org/matrix-react-sdk/pull/6070) + * Remove logo spinner + [\#6078](https://github.com/matrix-org/matrix-react-sdk/pull/6078) + * Fix add reaction prompt showing even when user is not joined to room + [\#6073](https://github.com/matrix-org/matrix-react-sdk/pull/6073) + * Vectorize spinners + [\#5680](https://github.com/matrix-org/matrix-react-sdk/pull/5680) + * Fix handling of via servers for suggested rooms + [\#6077](https://github.com/matrix-org/matrix-react-sdk/pull/6077) + * Upgrade showChatEffects to room-level setting exposure + [\#6075](https://github.com/matrix-org/matrix-react-sdk/pull/6075) + * Delete RoomView dead code + [\#6071](https://github.com/matrix-org/matrix-react-sdk/pull/6071) + * Reduce noise in tests + [\#6074](https://github.com/matrix-org/matrix-react-sdk/pull/6074) + * Fix room name issues in right panel summary card + [\#6069](https://github.com/matrix-org/matrix-react-sdk/pull/6069) + * Cache normalized room name + [\#6072](https://github.com/matrix-org/matrix-react-sdk/pull/6072) + * Update MemberList to reflect changes for invite permission change + [\#6061](https://github.com/matrix-org/matrix-react-sdk/pull/6061) + * Delete RoomView dead code + [\#6065](https://github.com/matrix-org/matrix-react-sdk/pull/6065) + * Show subspace rooms count even if it is 0 for consistency + [\#6067](https://github.com/matrix-org/matrix-react-sdk/pull/6067) + Changes in [3.22.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.22.0) (2021-05-24) ===================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.22.0-rc.1...v3.22.0) From 300b0016d60fd3f3b0527e68f987df3731f2feb0 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Tue, 1 Jun 2021 16:18:26 +0100 Subject: [PATCH 043/134] v3.23.0-rc.1 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 108a61cdaf..4f6a023383 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.22.0", + "version": "3.23.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", @@ -200,5 +200,6 @@ "coverageReporters": [ "text" ] - } + }, + "typings": "./lib/index.d.ts" } From b032422c6a536b856d7d105dd593a804b245c933 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 1 Jun 2021 17:37:31 -0400 Subject: [PATCH 044/134] Fix whitespace lints Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 59475b1b51..58759d7d42 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -184,13 +184,13 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr const previewLayout = SettingsStore.getValue("layout"); return -

{ _t("Message preview") }

+

{_t("Message preview")}

= ({ matrixClient: cli, event, permalinkCr
Date: Tue, 1 Jun 2021 17:56:46 -0400 Subject: [PATCH 045/134] Match forward dialog send failed indicator color with button Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 593fe12531..fc59259ca2 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -124,7 +124,8 @@ limitations under the License. } .mx_NotificationBadge { - opacity: 0.4; + // Match the failed to send indicator's color with the disabled button + background-color: $button-danger-disabled-fg-color; } &.mx_ForwardList_sending .mx_ForwardList_sendIcon { From c78167977a49421156f62d995cf5aab97801a758 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 1 Jun 2021 17:57:26 -0400 Subject: [PATCH 046/134] Remove unused class Signed-off-by: Robin Townsend --- src/components/views/context_menus/MessageContextMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 08fc5844ec..442470bb52 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -161,7 +161,7 @@ export default class MessageContextMenu extends React.Component { matrixClient: MatrixClientPeg.get(), event: this.props.mxEvent, permalinkCreator: this.props.permalinkCreator, - }, 'mx_Dialog_forwardMessage'); + }); this.closeMenu(); }; From 4ef69fcbf6cd5bb90261759eff4cd3e720a96f14 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 1 Jun 2021 18:09:51 -0400 Subject: [PATCH 047/134] Use settings hooks in forward dialog ...to dynamically watch for layout changes. Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 58759d7d42..2c4920da4b 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -22,7 +22,7 @@ import {MatrixClient} from "matrix-js-sdk/src/client"; import {_t} from "../../../languageHandler"; import dis from "../../../dispatcher/dispatcher"; -import SettingsStore from "../../../settings/SettingsStore"; +import {useSettingValue, useFeatureEnabled} from "../../../hooks/useSettings"; import {UIFeature} from "../../../settings/UIFeature"; import {Layout} from "../../../settings/Layout"; import {IDialogProps} from "./IDialogProps"; @@ -174,14 +174,16 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr const [query, setQuery] = useState(""); const lcQuery = query.toLowerCase(); + const spacesEnabled = useFeatureEnabled("feature_spaces"); + const flairEnabled = useFeatureEnabled(UIFeature.Flair); + const previewLayout = useSettingValue("layout"); + const rooms = useMemo(() => sortRooms( cli.getVisibleRooms().filter( room => room.getMyMembership() === "join" && - !(SettingsStore.getValue("feature_spaces") && room.isSpaceRoom()), + !(spacesEnabled && room.isSpaceRoom()), ), - ), [cli]).filter(room => room.name.toLowerCase().includes(lcQuery)); - - const previewLayout = SettingsStore.getValue("layout"); + ), [cli, spacesEnabled]).filter(room => room.name.toLowerCase().includes(lcQuery)); return = ({ matrixClient: cli, event, permalinkCr
From 59660df0cbe74dbe39ada90e4296d427e5375bbc Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 1 Jun 2021 20:17:20 -0400 Subject: [PATCH 048/134] Use a QueryMatcher for forward dialog filtering This also allows us to filter by room aliases. Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 15 ++++++++++++--- src/hooks/useSettings.ts | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 2c4920da4b..cba292ea25 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -38,6 +38,7 @@ import {StaticNotificationState} from "../../../stores/notifications/StaticNotif import NotificationBadge from "../rooms/NotificationBadge"; import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; +import QueryMatcher from "../../../autocomplete/QueryMatcher"; const AVATAR_SIZE = 30; @@ -176,14 +177,22 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr const spacesEnabled = useFeatureEnabled("feature_spaces"); const flairEnabled = useFeatureEnabled(UIFeature.Flair); - const previewLayout = useSettingValue("layout"); + const previewLayout = useSettingValue("layout"); - const rooms = useMemo(() => sortRooms( + let rooms = useMemo(() => sortRooms( cli.getVisibleRooms().filter( room => room.getMyMembership() === "join" && !(spacesEnabled && room.isSpaceRoom()), ), - ), [cli, spacesEnabled]).filter(room => room.name.toLowerCase().includes(lcQuery)); + ), [cli, spacesEnabled]); + + if (lcQuery) { + rooms = new QueryMatcher(rooms, { + keys: ["name"], + funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)], + shouldMatchWordsOnly: false, + }).match(lcQuery); + } return (settingName: string, roomId: string = null, e }; // Hook to fetch whether a feature is enabled and dynamically update when that changes -export const useFeatureEnabled = (featureName: string, roomId: string = null) => { - const [enabled, setEnabled] = useState(SettingsStore.getValue(featureName, roomId)); +export const useFeatureEnabled = (featureName: string, roomId: string = null): boolean => { + const [enabled, setEnabled] = useState(SettingsStore.getValue(featureName, roomId)); useEffect(() => { const ref = SettingsStore.watchSetting(featureName, roomId, () => { From 992861a1cd821c2d7564fd644b4294220f54ff96 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 1 Jun 2021 20:36:28 -0400 Subject: [PATCH 049/134] Fix forward dialog tests Signed-off-by: Robin Townsend --- test/test-utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-utils.js b/test/test-utils.js index c82885b5f0..6053924103 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -265,6 +265,8 @@ export function mkStubRoom(roomId = null, name) { isSpaceRoom: jest.fn(() => false), getUnreadNotificationCount: jest.fn(() => 0), getEventReadUpTo: jest.fn(() => null), + getCanonicalAlias: jest.fn(), + getAltAliases: jest.fn().mockReturnValue([]), timeline: [], }; } From 0c97d90fb98f08204c1d7853e0c0f6c30820e5a3 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 3 Jun 2021 16:44:28 +0100 Subject: [PATCH 050/134] Iterate PR based on feedback --- res/css/views/dialogs/_InviteDialog.scss | 6 +++++- src/components/views/dialogs/InviteDialog.tsx | 16 +++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index 8c0421b989..2e48b5d8e9 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -302,7 +302,11 @@ limitations under the License. margin-top: 4px; overflow-y: auto; padding: 0 45px 4px 0; - height: calc(100% - 175px); // mx_InviteDialog's height minus some for the upper and lower elements + height: calc(100% - 115px); // mx_InviteDialog's height minus some for the upper and lower elements +} + +.mx_InviteDialog_hasFooter .mx_InviteDialog_userSections { + height: calc(100% - 175px); } .mx_InviteDialog_helpText { diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 5cbcb12c4f..557ea416a8 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -14,7 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; +import classNames from 'classnames'; + import {_t, _td} from "../../../languageHandler"; import * as sdk from "../../../index"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; @@ -1252,7 +1254,7 @@ export default class InviteDialog extends React.PureComponent { e.preventDefault(); const target = e.target; // copy target before we go async and React throws it away @@ -1264,7 +1266,7 @@ export default class InviteDialog extends React.PureComponent + > +
+
} else if (this.props.kind === KIND_INVITE) { @@ -1437,7 +1441,9 @@ export default class InviteDialog extends React.PureComponent Date: Fri, 4 Jun 2021 11:34:54 +0100 Subject: [PATCH 051/134] Fix unpinning of pinned messages --- src/components/views/right_panel/PinnedMessagesCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index a3f1f2d9df..55809ee02b 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -155,7 +155,7 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { // show them in reverse, with latest pinned at the top content = pinnedEvents.filter(Boolean).reverse().map(ev => ( - + onUnpinClicked(ev)} /> )); } else { content =
From 93f41ce0ab484172a76f0e07e4036eace2fe9bce Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 4 Jun 2021 11:35:17 +0100 Subject: [PATCH 052/134] Actually finish the empty state for the pinned messages card --- .../right_panel/_PinnedMessagesCard.scss | 55 +++++++++++++++++++ .../views/right_panel/PinnedMessagesCard.tsx | 17 +++++- src/i18n/strings/en_EN.json | 6 +- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/res/css/views/right_panel/_PinnedMessagesCard.scss b/res/css/views/right_panel/_PinnedMessagesCard.scss index b6b8238bed..785aee09ca 100644 --- a/res/css/views/right_panel/_PinnedMessagesCard.scss +++ b/res/css/views/right_panel/_PinnedMessagesCard.scss @@ -32,4 +32,59 @@ limitations under the License. margin-right: 6px; } } + + .mx_PinnedMessagesCard_empty { + display: flex; + height: 100%; + + > div { + height: max-content; + text-align: center; + margin: auto 40px; + + .mx_PinnedMessagesCard_MessageActionBar { + pointer-events: none; + display: flex; + height: 32px; + line-height: $font-24px; + border-radius: 8px; + background: $primary-bg-color; + border: 1px solid $input-border-color; + padding: 1px; + width: max-content; + margin: 0 auto; + box-sizing: border-box; + + .mx_MessageActionBar_maskButton { + display: inline-block; + position: relative; + } + + .mx_MessageActionBar_optionsButton { + background: $roomlist-button-bg-color; + border-radius: 6px; + z-index: 1; + + &::after { + background-color: $primary-fg-color; + } + } + } + + > h2 { + font-weight: $font-semi-bold; + font-size: $font-15px; + line-height: $font-24px; + color: $primary-fg-color; + margin-top: 24px; + margin-bottom: 20px; + } + + > span { + font-size: $font-12px; + line-height: $font-15px; + color: $secondary-fg-color; + } + } + } } diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index 55809ee02b..3a4dc9cc92 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -158,9 +158,20 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { onUnpinClicked(ev)} /> )); } else { - content =
-

{_t("You’re all caught up")}

-

{_t("You have no visible notifications.")}

+ content =
+
+
+
+
+
+
+ +

{ _t("Nothing pinned, yet") }

+ { _t("If you have permissions, open the menu on any message and select " + + "Pin to stick them here.", {}, { + b: sub => { sub }, + }) } +
; } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9e85ea28c8..302c8709fa 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1717,8 +1717,8 @@ "The homeserver the user you’re verifying is connected to": "The homeserver the user you’re verifying is connected to", "Yours, or the other users’ internet connection": "Yours, or the other users’ internet connection", "Yours, or the other users’ session": "Yours, or the other users’ session", - "You’re all caught up": "You’re all caught up", - "You have no visible notifications.": "You have no visible notifications.", + "Nothing pinned, yet": "Nothing pinned, yet", + "If you have permissions, open the menu on any message and select Pin to stick them here.": "If you have permissions, open the menu on any message and select Pin to stick them here.", "Pinned messages": "Pinned messages", "Room Info": "Room Info", "You can only pin up to %(count)s widgets|other": "You can only pin up to %(count)s widgets", @@ -2628,6 +2628,8 @@ "Create a new community": "Create a new community", "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.": "Create a community to group together users and rooms! Build a custom homepage to mark out your space in the Matrix universe.", "Communities are changing to Spaces": "Communities are changing to Spaces", + "You’re all caught up": "You’re all caught up", + "You have no visible notifications.": "You have no visible notifications.", "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.": "%(brand)s failed to get the protocol list from the homeserver. The homeserver may be too old to support third party networks.", "%(brand)s failed to get the public room list.": "%(brand)s failed to get the public room list.", "The homeserver may be unavailable or overloaded.": "The homeserver may be unavailable or overloaded.", From 40d2f8228f4d2a3f7f386d320c42ae1970932ee4 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 01:16:52 -0400 Subject: [PATCH 053/134] Fix watching settings An accidental variable shadowing was preventing setting watcher callbacks from being fired. Signed-off-by: Robin Townsend --- src/settings/WatchManager.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/settings/WatchManager.ts b/src/settings/WatchManager.ts index 56f911f180..744d75b136 100644 --- a/src/settings/WatchManager.ts +++ b/src/settings/WatchManager.ts @@ -63,8 +63,7 @@ export class WatchManager { if (!inRoomId) { // Fire updates to all the individual room watchers too, as they probably care about the change higher up. - const callbacks = Array.from(roomWatchers.values()).flat(1); - callbacks.push(...callbacks); + callbacks.push(...Array.from(roomWatchers.values()).flat(1)); } else if (roomWatchers.has(IRRELEVANT_ROOM)) { callbacks.push(...roomWatchers.get(IRRELEVANT_ROOM)); } From 48d3e41351bd869c232176d956d8254d17f5dc77 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 01:23:51 -0400 Subject: [PATCH 054/134] Cache frequently used settings values in RoomContext Signed-off-by: Robin Townsend --- src/components/structures/RoomView.tsx | 64 +++++++++++++++++++++----- src/contexts/RoomContext.ts | 6 ++- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 5ffc2fd0da..fa67013ccb 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -155,7 +155,6 @@ export interface IState { canPeek: boolean; showApps: boolean; isPeeking: boolean; - showReadReceipts: boolean; showRightPanel: boolean; // error object, as from the matrix client/server API // If we failed to load information about the room, @@ -183,6 +182,11 @@ export interface IState { canReact: boolean; canReply: boolean; layout: Layout; + showReadReceipts: boolean; + showRedactions: boolean; + showJoinLeaves: boolean; + showAvatarChanges: boolean; + showDisplaynameChanges: boolean; matrixClientIsReady: boolean; showUrlPreview?: boolean; e2eStatus?: E2EStatus; @@ -200,8 +204,7 @@ export default class RoomView extends React.Component { private readonly dispatcherRef: string; private readonly roomStoreToken: EventSubscription; private readonly rightPanelStoreToken: EventSubscription; - private readonly showReadReceiptsWatchRef: string; - private readonly layoutWatcherRef: string; + private settingWatchers: string[]; private unmounted = false; private permalinkCreators: Record = {}; @@ -232,7 +235,6 @@ export default class RoomView extends React.Component { canPeek: false, showApps: false, isPeeking: false, - showReadReceipts: true, showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom, joining: false, atEndOfLiveTimeline: true, @@ -242,6 +244,11 @@ export default class RoomView extends React.Component { canReact: false, canReply: false, layout: SettingsStore.getValue("layout"), + showReadReceipts: true, + showRedactions: true, + showJoinLeaves: true, + showAvatarChanges: true, + showDisplaynameChanges: true, matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), dragCounter: 0, }; @@ -268,9 +275,11 @@ export default class RoomView extends React.Component { WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate); WidgetStore.instance.on(UPDATE_EVENT, this.onWidgetStoreUpdate); - this.showReadReceiptsWatchRef = SettingsStore.watchSetting("showReadReceipts", null, - this.onReadReceiptsChange); - this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, this.onLayoutChange); + this.settingWatchers = [ + SettingsStore.watchSetting("layout", null, () => + this.setState({ layout: SettingsStore.getValue("layout") }), + ), + ]; } private onWidgetStoreUpdate = () => { @@ -327,9 +336,42 @@ export default class RoomView extends React.Component { // we should only peek once we have a ready client shouldPeek: this.state.matrixClientIsReady && RoomViewStore.shouldPeek(), showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId), + showRedactions: SettingsStore.getValue("showRedactions", roomId), + showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId), + showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId), + showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId), wasContextSwitch: RoomViewStore.getWasContextSwitch(), }; + // Add watchers for each of the settings we just looked up + this.settingWatchers = this.settingWatchers.concat([ + SettingsStore.watchSetting("showReadReceipts", null, () => + this.setState({ + showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId), + }), + ), + SettingsStore.watchSetting("showRedactions", null, () => + this.setState({ + showRedactions: SettingsStore.getValue("showRedactions", roomId), + }), + ), + SettingsStore.watchSetting("showJoinLeaves", null, () => + this.setState({ + showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId), + }), + ), + SettingsStore.watchSetting("showAvatarChanges", null, () => + this.setState({ + showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId), + }), + ), + SettingsStore.watchSetting("showDisplaynameChanges", null, () => + this.setState({ + showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId), + }), + ), + ]); + if (!initial && this.state.shouldPeek && !newState.shouldPeek) { // Stop peeking because we have joined this room now this.context.stopPeeking(); @@ -638,10 +680,6 @@ export default class RoomView extends React.Component { ); } - if (this.showReadReceiptsWatchRef) { - SettingsStore.unwatchSetting(this.showReadReceiptsWatchRef); - } - // cancel any pending calls to the rate_limited_funcs this.updateRoomMembers.cancelPendingCall(); @@ -649,7 +687,9 @@ export default class RoomView extends React.Component { // console.log("Tinter.tint from RoomView.unmount"); // Tinter.tint(); // reset colourscheme - SettingsStore.unwatchSetting(this.layoutWatcherRef); + for (const watcher of this.settingWatchers) { + SettingsStore.unwatchSetting(watcher); + } } private onUserScroll = () => { diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts index e925f8624b..1efa1c03e7 100644 --- a/src/contexts/RoomContext.ts +++ b/src/contexts/RoomContext.ts @@ -31,7 +31,6 @@ const RoomContext = createContext({ canPeek: false, showApps: false, isPeeking: false, - showReadReceipts: true, showRightPanel: true, joining: false, atEndOfLiveTimeline: true, @@ -41,6 +40,11 @@ const RoomContext = createContext({ canReact: false, canReply: false, layout: Layout.Group, + showReadReceipts: true, + showRedactions: true, + showJoinLeaves: true, + showAvatarChanges: true, + showDisplaynameChanges: true, matrixClientIsReady: false, dragCounter: 0, }); From 13196b8146919f8ef781904d02c1edfd5f376dfe Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 01:25:01 -0400 Subject: [PATCH 055/134] Prefer cached settings values in shouldHideEvent Signed-off-by: Robin Townsend --- src/shouldHideEvent.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/shouldHideEvent.ts b/src/shouldHideEvent.ts index 2a47b9c417..31d610b28b 100644 --- a/src/shouldHideEvent.ts +++ b/src/shouldHideEvent.ts @@ -17,6 +17,7 @@ import {MatrixEvent} from "matrix-js-sdk/src/models/event"; import SettingsStore from "./settings/SettingsStore"; +import {IState} from "./components/structures/RoomView"; interface IDiff { isMemberEvent: boolean; @@ -47,11 +48,18 @@ function memberEventDiff(ev: MatrixEvent): IDiff { return diff; } -export default function shouldHideEvent(ev: MatrixEvent): boolean { - // Wrap getValue() for readability. Calling the SettingsStore can be - // fairly resource heavy, so the checks below should avoid hitting it - // where possible. - const isEnabled = (name) => SettingsStore.getValue(name, ev.getRoomId()); +/** + * Determines whether the given event should be hidden from timelines. + * @param ev The event + * @param ctx An optional RoomContext to pull cached settings values from to avoid + * hitting the settings store + */ +export default function shouldHideEvent(ev: MatrixEvent, ctx?: IState): boolean { + // Accessing the settings store directly can be expensive if done frequently, + // so we should prefer using cached values if a RoomContext is available + const isEnabled = ctx ? + name => ctx[name] : + name => SettingsStore.getValue(name, ev.getRoomId()); // Hide redacted events if (ev.isRedacted() && !isEnabled('showRedactions')) return true; From 3bf8e54d7f37477868c1fa229449749bd02f2894 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 01:25:43 -0400 Subject: [PATCH 056/134] Use cached RoomContext settings values throughout rooms Signed-off-by: Robin Townsend --- src/components/structures/MessagePanel.js | 5 ++++- src/components/structures/RoomView.tsx | 2 +- src/components/structures/TimelinePanel.js | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index 6709fef814..bca62e7b2f 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -26,6 +26,7 @@ import * as sdk from '../../index'; import {MatrixClientPeg} from '../../MatrixClientPeg'; import SettingsStore from '../../settings/SettingsStore'; +import RoomContext from "../../contexts/RoomContext"; import {Layout, LayoutPropType} from "../../settings/Layout"; import {_t} from "../../languageHandler"; import {haveTileForEvent} from "../views/rooms/EventTile"; @@ -152,6 +153,8 @@ export default class MessagePanel extends React.Component { enableFlair: PropTypes.bool, }; + static contextType = RoomContext; + constructor(props) { super(props); @@ -381,7 +384,7 @@ export default class MessagePanel extends React.Component { // Always show highlighted event if (this.props.highlightedEventId === mxEv.getId()) return true; - return !shouldHideEvent(mxEv); + return !shouldHideEvent(mxEv, this.context); } _readMarkerForEvent(eventId, isLastEvent) { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index fa67013ccb..b80d909a94 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -859,7 +859,7 @@ export default class RoomView extends React.Component { // update unread count when scrolled up if (!this.state.searchResults && this.state.atEndOfLiveTimeline) { // no change - } else if (!shouldHideEvent(ev)) { + } else if (!shouldHideEvent(ev, this.state)) { this.setState((state, props) => { return {numUnreadMessages: state.numUnreadMessages + 1}; }); diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 6300c7532e..c5ae2e87ba 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -26,6 +26,7 @@ import {EventTimeline} from "matrix-js-sdk/src/models/event-timeline"; import {TimelineWindow} from "matrix-js-sdk/src/timeline-window"; import { _t } from '../../languageHandler'; import {MatrixClientPeg} from "../../MatrixClientPeg"; +import RoomContext from "../../contexts/RoomContext"; import UserActivity from "../../UserActivity"; import Modal from "../../Modal"; import dis from "../../dispatcher/dispatcher"; @@ -122,6 +123,8 @@ class TimelinePanel extends React.Component { layout: LayoutPropType, } + static contextType = RoomContext; + // a map from room id to read marker event timestamp static roomReadMarkerTsMap = {}; @@ -1285,7 +1288,7 @@ class TimelinePanel extends React.Component { const shouldIgnore = !!ev.status || // local echo (ignoreOwn && ev.sender && ev.sender.userId == myUserId); // own message - const isWithoutTile = !haveTileForEvent(ev) || shouldHideEvent(ev); + const isWithoutTile = !haveTileForEvent(ev) || shouldHideEvent(ev, this.context); if (isWithoutTile || !node) { // don't start counting if the event should be ignored, From c24b239478aef6e4e19e3651a9f8376753f17f12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 13:36:25 +0000 Subject: [PATCH 057/134] Bump ws from 6.2.1 to 6.2.2 in /test/end-to-end-tests Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/commits) --- updated-dependencies: - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] --- test/end-to-end-tests/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/end-to-end-tests/yarn.lock b/test/end-to-end-tests/yarn.lock index 97b348fe50..bc942c4f51 100644 --- a/test/end-to-end-tests/yarn.lock +++ b/test/end-to-end-tests/yarn.lock @@ -760,9 +760,9 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== dependencies: async-limiter "~1.0.0" From 0f64f4d692f36287ace222eb13e07244fa6e1c63 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 10:49:44 -0400 Subject: [PATCH 058/134] Fix MessagePanel tests Signed-off-by: Robin Townsend --- test/components/structures/MessagePanel-test.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 5b466b4bb0..4f7fca1759 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -51,8 +51,20 @@ class WrappedMessagePanel extends React.Component { }; render() { + const roomContext = { + room, + roomId: room.roomId, + canReact: true, + canReply: true, + showReadReceipts: true, + showRedactions: false, + showJoinLeaves: false, + showAvatarChanges: false, + showDisplaynameChanges: true, + }; + return - + ; From bbd5fab7b5345f3147f8392907fb114129b6c74e Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 11:15:06 -0400 Subject: [PATCH 059/134] Fix type check As TypeScript points out, you can only set an id on HTML elements, not arbitrary components. Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index cba292ea25..355c92240e 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -214,7 +214,7 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr />

-
+
= ({ matrixClient: cli, event, permalinkCr autoComplete={true} autoFocus={true} /> - + { rooms.length > 0 ? (
{ rooms.map(room => From e891d18fa264491fe81fbbcd893fa5c9fdc1d51a Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 5 Jun 2021 21:41:28 -0400 Subject: [PATCH 060/134] Add my email to my copyright notices Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 2 +- src/components/views/dialogs/ForwardDialog.tsx | 2 +- test/components/views/dialogs/ForwardDialog-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index fc59259ca2..7422d39626 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -1,5 +1,5 @@ /* -Copyright 2021 Robin Townsend. +Copyright 2021 Robin Townsend 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/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 355c92240e..e97958973b 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 Robin Townsend. +Copyright 2021 Robin Townsend 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/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index 004954c713..c50fb073bf 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -1,5 +1,5 @@ /* -Copyright 2021 Robin Townsend. +Copyright 2021 Robin Townsend Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 1c8e34114318e472d7deee6ecc8dd99e2e6baa7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 6 Jun 2021 08:09:41 +0200 Subject: [PATCH 061/134] Reset all translation vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not doing this would result in jumps because everything would get out of sync Signed-off-by: Šimon Brandner --- src/components/views/elements/ImageView.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index df73e1a8cb..1b1decd6d5 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -283,6 +283,10 @@ export default class ImageView extends React.Component { translationX: 0, translationY: 0, }); + this.lastX = 0; + this.lastY = 0; + this.initX = 0; + this.initY = 0; } this.setState({moving: false}); }; From c0964b69b73af9de4759b2f45d97caf0d6c98b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 6 Jun 2021 08:14:43 +0200 Subject: [PATCH 062/134] Remove redundant vars 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 | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index 1b1decd6d5..d6256f7dd2 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -95,8 +95,6 @@ export default class ImageView extends React.Component { private initX = 0; private initY = 0; - private lastX = 0; - private lastY = 0; private previousX = 0; private previousY = 0; @@ -253,8 +251,8 @@ export default class ImageView extends React.Component { this.setState({moving: true}); this.previousX = this.state.translationX; this.previousY = this.state.translationY; - this.initX = ev.pageX - this.lastX; - this.initY = ev.pageY - this.lastY; + this.initX = ev.pageX - this.state.translationX; + this.initY = ev.pageY - this.state.translationY; }; private onMoving = (ev: React.MouseEvent) => { @@ -263,11 +261,9 @@ export default class ImageView extends React.Component { if (!this.state.moving) return; - this.lastX = ev.pageX - this.initX; - this.lastY = ev.pageY - this.initY; this.setState({ - translationX: this.lastX, - translationY: this.lastY, + translationX: ev.pageX - this.initX, + translationY: ev.pageY - this.initY, }); }; @@ -283,8 +279,6 @@ export default class ImageView extends React.Component { translationX: 0, translationY: 0, }); - this.lastX = 0; - this.lastY = 0; this.initX = 0; this.initY = 0; } From 28be581af18615ec24c4a664744ccae3a110696f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 6 Jun 2021 08:51:07 +0200 Subject: [PATCH 063/134] Take image rotation into account when zooming 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 | 31 +++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index d6256f7dd2..d4870a569b 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -97,29 +97,36 @@ export default class ImageView extends React.Component { private initY = 0; private previousX = 0; private previousY = 0; + private rotation = 0; componentDidMount() { // We have to use addEventListener() because the listener // needs to be passive in order to work with Chromium this.focusLock.current.addEventListener('wheel', this.onWheel, { passive: false }); // We want to recalculate zoom whenever the window's size changes - window.addEventListener("resize", this.calculateZoom); + window.addEventListener("resize", this.calculateZoomAndRotate); // After the image loads for the first time we want to calculate the zoom - this.image.current.addEventListener("load", this.calculateZoom); + this.image.current.addEventListener("load", this.calculateZoomAndRotate); } componentWillUnmount() { this.focusLock.current.removeEventListener('wheel', this.onWheel); - window.removeEventListener("resize", this.calculateZoom); - this.image.current.removeEventListener("load", this.calculateZoom); + window.removeEventListener("resize", this.calculateZoomAndRotate); + this.image.current.removeEventListener("load", this.calculateZoomAndRotate); } - private calculateZoom = () => { + private calculateZoomAndRotate = () => { const image = this.image.current; const imageWrapper = this.imageWrapper.current; - const zoomX = imageWrapper.clientWidth / image.naturalWidth; - const zoomY = imageWrapper.clientHeight / image.naturalHeight; + const landscape = this.rotation % 180 === 0; + + // If the image is rotated take it into account + const width = landscape ? image.naturalWidth : image.naturalHeight; + const height = landscape ? image.naturalHeight : image.naturalWidth; + + const zoomX = imageWrapper.clientWidth / width; + const zoomY = imageWrapper.clientHeight / height; // If the image is smaller in both dimensions set its the zoom to 1 to // display it in its original size @@ -128,6 +135,7 @@ export default class ImageView extends React.Component { zoom: 1, minZoom: 1, maxZoom: 1, + rotation: this.rotation, }); return; } @@ -140,6 +148,7 @@ export default class ImageView extends React.Component { this.setState({ minZoom: minZoom, maxZoom: 1, + rotation: this.rotation, }); } @@ -190,14 +199,14 @@ export default class ImageView extends React.Component { private onRotateCounterClockwiseClick = () => { const cur = this.state.rotation; - const rotationDegrees = cur - 90; - this.setState({ rotation: rotationDegrees }); + this.rotation = cur - 90; + this.calculateZoomAndRotate(); }; private onRotateClockwiseClick = () => { const cur = this.state.rotation; - const rotationDegrees = cur + 90; - this.setState({ rotation: rotationDegrees }); + this.rotation = cur + 90; + this.calculateZoomAndRotate(); }; private onDownloadClick = () => { From c3fdd733570550fcd48473834009bf6bafafeaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 6 Jun 2021 08:56:12 +0200 Subject: [PATCH 064/134] Avoid multiple setState() calls 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 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index d4870a569b..c4ec3497e4 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -144,11 +144,14 @@ export default class ImageView extends React.Component { // image by default const minZoom = Math.min(zoomX, zoomY) * MAX_SCALE; - if (this.state.zoom <= this.state.minZoom) this.setState({zoom: minZoom}); + // If zoom is smaller than minZoom don't go beneath that value + const zoom = (this.state.zoom <= this.state.minZoom) ? minZoom : this.state.zoom; + this.setState({ minZoom: minZoom, maxZoom: 1, rotation: this.rotation, + zoom: zoom, }); } From ba0f6766caefb700324a0a4441e0427689b8faf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 6 Jun 2021 09:02:30 +0200 Subject: [PATCH 065/134] Update curly braces styling 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 | 131 ++++++++++---------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index c4ec3497e4..948e005978 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -19,20 +19,20 @@ limitations under the License. import React, { createRef } from 'react'; import { _t } from '../../../languageHandler'; import AccessibleTooltipButton from "./AccessibleTooltipButton"; -import {Key} from "../../../Keyboard"; +import { Key } from "../../../Keyboard"; import FocusLock from "react-focus-lock"; import MemberAvatar from "../avatars/MemberAvatar"; -import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; +import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton"; import MessageContextMenu from "../context_menus/MessageContextMenu"; -import {aboveLeftOf, ContextMenu} from '../../structures/ContextMenu'; +import { aboveLeftOf, ContextMenu } from '../../structures/ContextMenu'; import MessageTimestamp from "../messages/MessageTimestamp"; import SettingsStore from "../../../settings/SettingsStore"; -import {formatFullDate} from "../../../DateUtils"; +import { formatFullDate } from "../../../DateUtils"; import dis from '../../../dispatcher/dispatcher'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks" -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {normalizeWheelEvent} from "../../../utils/Mouse"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks" +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { normalizeWheelEvent } from "../../../utils/Mouse"; // Max scale to keep gaps around the image const MAX_SCALE = 0.95; @@ -167,7 +167,7 @@ export default class ImageView extends React.Component { return; } if (newZoom >= this.state.maxZoom) { - this.setState({zoom: this.state.maxZoom}); + this.setState({ zoom: this.state.maxZoom }); return; } @@ -256,11 +256,11 @@ export default class ImageView extends React.Component { // Zoom in if we are completely zoomed out if (this.state.zoom === this.state.minZoom) { - this.setState({zoom: this.state.maxZoom}); + this.setState({ zoom: this.state.maxZoom }); return; } - this.setState({moving: true}); + this.setState({ moving: true }); this.previousX = this.state.translationX; this.previousY = this.state.translationY; this.initX = ev.pageX - this.state.translationX; @@ -294,7 +294,7 @@ export default class ImageView extends React.Component { this.initX = 0; this.initY = 0; } - this.setState({moving: false}); + this.setState({ moving: false }); }; private renderContextMenu() { @@ -302,14 +302,14 @@ export default class ImageView extends React.Component { if (this.state.contextMenuDisplayed) { contextMenu = ( ); @@ -347,10 +347,10 @@ export default class ImageView extends React.Component { const style = { cursor: cursor, transition: this.state.moving ? null : "transform 200ms ease 0s", - transform: `translateX(${translatePixelsX}) - translateY(${translatePixelsY}) - scale(${zoom}) - rotate(${rotationDegrees})`, + transform: `translateX(${ translatePixelsX }) + translateY(${ translatePixelsY }) + scale(${ zoom }) + rotate(${ rotationDegrees })`, }; let info; @@ -365,37 +365,38 @@ export default class ImageView extends React.Component { const senderName = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); const sender = (
- {senderName} + { senderName }
); const messageTimestamp = ( ); const avatar = ( ); info = (
- {avatar} + { avatar }
- {sender} - {messageTimestamp} + { sender } + { messageTimestamp }
); @@ -413,10 +414,10 @@ export default class ImageView extends React.Component { contextMenuButton = ( ); } @@ -427,14 +428,14 @@ export default class ImageView extends React.Component { zoomOutButton = ( + title={ _t("Zoom out") } + onClick={ this.onZoomOutClick }> ); zoomInButton = ( ); @@ -442,57 +443,57 @@ export default class ImageView extends React.Component { return (
- {info} + { info }
+ title={ _t("Rotate Right") } + onClick={ this.onRotateClockwiseClick }> - {zoomOutButton} - {zoomInButton} + { zoomOutButton } + { zoomInButton } - {contextMenuButton} + { contextMenuButton } - {this.renderContextMenu()} + { this.renderContextMenu() }
+ ref={ this.imageWrapper }>
From 903d4d252a0c2ac6043ec24251d4c446f33d7990 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sun, 6 Jun 2021 23:06:56 -0400 Subject: [PATCH 066/134] Add optimized function to determine whether event has text to display Signed-off-by: Robin Townsend --- src/TextForEvent.js | 274 ++++++++++++---------- src/components/structures/MessagePanel.js | 9 +- src/components/views/rooms/EventTile.tsx | 4 +- 3 files changed, 155 insertions(+), 132 deletions(-) diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 86f9ff20f4..22ce0dd9cf 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -21,6 +21,10 @@ import SettingsStore from "./settings/SettingsStore"; import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList"; import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore"; +// These functions are frequently used just to check whether an event has +// any text to display at all. For this reason they return deferred values +// to avoid the expense of looking up translations when they're not needed. + function textForMemberEvent(ev) { // XXX: SYJS-16 "sender is sometimes null for join messages" const senderName = ev.sender ? ev.sender.name : ev.getSender(); @@ -28,84 +32,84 @@ function textForMemberEvent(ev) { const prevContent = ev.getPrevContent(); const content = ev.getContent(); - const reason = content.reason ? (_t('Reason') + ': ' + content.reason) : ''; + const getReason = () => content.reason ? (_t('Reason') + ': ' + content.reason) : ''; switch (content.membership) { case 'invite': { const threePidContent = content.third_party_invite; if (threePidContent) { if (threePidContent.display_name) { - return _t('%(targetName)s accepted the invitation for %(displayName)s.', { + return () => _t('%(targetName)s accepted the invitation for %(displayName)s.', { targetName, displayName: threePidContent.display_name, }); } else { - return _t('%(targetName)s accepted an invitation.', {targetName}); + return () => _t('%(targetName)s accepted an invitation.', {targetName}); } } else { - return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName}); + return () => _t('%(senderName)s invited %(targetName)s.', {senderName, targetName}); } } case 'ban': - return _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + reason; + return () => _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + getReason(); case 'join': if (prevContent && prevContent.membership === 'join') { if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) { - return _t('%(oldDisplayName)s changed their display name to %(displayName)s.', { + return () => _t('%(oldDisplayName)s changed their display name to %(displayName)s.', { oldDisplayName: prevContent.displayname, displayName: content.displayname, }); } else if (!prevContent.displayname && content.displayname) { - return _t('%(senderName)s set their display name to %(displayName)s.', { + return () => _t('%(senderName)s set their display name to %(displayName)s.', { senderName: ev.getSender(), displayName: content.displayname, }); } else if (prevContent.displayname && !content.displayname) { - return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', { + return () => _t('%(senderName)s removed their display name (%(oldDisplayName)s).', { senderName, oldDisplayName: prevContent.displayname, }); } else if (prevContent.avatar_url && !content.avatar_url) { - return _t('%(senderName)s removed their profile picture.', {senderName}); + return () => _t('%(senderName)s removed their profile picture.', {senderName}); } else if (prevContent.avatar_url && content.avatar_url && prevContent.avatar_url !== content.avatar_url) { - return _t('%(senderName)s changed their profile picture.', {senderName}); + return () => _t('%(senderName)s changed their profile picture.', {senderName}); } else if (!prevContent.avatar_url && content.avatar_url) { - return _t('%(senderName)s set a profile picture.', {senderName}); + return () => _t('%(senderName)s set a profile picture.', {senderName}); } else if (SettingsStore.getValue("showHiddenEventsInTimeline")) { // This is a null rejoin, it will only be visible if the Labs option is enabled - return _t("%(senderName)s made no change.", {senderName}); + return () => _t("%(senderName)s made no change.", {senderName}); } else { - return ""; + return null; } } else { if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key); - return _t('%(targetName)s joined the room.', {targetName}); + return () => _t('%(targetName)s joined the room.', {targetName}); } case 'leave': if (ev.getSender() === ev.getStateKey()) { if (prevContent.membership === "invite") { - return _t('%(targetName)s rejected the invitation.', {targetName}); + return () => _t('%(targetName)s rejected the invitation.', {targetName}); } else { - return _t('%(targetName)s left the room.', {targetName}); + return () => _t('%(targetName)s left the room.', {targetName}); } } else if (prevContent.membership === "ban") { - return _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName}); + return () => _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName}); } else if (prevContent.membership === "invite") { - return _t('%(senderName)s withdrew %(targetName)s\'s invitation.', { + return () => _t('%(senderName)s withdrew %(targetName)s\'s invitation.', { senderName, targetName, - }) + ' ' + reason; + }) + ' ' + getReason(); } else if (prevContent.membership === "join") { - return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason; + return () => _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + getReason(); } else { - return ""; + return null; } } } function textForTopicEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); - return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', { + return () => _t('%(senderDisplayName)s changed the topic to "%(topic)s".', { senderDisplayName, topic: ev.getContent().topic, }); @@ -115,16 +119,16 @@ function textForRoomNameEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); if (!ev.getContent().name || ev.getContent().name.trim().length === 0) { - return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s removed the room name.', {senderDisplayName}); } if (ev.getPrevContent().name) { - return _t('%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.', { + return () => _t('%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.', { senderDisplayName, oldRoomName: ev.getPrevContent().name, newRoomName: ev.getContent().name, }); } - return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', { + return () => _t('%(senderDisplayName)s changed the room name to %(roomName)s.', { senderDisplayName, roomName: ev.getContent().name, }); @@ -132,19 +136,23 @@ function textForRoomNameEvent(ev) { function textForTombstoneEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); - return _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); } function textForJoinRulesEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().join_rule) { case "public": - return _t('%(senderDisplayName)s made the room public to whoever knows the link.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s made the room public to whoever knows the link.', { + senderDisplayName, + }); case "invite": - return _t('%(senderDisplayName)s made the room invite only.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s made the room invite only.', { + senderDisplayName, + }); default: // The spec supports "knock" and "private", however nothing implements these. - return _t('%(senderDisplayName)s changed the join rule to %(rule)s', { + return () => _t('%(senderDisplayName)s changed the join rule to %(rule)s', { senderDisplayName, rule: ev.getContent().join_rule, }); @@ -155,12 +163,12 @@ function textForGuestAccessEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().guest_access) { case "can_join": - return _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName}); case "forbidden": - return _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName}); default: // There's no other options we can expect, however just for safety's sake we'll do this. - return _t('%(senderDisplayName)s changed guest access to %(rule)s', { + return () => _t('%(senderDisplayName)s changed guest access to %(rule)s', { senderDisplayName, rule: ev.getContent().guest_access, }); @@ -175,17 +183,17 @@ function textForRelatedGroupsEvent(ev) { const removed = prevGroups.filter((g) => !groups.includes(g)); if (added.length && !removed.length) { - return _t('%(senderDisplayName)s enabled flair for %(groups)s in this room.', { + return () => _t('%(senderDisplayName)s enabled flair for %(groups)s in this room.', { senderDisplayName, groups: added.join(', '), }); } else if (!added.length && removed.length) { - return _t('%(senderDisplayName)s disabled flair for %(groups)s in this room.', { + return () => _t('%(senderDisplayName)s disabled flair for %(groups)s in this room.', { senderDisplayName, groups: removed.join(', '), }); } else if (added.length && removed.length) { - return _t('%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for ' + + return () => _t('%(senderDisplayName)s enabled flair for %(newGroups)s and disabled flair for ' + '%(oldGroups)s in this room.', { senderDisplayName, newGroups: added.join(', '), @@ -193,7 +201,7 @@ function textForRelatedGroupsEvent(ev) { }); } else { // Don't bother rendering this change (because there were no changes) - return ''; + return null; } } @@ -207,11 +215,11 @@ function textForServerACLEvent(ev) { allow_ip_literals: !(prevContent.allow_ip_literals === false), }; - let text = ""; + let getText = null; if (prev.deny.length === 0 && prev.allow.length === 0) { - text = _t("%(senderDisplayName)s set the server ACLs for this room.", {senderDisplayName}); + getText = () => _t("%(senderDisplayName)s set the server ACLs for this room.", {senderDisplayName}); } else { - text = _t("%(senderDisplayName)s changed the server ACLs for this room.", {senderDisplayName}); + getText = () => _t("%(senderDisplayName)s changed the server ACLs for this room.", {senderDisplayName}); } if (!Array.isArray(current.allow)) { @@ -220,21 +228,24 @@ function textForServerACLEvent(ev) { // If we know for sure everyone is banned, mark the room as obliterated if (current.allow.length === 0) { - return text + " " + _t("🎉 All servers are banned from participating! This room can no longer be used."); + return () => getText() + " " + + _t("🎉 All servers are banned from participating! This room can no longer be used."); } - return text; + return getText; } function textForMessageEvent(ev) { - const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); - let message = senderDisplayName + ': ' + ev.getContent().body; - if (ev.getContent().msgtype === "m.emote") { - message = "* " + senderDisplayName + " " + message; - } else if (ev.getContent().msgtype === "m.image") { - message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName}); - } - return message; + return () => { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + let message = senderDisplayName + ': ' + ev.getContent().body; + if (ev.getContent().msgtype === "m.emote") { + message = "* " + senderDisplayName + " " + message; + } else if (ev.getContent().msgtype === "m.image") { + message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName}); + } + return message; + }; } function textForCanonicalAliasEvent(ev) { @@ -248,96 +259,100 @@ function textForCanonicalAliasEvent(ev) { if (!removedAltAliases.length && !addedAltAliases.length) { if (newAlias) { - return _t('%(senderName)s set the main address for this room to %(address)s.', { + return () => _t('%(senderName)s set the main address for this room to %(address)s.', { senderName: senderName, address: ev.getContent().alias, }); } else if (oldAlias) { - return _t('%(senderName)s removed the main address for this room.', { + return () => _t('%(senderName)s removed the main address for this room.', { senderName: senderName, }); } } else if (newAlias === oldAlias) { if (addedAltAliases.length && !removedAltAliases.length) { - return _t('%(senderName)s added the alternative addresses %(addresses)s for this room.', { + return () => _t('%(senderName)s added the alternative addresses %(addresses)s for this room.', { senderName: senderName, addresses: addedAltAliases.join(", "), count: addedAltAliases.length, }); } if (removedAltAliases.length && !addedAltAliases.length) { - return _t('%(senderName)s removed the alternative addresses %(addresses)s for this room.', { + return () => _t('%(senderName)s removed the alternative addresses %(addresses)s for this room.', { senderName: senderName, addresses: removedAltAliases.join(", "), count: removedAltAliases.length, }); } if (removedAltAliases.length && addedAltAliases.length) { - return _t('%(senderName)s changed the alternative addresses for this room.', { + return () => _t('%(senderName)s changed the alternative addresses for this room.', { senderName: senderName, }); } } else { // both alias and alt_aliases where modified - return _t('%(senderName)s changed the main and alternative addresses for this room.', { + return () => _t('%(senderName)s changed the main and alternative addresses for this room.', { senderName: senderName, }); } // in case there is no difference between the two events, // say something as we can't simply hide the tile from here - return _t('%(senderName)s changed the addresses for this room.', { + return () => _t('%(senderName)s changed the addresses for this room.', { senderName: senderName, }); } function textForCallAnswerEvent(event) { - const senderName = event.sender ? event.sender.name : _t('Someone'); - const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)'); - return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported; + return () => { + const senderName = event.sender ? event.sender.name : _t('Someone'); + const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)'); + return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported; + }; } function textForCallHangupEvent(event) { - const senderName = event.sender ? event.sender.name : _t('Someone'); + const getSenderName = () => event.sender ? event.sender.name : _t('Someone'); const eventContent = event.getContent(); - let reason = ""; + let getReason = () => ""; if (!MatrixClientPeg.get().supportsVoip()) { - reason = _t('(not supported by this browser)'); + getReason = () => _t('(not supported by this browser)'); } else if (eventContent.reason) { if (eventContent.reason === "ice_failed") { // We couldn't establish a connection at all - reason = _t('(could not connect media)'); + getReason = () => _t('(could not connect media)'); } else if (eventContent.reason === "ice_timeout") { // We established a connection but it died - reason = _t('(connection failed)'); + getReason = () => _t('(connection failed)'); } else if (eventContent.reason === "user_media_failed") { // The other side couldn't open capture devices - reason = _t("(their device couldn't start the camera / microphone)"); + getReason = () => _t("(their device couldn't start the camera / microphone)"); } else if (eventContent.reason === "unknown_error") { // An error code the other side doesn't have a way to express // (as opposed to an error code they gave but we don't know about, // in which case we show the error code) - reason = _t("(an error occurred)"); + getReason = () => _t("(an error occurred)"); } else if (eventContent.reason === "invite_timeout") { - reason = _t('(no answer)'); + getReason = () => _t('(no answer)'); } else if (eventContent.reason === "user hangup" || eventContent.reason === "user_hangup") { // workaround for https://github.com/vector-im/element-web/issues/5178 // it seems Android randomly sets a reason of "user hangup" which is // interpreted as an error code :( // https://github.com/vector-im/riot-android/issues/2623 // Also the correct hangup code as of VoIP v1 (with underscore) - reason = ''; + getReason = () => ''; } else { - reason = _t('(unknown failure: %(reason)s)', {reason: eventContent.reason}); + getReason = () => _t('(unknown failure: %(reason)s)', {reason: eventContent.reason}); } } - return _t('%(senderName)s ended the call.', {senderName}) + ' ' + reason; + return () => _t('%(senderName)s ended the call.', {senderName: getSenderName()}) + ' ' + getReason(); } function textForCallRejectEvent(event) { - const senderName = event.sender ? event.sender.name : _t('Someone'); - return _t('%(senderName)s declined the call.', {senderName}); + return () => { + const senderName = event.sender ? event.sender.name : _t('Someone'); + return _t('%(senderName)s declined the call.', {senderName}); + }; } function textForCallInviteEvent(event) { - const senderName = event.sender ? event.sender.name : _t('Someone'); + const getSenderName = () => event.sender ? event.sender.name : _t('Someone'); // FIXME: Find a better way to determine this from the event? let isVoice = true; if (event.getContent().offer && event.getContent().offer.sdp && @@ -350,13 +365,21 @@ function textForCallInviteEvent(event) { // can have a hard time translating those strings. In an effort to make translations easier // and more accurate, we break out the string-based variables to a couple booleans. if (isVoice && isSupported) { - return _t("%(senderName)s placed a voice call.", {senderName}); + return () => _t("%(senderName)s placed a voice call.", { + senderName: getSenderName(), + }); } else if (isVoice && !isSupported) { - return _t("%(senderName)s placed a voice call. (not supported by this browser)", {senderName}); + return () => _t("%(senderName)s placed a voice call. (not supported by this browser)", { + senderName: getSenderName(), + }); } else if (!isVoice && isSupported) { - return _t("%(senderName)s placed a video call.", {senderName}); + return () => _t("%(senderName)s placed a video call.", { + senderName: getSenderName(), + }); } else if (!isVoice && !isSupported) { - return _t("%(senderName)s placed a video call. (not supported by this browser)", {senderName}); + return () => _t("%(senderName)s placed a video call. (not supported by this browser)", { + senderName: getSenderName(), + }); } } @@ -364,14 +387,13 @@ function textForThreePidInviteEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); if (!isValid3pidInvite(event)) { - const targetDisplayName = event.getPrevContent().display_name || _t("Someone"); - return _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { + return () => _t('%(senderName)s revoked the invitation for %(targetDisplayName)s to join the room.', { senderName, - targetDisplayName, + targetDisplayName: event.getPrevContent().display_name || _t("Someone"), }); } - return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', { + return () => _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', { senderName, targetDisplayName: event.getContent().display_name, }); @@ -381,17 +403,17 @@ function textForHistoryVisibilityEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); switch (event.getContent().history_visibility) { case 'invited': - return _t('%(senderName)s made future room history visible to all room members, ' + return () => _t('%(senderName)s made future room history visible to all room members, ' + 'from the point they are invited.', {senderName}); case 'joined': - return _t('%(senderName)s made future room history visible to all room members, ' + return () => _t('%(senderName)s made future room history visible to all room members, ' + 'from the point they joined.', {senderName}); case 'shared': - return _t('%(senderName)s made future room history visible to all room members.', {senderName}); + return () => _t('%(senderName)s made future room history visible to all room members.', {senderName}); case 'world_readable': - return _t('%(senderName)s made future room history visible to anyone.', {senderName}); + return () => _t('%(senderName)s made future room history visible to anyone.', {senderName}); default: - return _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', { + return () => _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', { senderName, visibility: event.getContent().history_visibility, }); @@ -403,7 +425,7 @@ function textForPowerEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); if (!event.getPrevContent() || !event.getPrevContent().users || !event.getContent() || !event.getContent().users) { - return ''; + return null; } const userDefault = event.getContent().users_default || 0; // Construct set of userIds @@ -418,35 +440,35 @@ function textForPowerEvent(event) { if (users.indexOf(userId) === -1) users.push(userId); }, ); - const diff = []; - // XXX: This is also surely broken for i18n + const diffs = []; users.forEach((userId) => { // Previous power level const from = event.getPrevContent().users[userId]; // Current power level const to = event.getContent().users[userId]; if (to !== from) { - diff.push( - _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', { - userId, - fromPowerLevel: Roles.textualPowerLevel(from, userDefault), - toPowerLevel: Roles.textualPowerLevel(to, userDefault), - }), - ); + diffs.push({ userId, from, to }); } }); - if (!diff.length) { - return ''; + if (!diffs.length) { + return null; } - return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', { + // XXX: This is also surely broken for i18n + return () => _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', { senderName, - powerLevelDiffText: diff.join(", "), + powerLevelDiffText: diffs.map(diff => + _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', { + userId: diff.userId, + fromPowerLevel: Roles.textualPowerLevel(diff.from, userDefault), + toPowerLevel: Roles.textualPowerLevel(diff.to, userDefault), + }), + ).join(", "), }); } function textForPinnedEvent(event) { const senderName = event.sender ? event.sender.name : event.getSender(); - return _t("%(senderName)s changed the pinned messages for the room.", {senderName}); + return () => _t("%(senderName)s changed the pinned messages for the room.", {senderName}); } function textForWidgetEvent(event) { @@ -464,16 +486,16 @@ function textForWidgetEvent(event) { // equivalent to that condition. if (url) { if (prevUrl) { - return _t('%(widgetName)s widget modified by %(senderName)s', { + return () => _t('%(widgetName)s widget modified by %(senderName)s', { widgetName, senderName, }); } else { - return _t('%(widgetName)s widget added by %(senderName)s', { + return () => _t('%(widgetName)s widget added by %(senderName)s', { widgetName, senderName, }); } } else { - return _t('%(widgetName)s widget removed by %(senderName)s', { + return () => _t('%(widgetName)s widget removed by %(senderName)s', { widgetName, senderName, }); } @@ -481,7 +503,7 @@ function textForWidgetEvent(event) { function textForWidgetLayoutEvent(event) { const senderName = event.sender?.name || event.getSender(); - return _t("%(senderName)s has updated the widget layout", {senderName}); + return () => _t("%(senderName)s has updated the widget layout", {senderName}); } function textForMjolnirEvent(event) { @@ -492,74 +514,74 @@ function textForMjolnirEvent(event) { // Rule removed if (!entity) { if (USER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s removed the rule banning users matching %(glob)s", + return () => _t("%(senderName)s removed the rule banning users matching %(glob)s", {senderName, glob: prevEntity}); } else if (ROOM_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s removed the rule banning rooms matching %(glob)s", + return () => _t("%(senderName)s removed the rule banning rooms matching %(glob)s", {senderName, glob: prevEntity}); } else if (SERVER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s removed the rule banning servers matching %(glob)s", + return () => _t("%(senderName)s removed the rule banning servers matching %(glob)s", {senderName, glob: prevEntity}); } // Unknown type. We'll say something, but we shouldn't end up here. - return _t("%(senderName)s removed a ban rule matching %(glob)s", {senderName, glob: prevEntity}); + return () => _t("%(senderName)s removed a ban rule matching %(glob)s", {senderName, glob: prevEntity}); } // Invalid rule - if (!recommendation || !reason) return _t(`%(senderName)s updated an invalid ban rule`, {senderName}); + if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, {senderName}); // Rule updated if (entity === prevEntity) { if (USER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } else if (ROOM_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } else if (SERVER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } // Unknown type. We'll say something but we shouldn't end up here. - return _t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } // New rule if (!prevEntity) { if (USER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } else if (ROOM_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } else if (SERVER_RULE_TYPES.includes(event.getType())) { - return _t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } // Unknown type. We'll say something but we shouldn't end up here. - return _t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s", + return () => _t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s", {senderName, glob: entity, reason}); } // else the entity !== prevEntity - count as a removal & add if (USER_RULE_TYPES.includes(event.getType())) { - return _t( + return () => _t( "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}, ); } else if (ROOM_RULE_TYPES.includes(event.getType())) { - return _t( + return () => _t( "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}, ); } else if (SERVER_RULE_TYPES.includes(event.getType())) { - return _t( + return () => _t( "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}, @@ -567,7 +589,7 @@ function textForMjolnirEvent(event) { } // Unknown type. We'll say something but we shouldn't end up here. - return _t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s " + + return () => _t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s " + "for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}); } @@ -604,8 +626,12 @@ for (const evType of ALL_RULE_TYPES) { stateHandlers[evType] = textForMjolnirEvent; } +export function hasText(ev) { + const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; + return Boolean(handler?.(ev)); +} + export function textForEvent(ev) { const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; - if (handler) return handler(ev); - return ''; + return handler?.(ev)?.() || ''; } diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index bca62e7b2f..d040944833 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -30,7 +30,7 @@ import RoomContext from "../../contexts/RoomContext"; import {Layout, LayoutPropType} from "../../settings/Layout"; import {_t} from "../../languageHandler"; import {haveTileForEvent} from "../views/rooms/EventTile"; -import {textForEvent} from "../../TextForEvent"; +import {hasText} from "../../TextForEvent"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import DMRoomMap from "../../utils/DMRoomMap"; import NewRoomIntro from "../views/rooms/NewRoomIntro"; @@ -1180,11 +1180,8 @@ class MemberGrouper { add(ev) { if (ev.getType() === 'm.room.member') { - // We'll just double check that it's worth our time to do so, through an - // ugly hack. If textForEvent returns something, we should group it for - // rendering but if it doesn't then we'll exclude it. - const renderText = textForEvent(ev); - if (!renderText || renderText.trim().length === 0) return; // quietly ignore + // We can ignore any events that don't actually have a message to display + if (!hasText(ev)) return; } this.readMarker = this.readMarker || this.panel._readMarkerForEvent( ev.getId(), diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 8cec067c39..fda2906f07 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -25,7 +25,7 @@ import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import ReplyThread from "../elements/ReplyThread"; import { _t } from '../../../languageHandler'; -import * as TextForEvent from "../../../TextForEvent"; +import { hasText } from "../../../TextForEvent"; import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; import SettingsStore from "../../../settings/SettingsStore"; @@ -1200,7 +1200,7 @@ export function haveTileForEvent(e) { const handler = getHandlerTile(e); if (handler === undefined) return false; if (handler === 'messages.TextualEvent') { - return TextForEvent.textForEvent(e) !== ''; + return hasText(e); } else if (handler === 'messages.RoomCreate') { return Boolean(e.getContent()['predecessor']); } else { From 1e574307d0a74c498429c6e2a22f07c61369550b Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sun, 6 Jun 2021 23:08:47 -0400 Subject: [PATCH 067/134] Cache lowBandwidth setting to speed up BaseAvatar Signed-off-by: Robin Townsend --- src/components/structures/RoomView.tsx | 5 +++++ src/components/views/avatars/BaseAvatar.tsx | 15 +++++++++++---- src/contexts/RoomContext.ts | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index b80d909a94..e4dc90f141 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -182,6 +182,7 @@ export interface IState { canReact: boolean; canReply: boolean; layout: Layout; + lowBandwidth: boolean; showReadReceipts: boolean; showRedactions: boolean; showJoinLeaves: boolean; @@ -244,6 +245,7 @@ export default class RoomView extends React.Component { canReact: false, canReply: false, layout: SettingsStore.getValue("layout"), + lowBandwidth: SettingsStore.getValue("lowBandwidth"), showReadReceipts: true, showRedactions: true, showJoinLeaves: true, @@ -279,6 +281,9 @@ export default class RoomView extends React.Component { SettingsStore.watchSetting("layout", null, () => this.setState({ layout: SettingsStore.getValue("layout") }), ), + SettingsStore.watchSetting("lowBandwidth", null, () => + this.setState({ lowBandwidth: SettingsStore.getValue("lowBandwidth") }), + ), ]; } diff --git a/src/components/views/avatars/BaseAvatar.tsx b/src/components/views/avatars/BaseAvatar.tsx index 8ce05e0a55..6949c14636 100644 --- a/src/components/views/avatars/BaseAvatar.tsx +++ b/src/components/views/avatars/BaseAvatar.tsx @@ -22,6 +22,7 @@ import classNames from 'classnames'; import * as AvatarLogic from '../../../Avatar'; import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from '../elements/AccessibleButton'; +import RoomContext from "../../../contexts/RoomContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {useEventEmitter} from "../../../hooks/useEventEmitter"; import {toPx} from "../../../utils/units"; @@ -44,12 +45,12 @@ interface IProps { className?: string; } -const calculateUrls = (url, urls) => { +const calculateUrls = (url, urls, lowBandwidth) => { // work out the full set of urls to try to load. This is formed like so: // imageUrls: [ props.url, ...props.urls ] let _urls = []; - if (!SettingsStore.getValue("lowBandwidth")) { + if (!lowBandwidth) { _urls = urls || []; if (url) { @@ -63,7 +64,13 @@ const calculateUrls = (url, urls) => { }; const useImageUrl = ({url, urls}): [string, () => void] => { - const [imageUrls, setUrls] = useState(calculateUrls(url, urls)); + // Since this is a hot code path and the settings store can be slow, we + // use the cached lowBandwidth value from the room context if it exists + const roomContext = useContext(RoomContext); + const lowBandwidth = roomContext ? + roomContext.lowBandwidth : SettingsStore.getValue("lowBandwidth"); + + const [imageUrls, setUrls] = useState(calculateUrls(url, urls, lowBandwidth)); const [urlsIndex, setIndex] = useState(0); const onError = useCallback(() => { @@ -71,7 +78,7 @@ const useImageUrl = ({url, urls}): [string, () => void] => { }, []); useEffect(() => { - setUrls(calculateUrls(url, urls)); + setUrls(calculateUrls(url, urls, lowBandwidth)); setIndex(0); }, [url, JSON.stringify(urls)]); // eslint-disable-line react-hooks/exhaustive-deps diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts index 1efa1c03e7..3464f952a6 100644 --- a/src/contexts/RoomContext.ts +++ b/src/contexts/RoomContext.ts @@ -40,6 +40,7 @@ const RoomContext = createContext({ canReact: false, canReply: false, layout: Layout.Group, + lowBandwidth: false, showReadReceipts: true, showRedactions: true, showJoinLeaves: true, From 21ff1f521fa191308852429214d2697ee35adda8 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sun, 6 Jun 2021 23:14:26 -0400 Subject: [PATCH 068/134] Fix i18n strings Signed-off-by: Robin Townsend --- 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 9e85ea28c8..5108ea7fe2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -556,8 +556,8 @@ "%(senderName)s made future room history visible to all room members.": "%(senderName)s made future room history visible to all room members.", "%(senderName)s made future room history visible to anyone.": "%(senderName)s made future room history visible to anyone.", "%(senderName)s made future room history visible to unknown (%(visibility)s).": "%(senderName)s made future room history visible to unknown (%(visibility)s).", - "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s", "%(senderName)s changed the power level of %(powerLevelDiffText)s.": "%(senderName)s changed the power level of %(powerLevelDiffText)s.", + "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s": "%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s", "%(senderName)s changed the pinned messages for the room.": "%(senderName)s changed the pinned messages for the room.", "%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s", "%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s", From 31d308a1fbdd94176a8a3ea43e1e20f5b41590db Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 7 Jun 2021 09:22:47 +0100 Subject: [PATCH 069/134] Fix Stickerpicker context menu --- .../views/context_menus/WidgetContextMenu.tsx | 46 ++++++++++++------- src/components/views/elements/AppTile.js | 2 + src/components/views/rooms/Stickerpicker.js | 6 +-- src/stores/widgets/WidgetLayoutStore.ts | 2 +- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/components/views/context_menus/WidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx index 623fe04f2f..068bfd6497 100644 --- a/src/components/views/context_menus/WidgetContextMenu.tsx +++ b/src/components/views/context_menus/WidgetContextMenu.tsx @@ -40,6 +40,8 @@ interface IProps extends React.ComponentProps { showUnpin?: boolean; // override delete handler onDeleteClick?(): void; + // override edit handler + onEditClick?(): void; } const WidgetContextMenu: React.FC = ({ @@ -47,6 +49,7 @@ const WidgetContextMenu: React.FC = ({ app, userWidget, onDeleteClick, + onEditClick, showUnpin, ...props }) => { @@ -89,12 +92,16 @@ const WidgetContextMenu: React.FC = ({ let editButton; if (canModify && WidgetUtils.isManagedByManager(app)) { - const onEditClick = () => { - WidgetUtils.editWidget(room, app); + const _onEditClick = () => { + if (onEditClick) { + onEditClick(); + } else { + WidgetUtils.editWidget(room, app); + } onFinished(); }; - editButton = ; + editButton = ; } let snapshotButton; @@ -116,24 +123,29 @@ const WidgetContextMenu: React.FC = ({ let deleteButton; if (onDeleteClick || canModify) { - const onDeleteClickDefault = () => { - // Show delete confirmation dialog - Modal.createTrackedDialog('Delete Widget', '', QuestionDialog, { - title: _t("Delete Widget"), - description: _t( - "Deleting a widget removes it for all users in this room." + - " Are you sure you want to delete this widget?"), - button: _t("Delete widget"), - onFinished: (confirmed) => { - if (!confirmed) return; - WidgetUtils.setRoomWidget(roomId, app.id); - }, - }); + const _onDeleteClick = () => { + if (onDeleteClick) { + onDeleteClick(); + } else { + // Show delete confirmation dialog + Modal.createTrackedDialog('Delete Widget', '', QuestionDialog, { + title: _t("Delete Widget"), + description: _t( + "Deleting a widget removes it for all users in this room." + + " Are you sure you want to delete this widget?"), + button: _t("Delete widget"), + onFinished: (confirmed) => { + if (!confirmed) return; + WidgetUtils.setRoomWidget(roomId, app.id); + }, + }); + } + onFinished(); }; deleteButton = ; } diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index b898ad2ebc..ad5cbfa6b3 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -417,6 +417,8 @@ export default class AppTile extends React.Component { onFinished={this._closeContextMenu} showUnpin={!this.props.userWidget} userWidget={this.props.userWidget} + onEditClick={this.props.onEditClick} + onDeleteClick={this.props.onDeleteClick} /> ); } diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 3d2300b83c..b9aaee7a57 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -367,7 +367,7 @@ export default class Stickerpicker extends React.PureComponent { /** * Launch the integration manager on the stickers integration page */ - _launchManageIntegrations() { + _launchManageIntegrations = () => { // TODO: Open the right integration manager for the widget if (SettingsStore.getValue("feature_many_integration_managers")) { IntegrationManagers.sharedInstance().openAll( @@ -382,7 +382,7 @@ export default class Stickerpicker extends React.PureComponent { this.state.widgetId, ); } - } + }; render() { let stickerPicker; @@ -401,7 +401,7 @@ export default class Stickerpicker extends React.PureComponent { key="controls_hide_stickers" className={className} onClick={this._onHideStickersClick} - active={this.state.showStickers} + active={this.state.showStickers.toString()} title={_t("Hide Stickers")} > ; diff --git a/src/stores/widgets/WidgetLayoutStore.ts b/src/stores/widgets/WidgetLayoutStore.ts index f5734d74c5..b74da98c9c 100644 --- a/src/stores/widgets/WidgetLayoutStore.ts +++ b/src/stores/widgets/WidgetLayoutStore.ts @@ -332,7 +332,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore { } public getContainerWidgets(room: Room, container: Container): IApp[] { - return this.byRoom[room.roomId]?.[container]?.ordered || []; + return this.byRoom[room?.roomId]?.[container]?.ordered || []; } public isInContainer(room: Room, widget: IApp, container: Container): boolean { From f3aa5056730c1bc94ca4988f0abacba30d4348ab Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 7 Jun 2021 14:14:31 +0100 Subject: [PATCH 070/134] Add warning to private space creation flow --- res/css/structures/_SpaceRoomView.scss | 39 +++++++++++++++++++++ src/components/structures/SpaceRoomView.tsx | 4 +++ src/i18n/strings/en_EN.json | 2 ++ 3 files changed, 45 insertions(+) diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index 4bc4af467c..12762cbc9d 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -365,6 +365,45 @@ $SpaceRoomViewInnerWidth: 428px; } } + .mx_SpaceRoomView_betaWarning { + padding: 12px 12px 12px 54px; + position: relative; + font-size: $font-15px; + line-height: $font-24px; + width: 432px; + border-radius: 8px; + background-color: $info-plinth-bg-color; + color: $secondary-fg-color; + box-sizing: border-box; + + > h3 { + font-weight: $font-semi-bold; + font-size: inherit; + line-height: inherit; + margin: 0; + } + + > p { + font-size: inherit; + line-height: inherit; + margin: 0; + } + + &::before { + mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + content: ''; + width: 20px; + height: 20px; + position: absolute; + top: 14px; + left: 14px; + background-color: $secondary-fg-color; + } + } + .mx_SpaceRoomView_inviteTeammates { // XXX remove this when spaces leaves Beta .mx_SpaceRoomView_inviteTeammates_betaDisclaimer { diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 06d2bda16e..276f4ae6ca 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -587,6 +587,10 @@ const SpaceSetupPrivateScope = ({ space, justCreatedOpts, onFinished }) => {

{ _t("Me and my teammates") }

{ _t("A private space for you and your teammates") }
+
+

{ _t("Teammates might not be able to view or join any private rooms you make.") }

+

{ _t("We're working on this as part of the beta, but just want to let you know.") }

+
; }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9e85ea28c8..16cfcccd11 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2723,6 +2723,8 @@ "A private space to organise your rooms": "A private space to organise your rooms", "Me and my teammates": "Me and my teammates", "A private space for you and your teammates": "A private space for you and your teammates", + "Teammates might not be able to view or join any private rooms you make.": "Teammates might not be able to view or join any private rooms you make.", + "We're working on this as part of the beta, but just want to let you know.": "We're working on this as part of the beta, but just want to let you know.", "Failed to invite the following users to your space: %(csvUsers)s": "Failed to invite the following users to your space: %(csvUsers)s", "Inviting...": "Inviting...", "Invite your teammates": "Invite your teammates", From 67c9fe1e070d41192d9ff8553523c5834ff9f38c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:25:57 +0200 Subject: [PATCH 071/134] Revert "Update curly braces styling" This reverts commit ba0f6766caefb700324a0a4441e0427689b8faf7. --- src/components/views/elements/ImageView.tsx | 131 ++++++++++---------- 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index 948e005978..c4ec3497e4 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -19,20 +19,20 @@ limitations under the License. import React, { createRef } from 'react'; import { _t } from '../../../languageHandler'; import AccessibleTooltipButton from "./AccessibleTooltipButton"; -import { Key } from "../../../Keyboard"; +import {Key} from "../../../Keyboard"; import FocusLock from "react-focus-lock"; import MemberAvatar from "../avatars/MemberAvatar"; -import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton"; +import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; import MessageContextMenu from "../context_menus/MessageContextMenu"; -import { aboveLeftOf, ContextMenu } from '../../structures/ContextMenu'; +import {aboveLeftOf, ContextMenu} from '../../structures/ContextMenu'; import MessageTimestamp from "../messages/MessageTimestamp"; import SettingsStore from "../../../settings/SettingsStore"; -import { formatFullDate } from "../../../DateUtils"; +import {formatFullDate} from "../../../DateUtils"; import dis from '../../../dispatcher/dispatcher'; -import { replaceableComponent } from "../../../utils/replaceableComponent"; -import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks" -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { normalizeWheelEvent } from "../../../utils/Mouse"; +import {replaceableComponent} from "../../../utils/replaceableComponent"; +import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks" +import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import {normalizeWheelEvent} from "../../../utils/Mouse"; // Max scale to keep gaps around the image const MAX_SCALE = 0.95; @@ -167,7 +167,7 @@ export default class ImageView extends React.Component { return; } if (newZoom >= this.state.maxZoom) { - this.setState({ zoom: this.state.maxZoom }); + this.setState({zoom: this.state.maxZoom}); return; } @@ -256,11 +256,11 @@ export default class ImageView extends React.Component { // Zoom in if we are completely zoomed out if (this.state.zoom === this.state.minZoom) { - this.setState({ zoom: this.state.maxZoom }); + this.setState({zoom: this.state.maxZoom}); return; } - this.setState({ moving: true }); + this.setState({moving: true}); this.previousX = this.state.translationX; this.previousY = this.state.translationY; this.initX = ev.pageX - this.state.translationX; @@ -294,7 +294,7 @@ export default class ImageView extends React.Component { this.initX = 0; this.initY = 0; } - this.setState({ moving: false }); + this.setState({moving: false}); }; private renderContextMenu() { @@ -302,14 +302,14 @@ export default class ImageView extends React.Component { if (this.state.contextMenuDisplayed) { contextMenu = ( ); @@ -347,10 +347,10 @@ export default class ImageView extends React.Component { const style = { cursor: cursor, transition: this.state.moving ? null : "transform 200ms ease 0s", - transform: `translateX(${ translatePixelsX }) - translateY(${ translatePixelsY }) - scale(${ zoom }) - rotate(${ rotationDegrees })`, + transform: `translateX(${translatePixelsX}) + translateY(${translatePixelsY}) + scale(${zoom}) + rotate(${rotationDegrees})`, }; let info; @@ -365,38 +365,37 @@ export default class ImageView extends React.Component { const senderName = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); const sender = (
- { senderName } + {senderName}
); const messageTimestamp = ( ); const avatar = ( ); info = (
- { avatar } + {avatar}
- { sender } - { messageTimestamp } + {sender} + {messageTimestamp}
); @@ -414,10 +413,10 @@ export default class ImageView extends React.Component { contextMenuButton = ( ); } @@ -428,14 +427,14 @@ export default class ImageView extends React.Component { zoomOutButton = ( + title={_t("Zoom out")} + onClick={this.onZoomOutClick}> ); zoomInButton = ( ); @@ -443,57 +442,57 @@ export default class ImageView extends React.Component { return (
- { info } + {info}
+ title={_t("Rotate Right")} + onClick={this.onRotateClockwiseClick}> - { zoomOutButton } - { zoomInButton } + {zoomOutButton} + {zoomInButton} - { contextMenuButton } + {contextMenuButton} - { this.renderContextMenu() } + {this.renderContextMenu()}
+ ref={this.imageWrapper}>
From 5880cb3b5f032f2a274fc1bcdd4a32b9ba31b8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:26:54 +0200 Subject: [PATCH 072/134] Better wording 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index c4ec3497e4..ebff886bb3 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -144,7 +144,7 @@ export default class ImageView extends React.Component { // image by default const minZoom = Math.min(zoomX, zoomY) * MAX_SCALE; - // If zoom is smaller than minZoom don't go beneath that value + // If zoom is smaller than minZoom don't go below that value const zoom = (this.state.zoom <= this.state.minZoom) ? minZoom : this.state.zoom; this.setState({ From 0918ebad0adf697a52354e8fc837a5b35ac56f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:28:37 +0200 Subject: [PATCH 073/134] calculateZoomAndRotate -> setZoomAndRotation 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 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index ebff886bb3..b5162c6084 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -104,18 +104,18 @@ export default class ImageView extends React.Component { // needs to be passive in order to work with Chromium this.focusLock.current.addEventListener('wheel', this.onWheel, { passive: false }); // We want to recalculate zoom whenever the window's size changes - window.addEventListener("resize", this.calculateZoomAndRotate); + window.addEventListener("resize", this.setZoomAndRotation); // After the image loads for the first time we want to calculate the zoom - this.image.current.addEventListener("load", this.calculateZoomAndRotate); + this.image.current.addEventListener("load", this.setZoomAndRotation); } componentWillUnmount() { this.focusLock.current.removeEventListener('wheel', this.onWheel); - window.removeEventListener("resize", this.calculateZoomAndRotate); - this.image.current.removeEventListener("load", this.calculateZoomAndRotate); + window.removeEventListener("resize", this.setZoomAndRotation); + this.image.current.removeEventListener("load", this.setZoomAndRotation); } - private calculateZoomAndRotate = () => { + private setZoomAndRotation = () => { const image = this.image.current; const imageWrapper = this.imageWrapper.current; @@ -203,13 +203,13 @@ export default class ImageView extends React.Component { private onRotateCounterClockwiseClick = () => { const cur = this.state.rotation; this.rotation = cur - 90; - this.calculateZoomAndRotate(); + this.setZoomAndRotation(); }; private onRotateClockwiseClick = () => { const cur = this.state.rotation; this.rotation = cur + 90; - this.calculateZoomAndRotate(); + this.setZoomAndRotation(); }; private onDownloadClick = () => { From 2e47a1176f6dd883d2b68b6d35cc13d590c52fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:39:11 +0200 Subject: [PATCH 074/134] Get rid of weird rotation prop 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 | 29 ++++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index b5162c6084..e0991a1023 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -97,29 +97,34 @@ export default class ImageView extends React.Component { private initY = 0; private previousX = 0; private previousY = 0; - private rotation = 0; componentDidMount() { // We have to use addEventListener() because the listener // needs to be passive in order to work with Chromium this.focusLock.current.addEventListener('wheel', this.onWheel, { passive: false }); // We want to recalculate zoom whenever the window's size changes - window.addEventListener("resize", this.setZoomAndRotation); + window.addEventListener("resize", this.recalculateZoom); // After the image loads for the first time we want to calculate the zoom - this.image.current.addEventListener("load", this.setZoomAndRotation); + this.image.current.addEventListener("load", this.recalculateZoom); } componentWillUnmount() { this.focusLock.current.removeEventListener('wheel', this.onWheel); - window.removeEventListener("resize", this.setZoomAndRotation); - this.image.current.removeEventListener("load", this.setZoomAndRotation); + window.removeEventListener("resize", this.recalculateZoom); + this.image.current.removeEventListener("load", this.recalculateZoom); } - private setZoomAndRotation = () => { + private recalculateZoom = () => { + this.setZoomAndRotation(); + } + + private setZoomAndRotation = (inputRotation?: number) => { const image = this.image.current; const imageWrapper = this.imageWrapper.current; - const landscape = this.rotation % 180 === 0; + const rotation = inputRotation || this.state.rotation; + + const landscape = rotation % 180 === 0; // If the image is rotated take it into account const width = landscape ? image.naturalWidth : image.naturalHeight; @@ -135,7 +140,7 @@ export default class ImageView extends React.Component { zoom: 1, minZoom: 1, maxZoom: 1, - rotation: this.rotation, + rotation: rotation, }); return; } @@ -150,7 +155,7 @@ export default class ImageView extends React.Component { this.setState({ minZoom: minZoom, maxZoom: 1, - rotation: this.rotation, + rotation: rotation, zoom: zoom, }); } @@ -202,14 +207,12 @@ export default class ImageView extends React.Component { private onRotateCounterClockwiseClick = () => { const cur = this.state.rotation; - this.rotation = cur - 90; - this.setZoomAndRotation(); + this.setZoomAndRotation(cur - 90); }; private onRotateClockwiseClick = () => { const cur = this.state.rotation; - this.rotation = cur + 90; - this.setZoomAndRotation(); + this.setZoomAndRotation(cur + 90); }; private onDownloadClick = () => { From b5d271759f227a03f1905759dcab4c92149cc15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:43:43 +0200 Subject: [PATCH 075/134] Why would I format this myself if eslint can do it for me? 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 | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index e0991a1023..d0dcb1fa00 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -19,20 +19,20 @@ limitations under the License. import React, { createRef } from 'react'; import { _t } from '../../../languageHandler'; import AccessibleTooltipButton from "./AccessibleTooltipButton"; -import {Key} from "../../../Keyboard"; +import { Key } from "../../../Keyboard"; import FocusLock from "react-focus-lock"; import MemberAvatar from "../avatars/MemberAvatar"; -import {ContextMenuTooltipButton} from "../../../accessibility/context_menu/ContextMenuTooltipButton"; +import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton"; import MessageContextMenu from "../context_menus/MessageContextMenu"; -import {aboveLeftOf, ContextMenu} from '../../structures/ContextMenu'; +import { aboveLeftOf, ContextMenu } from '../../structures/ContextMenu'; import MessageTimestamp from "../messages/MessageTimestamp"; import SettingsStore from "../../../settings/SettingsStore"; -import {formatFullDate} from "../../../DateUtils"; +import { formatFullDate } from "../../../DateUtils"; import dis from '../../../dispatcher/dispatcher'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks" -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {normalizeWheelEvent} from "../../../utils/Mouse"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks" +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { normalizeWheelEvent } from "../../../utils/Mouse"; // Max scale to keep gaps around the image const MAX_SCALE = 0.95; @@ -172,7 +172,7 @@ export default class ImageView extends React.Component { return; } if (newZoom >= this.state.maxZoom) { - this.setState({zoom: this.state.maxZoom}); + this.setState({ zoom: this.state.maxZoom }); return; } @@ -185,7 +185,7 @@ export default class ImageView extends React.Component { ev.stopPropagation(); ev.preventDefault(); - const {deltaY} = normalizeWheelEvent(ev); + const { deltaY } = normalizeWheelEvent(ev); this.zoom(-(deltaY * ZOOM_COEFFICIENT)); }; @@ -259,11 +259,11 @@ export default class ImageView extends React.Component { // Zoom in if we are completely zoomed out if (this.state.zoom === this.state.minZoom) { - this.setState({zoom: this.state.maxZoom}); + this.setState({ zoom: this.state.maxZoom }); return; } - this.setState({moving: true}); + this.setState({ moving: true }); this.previousX = this.state.translationX; this.previousY = this.state.translationY; this.initX = ev.pageX - this.state.translationX; @@ -297,7 +297,7 @@ export default class ImageView extends React.Component { this.initX = 0; this.initY = 0; } - this.setState({moving: false}); + this.setState({ moving: false }); }; private renderContextMenu() { From 255f9967109ae6024dbfbab0dd5581968691dbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 15:46:03 +0200 Subject: [PATCH 076/134] landscape -> imageIsNotFlipped 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 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index d0dcb1fa00..298951428f 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -124,11 +124,11 @@ export default class ImageView extends React.Component { const rotation = inputRotation || this.state.rotation; - const landscape = rotation % 180 === 0; + const imageIsNotFlipped = rotation % 180 === 0; // If the image is rotated take it into account - const width = landscape ? image.naturalWidth : image.naturalHeight; - const height = landscape ? image.naturalHeight : image.naturalWidth; + const width = imageIsNotFlipped ? image.naturalWidth : image.naturalHeight; + const height = imageIsNotFlipped ? image.naturalHeight : image.naturalWidth; const zoomX = imageWrapper.clientWidth / width; const zoomY = imageWrapper.clientHeight / height; From 20a3dd67d6b3029c75adac9da58f162aed5aa1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 16:12:06 +0200 Subject: [PATCH 077/134] Some more styling 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 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index 298951428f..630280120c 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -368,7 +368,7 @@ export default class ImageView extends React.Component { const senderName = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); const sender = (
- {senderName} + { senderName }
); const messageTimestamp = ( @@ -395,10 +395,10 @@ export default class ImageView extends React.Component { info = (
- {avatar} + { avatar }
- {sender} - {messageTimestamp} + { sender } + { messageTimestamp }
); @@ -438,7 +438,7 @@ export default class ImageView extends React.Component { + onClick={this.onZoomInClick}> ); } @@ -454,7 +454,7 @@ export default class ImageView extends React.Component { ref={this.focusLock} >
- {info} + { info }
{ title={_t("Rotate Right")} onClick={this.onRotateClockwiseClick}> - {zoomOutButton} - {zoomInButton} + { zoomOutButton } + { zoomInButton } - {contextMenuButton} + { contextMenuButton } - {this.renderContextMenu()} + { this.renderContextMenu() }
Date: Mon, 7 Jun 2021 16:21:53 +0100 Subject: [PATCH 078/134] Fix notif panel timestamp padding This restores some space around the timestamp in the notif panel. We were previously relying somewhat randomly on the presence on empty flair elements to create space. Fixes https://github.com/vector-im/element-web/issues/17580 --- res/css/structures/_NotificationPanel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index 1258ace069..e54feca175 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -82,7 +82,6 @@ limitations under the License. color: $primary-fg-color; font-size: $font-12px; display: inline; - padding-left: 0px; } .mx_NotificationPanel .mx_EventTile_senderDetails { @@ -103,6 +102,7 @@ limitations under the License. visibility: visible; position: initial; display: inline; + padding-left: 5px; } .mx_NotificationPanel .mx_EventTile_line { From 296186b844d286062e0fe2e401320d267bb2717b Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 7 Jun 2021 16:21:53 +0100 Subject: [PATCH 079/134] Fix notif panel timestamp padding This restores some space around the timestamp in the notif panel. We were previously relying somewhat randomly on the presence on empty flair elements to create space. Fixes https://github.com/vector-im/element-web/issues/17580 --- res/css/structures/_NotificationPanel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index 1258ace069..e54feca175 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -82,7 +82,6 @@ limitations under the License. color: $primary-fg-color; font-size: $font-12px; display: inline; - padding-left: 0px; } .mx_NotificationPanel .mx_EventTile_senderDetails { @@ -103,6 +102,7 @@ limitations under the License. visibility: visible; position: initial; display: inline; + padding-left: 5px; } .mx_NotificationPanel .mx_EventTile_line { From dd089bf9696a7c5ad0b765bc41e5bf1d9a351466 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 7 Jun 2021 17:03:05 +0100 Subject: [PATCH 080/134] Upgrade matrix-js-sdk to 11.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4f6a023383..5ee56ec8cf 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "11.2.0-rc.1", + "matrix-js-sdk": "11.2.0", "matrix-widget-api": "^0.1.0-beta.14", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 1b07d4502b..5e324b7ad2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5673,10 +5673,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@11.2.0-rc.1: - version "11.2.0-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-11.2.0-rc.1.tgz#339259d892ce08195864c1130780dd0b3d996af3" - integrity sha512-ACFONqdRqiPIj7aWf7G4f/2d0S/hfouIH6tdkFGDbizbWJCmqXRJ8EN2gmu0F3A6GGDo0+k9cqaeMf3Y1KIM8w== +matrix-js-sdk@11.2.0: + version "11.2.0" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-11.2.0.tgz#b49f1ebbb671f5a8ec76eec3b21eeda97f10fb31" + integrity sha512-YsdAQNPsvoWL3fKI2fb6evO81UKfSt+hYDkBOIylzb3AA/RtUsjtSNXcT4f6BsQIVTh6xAhEjPVoMfKORchf1Q== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 187a3671110f181c8129b1f1dd47e110621cd8a0 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 7 Jun 2021 17:11:14 +0100 Subject: [PATCH 081/134] Add prop to alwaysShowTimestamps on TimelinePanel --- src/components/structures/NotificationPanel.tsx | 1 + src/components/structures/TimelinePanel.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx index b4f13f6b37..6c22835447 100644 --- a/src/components/structures/NotificationPanel.tsx +++ b/src/components/structures/NotificationPanel.tsx @@ -50,6 +50,7 @@ export default class NotificationPanel extends React.PureComponent { showUrlPreview={false} tileShape="notif" empty={emptyState} + alwaysShowTimestamps={true} /> ); } else { diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 6300c7532e..a8b0dc88dd 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -120,6 +120,9 @@ class TimelinePanel extends React.Component { // which layout to use layout: LayoutPropType, + + // whether to always show timestamps for an event + alwaysShowTimestamps: PropTypes.bool, } // a map from room id to read marker event timestamp @@ -1440,7 +1443,7 @@ class TimelinePanel extends React.Component { onFillRequest={this.onMessageListFillRequest} onUnfillRequest={this.onMessageListUnfillRequest} isTwelveHour={this.state.isTwelveHour} - alwaysShowTimestamps={this.state.alwaysShowTimestamps} + alwaysShowTimestamps={this.props.alwaysShowTimestamps || this.state.alwaysShowTimestamps} className={this.props.className} tileShape={this.props.tileShape} resizeNotifier={this.props.resizeNotifier} From 2983b3ace21f55cf36efddecea9851918d336fd9 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 7 Jun 2021 17:41:18 +0100 Subject: [PATCH 082/134] Prepare changelog for v3.23.0 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3abd1f32b..94c9530941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +Changes in [3.23.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.23.0) (2021-06-07) +===================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.23.0-rc.1...v3.23.0) + + * Upgrade to JS SDK 11.2.0 + * [Release] Fix notif panel timestamp padding + [\#6158](https://github.com/matrix-org/matrix-react-sdk/pull/6158) + Changes in [3.23.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.23.0-rc.1) (2021-06-01) =============================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.22.0...v3.23.0-rc.1) From a3dac02e4c1b4a5d632c34ad35e634cd23e59813 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 7 Jun 2021 17:41:18 +0100 Subject: [PATCH 083/134] v3.23.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5ee56ec8cf..17067df933 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.23.0-rc.1", + "version": "3.23.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From bcd0ba8d456f93c45ab57f8b769ece0815227571 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 7 Jun 2021 17:42:46 +0100 Subject: [PATCH 084/134] Resetting package fields for development --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 17067df933..dee4013006 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", @@ -200,6 +200,5 @@ "coverageReporters": [ "text" ] - }, - "typings": "./lib/index.d.ts" + } } From 8ccdf9a3e8a038def7c6be8e920839f26dae2f83 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 7 Jun 2021 17:43:27 +0100 Subject: [PATCH 085/134] 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 dee4013006..2bff2a7b13 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "11.2.0", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "matrix-widget-api": "^0.1.0-beta.14", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 5e324b7ad2..97179550c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5673,10 +5673,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@11.2.0: +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": version "11.2.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-11.2.0.tgz#b49f1ebbb671f5a8ec76eec3b21eeda97f10fb31" - integrity sha512-YsdAQNPsvoWL3fKI2fb6evO81UKfSt+hYDkBOIylzb3AA/RtUsjtSNXcT4f6BsQIVTh6xAhEjPVoMfKORchf1Q== + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/35ecbed29d16982deff27a8c37b05167738225a2" dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From 4185185cdc9e97231ca8f25ca4c9a5041429225c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 19:42:48 +0200 Subject: [PATCH 086/134] Reduce number of DOM elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/messages/SenderProfile.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index a51f50525d..df75de34ba 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -146,12 +146,10 @@ export default class SenderProfile extends React.Component { } return ( -
-
- { displayNameElement } - { mxidElement } - { flair } -
+
+ { displayNameElement } + { mxidElement } + { flair }
); } From b39c615abc6f2787decfcd5ed4c38ae6ea01d072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 7 Jun 2021 19:44:58 +0200 Subject: [PATCH 087/134] Reorder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/messages/SenderProfile.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index df75de34ba..872dc132b9 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -118,18 +118,6 @@ export default class SenderProfile extends React.Component { return null; // emote message must include the name so don't duplicate it } - let flair; - if (this.props.enableFlair) { - const displayedGroups = this._getDisplayedGroups( - this.state.userGroups, this.state.relatedGroups, - ); - - flair = ; - } - const displayNameElement = ( { displayName } @@ -145,6 +133,18 @@ export default class SenderProfile extends React.Component { ); } + let flair; + if (this.props.enableFlair) { + const displayedGroups = this._getDisplayedGroups( + this.state.userGroups, this.state.relatedGroups, + ); + + flair = ; + } + return (
{ displayNameElement } From a5bf17ff659eeb8f3d915163217d9c8574d53f54 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 7 Jun 2021 16:54:36 -0500 Subject: [PATCH 088/134] Revert incorrect change to forShareableRoom Signed-off-by: Aaron Raimist --- src/utils/permalinks/Permalinks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/permalinks/Permalinks.ts b/src/utils/permalinks/Permalinks.ts index 2f268aaa0c..c2f95defd6 100644 --- a/src/utils/permalinks/Permalinks.ts +++ b/src/utils/permalinks/Permalinks.ts @@ -293,12 +293,12 @@ export function makeRoomPermalink(roomId: string): string { // If the roomId isn't actually a room ID, don't try to list the servers. // Aliases are already routable, and don't need extra information. - if (roomId[0] !== '!') return getPermalinkConstructor().forShareableRoom(roomId, []); + if (roomId[0] !== '!') return getPermalinkConstructor().forRoom(roomId, []); const client = MatrixClientPeg.get(); const room = client.getRoom(roomId); if (!room) { - return getPermalinkConstructor().forShareableRoom(roomId, []); + return getPermalinkConstructor().forRoom(roomId, []); } const permalinkCreator = new RoomPermalinkCreator(room); permalinkCreator.load(); From 773af6c7be6244775b3c2da79e38921381b401a9 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 7 Jun 2021 16:54:50 -0500 Subject: [PATCH 089/134] Fix test Signed-off-by: Aaron Raimist --- test/utils/permalinks/Permalinks-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/permalinks/Permalinks-test.js b/test/utils/permalinks/Permalinks-test.js index 0bd4466d97..3c4982b465 100644 --- a/test/utils/permalinks/Permalinks-test.js +++ b/test/utils/permalinks/Permalinks-test.js @@ -34,7 +34,7 @@ function mockRoom(roomId, members, serverACL) { return { roomId, - getCanonicalAlias: () => roomId, + getCanonicalAlias: () => null, getJoinedMembers: () => members, getMember: (userId) => members.find(m => m.userId === userId), currentState: { From 946416cf8756ac94d0229f038e561f9215ca695f Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 7 Jun 2021 17:09:43 -0500 Subject: [PATCH 090/134] Make serverCandidates optional Signed-off-by: Aaron Raimist --- src/utils/permalinks/PermalinkConstructor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/utils/permalinks/PermalinkConstructor.ts b/src/utils/permalinks/PermalinkConstructor.ts index 25855eb024..986d20d4d1 100644 --- a/src/utils/permalinks/PermalinkConstructor.ts +++ b/src/utils/permalinks/PermalinkConstructor.ts @@ -19,11 +19,11 @@ limitations under the License. * TODO: Convert this to a real TypeScript interface */ export default class PermalinkConstructor { - forEvent(roomId: string, eventId: string, serverCandidates: string[]): string { + forEvent(roomId: string, eventId: string, serverCandidates: string[] = []): string { throw new Error("Not implemented"); } - forRoom(roomIdOrAlias: string, serverCandidates: string[]): string { + forRoom(roomIdOrAlias: string, serverCandidates: string[] = []): string { throw new Error("Not implemented"); } @@ -73,12 +73,12 @@ export class PermalinkParts { return new PermalinkParts(null, null, null, groupId, null); } - static forRoom(roomIdOrAlias: string, viaServers: string[]): PermalinkParts { - return new PermalinkParts(roomIdOrAlias, null, null, null, viaServers || []); + static forRoom(roomIdOrAlias: string, viaServers: string[] = []): PermalinkParts { + return new PermalinkParts(roomIdOrAlias, null, null, null, viaServers); } - static forEvent(roomId: string, eventId: string, viaServers: string[]): PermalinkParts { - return new PermalinkParts(roomId, eventId, null, null, viaServers || []); + static forEvent(roomId: string, eventId: string, viaServers: string[] = []): PermalinkParts { + return new PermalinkParts(roomId, eventId, null, null, viaServers); } get primaryEntityId(): string { From a8dab04d5eed882f90244f0a5b1ec54cbfaaea58 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 7 Jun 2021 19:10:45 -0400 Subject: [PATCH 091/134] Remove mystery dot from forward dialog preview It was a bullet point, since EventTiles now get created as li by default :P Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index e97958973b..b89485943a 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -211,6 +211,7 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr layout={previewLayout} enableFlair={flairEnabled} permalinkCreator={permalinkCreator} + as="div" />

From b00ad63a35fa2aa18c0ca04b803b34e252fa270c Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 7 Jun 2021 19:16:00 -0400 Subject: [PATCH 092/134] Fix whitespace nitpick Signed-off-by: Robin Townsend --- src/components/views/dialogs/ForwardDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index b89485943a..1c90dca432 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -201,7 +201,7 @@ const ForwardDialog: React.FC = ({ matrixClient: cli, event, permalinkCr onFinished={onFinished} fixedWidth={false} > -

{_t("Message preview")}

+

{ _t("Message preview") }

Date: Mon, 7 Jun 2021 19:19:14 -0400 Subject: [PATCH 093/134] Hide download links from forward dialog preview since trying to interact with them is pointless. Signed-off-by: Robin Townsend --- res/css/views/dialogs/_ForwardDialog.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 7422d39626..1976a43ab9 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -49,6 +49,11 @@ limitations under the License. .mx_EventTile_e2eIcon_unencrypted { display: none; } + + // We also hide download links to not encourage users to try interacting + .mx_MFileBody_download { + display: none; + } } > hr { From 26a030abcd76daf27c9f360000e20d54fc65cb19 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 8 Jun 2021 12:40:38 +0100 Subject: [PATCH 094/134] Better handling for widgets that fail to load --- src/components/views/elements/AppTile.js | 40 +++++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index b898ad2ebc..91ffbf2c27 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -47,9 +47,14 @@ export default class AppTile extends React.Component { // The key used for PersistedElement this._persistKey = getPersistKey(this.props.app.id); - this._sgWidget = new StopGapWidget(this.props); - this._sgWidget.on("preparing", this._onWidgetPrepared); - this._sgWidget.on("ready", this._onWidgetReady); + try { + this._sgWidget = new StopGapWidget(this.props); + this._sgWidget.on("preparing", this._onWidgetPrepared); + this._sgWidget.on("ready", this._onWidgetReady); + } catch (e) { + console.log("Failed to construct widget", e); + this._sgWidget = null; + } this.iframe = null; // ref to the iframe (callback style) this.state = this._getNewState(props); @@ -97,7 +102,7 @@ export default class AppTile extends React.Component { // Force the widget to be non-persistent (able to be deleted/forgotten) ActiveWidgetStore.destroyPersistentWidget(this.props.app.id); PersistedElement.destroyElement(this._persistKey); - this._sgWidget.stop(); + if (this._sgWidget) this._sgWidget.stop(); } this.setState({ hasPermissionToLoad }); @@ -117,7 +122,7 @@ export default class AppTile extends React.Component { componentDidMount() { // Only fetch IM token on mount if we're showing and have permission to load - if (this.state.hasPermissionToLoad) { + if (this._sgWidget && this.state.hasPermissionToLoad) { this._startWidget(); } @@ -146,10 +151,15 @@ export default class AppTile extends React.Component { if (this._sgWidget) { this._sgWidget.stop(); } - this._sgWidget = new StopGapWidget(newProps); - this._sgWidget.on("preparing", this._onWidgetPrepared); - this._sgWidget.on("ready", this._onWidgetReady); - this._startWidget(); + try { + this._sgWidget = new StopGapWidget(newProps); + this._sgWidget.on("preparing", this._onWidgetPrepared); + this._sgWidget.on("ready", this._onWidgetReady); + this._startWidget(); + } catch (e) { + console.log("Failed to construct widget", e); + this._sgWidget = null; + } } _startWidget() { @@ -161,7 +171,7 @@ export default class AppTile extends React.Component { _iframeRefChange = (ref) => { this.iframe = ref; if (ref) { - this._sgWidget.start(ref); + if (this._sgWidget) this._sgWidget.start(ref); } else { this._resetWidget(this.props); } @@ -209,7 +219,7 @@ export default class AppTile extends React.Component { // Delete the widget from the persisted store for good measure. PersistedElement.destroyElement(this._persistKey); - this._sgWidget.stop({forceDestroy: true}); + if (this._sgWidget) this._sgWidget.stop({forceDestroy: true}); } _onWidgetPrepared = () => { @@ -340,7 +350,13 @@ export default class AppTile extends React.Component {
); - if (!this.state.hasPermissionToLoad) { + if (this._sgWidget === null) { + appTileBody = ( +
+ +
+ ); + } else if (!this.state.hasPermissionToLoad) { // only possible for room widgets, can assert this.props.room here const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId); appTileBody = ( From 5c62728d13ac23721c7747c10929e38fa4f2458b Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 8 Jun 2021 12:52:32 +0100 Subject: [PATCH 095/134] Migrate end to end tests pipeline to GitHub Actions --- .github/workflows/end-to-end-tests.yml | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/end-to-end-tests.yml diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml new file mode 100644 index 0000000000..271ea06529 --- /dev/null +++ b/.github/workflows/end-to-end-tests.yml @@ -0,0 +1,32 @@ +name: "end-to-end_tests" +on: [push] +jobs: + "end-to-end_tests": + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ${{ github.workspace }} + container: + image: vectorim/element-web-ci-e2etests-env:latest + env: + CI_PACKAGE: true + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_BASE_REF: ${{ github.base_ref }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: End-to-End tests + run: ./scripts/ci/end-to-end-tests.sh + - name: Archive logs + uses: actions/upload-artifact@v2 + with: + path: | + test/end-to-end-tests/logs/**/* + test/end-to-end-tests/synapse/installations/consent/homeserver.log + retention-days: 14 + - name: Archive performance benchmark + uses: actions/upload-artifact@v2 + with: + name: performance-entries.json + path: test/end-to-end-tests/performance-entries.json From 90a58380fd3732f250f63de65a4d542b0a0a6837 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 8 Jun 2021 16:15:20 +0100 Subject: [PATCH 096/134] Make it translateable And also the other one that I copied from --- src/components/views/elements/AppTile.js | 4 ++-- src/i18n/strings/en_EN.json | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 91ffbf2c27..4028909167 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -353,7 +353,7 @@ export default class AppTile extends React.Component { if (this._sgWidget === null) { appTileBody = (
- +
); } else if (!this.state.hasPermissionToLoad) { @@ -380,7 +380,7 @@ export default class AppTile extends React.Component { if (this.isMixedContent()) { appTileBody = (
- +
); } else { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 9e85ea28c8..64613d0d88 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1926,6 +1926,8 @@ "Widgets do not use message encryption.": "Widgets do not use message encryption.", "Widget added by": "Widget added by", "This widget may use cookies.": "This widget may use cookies.", + "Error loading Widget": "Error loading Widget", + "Error - Mixed content": "Error - Mixed content", "Popout widget": "Popout widget", "Use the Desktop app to see all encrypted files": "Use the Desktop app to see all encrypted files", "Use the Desktop app to search encrypted messages": "Use the Desktop app to search encrypted messages", From f84ee2276995a5abb42225fa443e8d777dddee65 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 8 Jun 2021 16:36:53 +0100 Subject: [PATCH 097/134] Add comment --- src/components/views/right_panel/PinnedMessagesCard.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index 3a4dc9cc92..a72731522f 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -160,6 +160,7 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { } else { content =
+ { /* XXX: We reuse the classes for simplicity, but deliberately not the components for non-interactivity. */ }
From 93eb9feaa7931700323d8406a9ecd912c3f660d6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 8 Jun 2021 16:42:58 +0100 Subject: [PATCH 098/134] iterate PR based on feedback --- src/components/views/dialogs/InviteDialog.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 557ea416a8..d7f1644d80 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -1249,12 +1249,12 @@ export default class InviteDialog extends React.PureComponent { + private onCopyClick = async e => { e.preventDefault(); const target = e.target; // copy target before we go async and React throws it away @@ -1348,7 +1348,7 @@ export default class InviteDialog extends React.PureComponent { _t("Some suggestions may be hidden for privacy.") } -

{ _t("If you can’t see who you’re looking for, send them your invite link below.") }

+

{ _t("If you can't see who you’re looking for, send them your invite link below.") }

; const link = makeUserPermalink(MatrixClientPeg.get().getUserId()); footer =
From 2b99afc741a4b4b9c71f9bc454cf1d433b93f564 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 8 Jun 2021 17:05:56 +0100 Subject: [PATCH 099/134] i18n --- 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 2e8e2b39d4..a5107cba70 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2256,7 +2256,7 @@ "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", "Some suggestions may be hidden for privacy.": "Some suggestions may be hidden for privacy.", - "If you can’t see who you’re looking for, send them your invite link below.": "If you can’t see who you’re looking for, send them your invite link below.", + "If you can't see who you’re looking for, send them your invite link below.": "If you can't see who you’re looking for, send them your invite link below.", "Or send invite link": "Or send invite link", "Unnamed Space": "Unnamed Space", "Invite to %(roomName)s": "Invite to %(roomName)s", From 90982f9b3fd1345c5af5e66a46986dd11e12dd2a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 8 Jun 2021 17:31:08 +0100 Subject: [PATCH 100/134] Fix upgrade to element home button in top left menu --- src/components/structures/HostSignupAction.tsx | 5 ++++- src/components/structures/UserMenu.tsx | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/structures/HostSignupAction.tsx b/src/components/structures/HostSignupAction.tsx index 769775d549..46e158d6c8 100644 --- a/src/components/structures/HostSignupAction.tsx +++ b/src/components/structures/HostSignupAction.tsx @@ -24,13 +24,16 @@ import { HostSignupStore } from "../../stores/HostSignupStore"; import SdkConfig from "../../SdkConfig"; import {replaceableComponent} from "../../utils/replaceableComponent"; -interface IProps {} +interface IProps { + onClick?(): void; +} interface IState {} @replaceableComponent("structures.HostSignupAction") export default class HostSignupAction extends React.PureComponent { private openDialog = async () => { + this.props.onClick?.(); await HostSignupStore.instance.setHostSignupActive(true); } diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index fb4829f879..6a449cf1a2 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -366,9 +366,7 @@ export default class UserMenu extends React.Component { const mxDomain = MatrixClientPeg.get().getDomain(); const validDomains = hostSignupDomains.filter(d => (d === mxDomain || mxDomain.endsWith(`.${d}`))); if (!hostSignupConfig.domains || validDomains.length > 0) { - topSection =
- -
; + topSection = ; } } } From 7155c033f23048acab1c864e758bfed2e3344b93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 19:20:10 +0000 Subject: [PATCH 101/134] Bump trim-newlines from 3.0.0 to 3.0.1 Bumps [trim-newlines](https://github.com/sindresorhus/trim-newlines) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/sindresorhus/trim-newlines/releases) - [Commits](https://github.com/sindresorhus/trim-newlines/commits) --- updated-dependencies: - dependency-name: trim-newlines dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 97179550c9..21243f4f58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7969,9 +7969,9 @@ tree-kill@^1.2.2: integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== trim-newlines@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" - integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== trough@^1.0.0: version "1.0.5" From dbb8aa47dcbaf0558607e705727c9c8e86bc12a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 20:08:39 +0000 Subject: [PATCH 102/134] Bump css-what from 5.0.0 to 5.0.1 Bumps [css-what](https://github.com/fb55/css-what) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/fb55/css-what/releases) - [Commits](https://github.com/fb55/css-what/compare/v5.0.0...v5.0.1) --- updated-dependencies: - dependency-name: css-what dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 21243f4f58..7c12ac51d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2721,9 +2721,9 @@ css-select@^4.1.2: nth-check "^2.0.0" css-what@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.0.tgz#f0bf4f8bac07582722346ab243f6a35b512cfc47" - integrity sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA== + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== cssesc@^3.0.0: version "3.0.0" From a28f5754c7cd86d7b6d795c8fcfc6a7468c8e1e6 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Tue, 8 Jun 2021 21:58:48 -0400 Subject: [PATCH 103/134] Convert TextForEvent to TypeScript Signed-off-by: Robin Townsend --- src/{TextForEvent.js => TextForEvent.ts} | 54 +++++++++++++----------- 1 file changed, 29 insertions(+), 25 deletions(-) rename src/{TextForEvent.js => TextForEvent.ts} (94%) diff --git a/src/TextForEvent.js b/src/TextForEvent.ts similarity index 94% rename from src/TextForEvent.js rename to src/TextForEvent.ts index 22ce0dd9cf..649c53664e 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.ts @@ -25,7 +25,7 @@ import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore"; // any text to display at all. For this reason they return deferred values // to avoid the expense of looking up translations when they're not needed. -function textForMemberEvent(ev) { +function textForMemberEvent(ev): () => string | null { // XXX: SYJS-16 "sender is sometimes null for join messages" const senderName = ev.sender ? ev.sender.name : ev.getSender(); const targetName = ev.target ? ev.target.name : ev.getStateKey(); @@ -107,7 +107,7 @@ function textForMemberEvent(ev) { } } -function textForTopicEvent(ev) { +function textForTopicEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); return () => _t('%(senderDisplayName)s changed the topic to "%(topic)s".', { senderDisplayName, @@ -115,7 +115,7 @@ function textForTopicEvent(ev) { }); } -function textForRoomNameEvent(ev) { +function textForRoomNameEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); if (!ev.getContent().name || ev.getContent().name.trim().length === 0) { @@ -134,12 +134,12 @@ function textForRoomNameEvent(ev) { }); } -function textForTombstoneEvent(ev) { +function textForTombstoneEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); return () => _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); } -function textForJoinRulesEvent(ev) { +function textForJoinRulesEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().join_rule) { case "public": @@ -159,7 +159,7 @@ function textForJoinRulesEvent(ev) { } } -function textForGuestAccessEvent(ev) { +function textForGuestAccessEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().guest_access) { case "can_join": @@ -175,7 +175,7 @@ function textForGuestAccessEvent(ev) { } } -function textForRelatedGroupsEvent(ev) { +function textForRelatedGroupsEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const groups = ev.getContent().groups || []; const prevGroups = ev.getPrevContent().groups || []; @@ -205,7 +205,7 @@ function textForRelatedGroupsEvent(ev) { } } -function textForServerACLEvent(ev) { +function textForServerACLEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const prevContent = ev.getPrevContent(); const current = ev.getContent(); @@ -235,7 +235,7 @@ function textForServerACLEvent(ev) { return getText; } -function textForMessageEvent(ev) { +function textForMessageEvent(ev): () => string | null { return () => { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); let message = senderDisplayName + ': ' + ev.getContent().body; @@ -248,7 +248,7 @@ function textForMessageEvent(ev) { }; } -function textForCanonicalAliasEvent(ev) { +function textForCanonicalAliasEvent(ev): () => string | null { const senderName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const oldAlias = ev.getPrevContent().alias; const oldAltAliases = ev.getPrevContent().alt_aliases || []; @@ -299,7 +299,7 @@ function textForCanonicalAliasEvent(ev) { }); } -function textForCallAnswerEvent(event) { +function textForCallAnswerEvent(event): () => string | null { return () => { const senderName = event.sender ? event.sender.name : _t('Someone'); const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)'); @@ -307,7 +307,7 @@ function textForCallAnswerEvent(event) { }; } -function textForCallHangupEvent(event) { +function textForCallHangupEvent(event): () => string | null { const getSenderName = () => event.sender ? event.sender.name : _t('Someone'); const eventContent = event.getContent(); let getReason = () => ""; @@ -344,14 +344,14 @@ function textForCallHangupEvent(event) { return () => _t('%(senderName)s ended the call.', {senderName: getSenderName()}) + ' ' + getReason(); } -function textForCallRejectEvent(event) { +function textForCallRejectEvent(event): () => string | null { return () => { const senderName = event.sender ? event.sender.name : _t('Someone'); return _t('%(senderName)s declined the call.', {senderName}); }; } -function textForCallInviteEvent(event) { +function textForCallInviteEvent(event): () => string | null { const getSenderName = () => event.sender ? event.sender.name : _t('Someone'); // FIXME: Find a better way to determine this from the event? let isVoice = true; @@ -383,7 +383,7 @@ function textForCallInviteEvent(event) { } } -function textForThreePidInviteEvent(event) { +function textForThreePidInviteEvent(event): () => string | null { const senderName = event.sender ? event.sender.name : event.getSender(); if (!isValid3pidInvite(event)) { @@ -399,7 +399,7 @@ function textForThreePidInviteEvent(event) { }); } -function textForHistoryVisibilityEvent(event) { +function textForHistoryVisibilityEvent(event): () => string | null { const senderName = event.sender ? event.sender.name : event.getSender(); switch (event.getContent().history_visibility) { case 'invited': @@ -421,7 +421,7 @@ function textForHistoryVisibilityEvent(event) { } // Currently will only display a change if a user's power level is changed -function textForPowerEvent(event) { +function textForPowerEvent(event): () => string | null { const senderName = event.sender ? event.sender.name : event.getSender(); if (!event.getPrevContent() || !event.getPrevContent().users || !event.getContent() || !event.getContent().users) { @@ -466,12 +466,12 @@ function textForPowerEvent(event) { }); } -function textForPinnedEvent(event) { +function textForPinnedEvent(event): () => string | null { const senderName = event.sender ? event.sender.name : event.getSender(); return () => _t("%(senderName)s changed the pinned messages for the room.", {senderName}); } -function textForWidgetEvent(event) { +function textForWidgetEvent(event): () => string | null { const senderName = event.getSender(); const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent(); const {name, type, url} = event.getContent() || {}; @@ -501,12 +501,12 @@ function textForWidgetEvent(event) { } } -function textForWidgetLayoutEvent(event) { +function textForWidgetLayoutEvent(event): () => string | null { const senderName = event.sender?.name || event.getSender(); return () => _t("%(senderName)s has updated the widget layout", {senderName}); } -function textForMjolnirEvent(event) { +function textForMjolnirEvent(event): () => string | null { const senderName = event.getSender(); const {entity: prevEntity} = event.getPrevContent(); const {entity, recommendation, reason} = event.getContent(); @@ -593,7 +593,11 @@ function textForMjolnirEvent(event) { "for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}); } -const handlers = { +interface IHandlers { + [type: string]: (ev: any) => (() => string | null); +} + +const handlers: IHandlers = { 'm.room.message': textForMessageEvent, 'm.call.invite': textForCallInviteEvent, 'm.call.answer': textForCallAnswerEvent, @@ -601,7 +605,7 @@ const handlers = { 'm.call.reject': textForCallRejectEvent, }; -const stateHandlers = { +const stateHandlers: IHandlers = { 'm.room.canonical_alias': textForCanonicalAliasEvent, 'm.room.name': textForRoomNameEvent, 'm.room.topic': textForTopicEvent, @@ -626,12 +630,12 @@ for (const evType of ALL_RULE_TYPES) { stateHandlers[evType] = textForMjolnirEvent; } -export function hasText(ev) { +export function hasText(ev): boolean { const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; return Boolean(handler?.(ev)); } -export function textForEvent(ev) { +export function textForEvent(ev): string { const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; return handler?.(ev)?.() || ''; } From fccd71f82e9101ebbcab23d3ec04e6521958359f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 9 Jun 2021 06:23:51 +0200 Subject: [PATCH 104/134] Update styling based on review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/messages/_SenderProfile.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index 378d9e6f1a..7aaafa6ac3 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -20,8 +20,7 @@ limitations under the License. .mx_SenderProfile_mxid { font-weight: 600; - font-family: monospace; - font-size: 1rem; + font-size: 1.1rem; color: $event-timestamp-color; margin-left: 5px; } From c9b1d1aef06ece68109c46871bf633f823d41c7c Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 9 Jun 2021 10:38:28 +0100 Subject: [PATCH 105/134] Only run e2e tests on develop and PR targetting develop Co-authored-by: J. Ryan Stinnett --- .github/workflows/end-to-end-tests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml index 271ea06529..abf7813bbc 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/end-to-end-tests.yml @@ -1,5 +1,9 @@ name: "end-to-end_tests" -on: [push] +on: + push: + branches: [develop] + pull_request: + branches: [develop] jobs: "end-to-end_tests": runs-on: ubuntu-latest From 85d1bb65c6046330c2fd732621d9e94ced82a072 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 11:40:20 +0100 Subject: [PATCH 106/134] Upgrade to React@17 --- package.json | 8 +- yarn.lock | 288 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 193 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index 13047b69cf..ab855b84be 100644 --- a/package.json +++ b/package.json @@ -90,9 +90,9 @@ "qrcode": "^1.4.4", "qs": "^6.9.6", "re-resizable": "^6.9.0", - "react": "^16.14.0", + "react": "^17.0.2", "react-beautiful-dnd": "^4.0.1", - "react-dom": "^16.14.0", + "react-dom": "^17.0.2", "react-focus-lock": "^2.5.0", "react-transition-group": "^4.4.1", "resize-observer-polyfill": "^1.5.1", @@ -147,7 +147,7 @@ "chokidar": "^3.5.1", "concurrently": "^5.3.0", "enzyme": "^3.11.0", - "enzyme-adapter-react-16": "^1.15.6", + "@wojtekmaj/enzyme-adapter-react-17": "^0.6.1", "eslint": "7.18.0", "eslint-config-matrix-org": "^0.2.0", "eslint-plugin-babel": "^5.3.1", @@ -162,7 +162,7 @@ "matrix-mock-request": "^1.2.3", "matrix-react-test-utils": "^0.2.2", "matrix-web-i18n": "github:matrix-org/matrix-web-i18n", - "react-test-renderer": "^16.14.0", + "react-test-renderer": "^17.0.2", "rimraf": "^3.0.2", "stylelint": "^13.9.0", "stylelint-config-standard": "^20.0.0", diff --git a/yarn.lock b/yarn.lock index 0ff235a660..32480a156f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1752,6 +1752,31 @@ "@typescript-eslint/types" "4.14.0" eslint-visitor-keys "^2.0.0" +"@wojtekmaj/enzyme-adapter-react-17@^0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.6.1.tgz#28caa37118c183e5f13c4dfb68cc32cde828ecbc" + integrity sha512-xgPfzLVpN0epIHeZofahwr5qwpukEDNAbrufgeDWN6vZPtfblGCC+OZG5TlfK+A6ePVy8sBkD8S2X4tO17JKjg== + dependencies: + "@wojtekmaj/enzyme-adapter-utils" "^0.1.0" + enzyme-shallow-equal "^1.0.0" + has "^1.0.0" + object.assign "^4.1.0" + object.values "^1.1.0" + prop-types "^15.7.0" + react-is "^17.0.0" + react-test-renderer "^17.0.0" + +"@wojtekmaj/enzyme-adapter-utils@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.1.0.tgz#3a2a3db756111d53357e2f119a1612a969ab8c38" + integrity sha512-EYK/Vy0Y1ap0jH2UNQjOKtR/7HWkbEq8N+cwC5+yDf+Mwp5uu7j4Qg70RmWuzsA35DGGwgkop6m4pQsGwNOF2A== + dependencies: + function.prototype.name "^1.1.0" + has "^1.0.0" + object.assign "^4.1.0" + object.fromentries "^2.0.0" + prop-types "^15.7.0" + abab@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -1780,21 +1805,6 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -airbnb-prop-types@^2.16.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz#b96274cefa1abb14f623f804173ee97c13971dc2" - integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg== - dependencies: - array.prototype.find "^2.1.1" - function.prototype.name "^1.1.2" - is-regex "^1.1.0" - object-is "^1.1.2" - object.assign "^4.1.0" - object.entries "^1.1.2" - prop-types "^15.7.2" - prop-types-exact "^1.2.0" - react-is "^16.13.1" - ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -1920,14 +1930,6 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.find@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.1.tgz#3baca26108ca7affb08db06bf0be6cb3115a969c" - integrity sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.4" - array.prototype.flat@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" @@ -3075,35 +3077,7 @@ entities@~2.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== -enzyme-adapter-react-16@^1.15.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.6.tgz#fd677a658d62661ac5afd7f7f541f141f8085901" - integrity sha512-yFlVJCXh8T+mcQo8M6my9sPgeGzj85HSHi6Apgf1Cvq/7EL/J9+1JoJmJsRxZgyTvPMAqOEpRSu/Ii/ZpyOk0g== - dependencies: - enzyme-adapter-utils "^1.14.0" - enzyme-shallow-equal "^1.0.4" - has "^1.0.3" - object.assign "^4.1.2" - object.values "^1.1.2" - prop-types "^15.7.2" - react-is "^16.13.1" - react-test-renderer "^16.0.0-0" - semver "^5.7.0" - -enzyme-adapter-utils@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.14.0.tgz#afbb0485e8033aa50c744efb5f5711e64fbf1ad0" - integrity sha512-F/z/7SeLt+reKFcb7597IThpDp0bmzcH1E9Oabqv+o01cID2/YInlqHbFl7HzWBl4h3OdZYedtwNDOmSKkk0bg== - dependencies: - airbnb-prop-types "^2.16.0" - function.prototype.name "^1.1.3" - has "^1.0.3" - object.assign "^4.1.2" - object.fromentries "^2.0.3" - prop-types "^15.7.2" - semver "^5.7.1" - -enzyme-shallow-equal@^1.0.1, enzyme-shallow-equal@^1.0.4: +enzyme-shallow-equal@^1.0.0, enzyme-shallow-equal@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz#b9256cb25a5f430f9bfe073a84808c1d74fced2e" integrity sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q== @@ -3146,7 +3120,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.4: +es-abstract@^1.17.0-next.1: version "1.17.7" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== @@ -3183,6 +3157,28 @@ es-abstract@^1.18.0-next.1: string.prototype.trimend "^1.0.3" string.prototype.trimstart "^1.0.3" +es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" + integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + es-get-iterator@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.1.tgz#b93ddd867af16d5118e00881396533c1c6647ad9" @@ -3965,7 +3961,17 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.2, function.prototype.name@^1.1.3: +function.prototype.name@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.4.tgz#e4ea839b9d3672ae99d0efd9f38d9191c5eaac83" + integrity sha512-iqy1pIotY/RmhdFZygSSlW0wko2yxkSCKqsuv4pr8QESohpYyG/Z7B/XXvPRKTJS//960rgguE5mSRUsDdaJrQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + functions-have-names "^1.2.2" + +function.prototype.name@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.3.tgz#0bb034bb308e7682826f215eb6b2ae64918847fe" integrity sha512-H51qkbNSp8mtkJt+nyW1gyStBiKZxfRqySNUR99ylq6BPXHKI4SEvIlTKp4odLfjRKJV04DFWMU3G/YRlQOsag== @@ -3980,7 +3986,7 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -functions-have-names@^1.2.0, functions-have-names@^1.2.1: +functions-have-names@^1.2.0, functions-have-names@^1.2.1, functions-have-names@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== @@ -4004,6 +4010,15 @@ get-intrinsic@^1.0.1, get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -4157,6 +4172,11 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -4172,6 +4192,11 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -4203,7 +4228,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1, has@^1.0.3: +has@^1.0.0, has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -4534,6 +4559,11 @@ is-callable@^1.0.4, is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.2: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== +is-callable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" + integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== + is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -4736,13 +4766,21 @@ is-potential-custom-element-name@^1.0.0: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= -is-regex@^1.0.3, is-regex@^1.0.4, is-regex@^1.0.5, is-regex@^1.1.0, is-regex@^1.1.1: +is-regex@^1.0.3, is-regex@^1.0.4, is-regex@^1.0.5, is-regex@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== dependencies: has-symbols "^1.0.1" +is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.2" + is-regexp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" @@ -4768,6 +4806,11 @@ is-string@^1.0.4, is-string@^1.0.5: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== + is-subset@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" @@ -6081,6 +6124,11 @@ object-inspect@^1.1.0, object-inspect@^1.7.0, object-inspect@^1.8.0, object-insp resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== +object-inspect@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== + object-is@^1.0.2, object-is@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.4.tgz#63d6c83c00a43f4cbc9434eb9757c8a5b8565068" @@ -6121,7 +6169,17 @@ object.entries@^1.1.0, object.entries@^1.1.1, object.entries@^1.1.2: es-abstract "^1.18.0-next.1" has "^1.0.3" -object.fromentries@^2.0.2, object.fromentries@^2.0.3: +object.fromentries@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.4.tgz#26e1ba5c4571c5c6f0890cef4473066456a120b8" + integrity sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + has "^1.0.3" + +object.fromentries@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.3.tgz#13cefcffa702dc67750314a3305e8cb3fad1d072" integrity sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw== @@ -6138,7 +6196,16 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.1, object.values@^1.1.2: +object.values@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + +object.values@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.2.tgz#7a2015e06fcb0f546bd652486ce8583a4731c731" integrity sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag== @@ -6588,16 +6655,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types-exact@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869" - integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== - dependencies: - has "^1.0.3" - object.assign "^4.1.0" - reflect.ownkeys "^0.2.0" - -prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -6729,15 +6787,14 @@ react-clientside-effect@^1.2.2: dependencies: "@babel/runtime" "^7.0.0" -react-dom@^16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" + scheduler "^0.20.2" react-focus-lock@^2.5.0: version "2.5.0" @@ -6751,7 +6808,12 @@ react-focus-lock@^2.5.0: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: +"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.0, react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -6788,15 +6850,23 @@ react-redux@^5.0.6: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-test-renderer@^16.0.0-0, react-test-renderer@^16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" - integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg== +react-shallow-renderer@^16.13.1: + version "16.14.1" + resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124" + integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg== dependencies: object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.8.6" - scheduler "^0.19.1" + react-is "^16.12.0 || ^17.0.0" + +react-test-renderer@^17.0.0, react-test-renderer@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c" + integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ== + dependencies: + object-assign "^4.1.1" + react-is "^17.0.2" + react-shallow-renderer "^16.13.1" + scheduler "^0.20.2" react-transition-group@^4.4.1: version "4.4.1" @@ -6808,14 +6878,13 @@ react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^16.14.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" read-pkg-up@^2.0.0: version "2.0.0" @@ -6923,11 +6992,6 @@ redux@^3.7.2: loose-envify "^1.1.0" symbol-observable "^1.0.3" -reflect.ownkeys@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" - integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= - regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -7266,15 +7330,15 @@ saxes@^5.0.0: dependencies: xmlchars "^2.2.0" -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -7622,6 +7686,14 @@ string.prototype.trimend@^1.0.1, string.prototype.trimend@^1.0.3: call-bind "^1.0.0" define-properties "^1.1.3" +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string.prototype.trimstart@^1.0.1, string.prototype.trimstart@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" @@ -7630,6 +7702,14 @@ string.prototype.trimstart@^1.0.1, string.prototype.trimstart@^1.0.3: call-bind "^1.0.0" define-properties "^1.1.3" +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -8078,6 +8158,16 @@ ua-parser-js@^0.7.18: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + unhomoglyph@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/unhomoglyph/-/unhomoglyph-1.0.6.tgz#ea41f926d0fcf598e3b8bb2980c2ddac66b081d3" @@ -8352,7 +8442,7 @@ whatwg-url@^8.0.0: tr46 "^2.0.2" webidl-conversions "^6.1.0" -which-boxed-primitive@^1.0.1: +which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== From d492ee4d8acbf0156492cbd97e3f2f3e8153a234 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 11:57:29 +0100 Subject: [PATCH 107/134] Update Enzyme adapter name --- test/accessibility/RovingTabIndex-test.js | 2 +- .../structures/MessagePanel-test.js | 32 +++++++++---------- .../views/messages/TextualBody-test.js | 2 +- .../views/rooms/SendMessageComposer-test.js | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/accessibility/RovingTabIndex-test.js b/test/accessibility/RovingTabIndex-test.js index 5aa93f99f3..7af28043e0 100644 --- a/test/accessibility/RovingTabIndex-test.js +++ b/test/accessibility/RovingTabIndex-test.js @@ -16,7 +16,7 @@ limitations under the License. import '../skinned-sdk'; // Must be first for skinning to work import React from "react"; -import Adapter from "enzyme-adapter-react-16"; +import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { configure, mount } from "enzyme"; import { diff --git a/test/components/structures/MessagePanel-test.js b/test/components/structures/MessagePanel-test.js index 5b466b4bb0..9426998160 100644 --- a/test/components/structures/MessagePanel-test.js +++ b/test/components/structures/MessagePanel-test.js @@ -32,7 +32,7 @@ import Matrix from 'matrix-js-sdk'; const test_utils = require('../../test-utils'); const mockclock = require('../../mock-clock'); -import Adapter from "enzyme-adapter-react-16"; +import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { configure, mount } from "enzyme"; import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; @@ -77,7 +77,7 @@ describe('MessagePanel', function() { DMRoomMap.makeShared(); }); - afterEach(function () { + afterEach(function() { clock.uninstall(); }); @@ -270,7 +270,7 @@ describe('MessagePanel', function() { it('should show the events', function() { const res = TestUtils.renderIntoDocument( - , + , ); // just check we have the right number of tiles for now @@ -298,8 +298,8 @@ describe('MessagePanel', function() { it('should insert the read-marker in the right place', function() { const res = TestUtils.renderIntoDocument( - , + , ); const tiles = TestUtils.scryRenderedComponentsWithType( @@ -316,8 +316,8 @@ describe('MessagePanel', function() { it('should show the read-marker that fall in summarised events after the summary', function() { const melsEvents = mkMelsEvents(); const res = TestUtils.renderIntoDocument( - , + , ); const summary = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_EventListSummary'); @@ -334,8 +334,8 @@ describe('MessagePanel', function() { it('should hide the read-marker at the end of summarised events', function() { const melsEvents = mkMelsEventsOnly(); const res = TestUtils.renderIntoDocument( - , + , ); const summary = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_EventListSummary'); @@ -358,9 +358,9 @@ describe('MessagePanel', function() { // first render with the RM in one place let mp = ReactDOM.render( - , parentDiv); + , parentDiv); const tiles = TestUtils.scryRenderedComponentsWithType( mp, sdk.getComponent('rooms.EventTile')); @@ -374,9 +374,9 @@ describe('MessagePanel', function() { // now move the RM mp = ReactDOM.render( - , parentDiv); + , parentDiv); // now there should be two RM containers const found = TestUtils.scryRenderedDOMComponentsWithClass(mp, 'mx_RoomView_myReadMarker_container'); @@ -451,7 +451,7 @@ describe('MessagePanel', function() { expect(isReadMarkerVisible(rm)).toBeFalsy(); }); - it('should render Date separators for the events', function () { + it('should render Date separators for the events', function() { const events = mkOneDayEvents(); const res = mount( Date: Wed, 9 Jun 2021 12:17:12 +0100 Subject: [PATCH 108/134] rename workflow --- .github/workflows/{end-to-end-tests.yml => develop.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{end-to-end-tests.yml => develop.yml} (96%) diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/develop.yml similarity index 96% rename from .github/workflows/end-to-end-tests.yml rename to .github/workflows/develop.yml index abf7813bbc..346dcbaaba 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/develop.yml @@ -1,11 +1,11 @@ -name: "end-to-end_tests" +name: Develop jobs on: push: branches: [develop] pull_request: branches: [develop] jobs: - "end-to-end_tests": + end-to-end: runs-on: ubuntu-latest defaults: run: From 4e14c612b78eec426ce88e4b9f880f9535d66365 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 12:17:49 +0100 Subject: [PATCH 109/134] Remove extraenous instructions --- .github/workflows/develop.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 346dcbaaba..3f82e61280 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -7,16 +7,7 @@ on: jobs: end-to-end: runs-on: ubuntu-latest - defaults: - run: - shell: bash - working-directory: ${{ github.workspace }} - container: - image: vectorim/element-web-ci-e2etests-env:latest - env: - CI_PACKAGE: true - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_BASE_REF: ${{ github.base_ref }} + container: vectorim/element-web-ci-e2etests-env:latest steps: - name: Checkout code uses: actions/checkout@v2 From 15132074e2bd899e55da8be97650e129a05a5b64 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 13:44:31 +0100 Subject: [PATCH 110/134] Restore copy button icon when sharing permalink --- res/css/views/dialogs/_ShareDialog.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/views/dialogs/_ShareDialog.scss b/res/css/views/dialogs/_ShareDialog.scss index ce3fdd021f..4d5e1409db 100644 --- a/res/css/views/dialogs/_ShareDialog.scss +++ b/res/css/views/dialogs/_ShareDialog.scss @@ -50,7 +50,8 @@ limitations under the License. margin-left: 20px; display: inherit; } -.mx_ShareDialog_matrixto_copy > div { +.mx_ShareDialog_matrixto_copy::after { + content: ""; mask-image: url($copy-button-url); background-color: $message-action-bar-fg-color; margin-left: 5px; From ceed6ecbe87f743ddd87252a673b16fd6a7bf96a Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 14:03:31 +0100 Subject: [PATCH 111/134] Restore Page Up/Down key bindings when focusing the composer --- src/components/structures/RoomView.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 463b71922f..fe90d2f873 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1669,6 +1669,24 @@ export default class RoomView extends React.Component { }); }; + /** + * called by the parent component when PageUp/Down/etc is pressed. + * + * We pass it down to the scroll panel. + */ + private handleScrollKey = ev => { + let panel; + if (this.searchResultsPanel.current) { + panel = this.searchResultsPanel.current; + } else if (this.messagePanel) { + panel = this.messagePanel; + } + + if (panel) { + panel.handleScrollKey(ev); + } + }; + /** * get any current call for this room */ From 927de02a8e8e7a86eafeac59aecc779fecb9e986 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 14:59:55 +0100 Subject: [PATCH 112/134] Revert refreshStickyHeaders optimisations --- src/components/structures/LeftPanel.tsx | 1 + src/components/views/rooms/RoomList.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 5b6b9c3717..af22db1350 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -439,6 +439,7 @@ export default class LeftPanel extends React.Component { onBlur={this.onBlur} isMinimized={this.props.isMinimized} activeSpace={this.state.activeSpace} + onResize={this.refreshStickyHeaders} onListCollapse={this.refreshStickyHeaders} />; diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index 8b36341ed0..5a1c3a24b3 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -55,6 +55,7 @@ interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; onFocus: (ev: React.FocusEvent) => void; onBlur: (ev: React.FocusEvent) => void; + onResize: () => void; onListCollapse?: (isExpanded: boolean) => void; resizeNotifier: ResizeNotifier; isMinimized: boolean; @@ -404,7 +405,9 @@ export default class RoomList extends React.PureComponent { const newSublists = objectWithOnly(newLists, newListIds); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); - this.setState({sublists, isNameFiltering}); + this.setState({sublists, isNameFiltering}, () => { + this.props.onResize(); + }); } }; From b43315c6c1c555ebce7a032dcc2f7950e999ed83 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 9 Jun 2021 15:46:10 +0100 Subject: [PATCH 113/134] Restore read receipt animation from event to event This restores expected read receipt animation by always including the positioned parent of read receipts. I imagine there's something smarter we could be doing, but for now, at least least get back to expected behaviour. Fixes https://github.com/vector-im/element-web/issues/17561 --- src/components/views/rooms/EventTile.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 9e9d7ef53d..354e84bcae 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -644,7 +644,18 @@ export default class EventTile extends React.Component { // return early if there are no read receipts if (!this.props.readReceipts || this.props.readReceipts.length === 0) { - return null; + // We currently must include `mx_EventTile_readAvatars` in the DOM + // of all events, as it is the positioned parent of the animated + // read receipts. We can't let it unmount when a receipt moves + // events, so for now we mount it for all events. With out it, the + // animation will start from the top of the timeline (because it + // lost its container). + // See also https://github.com/vector-im/element-web/issues/17561 + return ( +
+ +
+ ); } const ReadReceiptMarker = sdk.getComponent('rooms.ReadReceiptMarker'); From e566704bdf1baf5abc81601401d6f00422117923 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 9 Jun 2021 15:48:30 +0100 Subject: [PATCH 114/134] Remove redundant early return --- src/components/views/rooms/EventTile.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 354e84bcae..48118444a5 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -663,11 +663,7 @@ export default class EventTile extends React.Component { const receiptOffset = 15; let left = 0; - const receipts = this.props.readReceipts || []; - - if (receipts.length === 0) { - return null; - } + const receipts = this.props.readReceipts; for (let i = 0; i < receipts.length; ++i) { const receipt = receipts[i]; From c6972c4535c09e914a7aaa2c980c5e2f3fe78eb3 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 9 Jun 2021 15:53:38 +0100 Subject: [PATCH 115/134] Fix spelling --- src/components/views/rooms/EventTile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 48118444a5..0861f7fd5d 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -647,7 +647,7 @@ export default class EventTile extends React.Component { // We currently must include `mx_EventTile_readAvatars` in the DOM // of all events, as it is the positioned parent of the animated // read receipts. We can't let it unmount when a receipt moves - // events, so for now we mount it for all events. With out it, the + // events, so for now we mount it for all events. Without it, the // animation will start from the top of the timeline (because it // lost its container). // See also https://github.com/vector-im/element-web/issues/17561 From bd8fd246c67a4b79f7374e1cad18001080ff4741 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 9 Jun 2021 16:04:03 +0100 Subject: [PATCH 116/134] Add logging for which rooms calls are in --- src/CallHandler.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index 0d87451b5f..bf7cb3473d 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -542,6 +542,7 @@ export default class CallHandler extends EventEmitter { if (newMappedRoomId !== mappedRoomId) { this.removeCallForRoom(mappedRoomId); mappedRoomId = newMappedRoomId; + console.log("Moving call to room " + mappedRoomId); this.calls.set(mappedRoomId, call); this.emit(CallHandlerEvent.CallChangeRoom, call); } @@ -607,6 +608,7 @@ export default class CallHandler extends EventEmitter { } private removeCallForRoom(roomId: string) { + console.log("Removing call for room ", roomId); this.calls.delete(roomId); this.emit(CallHandlerEvent.CallsChanged, this.calls); } @@ -680,6 +682,7 @@ export default class CallHandler extends EventEmitter { console.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms"); const call = MatrixClientPeg.get().createCall(mappedRoomId); + console.log("Adding call for room ", roomId); this.calls.set(roomId, call); this.emit(CallHandlerEvent.CallsChanged, this.calls); if (transferee) { @@ -812,6 +815,7 @@ export default class CallHandler extends EventEmitter { } Analytics.trackEvent('voip', 'receiveCall', 'type', call.type); + console.log("Adding call for room ", mappedRoomId); this.calls.set(mappedRoomId, call) this.emit(CallHandlerEvent.CallsChanged, this.calls); this.setCallListeners(call); From b4cb275ca1e3e5b5d7d068b8cacfed85ee375ba7 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 9 Jun 2021 17:59:41 +0100 Subject: [PATCH 117/134] Fix expanding last collapsed sticky session when zoomed in --- src/components/views/rooms/RoomSublist.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 0bb7381dbc..ba8bbffbcc 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -454,8 +454,9 @@ export default class RoomSublist extends React.Component { const sublist = possibleSticky.parentElement.parentElement; const list = sublist.parentElement.parentElement; // the scrollTop is capped at the height of the header in LeftPanel, the top header is always sticky - const isAtTop = list.scrollTop <= HEADER_HEIGHT; - const isAtBottom = list.scrollTop >= list.scrollHeight - list.offsetHeight; + const listScrollTop = Math.round(list.scrollTop); + const isAtTop = listScrollTop <= Math.round(HEADER_HEIGHT); + const isAtBottom = listScrollTop >= Math.round(list.scrollHeight - list.offsetHeight); const isStickyTop = possibleSticky.classList.contains('mx_RoomSublist_headerContainer_stickyTop'); const isStickyBottom = possibleSticky.classList.contains('mx_RoomSublist_headerContainer_stickyBottom'); From 4f649f290cafbe49c9bc7ed8ac8c20e1ae77ab35 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 10 Jun 2021 10:46:21 +0100 Subject: [PATCH 118/134] Migrate RoomSettingsDialog to TypeScript --- ...ttingsDialog.js => RoomSettingsDialog.tsx} | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) rename src/components/views/dialogs/{RoomSettingsDialog.js => RoomSettingsDialog.tsx} (87%) diff --git a/src/components/views/dialogs/RoomSettingsDialog.js b/src/components/views/dialogs/RoomSettingsDialog.tsx similarity index 87% rename from src/components/views/dialogs/RoomSettingsDialog.js rename to src/components/views/dialogs/RoomSettingsDialog.tsx index b6c4d42243..9d1608c9e4 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.js +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -16,7 +16,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import TabbedView, {Tab} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab"; @@ -39,31 +38,35 @@ export const ROOM_NOTIFICATIONS_TAB = "ROOM_NOTIFICATIONS_TAB"; export const ROOM_BRIDGES_TAB = "ROOM_BRIDGES_TAB"; export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB"; +interface IProps { + roomId: string; + onFinished: (success: boolean) => void; +} + @replaceableComponent("views.dialogs.RoomSettingsDialog") -export default class RoomSettingsDialog extends React.Component { - static propTypes = { - roomId: PropTypes.string.isRequired, - onFinished: PropTypes.func.isRequired, - }; +export default class RoomSettingsDialog extends React.Component { + private dispatcherRef: string; - componentDidMount() { - this._dispatcherRef = dis.register(this._onAction); + public componentDidMount() { + this.dispatcherRef = dis.register(this.onAction); } - componentWillUnmount() { - if (this._dispatcherRef) dis.unregister(this._dispatcherRef); + public componentWillUnmount() { + if (this.dispatcherRef) { + dis.unregister(this.dispatcherRef); + } } - _onAction = (payload) => { + private onAction = (payload): void => { // When view changes below us, close the room settings // whilst the modal is open this can only be triggered when someone hits Leave Room if (payload.action === 'view_home_page') { - this.props.onFinished(); + this.props.onFinished(true); } }; - _getTabs() { - const tabs = []; + private getTabs(): Tab[] { + const tabs: Tab[] = []; tabs.push(new Tab( ROOM_GENERAL_TAB, @@ -123,7 +126,7 @@ export default class RoomSettingsDialog extends React.Component { title={_t("Room Settings - %(roomName)s", {roomName})} >
- +
); From 7f3173f17085ee598e78c20f94db916b7f297fa7 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 10 Jun 2021 11:14:43 +0100 Subject: [PATCH 119/134] Implement unencrypted warning slate in rooms --- .../views/dialogs/RoomSettingsDialog.tsx | 6 ++- .../views/messages/EventTileBubble.tsx | 3 +- src/components/views/rooms/NewRoomIntro.tsx | 37 +++++++++++++------ src/i18n/strings/en_EN.json | 3 +- src/stores/RoomViewStore.tsx | 1 + 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index 9d1608c9e4..1a664951c5 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -41,6 +41,7 @@ export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB"; interface IProps { roomId: string; onFinished: (success: boolean) => void; + initialTabId?: string; } @replaceableComponent("views.dialogs.RoomSettingsDialog") @@ -126,7 +127,10 @@ export default class RoomSettingsDialog extends React.Component { title={_t("Room Settings - %(roomName)s", {roomName})} >
- +
); diff --git a/src/components/views/messages/EventTileBubble.tsx b/src/components/views/messages/EventTileBubble.tsx index f797a97a3d..88913ac2d4 100644 --- a/src/components/views/messages/EventTileBubble.tsx +++ b/src/components/views/messages/EventTileBubble.tsx @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {forwardRef, ReactNode} from "react"; +import React, {forwardRef, ReactNode, ReactChildren} from "react"; import classNames from "classnames"; interface IProps { className: string; title: string; subtitle?: ReactNode; + children?: ReactChildren; } const EventTileBubble = forwardRef(({ className, title, subtitle, children }, ref) => { diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 9b003ade89..21282c415a 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -33,6 +33,9 @@ import {showSpaceInvite} from "../../../utils/space"; import { privateShouldBeEncrypted } from "../../../createRoom"; +import EventTileBubble from "../messages/EventTileBubble"; +import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog"; + function hasExpectedEncryptionSettings(room): boolean { const isEncrypted: boolean = room._client.isRoomEncrypted(room.roomId); const isPublic: boolean = room.getJoinRule() === "public"; @@ -174,20 +177,30 @@ const NewRoomIntro = () => { ; } + function openRoomSettings(event) { + event.preventDefault(); + dis.dispatch({ + action: "open_room_settings", + initial_tab_id: ROOM_SECURITY_TAB, + }); + } + + const sub2 = _t("Your private messages are normally encrypted, but this room isn't." + + "Usually this is because the room was created with a device or method that doesn't support " + + "encryption, like email invites. Enable encryption in settings.", {}, + { a: sub => {sub} }); + return
+ + { !hasExpectedEncryptionSettings(room) && ( + + )} + { body } - - { !hasExpectedEncryptionSettings(room) &&

- {_t("Messages in this room are not end-to-end encrypted. " + - "Messages sent in an unencrypted room can be seen by the server and third parties. " + - "Learn more about encryption.", {}, - { - a: sub => {sub}, - })} - -

}
; }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 8508d55eba..3ab69cdb11 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1509,7 +1509,8 @@ "Invite to just this room": "Invite to just this room", "Add a photo, so people can easily spot your room.": "Add a photo, so people can easily spot your room.", "This is the start of .": "This is the start of .", - "Messages in this room are not end-to-end encrypted. Messages sent in an unencrypted room can be seen by the server and third parties. Learn more about encryption.": "Messages in this room are not end-to-end encrypted. Messages sent in an unencrypted room can be seen by the server and third parties. Learn more about encryption.", + "Your private messages are normally encrypted, but this room isn't.Usually this is because the room was created with a device or method that doesn't support encryption, like email invites. Enable encryption in settings.": "Your private messages are normally encrypted, but this room isn't.Usually this is because the room was created with a device or method that doesn't support encryption, like email invites. Enable encryption in settings.", + "This room isn't end to end encrypted": "This room isn't end to end encrypted", "Unpin": "Unpin", "View message": "View message", "%(duration)ss": "%(duration)ss", diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index 8da565f603..cc3eafffcd 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -167,6 +167,7 @@ class RoomViewStore extends Store { const RoomSettingsDialog = sdk.getComponent("dialogs.RoomSettingsDialog"); Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, { roomId: payload.room_id || this.state.roomId, + initialTabId: payload.initial_tab_id, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); break; } From 0e2e327c4650d835abf8b2b0d9cee39982383144 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 10 Jun 2021 11:19:25 +0100 Subject: [PATCH 120/134] Delete new room intro stale CSS --- res/css/views/rooms/_NewRoomIntro.scss | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/res/css/views/rooms/_NewRoomIntro.scss b/res/css/views/rooms/_NewRoomIntro.scss index 357273b597..e0cccfa885 100644 --- a/res/css/views/rooms/_NewRoomIntro.scss +++ b/res/css/views/rooms/_NewRoomIntro.scss @@ -69,24 +69,4 @@ limitations under the License. font-size: $font-15px; color: $secondary-fg-color; } - - .mx_NewRoomIntro_message:not(:first-child) { - padding-top: 1em; - margin-top: 1em; - border-top: 1px solid currentColor; - } - - .mx_NewRoomIntro_message[role=alert]::before { - --size: 25px; - content: "!"; - float: left; - border-radius: 50%; - width: var(--size); - height: var(--size); - line-height: var(--size); - text-align: center; - background: $button-danger-bg-color; - color: #fff; - margin-right: calc(var(--size) / 2); - } } From 6606a1142ded38fe85953d1cc881599491aa3054 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 10 Jun 2021 11:29:10 +0100 Subject: [PATCH 121/134] Update unencrypted room warning copy --- src/components/views/rooms/NewRoomIntro.tsx | 8 ++++---- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 21282c415a..76240f6a2f 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -185,9 +185,9 @@ const NewRoomIntro = () => { }); } - const sub2 = _t("Your private messages are normally encrypted, but this room isn't." + - "Usually this is because the room was created with a device or method that doesn't support " + - "encryption, like email invites. Enable encryption in settings.", {}, + const sub2 = _t("Your private messages are normally encrypted, but this room isn't. "+ + "Usually this is due to an unsupported device or method being used, " + + "like email invites. Enable encryption in settings.", {}, { a: sub => {sub} }); return
@@ -195,7 +195,7 @@ const NewRoomIntro = () => { { !hasExpectedEncryptionSettings(room) && ( )} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3ab69cdb11..874dc11bd2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1509,8 +1509,8 @@ "Invite to just this room": "Invite to just this room", "Add a photo, so people can easily spot your room.": "Add a photo, so people can easily spot your room.", "This is the start of .": "This is the start of .", - "Your private messages are normally encrypted, but this room isn't.Usually this is because the room was created with a device or method that doesn't support encryption, like email invites. Enable encryption in settings.": "Your private messages are normally encrypted, but this room isn't.Usually this is because the room was created with a device or method that doesn't support encryption, like email invites. Enable encryption in settings.", - "This room isn't end to end encrypted": "This room isn't end to end encrypted", + "Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. Enable encryption in settings.": "Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites. Enable encryption in settings.", + "End-to-end encryption isn't enabled": "End-to-end encryption isn't enabled", "Unpin": "Unpin", "View message": "View message", "%(duration)ss": "%(duration)ss", From 9731e275f8665b59b8a50746603ad4754392848d Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 10 Jun 2021 12:15:55 +0100 Subject: [PATCH 122/134] cater for an undefined MatrixClient on rooms --- src/components/views/rooms/NewRoomIntro.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 76240f6a2f..390a570b26 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -37,7 +37,7 @@ import EventTileBubble from "../messages/EventTileBubble"; import { ROOM_SECURITY_TAB } from "../dialogs/RoomSettingsDialog"; function hasExpectedEncryptionSettings(room): boolean { - const isEncrypted: boolean = room._client.isRoomEncrypted(room.roomId); + const isEncrypted: boolean = room._client?.isRoomEncrypted(room.roomId); const isPublic: boolean = room.getJoinRule() === "public"; return isPublic || !privateShouldBeEncrypted() || isEncrypted; } From 79b8fbc2a909364972043ebe06019406247fb9b5 Mon Sep 17 00:00:00 2001 From: Germain Date: Thu, 10 Jun 2021 14:21:48 +0100 Subject: [PATCH 123/134] Add indentation for unencrypted warning text Co-authored-by: J. Ryan Stinnett --- src/components/views/rooms/NewRoomIntro.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index 390a570b26..3bf9a9db33 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -185,10 +185,12 @@ const NewRoomIntro = () => { }); } - const sub2 = _t("Your private messages are normally encrypted, but this room isn't. "+ - "Usually this is due to an unsupported device or method being used, " + - "like email invites. Enable encryption in settings.", {}, - { a: sub => {sub} }); + const sub2 = _t( + "Your private messages are normally encrypted, but this room isn't. "+ + "Usually this is due to an unsupported device or method being used, " + + "like email invites. Enable encryption in settings.", {}, + { a: sub => {sub} }, + ); return
From 8174973cfed821249db3c3db61a489c79d776039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 10 Jun 2021 15:31:27 +0200 Subject: [PATCH 124/134] Use the same styling as for mx_TextualEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/messages/_SenderProfile.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/messages/_SenderProfile.scss b/res/css/views/messages/_SenderProfile.scss index 7aaafa6ac3..08644b14e3 100644 --- a/res/css/views/messages/_SenderProfile.scss +++ b/res/css/views/messages/_SenderProfile.scss @@ -21,6 +21,6 @@ limitations under the License. .mx_SenderProfile_mxid { font-weight: 600; font-size: 1.1rem; - color: $event-timestamp-color; margin-left: 5px; + opacity: 0.5; // Match mx_TextualEvent } From 5343be7814e9fd120c3779aa8a33951716cb2d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 10 Jun 2021 18:53:56 +0200 Subject: [PATCH 125/134] Fix buggy hovering/selecting of event tiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_EventTile.scss | 18 +++++++++++------- res/css/views/rooms/_GroupLayout.scss | 8 -------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index c8b4138f27..3af266caee 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -16,6 +16,7 @@ limitations under the License. */ $left-gutter: 64px; +$hover-select-border: 4px; .mx_EventTile { max-width: 100%; @@ -142,8 +143,7 @@ $left-gutter: 64px; } .mx_EventTile_selected > div > a > .mx_MessageTimestamp { - left: 3px; - width: auto; + left: calc(-$hover-select-border); } .mx_EventTile:hover .mx_MessageActionBar, @@ -158,7 +158,7 @@ $left-gutter: 64px; */ .mx_EventTile_selected > .mx_EventTile_line { border-left: $accent-color 4px solid; - padding-left: 60px; + padding-left: calc($left-gutter - $hover-select-border); background-color: $event-selected-color; } @@ -171,8 +171,12 @@ $left-gutter: 64px; } } +.mx_EventTile_info .mx_EventTile_line { + padding-left: calc($left-gutter + 18px); +} + .mx_EventTile_selected.mx_EventTile_info .mx_EventTile_line { - padding-left: 78px; + padding-left: calc($left-gutter + 18px - $hover-select-border); } .mx_EventTile:hover .mx_EventTile_line, @@ -408,7 +412,7 @@ $left-gutter: 64px; .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line { - padding-left: 60px; + padding-left: calc($left-gutter - $hover-select-border); } .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line { @@ -426,7 +430,7 @@ $left-gutter: 64px; .mx_EventTile:hover.mx_EventTile_verified.mx_EventTile_info .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unverified.mx_EventTile_info .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unknown.mx_EventTile_info .mx_EventTile_line { - padding-left: 78px; + padding-left: calc($left-gutter + 18px - $hover-select-border); } /* End to end encryption stuff */ @@ -438,7 +442,7 @@ $left-gutter: 64px; .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line > a > .mx_MessageTimestamp, .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line > a > .mx_MessageTimestamp, .mx_EventTile:hover.mx_EventTile_unknown .mx_EventTile_line > a > .mx_MessageTimestamp { - width: $MessageTimestamp_width_hover; + left: calc(-$hover-select-border); } // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) diff --git a/res/css/views/rooms/_GroupLayout.scss b/res/css/views/rooms/_GroupLayout.scss index 818509785b..ddee81a914 100644 --- a/res/css/views/rooms/_GroupLayout.scss +++ b/res/css/views/rooms/_GroupLayout.scss @@ -24,10 +24,6 @@ $left-gutter: 64px; margin-left: $left-gutter; } - > .mx_EventTile_line { - padding-left: $left-gutter; - } - > .mx_EventTile_avatar { position: absolute; } @@ -43,10 +39,6 @@ $left-gutter: 64px; line-height: $font-22px; } } - - .mx_EventTile_info .mx_EventTile_line { - padding-left: calc($left-gutter + 18px); - } } /* Compact layout overrides */ From b1824ce579c805c8c293aee739808b71bc030614 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 11 Jun 2021 11:34:53 +0100 Subject: [PATCH 126/134] fix HTML tag for Event Tile when not rendered in a list --- .../views/elements/EventTilePreview.tsx | 1 + src/components/views/rooms/EventTile.tsx | 150 ++++++++++-------- src/components/views/rooms/ReplyPreview.js | 1 + 3 files changed, 82 insertions(+), 70 deletions(-) diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx index b15fbbed2b..cf3b7a6e61 100644 --- a/src/components/views/elements/EventTilePreview.tsx +++ b/src/components/views/elements/EventTilePreview.tsx @@ -128,6 +128,7 @@ export default class EventTilePreview extends React.Component { mxEvent={event} layout={this.props.layout} enableFlair={SettingsStore.getValue(UIFeature.Flair)} + as="div" />
; } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 0861f7fd5d..85b9cac2c4 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -1059,58 +1059,65 @@ export default class EventTile extends React.Component { switch (this.props.tileShape) { case 'notif': { const room = this.context.getRoom(this.props.mxEvent.getRoomId()); - return ( -
  • - - -
    - -
    -
  • - ); + return React.createElement(this.props.as || "li", { + "className": classes, + "aria-live": ariaLive, + "aria-atomic": true, + "data-scroll-tokens": scrollToken, + }, [ + , + , +
    + +
    , + ]); } case 'file_grid': { - return ( -
  • -
    - + return React.createElement(this.props.as || "li", { + "className": classes, + "aria-live": ariaLive, + "aria-atomic": true, + "data-scroll-tokens": scrollToken, + }, [ +
    + +
    , + +
    + { sender } + { timestamp }
    -
    -
    - { sender } - { timestamp } -
    -
    -
  • - ); + , + ]); } case 'reply': @@ -1126,27 +1133,30 @@ export default class EventTile extends React.Component { this.props.alwaysShowTimestamps || this.state.hover, ); } - return ( -
  • - { ircTimestamp } - { avatar } - { sender } - { ircPadlock } -
    - { groupTimestamp } - { groupPadlock } - { thread } - -
    -
  • - ); + return React.createElement(this.props.as || "li", { + "className": classes, + "aria-live": ariaLive, + "aria-atomic": true, + "data-scroll-tokens": scrollToken, + }, [ + ircTimestamp, + avatar, + sender, + ircPadlock, +
    + { groupTimestamp } + { groupPadlock } + { thread } + +
    , + ]); } default: { const thread = ReplyThread.makeThread( diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 5835eb9f36..c61424a059 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -95,6 +95,7 @@ export default class ReplyPreview extends React.Component { permalinkCreator={this.props.permalinkCreator} isTwelveHour={SettingsStore.getValue("showTwelveHourTimestamps")} enableFlair={SettingsStore.getValue(UIFeature.Flair)} + as="div" />
    ; From 84679cf8ec5bfe764cda2743f69a9099fe79c38a Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 11 Jun 2021 12:19:14 +0100 Subject: [PATCH 127/134] remove legacy polyfills and unused dependencies --- package.json | 3 --- src/ContentMessages.tsx | 2 -- src/CountlyAnalytics.ts | 7 ------- src/rageshake/submit-rageshake.ts | 6 ------ src/utils/MegolmExportEncryption.js | 11 ----------- yarn.lock | 10 ---------- 6 files changed, 39 deletions(-) diff --git a/package.json b/package.json index dbb6b29b53..4dc4bda3b2 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "dependencies": { "@babel/runtime": "^7.12.5", "await-lock": "^2.1.0", - "blueimp-canvas-to-blob": "^3.28.0", "browser-encrypt-attachment": "^0.3.0", "browser-request": "^0.3.3", "cheerio": "^1.0.0-rc.9", @@ -88,7 +87,6 @@ "png-chunks-extract": "^1.0.0", "prop-types": "^15.7.2", "qrcode": "^1.4.4", - "qs": "^6.9.6", "re-resizable": "^6.9.0", "react": "^17.0.2", "react-beautiful-dnd": "^4.0.1", @@ -99,7 +97,6 @@ "rfc4648": "^1.4.0", "sanitize-html": "^2.3.2", "tar-js": "^0.3.0", - "text-encoding-utf-8": "^1.0.2", "url": "^0.11.0", "what-input": "^5.2.10", "zxcvbn": "^4.4.2" diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index b21829ac63..9042d47243 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -28,8 +28,6 @@ import encrypt from "browser-encrypt-attachment"; import extractPngChunks from "png-chunks-extract"; import Spinner from "./components/views/elements/Spinner"; -// Polyfill for Canvas.toBlob API using Canvas.toDataURL -import "blueimp-canvas-to-blob"; import { Action } from "./dispatcher/actions"; import CountlyAnalytics from "./CountlyAnalytics"; import { diff --git a/src/CountlyAnalytics.ts b/src/CountlyAnalytics.ts index 5545ed8483..f494c1eb22 100644 --- a/src/CountlyAnalytics.ts +++ b/src/CountlyAnalytics.ts @@ -24,13 +24,6 @@ import {sleep} from "./utils/promise"; import RoomViewStore from "./stores/RoomViewStore"; import { Action } from "./dispatcher/actions"; -// polyfill textencoder if necessary -import * as TextEncodingUtf8 from 'text-encoding-utf-8'; -let TextEncoder = window.TextEncoder; -if (!TextEncoder) { - TextEncoder = TextEncodingUtf8.TextEncoder; -} - const INACTIVITY_TIME = 20; // seconds const HEARTBEAT_INTERVAL = 5_000; // ms const SESSION_UPDATE_INTERVAL = 60; // seconds diff --git a/src/rageshake/submit-rageshake.ts b/src/rageshake/submit-rageshake.ts index b2ad9fe6f6..08d8ccfd13 100644 --- a/src/rageshake/submit-rageshake.ts +++ b/src/rageshake/submit-rageshake.ts @@ -25,14 +25,8 @@ import Tar from "tar-js"; import * as rageshake from './rageshake'; -// polyfill textencoder if necessary -import * as TextEncodingUtf8 from 'text-encoding-utf-8'; import SettingsStore from "../settings/SettingsStore"; import SdkConfig from "../SdkConfig"; -let TextEncoder = window.TextEncoder; -if (!TextEncoder) { - TextEncoder = TextEncodingUtf8.TextEncoder; -} interface IOpts { label?: string; diff --git a/src/utils/MegolmExportEncryption.js b/src/utils/MegolmExportEncryption.js index 6f5c7104b1..ae6b2999fa 100644 --- a/src/utils/MegolmExportEncryption.js +++ b/src/utils/MegolmExportEncryption.js @@ -15,17 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -// polyfill textencoder if necessary -import * as TextEncodingUtf8 from 'text-encoding-utf-8'; -let TextEncoder = window.TextEncoder; -if (!TextEncoder) { - TextEncoder = TextEncodingUtf8.TextEncoder; -} -let TextDecoder = window.TextDecoder; -if (!TextDecoder) { - TextDecoder = TextEncodingUtf8.TextDecoder; -} - import { _t } from '../languageHandler'; import SdkConfig from '../SdkConfig'; diff --git a/yarn.lock b/yarn.lock index 2b8667c7a6..f98cb5845e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2181,11 +2181,6 @@ bluebird@^3.5.0: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -blueimp-canvas-to-blob@^3.28.0: - version "3.28.0" - resolved "https://registry.yarnpkg.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.28.0.tgz#c8ab4dc6bb08774a7f273798cdf94b0776adf6c8" - integrity sha512-5q+YHzgGsuHQ01iouGgJaPJXod2AzTxJXmVv90PpGrRxU7G7IqgPqWXz+PBmt3520jKKi6irWbNV87DicEa7wg== - boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -7945,11 +7940,6 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" From 37484e3fc465ef5a05a5001580facbea37d10bb5 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 11 Jun 2021 12:33:02 +0100 Subject: [PATCH 128/134] Add TextEncoder polyfill for test run --- test/setupTests.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/setupTests.js b/test/setupTests.js index 6d37d48987..9da412a7e8 100644 --- a/test/setupTests.js +++ b/test/setupTests.js @@ -1,6 +1,12 @@ import * as languageHandler from "../src/languageHandler"; +import { TextEncoder, TextDecoder } from 'util'; languageHandler.setLanguage('en'); languageHandler.setMissingEntryGenerator(key => key.split("|", 2)[1]); require('jest-fetch-mock').enableMocks(); + +// polyfilling TextEncoder as it is not available on JSDOM +// view https://github.com/facebook/jest/issues/9983 +global.TextEncoder = TextEncoder; +global.TextDecoder = TextDecoder; From e260e8671fab08da34f8c9abc30ec39e1aa486d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 11 Jun 2021 15:14:16 +0200 Subject: [PATCH 129/134] Inline display name into return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/messages/SenderProfile.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index 872dc132b9..805f842fbc 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -118,12 +118,6 @@ export default class SenderProfile extends React.Component { return null; // emote message must include the name so don't duplicate it } - const displayNameElement = ( - - { displayName } - - ); - let mxidElement; if (disambiguate) { mxidElement = ( @@ -147,7 +141,9 @@ export default class SenderProfile extends React.Component { return (
    - { displayNameElement } + + { displayName } + { mxidElement } { flair }
    From 2eafe132b8b0650b058faa4be3bbdc4e5167ff38 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 14 Jun 2021 13:31:58 -0600 Subject: [PATCH 130/134] Move various createRoom types to the js-sdk --- src/components/structures/SpaceRoomView.tsx | 3 +- .../views/dialogs/CreateRoomDialog.tsx | 21 ++++---- .../views/spaces/SpaceCreateMenu.tsx | 6 ++- src/createRoom.ts | 52 ++----------------- src/mjolnir/Mjolnir.ts | 3 +- 5 files changed, 23 insertions(+), 62 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 276f4ae6ca..3ccf2e5424 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -28,7 +28,7 @@ import RoomTopic from "../views/elements/RoomTopic"; import InlineSpinner from "../views/elements/InlineSpinner"; import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite"; import {useRoomMembers} from "../../hooks/useRoomMembers"; -import createRoom, {IOpts, Preset} from "../../createRoom"; +import createRoom, {IOpts} from "../../createRoom"; import Field from "../views/elements/Field"; import {useEventEmitter} from "../../hooks/useEventEmitter"; import withValidation from "../views/elements/Validation"; @@ -65,6 +65,7 @@ import dis from "../../dispatcher/dispatcher"; import Modal from "../../Modal"; import BetaFeedbackDialog from "../views/dialogs/BetaFeedbackDialog"; import SdkConfig from "../../SdkConfig"; +import { Preset } from "matrix-js-sdk/src/@types/partials"; interface IProps { space: Room; diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index cce6b6c34c..544f593708 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -15,22 +15,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ChangeEvent, createRef, KeyboardEvent, SyntheticEvent} from "react"; -import {Room} from "matrix-js-sdk/src/models/room"; +import React, { ChangeEvent, createRef, KeyboardEvent, SyntheticEvent } from "react"; +import { Room } from "matrix-js-sdk/src/models/room"; import SdkConfig from '../../../SdkConfig'; -import withValidation, {IFieldState} from '../elements/Validation'; -import {_t} from '../../../languageHandler'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {Key} from "../../../Keyboard"; -import {IOpts, Preset, privateShouldBeEncrypted, Visibility} from "../../../createRoom"; -import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import withValidation, { IFieldState } from '../elements/Validation'; +import { _t } from '../../../languageHandler'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import { Key } from "../../../Keyboard"; +import { IOpts, privateShouldBeEncrypted } from "../../../createRoom"; +import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import Field from "../elements/Field"; import RoomAliasField from "../elements/RoomAliasField"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import DialogButtons from "../elements/DialogButtons"; import BaseDialog from "../dialogs/BaseDialog"; +import { Preset, Visibility } from "matrix-js-sdk/src/@types/partials"; interface IProps { defaultPublic?: boolean; @@ -72,7 +73,7 @@ export default class CreateRoomDialog extends React.Component { canChangeEncryption: true, }; - MatrixClientPeg.get().doesServerForceEncryptionForPreset("private") + MatrixClientPeg.get().doesServerForceEncryptionForPreset(Preset.PrivateChat) .then(isForced => this.setState({ canChangeEncryption: !isForced })); } diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 0ebf511018..6a935ab276 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -22,7 +22,7 @@ import FocusLock from "react-focus-lock"; import {_t} from "../../../languageHandler"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import {ChevronFace, ContextMenu} from "../../structures/ContextMenu"; -import createRoom, {IStateEvent, Preset} from "../../../createRoom"; +import createRoom from "../../../createRoom"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {SpaceAvatar} from "./SpaceBasicSettings"; import AccessibleButton from "../elements/AccessibleButton"; @@ -33,6 +33,8 @@ import {USER_LABS_TAB} from "../dialogs/UserSettingsDialog"; import Field from "../elements/Field"; import withValidation from "../elements/Validation"; import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView"; +import { Preset } from "matrix-js-sdk/src/@types/partials"; +import { ICreateRoomStateEvent } from "matrix-js-sdk/src/@types/requests"; const SpaceCreateMenuType = ({ title, description, className, onClick }) => { return ( @@ -81,7 +83,7 @@ const SpaceCreateMenu = ({ onFinished }) => { return; } - const initialState: IStateEvent[] = [ + const initialState: ICreateRoomStateEvent[] = [ { type: EventType.RoomHistoryVisibility, content: { diff --git a/src/createRoom.ts b/src/createRoom.ts index c6507b1380..2641492588 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -35,53 +35,15 @@ import { VIRTUAL_ROOM_EVENT_TYPE } from "./CallHandler"; import SpaceStore from "./stores/SpaceStore"; import { makeSpaceParentEvent } from "./utils/space"; import { Action } from "./dispatcher/actions" +import { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests"; +import { Preset, Visibility } from "matrix-js-sdk/src/@types/partials"; // we define a number of interfaces which take their names from the js-sdk /* eslint-disable camelcase */ -// TODO move these interfaces over to js-sdk once it has been typescripted enough to accept them -export enum Visibility { - Public = "public", - Private = "private", -} - -export enum Preset { - PrivateChat = "private_chat", - TrustedPrivateChat = "trusted_private_chat", - PublicChat = "public_chat", -} - -interface Invite3PID { - id_server: string; - id_access_token?: string; // this gets injected by the js-sdk - medium: string; - address: string; -} - -export interface IStateEvent { - type: string; - state_key?: string; // defaults to an empty string - content: object; -} - -interface ICreateOpts { - visibility?: Visibility; - room_alias_name?: string; - name?: string; - topic?: string; - invite?: string[]; - invite_3pid?: Invite3PID[]; - room_version?: string; - creation_content?: object; - initial_state?: IStateEvent[]; - preset?: Preset; - is_direct?: boolean; - power_level_content_override?: object; -} - export interface IOpts { dmUserId?: string; - createOpts?: ICreateOpts; + createOpts?: ICreateRoomOpts; spinner?: boolean; guestAccess?: boolean; encryption?: boolean; @@ -91,12 +53,6 @@ export interface IOpts { parentSpace?: Room; } -export interface IInvite3PID { - id_server: string, - medium: 'email', - address: string, -} - /** * Create a new room, and switch to it. * @@ -136,7 +92,7 @@ export default function createRoom(opts: IOpts): Promise { const defaultPreset = opts.dmUserId ? Preset.TrustedPrivateChat : Preset.PrivateChat; // set some defaults for the creation - const createOpts = opts.createOpts || {}; + const createOpts: ICreateRoomOpts = opts.createOpts || {}; createOpts.preset = createOpts.preset || defaultPreset; createOpts.visibility = createOpts.visibility || Visibility.Private; if (opts.dmUserId && createOpts.invite === undefined) { diff --git a/src/mjolnir/Mjolnir.ts b/src/mjolnir/Mjolnir.ts index 891438bbb9..f1fe816642 100644 --- a/src/mjolnir/Mjolnir.ts +++ b/src/mjolnir/Mjolnir.ts @@ -20,6 +20,7 @@ import SettingsStore from "../settings/SettingsStore"; import {_t} from "../languageHandler"; import dis from "../dispatcher/dispatcher"; import {SettingLevel} from "../settings/SettingLevel"; +import { Preset } from "matrix-js-sdk/src/@types/partials"; // TODO: Move this and related files to the js-sdk or something once finalized. @@ -86,7 +87,7 @@ export class Mjolnir { const resp = await MatrixClientPeg.get().createRoom({ name: _t("My Ban List"), topic: _t("This is your list of users/servers you have blocked - don't leave the room!"), - preset: "private_chat", + preset: Preset.PrivateChat, }); personalRoomId = resp['room_id']; await SettingsStore.setValue( From 951fbf4a1a06f52d40b2eefc21937a3383e983ea Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 14 Jun 2021 13:38:43 -0600 Subject: [PATCH 131/134] fix import --- src/components/views/dialogs/InviteDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index b006205f11..d90214110f 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -31,7 +31,6 @@ import Modal from "../../../Modal"; import {humanizeTime} from "../../../utils/humanize"; import createRoom, { canEncryptToAllUsers, ensureDMExists, findDMForUser, privateShouldBeEncrypted, - IInvite3PID, } from "../../../createRoom"; import {inviteMultipleToRoom, showCommunityInviteDialog} from "../../../RoomInvite"; import {Key} from "../../../Keyboard"; @@ -50,6 +49,7 @@ import {getAddressType} from "../../../UserAddress"; import BaseAvatar from '../avatars/BaseAvatar'; import AccessibleButton from '../elements/AccessibleButton'; import { compare } from '../../../utils/strings'; +import { IInvite3PID } from "matrix-js-sdk/src/@types/requests"; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ From f8eea2ae23ccf9bc58af983d236249d1ed878831 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 14 Jun 2021 22:18:02 +0100 Subject: [PATCH 132/134] Fix word wrap in space descriptions --- res/css/structures/_SpaceRoomView.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index 12762cbc9d..48b565be7f 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -328,7 +328,8 @@ $SpaceRoomViewInnerWidth: 428px; font-size: $font-15px; margin-top: 12px; margin-bottom: 16px; - white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; } > hr { From 430ec8cecd002cbc5996ec313bb0f7322a6eee14 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 14 Jun 2021 22:18:18 +0100 Subject: [PATCH 133/134] Clear selected rooms after operation in manage space rooms --- src/components/structures/SpaceRoomDirectory.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index 8d59fe6c68..acbde0b097 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -520,6 +520,7 @@ export const SpaceHierarchy: React.FC = ({ setError("Failed to update some suggestions. Try again later"); } setSaving(false); + setSelected(new Map()); }} kind="primary_outline" disabled={disabled} From d08495bde68f206ba39d3941950a3a34f279abbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 15 Jun 2021 06:30:22 +0200 Subject: [PATCH 134/134] Fix display name overlap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- res/css/views/rooms/_IRCLayout.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss index cf61ce569d..ae8d22a462 100644 --- a/res/css/views/rooms/_IRCLayout.scss +++ b/res/css/views/rooms/_IRCLayout.scss @@ -178,7 +178,7 @@ $irc-line-height: $font-18px; overflow: hidden; display: flex; - > .mx_SenderProfile_name { + > .mx_SenderProfile_displayName { overflow: hidden; text-overflow: ellipsis; min-width: var(--name-width); @@ -207,7 +207,7 @@ $irc-line-height: $font-18px; background: transparent; > span { - > .mx_SenderProfile_name { + > .mx_SenderProfile_displayName { min-width: inherit; } }