Merge pull request #6382 from matrix-org/t3chguy/console
						commit
						ea20e041b1
					
				|  | @ -32,7 +32,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; | |||
| // 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): () => string | null { | ||||
| function textForMemberEvent(ev: MatrixEvent): () => 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(); | ||||
|  | @ -127,7 +127,7 @@ function textForMemberEvent(ev): () => string | null { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| function textForTopicEvent(ev): () => string | null { | ||||
| function textForTopicEvent(ev: MatrixEvent): () => 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, | ||||
|  | @ -135,7 +135,7 @@ function textForTopicEvent(ev): () => string | null { | |||
|     }); | ||||
| } | ||||
| 
 | ||||
| function textForRoomNameEvent(ev): () => string | null { | ||||
| function textForRoomNameEvent(ev: MatrixEvent): () => string | null { | ||||
|     const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
| 
 | ||||
|     if (!ev.getContent().name || ev.getContent().name.trim().length === 0) { | ||||
|  | @ -154,12 +154,12 @@ function textForRoomNameEvent(ev): () => string | null { | |||
|     }); | ||||
| } | ||||
| 
 | ||||
| function textForTombstoneEvent(ev): () => string | null { | ||||
| function textForTombstoneEvent(ev: MatrixEvent): () => 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): () => string | null { | ||||
| function textForJoinRulesEvent(ev: MatrixEvent): () => string | null { | ||||
|     const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
|     switch (ev.getContent().join_rule) { | ||||
|         case "public": | ||||
|  | @ -179,7 +179,7 @@ function textForJoinRulesEvent(ev): () => string | null { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| function textForGuestAccessEvent(ev): () => string | null { | ||||
| function textForGuestAccessEvent(ev: MatrixEvent): () => string | null { | ||||
|     const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
|     switch (ev.getContent().guest_access) { | ||||
|         case "can_join": | ||||
|  | @ -195,7 +195,7 @@ function textForGuestAccessEvent(ev): () => string | null { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| function textForRelatedGroupsEvent(ev): () => string | null { | ||||
| function textForRelatedGroupsEvent(ev: MatrixEvent): () => string | null { | ||||
|     const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
|     const groups = ev.getContent().groups || []; | ||||
|     const prevGroups = ev.getPrevContent().groups || []; | ||||
|  | @ -225,7 +225,7 @@ function textForRelatedGroupsEvent(ev): () => string | null { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| function textForServerACLEvent(ev): () => string | null { | ||||
| function textForServerACLEvent(ev: MatrixEvent): () => string | null { | ||||
|     const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
|     const prevContent = ev.getPrevContent(); | ||||
|     const current = ev.getContent(); | ||||
|  | @ -255,7 +255,7 @@ function textForServerACLEvent(ev): () => string | null { | |||
|     return getText; | ||||
| } | ||||
| 
 | ||||
| function textForMessageEvent(ev): () => string | null { | ||||
| function textForMessageEvent(ev: MatrixEvent): () => string | null { | ||||
|     return () => { | ||||
|         const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); | ||||
|         let message = senderDisplayName + ': ' + ev.getContent().body; | ||||
|  | @ -268,7 +268,7 @@ function textForMessageEvent(ev): () => string | null { | |||
|     }; | ||||
| } | ||||
| 
 | ||||
| function textForCanonicalAliasEvent(ev): () => string | null { | ||||
| function textForCanonicalAliasEvent(ev: MatrixEvent): () => 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 || []; | ||||
|  | @ -682,7 +682,7 @@ for (const evType of ALL_RULE_TYPES) { | |||
|     stateHandlers[evType] = textForMjolnirEvent; | ||||
| } | ||||
| 
 | ||||
| export function hasText(ev): boolean { | ||||
| export function hasText(ev: MatrixEvent): boolean { | ||||
|     const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; | ||||
|     return Boolean(handler?.(ev)); | ||||
| } | ||||
|  |  | |||
|  | @ -917,6 +917,7 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     // called when state.room is first initialised (either at initial load,
 | ||||
|     // after a successful peek, or after we join the room).
 | ||||
|     private onRoomLoaded = (room: Room) => { | ||||
|         if (this.unmounted) return; | ||||
|         // Attach a widget store listener only when we get a room
 | ||||
|         WidgetLayoutStore.instance.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange); | ||||
|         this.onWidgetLayoutChange(); // provoke an update
 | ||||
|  | @ -931,9 +932,9 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private async calculateRecommendedVersion(room: Room) { | ||||
|         this.setState({ | ||||
|             upgradeRecommendation: await room.getRecommendedVersion(), | ||||
|         }); | ||||
|         const upgradeRecommendation = await room.getRecommendedVersion(); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ upgradeRecommendation }); | ||||
|     } | ||||
| 
 | ||||
|     private async loadMembersIfJoined(room: Room) { | ||||
|  | @ -1023,23 +1024,19 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     }; | ||||
| 
 | ||||
|     private async updateE2EStatus(room: Room) { | ||||
|         if (!this.context.isRoomEncrypted(room.roomId)) { | ||||
|             return; | ||||
|         } | ||||
|         if (!this.context.isCryptoEnabled()) { | ||||
|             // If crypto is not currently enabled, we aren't tracking devices at all,
 | ||||
|             // so we don't know what the answer is. Let's error on the safe side and show
 | ||||
|             // a warning for this case.
 | ||||
|             this.setState({ | ||||
|                 e2eStatus: E2EStatus.Warning, | ||||
|             }); | ||||
|             return; | ||||
|         if (!this.context.isRoomEncrypted(room.roomId)) return; | ||||
| 
 | ||||
|         // If crypto is not currently enabled, we aren't tracking devices at all,
 | ||||
|         // so we don't know what the answer is. Let's error on the safe side and show
 | ||||
|         // a warning for this case.
 | ||||
|         let e2eStatus = E2EStatus.Warning; | ||||
|         if (this.context.isCryptoEnabled()) { | ||||
|             /* At this point, the user has encryption on and cross-signing on */ | ||||
|             e2eStatus = await shieldStatusForRoom(this.context, room); | ||||
|         } | ||||
| 
 | ||||
|         /* At this point, the user has encryption on and cross-signing on */ | ||||
|         this.setState({ | ||||
|             e2eStatus: await shieldStatusForRoom(this.context, room), | ||||
|         }); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ e2eStatus }); | ||||
|     } | ||||
| 
 | ||||
|     private onAccountData = (event: MatrixEvent) => { | ||||
|  |  | |||
|  | @ -1051,6 +1051,8 @@ class TimelinePanel extends React.Component<IProps, IState> { | |||
|             { windowLimit: this.props.timelineCap }); | ||||
| 
 | ||||
|         const onLoaded = () => { | ||||
|             if (this.unmounted) return; | ||||
| 
 | ||||
|             // clear the timeline min-height when
 | ||||
|             // (re)loading the timeline
 | ||||
|             if (this.messagePanel.current) { | ||||
|  | @ -1092,6 +1094,8 @@ class TimelinePanel extends React.Component<IProps, IState> { | |||
|         }; | ||||
| 
 | ||||
|         const onError = (error) => { | ||||
|             if (this.unmounted) return; | ||||
| 
 | ||||
|             this.setState({ timelineLoading: false }); | ||||
|             console.error( | ||||
|                 `Error loading timeline panel at ${eventId}: ${error}`, | ||||
|  |  | |||
|  | @ -15,12 +15,14 @@ | |||
|  */ | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import { MatrixEvent } from "matrix-js-sdk/src/models/event"; | ||||
| import { MsgType } from "matrix-js-sdk/src/@types/event"; | ||||
| 
 | ||||
| import Flair from '../elements/Flair'; | ||||
| 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; | ||||
|  | @ -36,7 +38,7 @@ interface IState { | |||
| @replaceableComponent("views.messages.SenderProfile") | ||||
| export default class SenderProfile extends React.Component<IProps, IState> { | ||||
|     static contextType = MatrixClientContext; | ||||
|     private unmounted: boolean; | ||||
|     private unmounted = false; | ||||
| 
 | ||||
|     constructor(props: IProps) { | ||||
|         super(props); | ||||
|  | @ -49,8 +51,7 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     componentDidMount() { | ||||
|         this.unmounted = false; | ||||
|         this._updateRelatedGroups(); | ||||
|         this.updateRelatedGroups(); | ||||
| 
 | ||||
|         if (this.state.userGroups.length === 0) { | ||||
|             this.getPublicisedGroups(); | ||||
|  | @ -64,35 +65,29 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
|         this.context.removeListener('RoomState.events', this.onRoomStateEvents); | ||||
|     } | ||||
| 
 | ||||
|     async getPublicisedGroups() { | ||||
|         if (!this.unmounted) { | ||||
|             const userGroups = await FlairStore.getPublicisedGroupsCached( | ||||
|                 this.context, this.props.mxEvent.getSender(), | ||||
|             ); | ||||
|             this.setState({ userGroups }); | ||||
|         } | ||||
|     private async getPublicisedGroups() { | ||||
|         const userGroups = await FlairStore.getPublicisedGroupsCached(this.context, this.props.mxEvent.getSender()); | ||||
|         if (this.unmounted) return; | ||||
|         this.setState({ userGroups }); | ||||
|     } | ||||
| 
 | ||||
|     onRoomStateEvents = event => { | ||||
|         if (event.getType() === 'm.room.related_groups' && | ||||
|             event.getRoomId() === this.props.mxEvent.getRoomId() | ||||
|         ) { | ||||
|             this._updateRelatedGroups(); | ||||
|     private onRoomStateEvents = (event: MatrixEvent) => { | ||||
|         if (event.getType() === 'm.room.related_groups' && event.getRoomId() === this.props.mxEvent.getRoomId()) { | ||||
|             this.updateRelatedGroups(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     _updateRelatedGroups() { | ||||
|         if (this.unmounted) return; | ||||
|     private updateRelatedGroups() { | ||||
|         const room = this.context.getRoom(this.props.mxEvent.getRoomId()); | ||||
|         if (!room) return; | ||||
| 
 | ||||
|         const relatedGroupsEvent = room.currentState.getStateEvents('m.room.related_groups', ''); | ||||
|         this.setState({ | ||||
|             relatedGroups: relatedGroupsEvent ? relatedGroupsEvent.getContent().groups || [] : [], | ||||
|             relatedGroups: relatedGroupsEvent?.getContent().groups || [], | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     _getDisplayedGroups(userGroups, relatedGroups) { | ||||
|     private getDisplayedGroups(userGroups?: string[], relatedGroups?: string[]) { | ||||
|         let displayedGroups = userGroups || []; | ||||
|         if (relatedGroups && relatedGroups.length > 0) { | ||||
|             displayedGroups = relatedGroups.filter((groupId) => { | ||||
|  | @ -113,7 +108,7 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
|         const displayName = mxEvent.sender?.rawDisplayName || mxEvent.getSender() || ""; | ||||
|         const mxid = mxEvent.sender?.userId || mxEvent.getSender() || ""; | ||||
| 
 | ||||
|         if (msgtype === 'm.emote') { | ||||
|         if (msgtype === MsgType.Emote) { | ||||
|             return null; // emote message must include the name so don't duplicate it
 | ||||
|         } | ||||
| 
 | ||||
|  | @ -128,7 +123,7 @@ export default class SenderProfile extends React.Component<IProps, IState> { | |||
| 
 | ||||
|         let flair; | ||||
|         if (this.props.enableFlair) { | ||||
|             const displayedGroups = this._getDisplayedGroups( | ||||
|             const displayedGroups = this.getDisplayedGroups( | ||||
|                 this.state.userGroups, this.state.relatedGroups, | ||||
|             ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1152,11 +1152,11 @@ export default class EventTile extends React.Component<IProps, IState> { | |||
|                     "aria-live": ariaLive, | ||||
|                     "aria-atomic": true, | ||||
|                     "data-scroll-tokens": scrollToken, | ||||
|                 }, [ | ||||
|                     ircTimestamp, | ||||
|                     avatar, | ||||
|                     sender, | ||||
|                     ircPadlock, | ||||
|                 }, <> | ||||
|                     { ircTimestamp } | ||||
|                     { avatar } | ||||
|                     { sender } | ||||
|                     { ircPadlock } | ||||
|                     <div className="mx_EventTile_reply" key="mx_EventTile_reply"> | ||||
|                         { groupTimestamp } | ||||
|                         { groupPadlock } | ||||
|  | @ -1169,8 +1169,8 @@ export default class EventTile extends React.Component<IProps, IState> { | |||
|                             replacingEventId={this.props.replacingEventId} | ||||
|                             showUrlPreview={false} | ||||
|                         /> | ||||
|                     </div>, | ||||
|                 ]); | ||||
|                     </div> | ||||
|                 </>); | ||||
|             } | ||||
|             default: { | ||||
|                 const thread = ReplyThread.makeThread( | ||||
|  | @ -1193,10 +1193,10 @@ export default class EventTile extends React.Component<IProps, IState> { | |||
|                         "data-scroll-tokens": scrollToken, | ||||
|                         "onMouseEnter": () => this.setState({ hover: true }), | ||||
|                         "onMouseLeave": () => this.setState({ hover: false }), | ||||
|                     }, [ | ||||
|                         ircTimestamp, | ||||
|                         sender, | ||||
|                         ircPadlock, | ||||
|                     }, <> | ||||
|                         { ircTimestamp } | ||||
|                         { sender } | ||||
|                         { ircPadlock } | ||||
|                         <div className="mx_EventTile_line" key="mx_EventTile_line"> | ||||
|                             { groupTimestamp } | ||||
|                             { groupPadlock } | ||||
|  | @ -1214,11 +1214,10 @@ export default class EventTile extends React.Component<IProps, IState> { | |||
|                             { keyRequestInfo } | ||||
|                             { reactionsRow } | ||||
|                             { actionBar } | ||||
|                         </div>, | ||||
|                         msgOption, | ||||
|                         avatar, | ||||
| 
 | ||||
|                     ]) | ||||
|                         </div> | ||||
|                         { msgOption } | ||||
|                         { avatar } | ||||
|                     </>) | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -40,10 +40,12 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH | |||
| 
 | ||||
|     const ts = mxEvent.getTs(); | ||||
|     const previews = useAsyncMemo<[string, IPreviewUrlResponse][]>(async () => { | ||||
|         return Promise.all<[string, IPreviewUrlResponse] | void>(links.map(link => { | ||||
|             return cli.getUrlPreview(link, ts).then(preview => [link, preview], error => { | ||||
|         return Promise.all<[string, IPreviewUrlResponse] | void>(links.map(async link => { | ||||
|             try { | ||||
|                 return [link, await cli.getUrlPreview(link, ts)]; | ||||
|             } catch (error) { | ||||
|                 console.error("Failed to get URL preview: " + error); | ||||
|             }); | ||||
|             } | ||||
|         })).then(a => a.filter(Boolean)) as Promise<[string, IPreviewUrlResponse][]>; | ||||
|     }, [links, ts], []); | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,6 +76,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|     private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); | ||||
| 
 | ||||
|     private themeTimer: number; | ||||
|     private unmounted = false; | ||||
| 
 | ||||
|     constructor(props: IProps) { | ||||
|         super(props); | ||||
|  | @ -101,6 +102,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|         const client = MatrixClientPeg.get(); | ||||
|         const userId = client.getUserId(); | ||||
|         const profileInfo = await client.getProfileInfo(userId); | ||||
|         if (this.unmounted) return; | ||||
| 
 | ||||
|         this.setState({ | ||||
|             userId, | ||||
|  | @ -109,6 +111,10 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I | |||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     componentWillUnmount() { | ||||
|         this.unmounted = true; | ||||
|     } | ||||
| 
 | ||||
|     private calculateThemeState(): IThemeState { | ||||
|         // We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
 | ||||
|         // show the right values for things.
 | ||||
|  |  | |||
|  | @ -74,6 +74,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> { | |||
| 
 | ||||
|     constructor() { | ||||
|         super(defaultDispatcher); | ||||
|         this.setMaxListeners(20); // CustomRoomTagStore + RoomList + LeftPanel + 8xRoomSubList + spares
 | ||||
|     } | ||||
| 
 | ||||
|     private setupWatchers() { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Michael Telatynski
						Michael Telatynski