From a29487625eef9adaba8ca2653a8a82cc81f47ad1 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Thu, 9 Sep 2021 02:11:47 -0400 Subject: [PATCH 01/27] Set dark theme colors for auth components Fixes https://github.com/vector-im/element-web/issues/18865 Signed-off-by: Andrew Ferrazzutti --- res/themes/dark/css/_dark.scss | 3 +++ res/themes/light-custom/css/_custom.scss | 2 ++ 2 files changed, 5 insertions(+) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 4a6db5dd55..f323fb8087 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -184,6 +184,9 @@ $visual-bell-bg-color: #800; $room-warning-bg-color: $header-panel-bg-color; +$authpage-body-bg-color: $background; +$authpage-primary-color: $text-primary-color; + $dark-panel-bg-color: $header-panel-bg-color; $panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1); diff --git a/res/themes/light-custom/css/_custom.scss b/res/themes/light-custom/css/_custom.scss index f4685fe8fa..455798a556 100644 --- a/res/themes/light-custom/css/_custom.scss +++ b/res/themes/light-custom/css/_custom.scss @@ -82,6 +82,8 @@ $tab-label-fg-color: var(--timeline-text-color); // was #4e5054 $authpage-lang-color: var(--timeline-text-color); $roomheader-color: var(--timeline-text-color); +// was #232f32 +$authpage-primary-color: var(--timeline-text-color); // --roomlist-text-secondary-color $roomtile-preview-color: var(--roomlist-text-secondary-color); $roomlist-header-color: var(--roomlist-text-secondary-color); From 329bc8a89e409e342364ff2bc9f3dc52797b7732 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 9 Sep 2021 13:14:05 +0100 Subject: [PATCH 02/27] Move unsent event badge handling into RoomNotificationState --- src/components/views/rooms/RoomTile.tsx | 49 ++++--------------- .../notifications/RoomNotificationState.ts | 14 +++++- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 4d6de10e1f..8ed2ca85e9 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { createRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import classNames from "classnames"; import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton"; @@ -51,8 +50,6 @@ import IconizedContextMenu, { } from "../context_menus/IconizedContextMenu"; import { CommunityPrototypeStore, IRoomProfile } from "../../../stores/CommunityPrototypeStore"; import { replaceableComponent } from "../../../utils/replaceableComponent"; -import { getUnsentMessages } from "../../structures/RoomStatusBar"; -import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState"; interface IProps { room: Room; @@ -68,7 +65,6 @@ interface IState { notificationsMenuPosition: PartialDOMRect; generalMenuPosition: PartialDOMRect; messagePreview?: string; - hasUnsentEvents: boolean; } const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`; @@ -95,7 +91,6 @@ export default class RoomTile extends React.PureComponent { selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId, notificationsMenuPosition: null, generalMenuPosition: null, - hasUnsentEvents: this.countUnsentEvents() > 0, // generatePreview() will return nothing if the user has previews disabled messagePreview: "", @@ -106,10 +101,6 @@ export default class RoomTile extends React.PureComponent { this.roomProps = EchoChamber.forRoom(this.props.room); } - private countUnsentEvents(): number { - return getUnsentMessages(this.props.room).length; - } - private onRoomNameUpdate = (room) => { this.forceUpdate(); }; @@ -118,11 +109,6 @@ export default class RoomTile extends React.PureComponent { this.forceUpdate(); // notification state changed - update }; - private onLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { - if (room?.roomId !== this.props.room.roomId) return; - this.setState({ hasUnsentEvents: this.countUnsentEvents() > 0 }); - }; - private onRoomPropertyUpdate = (property: CachedRoomKey) => { if (property === CachedRoomKey.NotificationVolume) this.onNotificationUpdate(); // else ignore - not important for this tile @@ -183,7 +169,6 @@ export default class RoomTile extends React.PureComponent { CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId), this.onCommunityUpdate, ); - MatrixClientPeg.get().on("Room.localEchoUpdated", this.onLocalEchoUpdated); } public componentWillUnmount() { @@ -208,7 +193,6 @@ export default class RoomTile extends React.PureComponent { CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId), this.onCommunityUpdate, ); - MatrixClientPeg.get()?.removeListener("Room.localEchoUpdated", this.onLocalEchoUpdated); } private onAction = (payload: ActionPayload) => { @@ -587,30 +571,17 @@ export default class RoomTile extends React.PureComponent { />; let badge: React.ReactNode; - if (!this.props.isMinimized) { + if (!this.props.isMinimized && this.notificationState) { // aria-hidden because we summarise the unread count/highlight status in a manual aria-label below - if (this.state.hasUnsentEvents) { - // hardcode the badge to a danger state when there's unsent messages - badge = ( - - ); - } else if (this.notificationState) { - badge = ( - - ); - } + badge = ( + + ); } let messagePreview = null; diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts index 3fadbe7d7a..0a2e801620 100644 --- a/src/stores/notifications/RoomNotificationState.ts +++ b/src/stores/notifications/RoomNotificationState.ts @@ -24,6 +24,7 @@ import { Room } from "matrix-js-sdk/src/models/room"; import * as RoomNotifs from '../../RoomNotifs'; import * as Unread from '../../Unread'; import { NotificationState } from "./NotificationState"; +import { getUnsentMessages } from "../../components/structures/RoomStatusBar"; export class RoomNotificationState extends NotificationState implements IDestroyable { constructor(public readonly room: Room) { @@ -32,6 +33,7 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.room.on("Room.timeline", this.handleRoomEventUpdate); this.room.on("Room.redaction", this.handleRoomEventUpdate); this.room.on("Room.myMembership", this.handleMembershipUpdate); + this.room.on("Room.localEchoUpdated", this.handleLocalEchoUpdated); MatrixClientPeg.get().on("Event.decrypted", this.handleRoomEventUpdate); MatrixClientPeg.get().on("accountData", this.handleAccountDataUpdate); this.updateNotificationState(); @@ -47,12 +49,17 @@ export class RoomNotificationState extends NotificationState implements IDestroy this.room.removeListener("Room.timeline", this.handleRoomEventUpdate); this.room.removeListener("Room.redaction", this.handleRoomEventUpdate); this.room.removeListener("Room.myMembership", this.handleMembershipUpdate); + this.room.removeListener("Room.localEchoUpdated", this.handleLocalEchoUpdated); if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Event.decrypted", this.handleRoomEventUpdate); MatrixClientPeg.get().removeListener("accountData", this.handleAccountDataUpdate); } } + private handleLocalEchoUpdated = () => { + this.updateNotificationState(); + }; + private handleReadReceipt = (event: MatrixEvent, room: Room) => { if (!readReceiptChangeIsFor(event, MatrixClientPeg.get())) return; // not our own - ignore if (room.roomId !== this.room.roomId) return; // not for us - ignore @@ -79,7 +86,12 @@ export class RoomNotificationState extends NotificationState implements IDestroy private updateNotificationState() { const snapshot = this.snapshot(); - if (RoomNotifs.getRoomNotifsState(this.room.roomId) === RoomNotifs.MUTE) { + if (getUnsentMessages(this.room).length > 0) { + // When there are unsent messages we show a red `!` + this._color = NotificationColor.Red; + this._symbol = "!"; + this._count = 1; // not used, technically + } else if (RoomNotifs.getRoomNotifsState(this.room.roomId) === RoomNotifs.MUTE) { // When muted we suppress all notification states, even if we have context on them. this._color = NotificationColor.None; this._symbol = null; From 09ef07a3b06206c075eaed87aacb01b692669acc Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Fri, 10 Sep 2021 01:21:53 -0400 Subject: [PATCH 03/27] Replace dark theme's $authpage-primary-color Use `$primary-content` instead of `$text-primary-color`. Signed-off-by: Andrew Ferrazzutti --- res/themes/dark/css/_dark.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index f323fb8087..0bc61d438d 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -185,7 +185,7 @@ $visual-bell-bg-color: #800; $room-warning-bg-color: $header-panel-bg-color; $authpage-body-bg-color: $background; -$authpage-primary-color: $text-primary-color; +$authpage-primary-color: $primary-content; $dark-panel-bg-color: $header-panel-bg-color; $panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1); From bbe714257ee57207b05aa592a025edcf098a030b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 10 Sep 2021 09:15:54 +0100 Subject: [PATCH 04/27] Show unsent message warning on Space panel button --- .../views/rooms/NotificationBadge.tsx | 39 +++++++++++++++++-- .../views/spaces/SpaceTreeLevel.tsx | 1 + src/i18n/strings/en_EN.json | 1 + src/stores/notifications/NotificationColor.ts | 1 + .../notifications/RoomNotificationState.ts | 2 +- .../notifications/SpaceNotificationState.ts | 8 ++-- 6 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index 8329de7391..a70ff93bd2 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { MouseEvent } from "react"; import classNames from "classnames"; import { formatCount } from "../../../utils/FormattingUtils"; import SettingsStore from "../../../settings/SettingsStore"; @@ -22,6 +22,9 @@ import AccessibleButton from "../elements/AccessibleButton"; import { XOR } from "../../../@types/common"; import { NOTIFICATION_STATE_UPDATE, NotificationState } from "../../../stores/notifications/NotificationState"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import Tooltip from "../elements/Tooltip"; +import { _t } from "../../../languageHandler"; +import { NotificationColor } from "../../../stores/notifications/NotificationColor"; interface IProps { notification: NotificationState; @@ -39,6 +42,7 @@ interface IProps { } interface IClickableProps extends IProps, React.InputHTMLAttributes { + showUnsentTooltip?: boolean; /** * If specified will return an AccessibleButton instead of a div. */ @@ -47,6 +51,7 @@ interface IClickableProps extends IProps, React.InputHTMLAttributes { interface IState { showCounts: boolean; // whether or not to show counts. Independent of props.forceCount + showTooltip: boolean; } @replaceableComponent("views.rooms.NotificationBadge") @@ -59,6 +64,7 @@ export default class NotificationBadge extends React.PureComponent { + e.stopPropagation(); + this.setState({ + showTooltip: true, + }); + }; + + private onMouseLeave = () => { + this.setState({ + showTooltip: false, + }); + }; + public render(): React.ReactElement { /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */ - const { notification, forceCount, roomId, onClick, ...props } = this.props; + const { notification, showUnsentTooltip, forceCount, roomId, onClick, ...props } = this.props; // Don't show a badge if we don't need to if (notification.isIdle) return null; @@ -124,9 +143,23 @@ export default class NotificationBadge extends React.PureComponent + ); + } + return ( - + { symbol } + { tooltip } ); } diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index dda58ae944..f9d901a298 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -93,6 +93,7 @@ export const SpaceButton: React.FC = ({ notification={notificationState} aria-label={ariaLabel} tabIndex={tabIndex} + showUnsentTooltip={true} /> ; } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index deb854868f..ff5eb29f99 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1587,6 +1587,7 @@ "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.": "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.": "Enable encryption in settings.", "End-to-end encryption isn't enabled": "End-to-end encryption isn't enabled", + "Message didn't send. Click for info.": "Message didn't send. Click for info.", "Unpin": "Unpin", "View message": "View message", "%(duration)ss": "%(duration)ss", diff --git a/src/stores/notifications/NotificationColor.ts b/src/stores/notifications/NotificationColor.ts index b12f2b7c00..fadd5ac67e 100644 --- a/src/stores/notifications/NotificationColor.ts +++ b/src/stores/notifications/NotificationColor.ts @@ -21,4 +21,5 @@ export enum NotificationColor { Bold, // no badge, show as unread Grey, // unread notified messages Red, // unread pings + Unsent, // some messages failed to send } diff --git a/src/stores/notifications/RoomNotificationState.ts b/src/stores/notifications/RoomNotificationState.ts index 0a2e801620..d0479200bd 100644 --- a/src/stores/notifications/RoomNotificationState.ts +++ b/src/stores/notifications/RoomNotificationState.ts @@ -88,7 +88,7 @@ export class RoomNotificationState extends NotificationState implements IDestroy if (getUnsentMessages(this.room).length > 0) { // When there are unsent messages we show a red `!` - this._color = NotificationColor.Red; + this._color = NotificationColor.Unsent; this._symbol = "!"; this._count = 1; // not used, technically } else if (RoomNotifs.getRoomNotifsState(this.room.roomId) === RoomNotifs.MUTE) { diff --git a/src/stores/notifications/SpaceNotificationState.ts b/src/stores/notifications/SpaceNotificationState.ts index f8eb07251b..c414a01fc2 100644 --- a/src/stores/notifications/SpaceNotificationState.ts +++ b/src/stores/notifications/SpaceNotificationState.ts @@ -30,10 +30,6 @@ export class SpaceNotificationState extends NotificationState { super(); } - public get symbol(): string { - return null; // This notification state doesn't support symbols - } - public setRooms(rooms: Room[]) { const oldRooms = this.rooms; const diff = arrayDiff(oldRooms, rooms); @@ -54,7 +50,7 @@ export class SpaceNotificationState extends NotificationState { } public getFirstRoomWithNotifications() { - return this.rooms.find((room) => room.getUnreadNotificationCount() > 0).roomId; + return Object.values(this.states).find(state => state.color >= this.color)?.room.roomId; } public destroy() { @@ -79,6 +75,8 @@ export class SpaceNotificationState extends NotificationState { this._color = Math.max(this.color, state.color); } + this._symbol = this._color === NotificationColor.Unsent ? "!" : null; + // finally, publish an update if needed this.emitIfUpdated(snapshot); } From aff9be6120a0714532f6675b1aa7b5afc63cbebf Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 10 Sep 2021 10:58:13 +0100 Subject: [PATCH 05/27] Surface unsent messages on the sublist notification badge too --- src/components/views/rooms/NotificationBadge.tsx | 9 +++++---- src/components/views/rooms/RoomSublist.tsx | 1 + src/stores/notifications/ListNotificationState.ts | 9 +++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index a70ff93bd2..a97d51fc90 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -143,15 +143,16 @@ export default class NotificationBadge extends React.PureComponent - ); + label = _t("Message didn't send. Click for info."); + tooltip = ; } return ( { onClick={this.onBadgeClick} tabIndex={tabIndex} aria-label={ariaLabel} + showUnsentTooltip={true} /> ); diff --git a/src/stores/notifications/ListNotificationState.ts b/src/stores/notifications/ListNotificationState.ts index 6c67dbdd08..4168fe80b6 100644 --- a/src/stores/notifications/ListNotificationState.ts +++ b/src/stores/notifications/ListNotificationState.ts @@ -31,10 +31,6 @@ export class ListNotificationState extends NotificationState { super(); } - public get symbol(): string { - return null; // This notification state doesn't support symbols - } - public setRooms(rooms: Room[]) { // If we're only concerned about the tile count, don't bother setting up listeners. if (this.byTileCount) { @@ -82,6 +78,7 @@ export class ListNotificationState extends NotificationState { private calculateTotalState() { const snapshot = this.snapshot(); + this._symbol = null; if (this.byTileCount) { this._color = NotificationColor.Red; this._count = this.rooms.length; @@ -92,6 +89,10 @@ export class ListNotificationState extends NotificationState { this._count += state.count; this._color = Math.max(this.color, state.color); } + + if (this._color === NotificationColor.Unsent) { + this._symbol = "!"; + } } // finally, publish an update if needed From 9a8a45382744f26ed42e43873464ee4e0805e8b1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 10 Sep 2021 11:09:46 +0100 Subject: [PATCH 06/27] tidy --- src/stores/notifications/ListNotificationState.ts | 9 ++++----- src/stores/notifications/SpaceNotificationState.ts | 7 ++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/stores/notifications/ListNotificationState.ts b/src/stores/notifications/ListNotificationState.ts index 4168fe80b6..97ba2bd80b 100644 --- a/src/stores/notifications/ListNotificationState.ts +++ b/src/stores/notifications/ListNotificationState.ts @@ -31,6 +31,10 @@ export class ListNotificationState extends NotificationState { super(); } + public get symbol(): string { + return this._color === NotificationColor.Unsent ? "!" : null; + } + public setRooms(rooms: Room[]) { // If we're only concerned about the tile count, don't bother setting up listeners. if (this.byTileCount) { @@ -78,7 +82,6 @@ export class ListNotificationState extends NotificationState { private calculateTotalState() { const snapshot = this.snapshot(); - this._symbol = null; if (this.byTileCount) { this._color = NotificationColor.Red; this._count = this.rooms.length; @@ -89,10 +92,6 @@ export class ListNotificationState extends NotificationState { this._count += state.count; this._color = Math.max(this.color, state.color); } - - if (this._color === NotificationColor.Unsent) { - this._symbol = "!"; - } } // finally, publish an update if needed diff --git a/src/stores/notifications/SpaceNotificationState.ts b/src/stores/notifications/SpaceNotificationState.ts index c414a01fc2..137b2ca0f2 100644 --- a/src/stores/notifications/SpaceNotificationState.ts +++ b/src/stores/notifications/SpaceNotificationState.ts @@ -30,6 +30,10 @@ export class SpaceNotificationState extends NotificationState { super(); } + public get symbol(): string { + return this._color === NotificationColor.Unsent ? "!" : null; + } + public setRooms(rooms: Room[]) { const oldRooms = this.rooms; const diff = arrayDiff(oldRooms, rooms); @@ -75,10 +79,7 @@ export class SpaceNotificationState extends NotificationState { this._color = Math.max(this.color, state.color); } - this._symbol = this._color === NotificationColor.Unsent ? "!" : null; - // finally, publish an update if needed this.emitIfUpdated(snapshot); } } - From 6fcd930d0b49e565c506f556b12e0f5d5d04c79b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 10 Sep 2021 11:54:25 +0100 Subject: [PATCH 07/27] fix unrelated issues --- .../views/settings/tabs/room/SecurityRoomSettingsTab.tsx | 2 +- src/components/views/spaces/SpaceSettingsVisibilityTab.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx index b467dc7680..d1c5bc8448 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx @@ -425,7 +425,7 @@ export default class SecurityRoomSettingsTab extends React.Component state.getJoinRule()); const [guestAccessEnabled, setGuestAccessEnabled] = useLocalEcho( () => space.currentState.getStateEvents(EventType.RoomGuestAccess, "") ?.getContent()?.guest_access === GuestAccess.CanJoin, @@ -64,7 +66,7 @@ const SpaceSettingsVisibilityTab = ({ matrixClient: cli, space, closeSettingsFn const canonicalAliasEv = space.currentState.getStateEvents(EventType.RoomCanonicalAlias, ""); let advancedSection; - if (visibility === SpaceVisibility.Unlisted) { + if (joinRule === JoinRule.Public) { if (showAdvancedSection) { advancedSection = <> From 049040b67d0ac71c679e79b384b97a31db0f62c5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 11 Sep 2021 02:03:55 -0500 Subject: [PATCH 08/27] Optimize input label transition on focus Fix https://github.com/vector-im/element-web/issues/12876 --- res/css/views/elements/_Field.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index d74c985d4c..71d37a015d 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -98,14 +98,14 @@ limitations under the License. transition: font-size 0.25s ease-out 0.1s, color 0.25s ease-out 0.1s, - top 0.25s ease-out 0.1s, + transform 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s; color: $primary-content; background-color: transparent; font-size: $font-14px; + transform: translateY(0); position: absolute; left: 0px; - top: 0px; margin: 7px 8px; padding: 2px; pointer-events: none; // Allow clicks to fall through to the input @@ -124,10 +124,10 @@ limitations under the License. transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, - top 0.25s ease-out 0s, + transform 0.25s ease-out 0s, background-color 0.25s ease-out 0s; font-size: $font-10px; - top: -13px; + transform: translateY(-13px); padding: 0 2px; background-color: $field-focused-label-bg-color; pointer-events: initial; From 354d0cfba45b45b048aad1c1040644bd7977f342 Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Sat, 11 Sep 2021 10:52:30 -0500 Subject: [PATCH 09/27] Redirect from /#/welcome to /#/home if already logged in Signed-off-by: Aaron Raimist --- src/components/structures/MatrixChat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 531dc9fbe9..14a9e54259 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -143,7 +143,7 @@ export enum Views { SOFT_LOGOUT, } -const AUTH_SCREENS = ["register", "login", "forgot_password", "start_sso", "start_cas"]; +const AUTH_SCREENS = ["register", "login", "forgot_password", "start_sso", "start_cas", "welcome"]; // Actions that are redirected through the onboarding process prior to being // re-dispatched. NOTE: some actions are non-trivial and would require From bfd563e564517ee1e780fdc67f02cb8c303dd82f Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 13 Sep 2021 12:53:15 +0100 Subject: [PATCH 10/27] Changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e186220f..3fcf11e37e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +Changes in [3.29.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.29.1) (2021-09-13) +=================================================================================================== + +## 🔒 SECURITY FIXES + * Fix a security issue with message key sharing. See https://matrix.org/blog/2021/09/13/vulnerability-disclosure-key-sharing + for details. + Changes in [3.29.0](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0) (2021-08-31) =================================================================================================== From 2a2c2c19cf1d172d42c263acc765dcaba9708bca Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 13 Sep 2021 12:54:01 +0100 Subject: [PATCH 11/27] Upgrade matrix-js-sdk to 12.4.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 08c057b35d..d004afd99a 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "katex": "^0.12.0", "linkifyjs": "^2.1.9", "lodash": "^4.17.20", - "matrix-js-sdk": "12.4.0", + "matrix-js-sdk": "12.4.1", "matrix-widget-api": "^0.1.0-beta.15", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", diff --git a/yarn.lock b/yarn.lock index 7fe5e3c143..b157a70403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5801,10 +5801,10 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -matrix-js-sdk@12.4.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.0.tgz#ff60306f9a9e39fd1ae6c7e501001f80eb779dd7" - integrity sha512-KamHmvNle4mkdErmNgVsGIL3n8/zgPe60DLVaEA2t4aSNwQLEmRS+oVpIgsO3ZrUivBvn4oc9sBqxP0OIl6kUg== +matrix-js-sdk@12.4.1: + version "12.4.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-12.4.1.tgz#966f506b4146e4fafffa5bbe80f5c53515e1bc78" + integrity sha512-C9aSGX9e4GoCm0Rli+iGBXmcnRxnwETw7MvgNcSBfPaLHOMZi/wz4YOV7HEZK8R+OXuDrDYyglncWSJkkoDpAQ== dependencies: "@babel/runtime" "^7.12.5" another-json "^0.2.0" From df20960ee88b2290ee5fc5bd5ba76faa69033601 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 13 Sep 2021 12:54:45 +0100 Subject: [PATCH 12/27] v3.29.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d004afd99a..2bba17397f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.29.0", + "version": "3.29.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From d75820a491667bd63645192cdf1ccf4d69afa411 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 13 Sep 2021 13:49:24 +0100 Subject: [PATCH 13/27] Hide mute/unmute button in UserInfo for Spaces as it makes no sense --- src/components/views/right_panel/UserInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index f90643f1df..4446ee1415 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -826,7 +826,7 @@ const RoomAdminToolsContainer: React.FC = ({ if (canAffectUser && me.powerLevel >= banPowerLevel) { banButton = ; } - if (canAffectUser && me.powerLevel >= editPowerLevel) { + if (canAffectUser && me.powerLevel >= editPowerLevel && !room.isSpaceRoom()) { muteButton = ( Date: Mon, 13 Sep 2021 16:27:46 +0100 Subject: [PATCH 14/27] Fix broken edge case with public space creation with no alias --- .../views/spaces/SpaceCreateMenu.tsx | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 59c970c7d0..4afc44cfdf 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -97,9 +97,8 @@ const spaceNameValidator = withValidation({ ], }); -const nameToAlias = (name: string, domain: string): string => { - const localpart = name.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9_-]+/gi, ""); - return `#${localpart}:${domain}`; +const nameToLocalpart = (name: string): string => { + return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9_-]+/gi, ""); }; // XXX: Temporary for the Spaces release only @@ -176,8 +175,8 @@ export const SpaceCreateForm: React.FC = ({ value={name} onChange={ev => { const newName = ev.target.value; - if (!alias || alias === nameToAlias(name, domain)) { - setAlias(nameToAlias(newName, domain)); + if (!alias || alias === `#${nameToLocalpart(name)}:${domain}`) { + setAlias(`#${nameToLocalpart(newName)}:${domain}`); } setName(newName); }} @@ -194,7 +193,7 @@ export const SpaceCreateForm: React.FC = ({ onChange={setAlias} domain={domain} value={alias} - placeholder={name ? nameToAlias(name, domain) : _t("e.g. my-space")} + placeholder={name ? nameToLocalpart(name) : _t("e.g. my-space")} label={_t("Address")} disabled={busy} onKeyDown={onKeyDown} @@ -217,6 +216,7 @@ export const SpaceCreateForm: React.FC = ({ }; const SpaceCreateMenu = ({ onFinished }) => { + const cli = useContext(MatrixClientContext); const [visibility, setVisibility] = useState(null); const [busy, setBusy] = useState(false); @@ -233,14 +233,18 @@ const SpaceCreateMenu = ({ onFinished }) => { setBusy(true); // require & validate the space name field - if (!await spaceNameField.current.validate({ allowEmpty: false })) { + if (!(await spaceNameField.current.validate({ allowEmpty: false }))) { spaceNameField.current.focus(); spaceNameField.current.validate({ allowEmpty: false, focused: true }); setBusy(false); return; } - // validate the space name alias field but do not require it - if (visibility === Visibility.Public && !await spaceAliasField.current.validate({ allowEmpty: true })) { + + // validate the space alias field but do not require it + const aliasLocalpart = alias.substring(1, alias.length - cli.getDomain().length - 1); + if (visibility === Visibility.Public && aliasLocalpart && + (await spaceAliasField.current.validate({ allowEmpty: true })) === false + ) { spaceAliasField.current.focus(); spaceAliasField.current.validate({ allowEmpty: true, focused: true }); setBusy(false); @@ -248,7 +252,13 @@ const SpaceCreateMenu = ({ onFinished }) => { } try { - await createSpace(name, visibility === Visibility.Public, alias, topic, avatar); + await createSpace( + name, + visibility === Visibility.Public, + aliasLocalpart ? alias : undefined, + topic, + avatar, + ); onFinished(); } catch (e) { From 4a470e43410001c213c29b2f032b258e64861867 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 13 Sep 2021 17:15:52 +0100 Subject: [PATCH 15/27] Fix automatic field population in space create menu not validating --- src/components/views/spaces/SpaceCreateMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 59c970c7d0..9e1f8a3b62 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -178,6 +178,7 @@ export const SpaceCreateForm: React.FC = ({ const newName = ev.target.value; if (!alias || alias === nameToAlias(name, domain)) { setAlias(nameToAlias(newName, domain)); + aliasFieldRef.current.validate({ allowEmpty: true }); } setName(newName); }} From e913f03a6773c320d409fae6ac09901632748acc Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Mon, 13 Sep 2021 22:11:43 +0200 Subject: [PATCH 16/27] Add missing types --- src/components/structures/ContextMenu.tsx | 14 ++++++++++++-- src/components/views/rooms/MessageComposer.tsx | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 332b6cd318..d503e56a6d 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -404,17 +404,27 @@ export class ContextMenu extends React.PureComponent { } } +export type ToRightOf = { + left: number; + top: number; + chevronOffset: number; +}; + // Placement method for to position context menu to right of elementRect with chevronOffset -export const toRightOf = (elementRect: Pick, chevronOffset = 12) => { +export const toRightOf = (elementRect: Pick, chevronOffset = 12): ToRightOf => { const left = elementRect.right + window.pageXOffset + 3; let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset; top -= chevronOffset + 8; // where 8 is half the height of the chevron return { left, top, chevronOffset }; }; +export type AboveLeftOf = IPosition & { + chevronFace: ChevronFace; +}; + // Placement method for to position context menu right-aligned and flowing to the left of elementRect, // and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?) -export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None, vPadding = 0) => { +export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None, vPadding = 0): AboveLeftOf => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonRight = elementRect.right + window.pageXOffset; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index dd6ce10825..506bf09a92 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -32,6 +32,7 @@ import { ContextMenu, useContextMenu, MenuItem, + AboveLeftOf, } from "../../structures/ContextMenu"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import ReplyPreview from "./ReplyPreview"; @@ -511,7 +512,7 @@ export default class MessageComposer extends React.Component { null, ]; - let menuPosition; + let menuPosition: AboveLeftOf | undefined; if (this.ref.current) { const contentRect = this.ref.current.getBoundingClientRect(); menuPosition = aboveLeftOf(contentRect); From ceafa833929d0d1a3474b65a167766fcfa349b83 Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Mon, 13 Sep 2021 22:11:58 +0200 Subject: [PATCH 17/27] Fix invalid ContextualMenu positions --- src/components/structures/ContextMenu.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index d503e56a6d..0c2c0e207f 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -322,10 +322,11 @@ export class ContextMenu extends React.PureComponent { const menuClasses = classNames({ 'mx_ContextualMenu': true, - 'mx_ContextualMenu_left': !hasChevron && position.left, - 'mx_ContextualMenu_right': !hasChevron && position.right, - 'mx_ContextualMenu_top': !hasChevron && position.top, - 'mx_ContextualMenu_bottom': !hasChevron && position.bottom, + // Defensively check for counter cases + 'mx_ContextualMenu_left': !hasChevron && position.left !== undefined && !position.right, + 'mx_ContextualMenu_right': !hasChevron && position.right !== undefined && !position.left, + 'mx_ContextualMenu_top': !hasChevron && position.top !== undefined && !position.bottom, + 'mx_ContextualMenu_bottom': !hasChevron && position.bottom !== undefined && !position.top, 'mx_ContextualMenu_withChevron_left': chevronFace === ChevronFace.Left, 'mx_ContextualMenu_withChevron_right': chevronFace === ChevronFace.Right, 'mx_ContextualMenu_withChevron_top': chevronFace === ChevronFace.Top, From 87c9551507a06803e5809d3930052e3693e4207e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 12:49:18 +0100 Subject: [PATCH 18/27] Fix edge cases around joining new room which does not belong to active space --- src/stores/SpaceStore.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index f49d51454b..eebc196f4c 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -629,11 +629,18 @@ export class SpaceStoreClass extends AsyncStoreWithClient { }; private onRoom = (room: Room, newMembership?: string, oldMembership?: string) => { - const membership = newMembership || room.getMyMembership(); + const roomMembership = room.getMyMembership(); + if (roomMembership === null) { + // room is still being baked in the js-sdk, we'll process it at Room.myMembership instead + return; + } + const membership = newMembership || roomMembership; if (!room.isSpaceRoom()) { // this.onRoomUpdate(room); - this.onRoomsUpdate(); + // this.onRoomsUpdate(); + // ideally we only need onRoomsUpdate here but it doesn't rebuild parentMap so always adds new rooms to Home + this.rebuild(); if (membership === "join") { // the user just joined a room, remove it from the suggested list if it was there From 527e1eb462b476c2849854e29e6c328df9f0c702 Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Tue, 14 Sep 2021 14:45:47 +0200 Subject: [PATCH 19/27] Fix autocomplete not having y-scroll After changing flex-order the children did not have a max-height which ended up in the child growing to outside of the screen instead of being properly constrained. Fix https://github.com/vector-im/element-web/issues/18997 --- res/css/views/rooms/_Autocomplete.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/rooms/_Autocomplete.scss b/res/css/views/rooms/_Autocomplete.scss index 8d2b338d9d..fcdab37f5a 100644 --- a/res/css/views/rooms/_Autocomplete.scss +++ b/res/css/views/rooms/_Autocomplete.scss @@ -7,7 +7,6 @@ background: $background; border-bottom: none; border-radius: 8px 8px 0 0; - max-height: 35vh; overflow: clip; display: flex; flex-direction: column; @@ -64,6 +63,7 @@ margin: 12px; height: 100%; overflow-y: scroll; + max-height: 35vh; } .mx_Autocomplete_Completion_container_truncate { From 60174c9836aa1c6a7da2b1a8625790ddbd7d5bfb Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Tue, 14 Sep 2021 14:51:17 +0200 Subject: [PATCH 20/27] Add a better comment describing the behavior --- src/components/structures/ContextMenu.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 0c2c0e207f..d65f8e3a10 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -322,7 +322,12 @@ export class ContextMenu extends React.PureComponent { const menuClasses = classNames({ 'mx_ContextualMenu': true, - // Defensively check for counter cases + /** + * In some cases we may get the number of 0, which still means that we're supposed to properly + * add the specific position class, but as it was falsy things didn't work as intended. + * In addition, defensively check for counter cases where we may get more than one value, + * even if we shouldn't. + */ 'mx_ContextualMenu_left': !hasChevron && position.left !== undefined && !position.right, 'mx_ContextualMenu_right': !hasChevron && position.right !== undefined && !position.left, 'mx_ContextualMenu_top': !hasChevron && position.top !== undefined && !position.bottom, From e3ec00bcdf8d08aacf721cbaf5090c4282921adb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 14:35:33 +0100 Subject: [PATCH 21/27] Fix space create menu eating first character of name in private space creation --- src/components/views/spaces/SpaceCreateMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 2028e66625..c09b26e45f 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -177,7 +177,7 @@ export const SpaceCreateForm: React.FC = ({ const newName = ev.target.value; if (!alias || alias === `#${nameToLocalpart(name)}:${domain}`) { setAlias(`#${nameToLocalpart(newName)}:${domain}`); - aliasFieldRef.current.validate({ allowEmpty: true }); + aliasFieldRef.current?.validate({ allowEmpty: true }); } setName(newName); }} From e37f6b96d714bc52ff89d5384c24f7fbd621a596 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 14:36:11 +0100 Subject: [PATCH 22/27] Fix RoomTile subscribing to wrong event emitter for room name --- src/components/views/rooms/RoomTile.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 8ed2ca85e9..970915d653 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -101,7 +101,7 @@ export default class RoomTile extends React.PureComponent { this.roomProps = EchoChamber.forRoom(this.props.room); } - private onRoomNameUpdate = (room) => { + private onRoomNameUpdate = (room: Room) => { this.forceUpdate(); }; @@ -164,7 +164,7 @@ export default class RoomTile extends React.PureComponent { ); this.notificationState.on(NOTIFICATION_STATE_UPDATE, this.onNotificationUpdate); this.roomProps.on(PROPERTY_UPDATED, this.onRoomPropertyUpdate); - this.roomProps.on("Room.name", this.onRoomNameUpdate); + this.props.room?.on("Room.name", this.onRoomNameUpdate); CommunityPrototypeStore.instance.on( CommunityPrototypeStore.getUpdateEventName(this.props.room.roomId), this.onCommunityUpdate, From 5048e41e8b64f9a5d315499565cbf90884f9e05b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 14:41:51 +0100 Subject: [PATCH 23/27] Space Hierarchy react to known local rooms changing names --- src/components/structures/SpaceHierarchy.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/structures/SpaceHierarchy.tsx b/src/components/structures/SpaceHierarchy.tsx index a0d4d9c42a..09099032dc 100644 --- a/src/components/structures/SpaceHierarchy.tsx +++ b/src/components/structures/SpaceHierarchy.tsx @@ -57,6 +57,7 @@ import { Key } from "../../Keyboard"; import { IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex"; import { getDisplayAliasForRoom } from "./RoomDirectory"; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import { useEventEmitterState } from "../../hooks/useEventEmitter"; interface IProps { space: Room; @@ -87,7 +88,8 @@ const Tile: React.FC = ({ }) => { const cli = useContext(MatrixClientContext); const joinedRoom = cli.getRoom(room.room_id)?.getMyMembership() === "join" ? cli.getRoom(room.room_id) : null; - const name = joinedRoom?.name || room.name || room.canonical_alias || room.aliases?.[0] + const joinedRoomName = useEventEmitterState(joinedRoom, "Room.name", room => room?.name); + const name = joinedRoomName || room.name || room.canonical_alias || room.aliases?.[0] || (room.room_type === RoomType.Space ? _t("Unnamed Space") : _t("Unnamed Room")); const [showChildren, toggleShowChildren] = useStateToggle(true); From f59baf1efb1c40a95724ad20b858baae2a46d528 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 14:41:55 +0100 Subject: [PATCH 24/27] Tidy some types --- src/hooks/useEventEmitter.ts | 12 ++++++++++-- src/hooks/useRoomState.ts | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/hooks/useEventEmitter.ts b/src/hooks/useEventEmitter.ts index 74b23f0198..693eebc0e3 100644 --- a/src/hooks/useEventEmitter.ts +++ b/src/hooks/useEventEmitter.ts @@ -20,7 +20,11 @@ import type { EventEmitter } from "events"; type Handler = (...args: any[]) => void; // Hook to wrap event emitter on and removeListener in hook lifecycle -export const useEventEmitter = (emitter: EventEmitter, eventName: string | symbol, handler: Handler) => { +export const useEventEmitter = ( + emitter: EventEmitter | undefined, + eventName: string | symbol, + handler: Handler, +) => { // Create a ref that stores handler const savedHandler = useRef(handler); @@ -51,7 +55,11 @@ export const useEventEmitter = (emitter: EventEmitter, eventName: string | symbo type Mapper = (...args: any[]) => T; -export const useEventEmitterState = (emitter: EventEmitter, eventName: string | symbol, fn: Mapper): T => { +export const useEventEmitterState = ( + emitter: EventEmitter | undefined, + eventName: string | symbol, + fn: Mapper, +): T => { const [value, setValue] = useState(fn()); const handler = useCallback((...args: any[]) => { setValue(fn(...args)); diff --git a/src/hooks/useRoomState.ts b/src/hooks/useRoomState.ts index e778acf8a9..89c94df10b 100644 --- a/src/hooks/useRoomState.ts +++ b/src/hooks/useRoomState.ts @@ -25,7 +25,7 @@ const defaultMapper: Mapper = (roomState: RoomState) => roomState; // Hook to simplify watching Matrix Room state export const useRoomState = ( - room: Room, + room?: Room, mapper: Mapper = defaultMapper as Mapper, ): T => { const [value, setValue] = useState(room ? mapper(room.currentState) : undefined); From 6672be91a186147dcf84cdd1722703c75d702797 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 15:00:44 +0100 Subject: [PATCH 25/27] Simplify Space Panel layout --- res/css/structures/_SpacePanel.scss | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index bbb1867f16..29c8c0c36d 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -139,7 +139,6 @@ $activeBorderColor: $secondary-content; &:not(.mx_SpaceButton_narrow) { .mx_SpaceButton_selectionWrapper { width: 100%; - padding-right: 16px; overflow: hidden; } } @@ -151,7 +150,6 @@ $activeBorderColor: $secondary-content; display: block; text-overflow: ellipsis; overflow: hidden; - padding-right: 8px; font-size: $font-14px; line-height: $font-18px; } @@ -225,8 +223,7 @@ $activeBorderColor: $secondary-content; margin-top: auto; margin-bottom: auto; display: none; - position: absolute; - right: 4px; + position: relative; &::before { top: 2px; @@ -245,8 +242,6 @@ $activeBorderColor: $secondary-content; } .mx_SpacePanel_badgeContainer { - position: absolute; - // Create a flexbox to make aligning dot badges easier display: flex; align-items: center; @@ -264,6 +259,7 @@ $activeBorderColor: $secondary-content; &.collapsed { .mx_SpaceButton { .mx_SpacePanel_badgeContainer { + position: absolute; right: 0; top: 0; @@ -293,19 +289,12 @@ $activeBorderColor: $secondary-content; } &:not(.collapsed) { - .mx_SpacePanel_badgeContainer { - position: absolute; - right: 4px; - } - .mx_SpaceButton:hover, .mx_SpaceButton:focus-within, .mx_SpaceButton_hasMenuOpen { &:not(.mx_SpaceButton_invite) { // Hide the badge container on hover because it'll be a menu button .mx_SpacePanel_badgeContainer { - width: 0; - height: 0; display: none; } From 60f43f01715b35b5da0141ca15bdef61ab724eac Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 15:12:25 +0100 Subject: [PATCH 26/27] Stop spinner on space preview if the join fails --- src/components/structures/SpaceRoomView.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 6bb0433448..3837d26564 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -78,6 +78,7 @@ import { CreateEventField, IGroupSummary } from "../views/dialogs/CreateSpaceFro import { useAsyncMemo } from "../../hooks/useAsyncMemo"; import Spinner from "../views/elements/Spinner"; import GroupAvatar from "../views/avatars/GroupAvatar"; +import { useDispatcher } from "../../hooks/useDispatcher"; interface IProps { space: Room; @@ -191,6 +192,11 @@ interface ISpacePreviewProps { const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }: ISpacePreviewProps) => { const cli = useContext(MatrixClientContext); const myMembership = useMyRoomMembership(space); + useDispatcher(defaultDispatcher, payload => { + if (payload.action === Action.JoinRoomError && payload.roomId === space.roomId) { + setBusy(false); // stop the spinner, join failed + } + }); const [busy, setBusy] = useState(false); From 919270ff0cfe739f65ec8551c592584a4b067b1a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 14 Sep 2021 15:50:51 +0100 Subject: [PATCH 27/27] Update src/stores/SpaceStore.tsx Co-authored-by: Travis Ralston --- src/stores/SpaceStore.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.tsx index eebc196f4c..cd0acc9d88 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.tsx @@ -630,7 +630,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { private onRoom = (room: Room, newMembership?: string, oldMembership?: string) => { const roomMembership = room.getMyMembership(); - if (roomMembership === null) { + if (!roomMembership) { // room is still being baked in the js-sdk, we'll process it at Room.myMembership instead return; }