Conform more of the codebase to strictNullChecks
(#10358
* Conform more of the codebase to `strictNullChecks` * Fix types * Iterate * Iterate
This commit is contained in:
parent
41d88ad6ae
commit
503df62191
76 changed files with 323 additions and 327 deletions
|
@ -117,7 +117,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
// Hide the autocomplete box
|
||||
hide: true,
|
||||
});
|
||||
return Promise.resolve(null);
|
||||
return Promise.resolve();
|
||||
}
|
||||
let autocompleteDelay = SettingsStore.getValue("autocompleteDelay");
|
||||
|
||||
|
@ -204,7 +204,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
this.setSelection(1 + index);
|
||||
}
|
||||
|
||||
public onEscape(e: KeyboardEvent): boolean {
|
||||
public onEscape(e: KeyboardEvent): boolean | undefined {
|
||||
const completionCount = this.countCompletions();
|
||||
if (completionCount === 0) {
|
||||
// autocomplete is already empty, so don't preventDefault
|
||||
|
|
|
@ -132,7 +132,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private _isCaretAtEnd: boolean;
|
||||
private lastCaret: DocumentOffset;
|
||||
private lastSelection: ReturnType<typeof cloneSelection>;
|
||||
private lastSelection: ReturnType<typeof cloneSelection> | null;
|
||||
|
||||
private readonly useMarkdownHandle: string;
|
||||
private readonly emoticonSettingHandle: string;
|
||||
|
@ -188,7 +188,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
public replaceEmoticon(caretPosition: DocumentPosition, regex: RegExp): number {
|
||||
public replaceEmoticon(caretPosition: DocumentPosition, regex: RegExp): number | undefined {
|
||||
const { model } = this.props;
|
||||
const range = model.startRange(caretPosition);
|
||||
// expand range max 9 characters backwards from caretPosition,
|
||||
|
@ -352,7 +352,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
this.onCutCopy(event, "cut");
|
||||
};
|
||||
|
||||
private onPaste = (event: ClipboardEvent<HTMLDivElement>): boolean => {
|
||||
private onPaste = (event: ClipboardEvent<HTMLDivElement>): boolean | undefined => {
|
||||
event.preventDefault(); // we always handle the paste ourselves
|
||||
if (this.props.onPaste?.(event, this.props.model)) {
|
||||
// to prevent double handling, allow props.onPaste to skip internal onPaste
|
||||
|
@ -415,7 +415,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
this.lastSelection = cloneSelection(document.getSelection());
|
||||
}
|
||||
|
||||
private refreshLastCaretIfNeeded(): DocumentOffset {
|
||||
private refreshLastCaretIfNeeded(): DocumentOffset | undefined {
|
||||
// XXX: needed when going up and down in editing messages ... not sure why yet
|
||||
// because the editors should stop doing this when when blurred ...
|
||||
// maybe it's on focus and the _editorRef isn't available yet or something.
|
||||
|
@ -441,7 +441,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
public isSelectionCollapsed(): boolean {
|
||||
return !this.lastSelection || this.lastSelection.isCollapsed;
|
||||
return !this.lastSelection || !!this.lastSelection.isCollapsed;
|
||||
}
|
||||
|
||||
public isCaretAtStart(): boolean {
|
||||
|
@ -537,7 +537,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
// there is no current autocomplete window, try to open it
|
||||
this.tabCompleteName();
|
||||
handled = true;
|
||||
} else if ([KeyBindingAction.Delete, KeyBindingAction.Backspace].includes(accessibilityAction)) {
|
||||
} else if ([KeyBindingAction.Delete, KeyBindingAction.Backspace].includes(accessibilityAction!)) {
|
||||
this.formatBarRef.current.hide();
|
||||
}
|
||||
|
||||
|
@ -750,7 +750,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let autoComplete;
|
||||
let autoComplete: JSX.Element | undefined;
|
||||
if (this.state.autoComplete) {
|
||||
const query = this.state.query;
|
||||
const queryLen = query.length;
|
||||
|
@ -785,7 +785,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
const { completionIndex } = this.state;
|
||||
const hasAutocomplete = Boolean(this.state.autoComplete);
|
||||
let activeDescendant: string;
|
||||
let activeDescendant: string | undefined;
|
||||
if (hasAutocomplete && completionIndex >= 0) {
|
||||
activeDescendant = generateCompletionDomId(completionIndex);
|
||||
}
|
||||
|
@ -800,7 +800,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
/>
|
||||
<div
|
||||
className={classes}
|
||||
contentEditable={this.props.disabled ? null : true}
|
||||
contentEditable={this.props.disabled ? undefined : true}
|
||||
tabIndex={0}
|
||||
onBlur={this.onBlur}
|
||||
onFocus={this.onFocus}
|
||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from "react";
|
||||
import React, { CSSProperties, useState } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { _t, _td } from "../../../languageHandler";
|
||||
|
@ -44,7 +44,7 @@ const crossSigningRoomTitles: { [key in E2EState]?: string } = {
|
|||
|
||||
interface IProps {
|
||||
isUser?: boolean;
|
||||
status: E2EState | E2EStatus;
|
||||
status?: E2EState | E2EStatus;
|
||||
className?: string;
|
||||
size?: number;
|
||||
onClick?: () => void;
|
||||
|
@ -77,13 +77,15 @@ const E2EIcon: React.FC<IProps> = ({
|
|||
);
|
||||
|
||||
let e2eTitle: string | undefined;
|
||||
if (isUser) {
|
||||
e2eTitle = crossSigningUserTitles[status];
|
||||
} else {
|
||||
e2eTitle = crossSigningRoomTitles[status];
|
||||
if (status) {
|
||||
if (isUser) {
|
||||
e2eTitle = crossSigningUserTitles[status];
|
||||
} else {
|
||||
e2eTitle = crossSigningRoomTitles[status];
|
||||
}
|
||||
}
|
||||
|
||||
let style;
|
||||
let style: CSSProperties | undefined;
|
||||
if (size) {
|
||||
style = { width: `${size}px`, height: `${size}px` };
|
||||
}
|
||||
|
@ -91,7 +93,7 @@ const E2EIcon: React.FC<IProps> = ({
|
|||
const onMouseOver = (): void => setHover(true);
|
||||
const onMouseLeave = (): void => setHover(false);
|
||||
|
||||
let tip;
|
||||
let tip: JSX.Element | undefined;
|
||||
if (hover && !hideTooltip) {
|
||||
tip = <Tooltip label={e2eTitle ? _t(e2eTitle) : ""} alignment={tooltipAlignment} />;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } fr
|
|||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { PosthogAnalytics } from "../../../PosthogAnalytics";
|
||||
import { editorRoomKey, editorStateKey } from "../../../Editing";
|
||||
import DocumentOffset from "../../../editor/offset";
|
||||
|
||||
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
||||
const html = mxEvent.getContent().formatted_body;
|
||||
|
@ -130,7 +131,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
|
||||
private readonly editorRef = createRef<BasicMessageComposer>();
|
||||
private readonly dispatcherRef: string;
|
||||
private model: EditorModel = null;
|
||||
private model: EditorModel;
|
||||
|
||||
public constructor(props: IEditMessageComposerProps, context: React.ContextType<typeof RoomContext>) {
|
||||
super(props);
|
||||
|
@ -250,7 +251,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
return localStorage.getItem(this.editorRoomKey) !== null;
|
||||
}
|
||||
|
||||
private restoreStoredEditorState(partCreator: PartCreator): Part[] {
|
||||
private restoreStoredEditorState(partCreator: PartCreator): Part[] | undefined {
|
||||
const json = localStorage.getItem(this.editorStateKey);
|
||||
if (json) {
|
||||
try {
|
||||
|
@ -382,7 +383,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
// editorstate so it can be restored when the remote echo event tile gets rendered
|
||||
// in case we're currently editing a pending event
|
||||
const sel = document.getSelection();
|
||||
let caret;
|
||||
let caret: DocumentOffset | undefined;
|
||||
if (sel.focusNode) {
|
||||
caret = getCaretOffsetAndText(this.editorRef.current?.editorRef.current, sel).caret;
|
||||
}
|
||||
|
@ -390,7 +391,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
// if caret is undefined because for some reason there isn't a valid selection,
|
||||
// then when mounting the editor again with the same editor state,
|
||||
// it will set the cursor at the end.
|
||||
this.props.editState.setEditorState(caret, parts);
|
||||
this.props.editState.setEditorState(caret ?? null, parts);
|
||||
window.removeEventListener("beforeunload", this.saveStoredEditorState);
|
||||
if (this.shouldSaveStoredEditorState) {
|
||||
this.saveStoredEditorState();
|
||||
|
@ -462,7 +463,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
model={this.model}
|
||||
room={this.getRoom()}
|
||||
threadId={this.props.editState?.getEvent()?.getThread()?.id}
|
||||
initialCaret={this.props.editState.getCaret()}
|
||||
initialCaret={this.props.editState.getCaret() ?? undefined}
|
||||
label={_t("Edit message")}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
|
|
|
@ -69,14 +69,14 @@ interface IProps {
|
|||
title?: string;
|
||||
avatarJsx?: JSX.Element; // <BaseAvatar />
|
||||
className?: string;
|
||||
presenceState?: PresenceState;
|
||||
presenceLastActiveAgo?: number;
|
||||
presenceLastTs?: number;
|
||||
presenceState: PresenceState;
|
||||
presenceLastActiveAgo: number;
|
||||
presenceLastTs: number;
|
||||
presenceCurrentlyActive?: boolean;
|
||||
showInviteButton?: boolean;
|
||||
showInviteButton: boolean;
|
||||
onClick(): void;
|
||||
suppressOnHover?: boolean;
|
||||
showPresence?: boolean;
|
||||
suppressOnHover: boolean;
|
||||
showPresence: boolean;
|
||||
subtextLabel?: string;
|
||||
e2eStatus?: E2EState;
|
||||
powerStatus?: PowerStatus;
|
||||
|
|
|
@ -274,8 +274,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
verified: null,
|
||||
// The Relations model from the JS SDK for reactions to `mxEvent`
|
||||
reactions: this.getReactions(),
|
||||
// Context menu position
|
||||
contextMenu: null,
|
||||
|
||||
hover: false,
|
||||
|
||||
|
@ -697,13 +695,13 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
});
|
||||
};
|
||||
|
||||
private renderE2EPadlock(): JSX.Element {
|
||||
private renderE2EPadlock(): ReactNode {
|
||||
// if the event was edited, show the verification info for the edit, not
|
||||
// the original
|
||||
const ev = this.props.mxEvent.replacingEvent() ?? this.props.mxEvent;
|
||||
|
||||
// no icon for local rooms
|
||||
if (isLocalRoom(ev.getRoomId()!)) return;
|
||||
if (isLocalRoom(ev.getRoomId()!)) return null;
|
||||
|
||||
// event could not be decrypted
|
||||
if (ev.isDecryptionFailure()) {
|
||||
|
@ -713,9 +711,9 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
// event is encrypted and not redacted, display padlock corresponding to whether or not it is verified
|
||||
if (ev.isEncrypted() && !ev.isRedacted()) {
|
||||
if (this.state.verified === E2EState.Normal) {
|
||||
return; // no icon if we've not even cross-signed the user
|
||||
return null; // no icon if we've not even cross-signed the user
|
||||
} else if (this.state.verified === E2EState.Verified) {
|
||||
return; // no icon for verified
|
||||
return null; // no icon for verified
|
||||
} else if (this.state.verified === E2EState.Unauthenticated) {
|
||||
return <E2ePadlockUnauthenticated />;
|
||||
} else if (this.state.verified === E2EState.Unknown) {
|
||||
|
@ -729,16 +727,16 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
// else if room is encrypted
|
||||
// and event is being encrypted or is not_sent (Unknown Devices/Network Error)
|
||||
if (ev.status === EventStatus.ENCRYPTING) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (ev.status === EventStatus.NOT_SENT) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
if (ev.isState()) {
|
||||
return; // we expect this to be unencrypted
|
||||
return null; // we expect this to be unencrypted
|
||||
}
|
||||
if (ev.isRedacted()) {
|
||||
return; // we expect this to be unencrypted
|
||||
return null; // we expect this to be unencrypted
|
||||
}
|
||||
// if the event is not encrypted, but it's an e2e room, show the open padlock
|
||||
return <E2ePadlockUnencrypted />;
|
||||
|
@ -752,16 +750,16 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
this.setState({ actionBarFocused });
|
||||
};
|
||||
|
||||
private getTile: () => IEventTileType = () => this.tile.current;
|
||||
private getTile: () => IEventTileType | null = () => this.tile.current;
|
||||
|
||||
private getReplyChain = (): ReplyChain => this.replyChain.current;
|
||||
private getReplyChain = (): ReplyChain | null => this.replyChain.current;
|
||||
|
||||
private getReactions = (): Relations => {
|
||||
private getReactions = (): Relations | null => {
|
||||
if (!this.props.showReactions || !this.props.getRelationsForEvent) {
|
||||
return null;
|
||||
}
|
||||
const eventId = this.props.mxEvent.getId();
|
||||
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction");
|
||||
return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction") ?? null;
|
||||
};
|
||||
|
||||
private onReactionsCreated = (relationType: string, eventType: string): void => {
|
||||
|
@ -795,7 +793,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
// Return if we're in a browser and click either an a tag or we have
|
||||
// selected text, as in those cases we want to use the native browser
|
||||
// menu
|
||||
if (!PlatformPeg.get().allowOverridingNativeContextMenus() && (getSelectedText() || anchorElement)) return;
|
||||
if (!PlatformPeg.get()?.allowOverridingNativeContextMenus() && (getSelectedText() || anchorElement)) return;
|
||||
|
||||
// We don't want to show the menu when editing a message
|
||||
if (this.props.editState) return;
|
||||
|
@ -817,7 +815,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
|
||||
private onCloseMenu = (): void => {
|
||||
this.setState({
|
||||
contextMenu: null,
|
||||
contextMenu: undefined,
|
||||
actionBarFocused: false,
|
||||
});
|
||||
};
|
||||
|
@ -901,7 +899,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
this.props.mxEvent.getContent().msgtype === MsgType.Emote,
|
||||
});
|
||||
|
||||
const isSending = ["sending", "queued", "encrypting"].indexOf(this.props.eventSendStatus) !== -1;
|
||||
const isSending = ["sending", "queued", "encrypting"].includes(this.props.eventSendStatus!);
|
||||
const isRedacted = isMessageEvent(this.props.mxEvent) && this.props.isRedacted;
|
||||
const isEncryptionFailure = this.props.mxEvent.isDecryptionFailure();
|
||||
|
||||
|
@ -1110,7 +1108,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
const groupPadlock = !useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
|
||||
const ircPadlock = useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
|
||||
|
||||
let msgOption;
|
||||
let msgOption: JSX.Element | undefined;
|
||||
if (this.props.showReadReceipts) {
|
||||
if (this.shouldShowSentReceipt || this.shouldShowSendingReceipt) {
|
||||
msgOption = <SentReceipt messageState={this.props.mxEvent.getAssociatedStatus()} />;
|
||||
|
@ -1127,7 +1125,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
let replyChain;
|
||||
let replyChain: JSX.Element | undefined;
|
||||
if (
|
||||
haveRendererForEvent(this.props.mxEvent, this.context.showHiddenEvents) &&
|
||||
shouldDisplayReply(this.props.mxEvent)
|
||||
|
@ -1480,7 +1478,7 @@ class E2ePadlock extends React.Component<IE2ePadlockProps, IE2ePadlockState> {
|
|||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let tooltip = null;
|
||||
let tooltip: JSX.Element | undefined;
|
||||
if (this.state.hover) {
|
||||
tooltip = <Tooltip className="mx_EventTile_e2eIcon_tooltip" label={this.props.title} />;
|
||||
}
|
||||
|
@ -1506,7 +1504,7 @@ function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
|
|||
mx_EventTile_receiptSending: !isSent && !isFailed,
|
||||
});
|
||||
|
||||
let nonCssBadge = null;
|
||||
let nonCssBadge: JSX.Element | undefined;
|
||||
if (isFailed) {
|
||||
nonCssBadge = <NotificationBadge notification={StaticNotificationState.RED_EXCLAMATION} />;
|
||||
}
|
||||
|
|
|
@ -24,11 +24,11 @@ import { _t } from "../../../languageHandler";
|
|||
const HistoryTile: React.FC = () => {
|
||||
const { room } = useContext(RoomContext);
|
||||
|
||||
const oldState = room.getLiveTimeline().getState(EventTimeline.BACKWARDS);
|
||||
const encryptionState = oldState.getStateEvents("m.room.encryption")[0];
|
||||
const historyState = oldState.getStateEvents("m.room.history_visibility")[0]?.getContent().history_visibility;
|
||||
const oldState = room?.getLiveTimeline().getState(EventTimeline.BACKWARDS);
|
||||
const encryptionState = oldState?.getStateEvents("m.room.encryption")[0];
|
||||
const historyState = oldState?.getStateEvents("m.room.history_visibility")[0]?.getContent().history_visibility;
|
||||
|
||||
let subtitle;
|
||||
let subtitle: string | undefined;
|
||||
if (historyState == "invited") {
|
||||
subtitle = _t("You don't have permission to view messages from before you were invited.");
|
||||
} else if (historyState == "joined") {
|
||||
|
|
|
@ -54,7 +54,7 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH
|
|||
|
||||
const showPreviews = expanded ? previews : previews.slice(0, INITIAL_NUM_PREVIEWS);
|
||||
|
||||
let toggleButton: JSX.Element;
|
||||
let toggleButton: JSX.Element | undefined;
|
||||
if (previews.length > INITIAL_NUM_PREVIEWS) {
|
||||
toggleButton = (
|
||||
<AccessibleButton onClick={toggleExpanded}>
|
||||
|
@ -94,7 +94,7 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH
|
|||
|
||||
const fetchPreviews = (cli: MatrixClient, links: string[], ts: number): Promise<[string, IPreviewUrlResponse][]> => {
|
||||
return Promise.all<[string, IPreviewUrlResponse] | void>(
|
||||
links.map(async (link): Promise<[string, IPreviewUrlResponse]> => {
|
||||
links.map(async (link): Promise<[string, IPreviewUrlResponse] | undefined> => {
|
||||
try {
|
||||
const preview = await cli.getUrlPreview(link, ts);
|
||||
if (preview && Object.keys(preview).length > 0) {
|
||||
|
|
|
@ -44,7 +44,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
ev.preventDefault();
|
||||
|
||||
let src = p["og:image"];
|
||||
if (src && src.startsWith("mxc://")) {
|
||||
if (src?.startsWith("mxc://")) {
|
||||
src = mediaFromMxc(src).srcHttp;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
};
|
||||
}
|
||||
|
||||
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true);
|
||||
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", undefined, true);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
@ -78,7 +78,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
}
|
||||
|
||||
// FIXME: do we want to factor out all image displaying between this and MImageBody - especially for lightboxing?
|
||||
let image = p["og:image"];
|
||||
let image: string | null = p["og:image"] ?? null;
|
||||
if (!SettingsStore.getValue("showImages")) {
|
||||
image = null; // Don't render a button to show the image, just hide it outright
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
);
|
||||
}
|
||||
|
||||
let img;
|
||||
let img: JSX.Element | undefined;
|
||||
if (image) {
|
||||
img = (
|
||||
<div className="mx_LinkPreviewWidget_image" style={{ height: thumbHeight }}>
|
||||
|
|
|
@ -123,7 +123,9 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||
const cli = MatrixClientPeg.get();
|
||||
const room = cli.getRoom(this.props.roomId);
|
||||
|
||||
return room?.canInvite(cli.getUserId()) || (room?.isSpaceRoom() && room.getJoinRule() === JoinRule.Public);
|
||||
return (
|
||||
!!room?.canInvite(cli.getSafeUserId()) || !!(room?.isSpaceRoom() && room.getJoinRule() === JoinRule.Public)
|
||||
);
|
||||
}
|
||||
|
||||
private getMembersState(invitedMembers: Array<RoomMember>, joinedMembers: Array<RoomMember>): IState {
|
||||
|
@ -276,7 +278,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private getPending3PidInvites(): Array<MatrixEvent> {
|
||||
private getPending3PidInvites(): MatrixEvent[] | undefined {
|
||||
// include 3pid invites (m.room.third_party_invite) state events.
|
||||
// The HS may have already converted these into m.room.member invites so
|
||||
// we shouldn't add them if the 3pid invite state key (token) is in the
|
||||
|
|
|
@ -41,7 +41,7 @@ interface IProps {
|
|||
|
||||
interface IState {
|
||||
isRoomEncrypted: boolean;
|
||||
e2eStatus: E2EState;
|
||||
e2eStatus?: E2EState;
|
||||
}
|
||||
|
||||
export default class MemberTile extends React.Component<IProps, IState> {
|
||||
|
@ -57,7 +57,6 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
|
||||
this.state = {
|
||||
isRoomEncrypted: false,
|
||||
e2eStatus: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -187,7 +186,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
public render(): React.ReactNode {
|
||||
const member = this.props.member;
|
||||
const name = this.getDisplayName();
|
||||
const presenceState = member.user?.presence ?? null;
|
||||
const presenceState = member.user?.presence as PresenceState | undefined;
|
||||
|
||||
const av = <MemberAvatar member={member} width={36} height={36} aria-hidden="true" />;
|
||||
|
||||
|
@ -222,7 +221,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
return (
|
||||
<EntityTile
|
||||
{...this.props}
|
||||
presenceState={presenceState as PresenceState | null}
|
||||
presenceState={presenceState}
|
||||
presenceLastActiveAgo={member.user ? member.user.lastActiveAgo : 0}
|
||||
presenceLastTs={member.user ? member.user.lastPresenceTs : 0}
|
||||
presenceCurrentlyActive={member.user ? member.user.currentlyActive : false}
|
||||
|
|
|
@ -172,7 +172,7 @@ export const UploadButtonContext = createContext<UploadButtonFn | null>(null);
|
|||
|
||||
interface IUploadButtonProps {
|
||||
roomId: string;
|
||||
relation?: IEventRelation | null;
|
||||
relation?: IEventRelation;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
|
@ -197,11 +197,11 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
|||
});
|
||||
|
||||
const onUploadFileInputChange = (ev: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
if (ev.target.files.length === 0) return;
|
||||
if (ev.target.files?.length === 0) return;
|
||||
|
||||
// Take a copy, so we can safely reset the value of the form control
|
||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||
Array.from(ev.target.files),
|
||||
Array.from(ev.target.files!),
|
||||
roomId,
|
||||
relation,
|
||||
cli,
|
||||
|
@ -316,7 +316,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
|
|||
});
|
||||
} else {
|
||||
const threadId =
|
||||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation.event_id : null;
|
||||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation.event_id : undefined;
|
||||
|
||||
Modal.createDialog(
|
||||
PollCreateDialog,
|
||||
|
|
|
@ -166,7 +166,7 @@ const NewRoomIntro: React.FC = () => {
|
|||
const creator = room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
|
||||
const creatorName = room?.getMember(creator)?.rawDisplayName || creator;
|
||||
|
||||
let createdText;
|
||||
let createdText: string;
|
||||
if (creator === cli.getUserId()) {
|
||||
createdText = _t("You created this room.");
|
||||
} else {
|
||||
|
@ -175,15 +175,15 @@ const NewRoomIntro: React.FC = () => {
|
|||
});
|
||||
}
|
||||
|
||||
let parentSpace: Room;
|
||||
let parentSpace: Room | undefined;
|
||||
if (
|
||||
SpaceStore.instance.activeSpaceRoom?.canInvite(cli.getUserId()) &&
|
||||
SpaceStore.instance.activeSpaceRoom?.canInvite(cli.getSafeUserId()) &&
|
||||
SpaceStore.instance.isRoomInSpace(SpaceStore.instance.activeSpace, room.roomId)
|
||||
) {
|
||||
parentSpace = SpaceStore.instance.activeSpaceRoom;
|
||||
}
|
||||
|
||||
let buttons;
|
||||
let buttons: JSX.Element | undefined;
|
||||
if (parentSpace && shouldShowComponent(UIComponent.InviteUsers)) {
|
||||
buttons = (
|
||||
<div className="mx_NewRoomIntro_buttons">
|
||||
|
@ -191,12 +191,12 @@ const NewRoomIntro: React.FC = () => {
|
|||
className="mx_NewRoomIntro_inviteButton"
|
||||
kind="primary"
|
||||
onClick={() => {
|
||||
showSpaceInvite(parentSpace);
|
||||
showSpaceInvite(parentSpace!);
|
||||
}}
|
||||
>
|
||||
{_t("Invite to %(spaceName)s", { spaceName: parentSpace.name })}
|
||||
</AccessibleButton>
|
||||
{room.canInvite(cli.getUserId()) && (
|
||||
{room.canInvite(cli.getSafeUserId()) && (
|
||||
<AccessibleButton
|
||||
className="mx_NewRoomIntro_inviteButton"
|
||||
kind="primary_outline"
|
||||
|
@ -209,7 +209,7 @@ const NewRoomIntro: React.FC = () => {
|
|||
)}
|
||||
</div>
|
||||
);
|
||||
} else if (room.canInvite(cli.getUserId()) && shouldShowComponent(UIComponent.InviteUsers)) {
|
||||
} else if (room.canInvite(cli.getSafeUserId()) && shouldShowComponent(UIComponent.InviteUsers)) {
|
||||
buttons = (
|
||||
<div className="mx_NewRoomIntro_buttons">
|
||||
<AccessibleButton
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { MouseEvent } from "react";
|
||||
import React, { MouseEvent, ReactNode } from "react";
|
||||
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { XOR } from "../../../@types/common";
|
||||
|
@ -71,7 +71,7 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
|||
);
|
||||
}
|
||||
|
||||
private get roomId(): string {
|
||||
private get roomId(): string | null {
|
||||
// We should convert this to null for safety with the SettingsStore
|
||||
return this.props.roomId || null;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
|||
});
|
||||
};
|
||||
|
||||
public render(): React.ReactElement {
|
||||
public render(): ReactNode {
|
||||
/* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */
|
||||
const { notification, showUnsentTooltip, forceCount, onClick } = this.props;
|
||||
|
||||
|
@ -119,8 +119,8 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
|||
if (!notification.hasUnreadCount) return null; // Can't render a badge
|
||||
}
|
||||
|
||||
let label: string;
|
||||
let tooltip: JSX.Element;
|
||||
let label: string | undefined;
|
||||
let tooltip: JSX.Element | undefined;
|
||||
if (showUnsentTooltip && this.state.showTooltip && notification.color === NotificationColor.Unsent) {
|
||||
label = _t("Message didn't send. Click for info.");
|
||||
tooltip = <Tooltip className="mx_RoleButton_tooltip" label={label} />;
|
||||
|
|
|
@ -42,9 +42,9 @@ export const READ_AVATAR_SIZE = 16;
|
|||
interface Props {
|
||||
readReceipts: IReadReceiptProps[];
|
||||
readReceiptMap: { [userId: string]: IReadReceiptInfo };
|
||||
checkUnmounting: () => boolean;
|
||||
checkUnmounting?: () => boolean;
|
||||
suppressAnimation: boolean;
|
||||
isTwelveHour: boolean;
|
||||
isTwelveHour?: boolean;
|
||||
}
|
||||
|
||||
interface IAvatarPosition {
|
||||
|
@ -169,8 +169,8 @@ export function ReadReceiptGroup({
|
|||
);
|
||||
}
|
||||
|
||||
let contextMenu;
|
||||
if (menuDisplayed) {
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (menuDisplayed && button.current) {
|
||||
const buttonRect = button.current.getBoundingClientRect();
|
||||
contextMenu = (
|
||||
<ContextMenu menuClassName="mx_ReadReceiptGroup_popup" onFinished={closeMenu} {...aboveLeftOf(buttonRect)}>
|
||||
|
@ -226,7 +226,7 @@ export function ReadReceiptGroup({
|
|||
}
|
||||
|
||||
interface ReadReceiptPersonProps extends IReadReceiptProps {
|
||||
isTwelveHour: boolean;
|
||||
isTwelveHour?: boolean;
|
||||
onAfterClick?: () => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ interface IProps {
|
|||
suppressAnimation?: boolean;
|
||||
|
||||
// an opaque object for storing information about this user's RR in this room
|
||||
readReceiptInfo: IReadReceiptInfo;
|
||||
readReceiptInfo?: IReadReceiptInfo;
|
||||
|
||||
// A function which is used to check if the parent panel is being
|
||||
// unmounted, to avoid unnecessary work. Should return true if we
|
||||
|
|
|
@ -215,9 +215,9 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
if (!myMember) {
|
||||
return {};
|
||||
}
|
||||
const kickerMember = this.props.room.currentState.getMember(myMember.events.member.getSender());
|
||||
const kickerMember = this.props.room?.currentState.getMember(myMember.events.member.getSender());
|
||||
const memberName = kickerMember ? kickerMember.name : myMember.events.member.getSender();
|
||||
const reason = myMember.events.member.getContent().reason;
|
||||
const reason = myMember.events.member?.getContent().reason;
|
||||
return { memberName, reason };
|
||||
}
|
||||
|
||||
|
@ -252,8 +252,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
if (!myMember) {
|
||||
return false;
|
||||
}
|
||||
const memberEvent = myMember.events.member;
|
||||
const memberContent = memberEvent.getContent();
|
||||
const memberContent = myMember.events.member.getContent();
|
||||
return memberContent.membership === "invite" && memberContent.is_direct;
|
||||
}
|
||||
|
||||
|
@ -397,7 +396,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
const errCodeMessage = _t(
|
||||
"An error (%(errcode)s) was returned while trying to validate your " +
|
||||
"invite. You could try to pass this information on to the person who invited you.",
|
||||
{ errcode: this.state.threePidFetchError.errcode || _t("unknown error code") },
|
||||
{ errcode: this.state.threePidFetchError?.errcode || _t("unknown error code") },
|
||||
);
|
||||
switch (joinRule) {
|
||||
case "invite":
|
||||
|
|
|
@ -204,7 +204,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
|
||||
private async generatePreview(): Promise<void> {
|
||||
if (!this.showMessagePreview) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
const messagePreview = await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue