Make more code conform to strict null checks (#10219
* Make more code conform to strict null checks * Fix types * Fix tests * Fix remaining test assertions * Iterate PR
This commit is contained in:
parent
4c79ecf141
commit
76b82b4b2b
130 changed files with 603 additions and 603 deletions
|
@ -241,7 +241,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
|
||||
private waitForOwnMember(): void {
|
||||
// If we have the member already, do that
|
||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId());
|
||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId()!);
|
||||
if (me) {
|
||||
this.setState({ me });
|
||||
return;
|
||||
|
@ -250,14 +250,14 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
// The members should already be loading, and loadMembersIfNeeded
|
||||
// will return the promise for the existing operation
|
||||
this.props.room.loadMembersIfNeeded().then(() => {
|
||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId());
|
||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId()!);
|
||||
this.setState({ me });
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
VoiceRecordingStore.instance.off(UPDATE_EVENT, this.onVoiceStoreUpdate);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||
UIStore.instance.stopTrackingElementDimensions(`MessageComposer${this.instanceId}`);
|
||||
UIStore.instance.removeListener(`MessageComposer${this.instanceId}`, this.onResize);
|
||||
|
||||
|
@ -268,12 +268,12 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
private onTombstoneClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
|
||||
const replacementRoomId = this.context.tombstone.getContent()["replacement_room"];
|
||||
const replacementRoomId = this.context.tombstone?.getContent()["replacement_room"];
|
||||
const replacementRoom = MatrixClientPeg.get().getRoom(replacementRoomId);
|
||||
let createEventId = null;
|
||||
let createEventId: string | undefined;
|
||||
if (replacementRoom) {
|
||||
const createEvent = replacementRoom.currentState.getStateEvents(EventType.RoomCreate, "");
|
||||
if (createEvent && createEvent.getId()) createEventId = createEvent.getId();
|
||||
if (createEvent?.getId()) createEventId = createEvent.getId();
|
||||
}
|
||||
|
||||
const viaServers = [this.context.tombstone.getSender().split(":").slice(1).join(":")];
|
||||
|
@ -408,7 +408,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
|
||||
private onRecordingEndingSoon = ({ secondsLeft }: { secondsLeft: number }): void => {
|
||||
this.setState({ recordingTimeLeftSeconds: secondsLeft });
|
||||
window.setTimeout(() => this.setState({ recordingTimeLeftSeconds: null }), 3000);
|
||||
window.setTimeout(() => this.setState({ recordingTimeLeftSeconds: undefined }), 3000);
|
||||
};
|
||||
|
||||
private setStickerPickerOpen = (isStickerPickerOpen: boolean): void => {
|
||||
|
|
|
@ -38,7 +38,7 @@ export function StatelessNotificationBadge({ symbol, count, color, ...props }: P
|
|||
|
||||
// Don't show a badge if we don't need to
|
||||
if (color === NotificationColor.None || (hideBold && color == NotificationColor.Bold)) {
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const hasUnreadCount = color >= NotificationColor.Grey && (!!count || !!symbol);
|
||||
|
@ -54,8 +54,8 @@ export function StatelessNotificationBadge({ symbol, count, color, ...props }: P
|
|||
mx_NotificationBadge_visible: isEmptyBadge ? true : hasUnreadCount,
|
||||
mx_NotificationBadge_highlighted: color >= NotificationColor.Red,
|
||||
mx_NotificationBadge_dot: isEmptyBadge,
|
||||
mx_NotificationBadge_2char: symbol?.length > 0 && symbol?.length < 3,
|
||||
mx_NotificationBadge_3char: symbol?.length > 2,
|
||||
mx_NotificationBadge_2char: symbol && symbol.length > 0 && symbol.length < 3,
|
||||
mx_NotificationBadge_3char: symbol && symbol.length > 2,
|
||||
});
|
||||
|
||||
if (props.onClick) {
|
||||
|
|
|
@ -62,7 +62,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
|
|||
eventId: string,
|
||||
relationType: RelationType | string,
|
||||
eventType: EventType | string,
|
||||
): Relations => {
|
||||
): Relations | undefined => {
|
||||
if (eventId === this.props.event.getId()) {
|
||||
return this.relations.get(relationType)?.get(eventType);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
|
|||
public render(): React.ReactNode {
|
||||
const sender = this.props.event.getSender();
|
||||
|
||||
let unpinButton = null;
|
||||
let unpinButton: JSX.Element | undefined;
|
||||
if (this.props.onUnpinClicked) {
|
||||
unpinButton = (
|
||||
<AccessibleTooltipButton
|
||||
|
|
|
@ -66,7 +66,7 @@ export function determineAvatarPosition(index: number, max: number): IAvatarPosi
|
|||
}
|
||||
}
|
||||
|
||||
export function readReceiptTooltip(members: string[], hasMore: boolean): string | null {
|
||||
export function readReceiptTooltip(members: string[], hasMore: boolean): string | undefined {
|
||||
if (hasMore) {
|
||||
return _t("%(members)s and more", {
|
||||
members: members.join(", "),
|
||||
|
@ -78,8 +78,6 @@ export function readReceiptTooltip(members: string[], hasMore: boolean): string
|
|||
});
|
||||
} else if (members.length) {
|
||||
return members[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +132,7 @@ export function ReadReceiptGroup({
|
|||
const { hidden, position } = determineAvatarPosition(index, maxAvatars);
|
||||
|
||||
const userId = receipt.userId;
|
||||
let readReceiptInfo: IReadReceiptInfo;
|
||||
let readReceiptInfo: IReadReceiptInfo | undefined;
|
||||
|
||||
if (readReceiptMap) {
|
||||
readReceiptInfo = readReceiptMap[userId];
|
||||
|
@ -161,7 +159,7 @@ export function ReadReceiptGroup({
|
|||
})
|
||||
.reverse();
|
||||
|
||||
let remText: JSX.Element;
|
||||
let remText: JSX.Element | undefined;
|
||||
const remainder = readReceipts.length - maxAvatars;
|
||||
if (remainder > 0) {
|
||||
remText = (
|
||||
|
|
|
@ -133,7 +133,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
|
|||
|
||||
target.top = 0;
|
||||
target.right = 0;
|
||||
target.parent = null;
|
||||
target.parent = undefined;
|
||||
return target;
|
||||
}
|
||||
// this is the mx_ReadReceiptsGroup
|
||||
|
@ -146,7 +146,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
|
|||
|
||||
target.top = 0;
|
||||
target.right = 0;
|
||||
target.parent = null;
|
||||
target.parent = undefined;
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
|
|||
: // treat new RRs as though they were off the top of the screen
|
||||
-READ_AVATAR_SIZE;
|
||||
|
||||
const startStyles = [];
|
||||
const startStyles: IReadReceiptMarkerStyle[] = [];
|
||||
if (oldInfo?.right) {
|
||||
startStyles.push({
|
||||
top: oldPosition - newPosition,
|
||||
|
@ -210,7 +210,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
|
|||
return (
|
||||
<NodeAnimator startStyles={this.state.startStyles}>
|
||||
<MemberAvatar
|
||||
member={this.props.member}
|
||||
member={this.props.member ?? null}
|
||||
fallbackUserId={this.props.fallbackUserId}
|
||||
aria-hidden="true"
|
||||
aria-live="off"
|
||||
|
|
|
@ -168,7 +168,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
|
|||
...this.props,
|
||||
|
||||
// overrides
|
||||
ref: null,
|
||||
ref: undefined,
|
||||
showUrlPreview: false,
|
||||
overrideBodyTypes: msgtypeOverrides,
|
||||
overrideEventTypes: evOverrides,
|
||||
|
|
|
@ -37,5 +37,5 @@ export function RoomContextDetails<T extends keyof ReactHTML>({ room, component,
|
|||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ const RoomInfoLine: FC<IProps> = ({ room }) => {
|
|||
roomType = room.isSpaceRoom() ? _t("Private space") : _t("Private room");
|
||||
}
|
||||
|
||||
let members: JSX.Element;
|
||||
let members: JSX.Element | undefined;
|
||||
if (membership === "invite" && summary) {
|
||||
// Don't trust local state and instead use the summary API
|
||||
members = (
|
||||
|
|
|
@ -117,7 +117,7 @@ const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>): MenuPr
|
|||
|
||||
const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = defaultDispatcher }) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const activeSpace: Room = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
const activeSpace = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
return SpaceStore.instance.activeSpaceRoom;
|
||||
});
|
||||
|
||||
|
@ -125,7 +125,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
|
|||
const showInviteUsers = shouldShowComponent(UIComponent.InviteUsers);
|
||||
|
||||
if (activeSpace && (showCreateRooms || showInviteUsers)) {
|
||||
let contextMenu: JSX.Element;
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (menuDisplayed) {
|
||||
const canInvite = shouldShowSpaceInvite(activeSpace);
|
||||
|
||||
|
@ -208,7 +208,7 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
|
|||
|
||||
const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const activeSpace = useEventEmitterState<Room>(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
const activeSpace = useEventEmitterState<Room | null>(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
return SpaceStore.instance.activeSpaceRoom;
|
||||
});
|
||||
|
||||
|
@ -216,11 +216,11 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
|
|||
const videoRoomsEnabled = useFeatureEnabled("feature_video_rooms");
|
||||
const elementCallVideoRoomsEnabled = useFeatureEnabled("feature_element_call_video_rooms");
|
||||
|
||||
let contextMenuContent: JSX.Element | null = null;
|
||||
let contextMenuContent: JSX.Element | undefined;
|
||||
if (menuDisplayed && activeSpace) {
|
||||
const canAddRooms = activeSpace.currentState.maySendStateEvent(
|
||||
EventType.SpaceChild,
|
||||
MatrixClientPeg.get().getUserId(),
|
||||
MatrixClientPeg.get().getUserId()!,
|
||||
);
|
||||
|
||||
contextMenuContent = (
|
||||
|
@ -469,13 +469,13 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
SpaceStore.instance.off(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms);
|
||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists);
|
||||
SettingsStore.unwatchSetting(this.favouriteMessageWatcher);
|
||||
defaultDispatcher.unregister(this.dispatcherRef);
|
||||
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
|
||||
SdkContextClass.instance.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
}
|
||||
|
||||
private onRoomViewStoreUpdate = (): void => {
|
||||
this.setState({
|
||||
currentRoomId: SdkContextClass.instance.roomViewStore.getRoomId(),
|
||||
currentRoomId: SdkContextClass.instance.roomViewStore.getRoomId() ?? undefined,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -629,7 +629,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
Object.values(RoomListStore.instance.orderedLists).every((list) => !list?.length);
|
||||
|
||||
return TAG_ORDER.map((orderedTagId) => {
|
||||
let extraTiles = null;
|
||||
let extraTiles: ReactComponentElement<typeof ExtraTile>[] | undefined;
|
||||
if (orderedTagId === DefaultTagID.Suggested) {
|
||||
extraTiles = this.renderSuggestedRooms();
|
||||
} else if (this.state.feature_favourite_messages && orderedTagId === DefaultTagID.SavedItems) {
|
||||
|
|
|
@ -137,12 +137,10 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
}
|
||||
}, [closeMainMenu, canShowMainMenu, mainMenuDisplayed]);
|
||||
|
||||
const spaceName = useTypedEventEmitterState(activeSpace, RoomEvent.Name, () => activeSpace?.name);
|
||||
const spaceName = useTypedEventEmitterState(activeSpace ?? undefined, RoomEvent.Name, () => activeSpace?.name);
|
||||
|
||||
useEffect(() => {
|
||||
if (onVisibilityChange) {
|
||||
onVisibilityChange();
|
||||
}
|
||||
onVisibilityChange?.();
|
||||
}, [onVisibilityChange]);
|
||||
|
||||
const canExploreRooms = shouldShowComponent(UIComponent.ExploreRooms);
|
||||
|
@ -151,7 +149,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
|
||||
const hasPermissionToAddSpaceChild = activeSpace?.currentState?.maySendStateEvent(
|
||||
EventType.SpaceChild,
|
||||
cli.getUserId(),
|
||||
cli.getUserId()!,
|
||||
);
|
||||
const canAddSubRooms = hasPermissionToAddSpaceChild && canCreateRooms;
|
||||
const canAddSubSpaces = hasPermissionToAddSpaceChild && canCreateSpaces;
|
||||
|
@ -161,7 +159,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
// communities and spaces, but is at risk of no options on the Home tab.
|
||||
const canShowPlusMenu = canCreateRooms || canExploreRooms || canCreateSpaces || activeSpace;
|
||||
|
||||
let contextMenu: JSX.Element;
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (mainMenuDisplayed && mainMenuHandle.current) {
|
||||
let ContextMenuComponent;
|
||||
if (activeSpace) {
|
||||
|
@ -179,7 +177,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
/>
|
||||
);
|
||||
} else if (plusMenuDisplayed && activeSpace) {
|
||||
let inviteOption: JSX.Element;
|
||||
let inviteOption: JSX.Element | undefined;
|
||||
if (shouldShowSpaceInvite(activeSpace)) {
|
||||
inviteOption = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -195,8 +193,8 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
);
|
||||
}
|
||||
|
||||
let newRoomOptions: JSX.Element;
|
||||
if (activeSpace?.currentState.maySendStateEvent(EventType.RoomAvatar, cli.getUserId())) {
|
||||
let newRoomOptions: JSX.Element | undefined;
|
||||
if (activeSpace?.currentState.maySendStateEvent(EventType.RoomAvatar, cli.getUserId()!)) {
|
||||
newRoomOptions = (
|
||||
<>
|
||||
<IconizedContextMenuOption
|
||||
|
@ -265,7 +263,9 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
closePlusMenu();
|
||||
}}
|
||||
disabled={!canAddSubRooms}
|
||||
tooltip={!canAddSubRooms && _t("You do not have permissions to add rooms to this space")}
|
||||
tooltip={
|
||||
!canAddSubRooms ? _t("You do not have permissions to add rooms to this space") : undefined
|
||||
}
|
||||
/>
|
||||
{canCreateSpaces && (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -278,7 +278,11 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
closePlusMenu();
|
||||
}}
|
||||
disabled={!canAddSubSpaces}
|
||||
tooltip={!canAddSubSpaces && _t("You do not have permissions to add spaces to this space")}
|
||||
tooltip={
|
||||
!canAddSubSpaces
|
||||
? _t("You do not have permissions to add spaces to this space")
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<BetaPill />
|
||||
</IconizedContextMenuOption>
|
||||
|
@ -287,8 +291,8 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
</IconizedContextMenu>
|
||||
);
|
||||
} else if (plusMenuDisplayed) {
|
||||
let newRoomOpts: JSX.Element;
|
||||
let joinRoomOpt: JSX.Element;
|
||||
let newRoomOpts: JSX.Element | undefined;
|
||||
let joinRoomOpt: JSX.Element | undefined;
|
||||
|
||||
if (canCreateRooms) {
|
||||
newRoomOpts = (
|
||||
|
@ -366,7 +370,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
}
|
||||
|
||||
let title: string;
|
||||
if (activeSpace) {
|
||||
if (activeSpace && spaceName) {
|
||||
title = spaceName;
|
||||
} else {
|
||||
title = getMetaSpaceName(spaceKey as MetaSpace, allRoomsInHome);
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { ReactNode } from "react";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
|
@ -221,25 +221,27 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
return { memberName, reason };
|
||||
}
|
||||
|
||||
private joinRule(): JoinRule {
|
||||
return this.props.room?.currentState
|
||||
.getStateEvents(EventType.RoomJoinRules, "")
|
||||
?.getContent<IJoinRuleEventContent>().join_rule;
|
||||
private joinRule(): JoinRule | null {
|
||||
return (
|
||||
this.props.room?.currentState
|
||||
.getStateEvents(EventType.RoomJoinRules, "")
|
||||
?.getContent<IJoinRuleEventContent>().join_rule ?? null
|
||||
);
|
||||
}
|
||||
|
||||
private getMyMember(): RoomMember {
|
||||
return this.props.room?.getMember(MatrixClientPeg.get().getUserId());
|
||||
private getMyMember(): RoomMember | null {
|
||||
return this.props.room?.getMember(MatrixClientPeg.get().getUserId()!) ?? null;
|
||||
}
|
||||
|
||||
private getInviteMember(): RoomMember {
|
||||
private getInviteMember(): RoomMember | null {
|
||||
const { room } = this.props;
|
||||
if (!room) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const myUserId = MatrixClientPeg.get().getUserId();
|
||||
const myUserId = MatrixClientPeg.get().getUserId()!;
|
||||
const inviteEvent = room.currentState.getMember(myUserId);
|
||||
if (!inviteEvent) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const inviterUserId = inviteEvent.events.member.getSender();
|
||||
return room.currentState.getMember(inviterUserId);
|
||||
|
@ -282,15 +284,15 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
const isSpace = this.props.room?.isSpaceRoom() ?? this.props.oobData?.roomType === RoomType.Space;
|
||||
|
||||
let showSpinner = false;
|
||||
let title;
|
||||
let subTitle;
|
||||
let reasonElement;
|
||||
let primaryActionHandler;
|
||||
let primaryActionLabel;
|
||||
let secondaryActionHandler;
|
||||
let secondaryActionLabel;
|
||||
let footer;
|
||||
const extraComponents = [];
|
||||
let title: string | undefined;
|
||||
let subTitle: string | ReactNode[] | undefined;
|
||||
let reasonElement: JSX.Element | undefined;
|
||||
let primaryActionHandler: (() => void) | undefined;
|
||||
let primaryActionLabel: string | undefined;
|
||||
let secondaryActionHandler: (() => void) | undefined;
|
||||
let secondaryActionLabel: string | undefined;
|
||||
let footer: JSX.Element | undefined;
|
||||
const extraComponents: JSX.Element[] = [];
|
||||
|
||||
const messageCase = this.getMessageCase();
|
||||
switch (messageCase) {
|
||||
|
@ -351,7 +353,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
} else {
|
||||
title = _t("You were removed by %(memberName)s", { memberName });
|
||||
}
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : null;
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : undefined;
|
||||
|
||||
if (isSpace) {
|
||||
primaryActionLabel = _t("Forget this space");
|
||||
|
@ -376,7 +378,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
} else {
|
||||
title = _t("You were banned by %(memberName)s", { memberName });
|
||||
}
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : null;
|
||||
subTitle = reason ? _t("Reason: %(reason)s", { reason }) : undefined;
|
||||
if (isSpace) {
|
||||
primaryActionLabel = _t("Forget this space");
|
||||
} else {
|
||||
|
@ -499,7 +501,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
primaryActionLabel = _t("Accept");
|
||||
}
|
||||
|
||||
const myUserId = MatrixClientPeg.get().getUserId();
|
||||
const myUserId = MatrixClientPeg.get().getUserId()!;
|
||||
const member = this.props.room?.currentState.getMember(myUserId);
|
||||
const memberEventContent = member?.events.member?.getContent();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { Dispatcher } from "flux";
|
|||
import { Enable, Resizable } from "re-resizable";
|
||||
import { Direction } from "re-resizable/lib/resizer";
|
||||
import * as React from "react";
|
||||
import { ComponentType, createRef, ReactComponentElement } from "react";
|
||||
import { ComponentType, createRef, ReactComponentElement, ReactNode } from "react";
|
||||
|
||||
import { polyfillTouchEvent } from "../../../@types/polyfill";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
@ -95,7 +95,7 @@ interface ResizeDelta {
|
|||
type PartialDOMRect = Pick<DOMRect, "left" | "top" | "height">;
|
||||
|
||||
interface IState {
|
||||
contextMenuPosition: PartialDOMRect;
|
||||
contextMenuPosition?: PartialDOMRect;
|
||||
isResizing: boolean;
|
||||
isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered
|
||||
height: number;
|
||||
|
@ -123,7 +123,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
this.heightAtStart = 0;
|
||||
this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId);
|
||||
this.state = {
|
||||
contextMenuPosition: null,
|
||||
isResizing: false,
|
||||
isExpanded: !this.layout.isCollapsed,
|
||||
height: 0, // to be fixed in a moment, we need `rooms` to calculate this.
|
||||
|
@ -160,10 +159,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
private get extraTiles(): ReactComponentElement<typeof ExtraTile>[] | null {
|
||||
if (this.props.extraTiles) {
|
||||
return this.props.extraTiles;
|
||||
}
|
||||
return null;
|
||||
return this.props.extraTiles ?? null;
|
||||
}
|
||||
|
||||
private get numTiles(): number {
|
||||
|
@ -390,7 +386,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private onCloseMenu = (): void => {
|
||||
this.setState({ contextMenuPosition: null });
|
||||
this.setState({ contextMenuPosition: undefined });
|
||||
};
|
||||
|
||||
private onUnreadFirstChanged = (): void => {
|
||||
|
@ -506,7 +502,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
// On ArrowLeft go to the sublist header
|
||||
case KeyBindingAction.ArrowLeft:
|
||||
ev.stopPropagation();
|
||||
this.headerButton.current.focus();
|
||||
this.headerButton.current?.focus();
|
||||
break;
|
||||
// Consume ArrowRight so it doesn't cause focus to get sent to composer
|
||||
case KeyBindingAction.ArrowRight:
|
||||
|
@ -557,10 +553,10 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
return tiles;
|
||||
}
|
||||
|
||||
private renderMenu(): React.ReactElement {
|
||||
private renderMenu(): ReactNode {
|
||||
if (this.props.tagId === DefaultTagID.Suggested || this.props.tagId === DefaultTagID.SavedItems) return null; // not sortable
|
||||
|
||||
let contextMenu = null;
|
||||
let contextMenu: JSX.Element | undefined;
|
||||
if (this.state.contextMenuPosition) {
|
||||
let isAlphabetical = RoomListStore.instance.getTagSorting(this.props.tagId) === SortAlgorithm.Alphabetic;
|
||||
let isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
|
||||
|
@ -571,7 +567,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
// Invites don't get some nonsense options, so only add them if we have to.
|
||||
let otherSections = null;
|
||||
let otherSections: JSX.Element | undefined;
|
||||
if (this.props.tagId !== DefaultTagID.Invite) {
|
||||
otherSections = (
|
||||
<React.Fragment>
|
||||
|
@ -665,7 +661,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
/>
|
||||
);
|
||||
|
||||
let addRoomButton = null;
|
||||
let addRoomButton: JSX.Element | undefined;
|
||||
if (this.props.AuxButtonComponent) {
|
||||
const AuxButtonComponent = this.props.AuxButtonComponent;
|
||||
addRoomButton = <AuxButtonComponent tabIndex={tabIndex} />;
|
||||
|
@ -747,7 +743,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
mx_RoomSublist_hidden: hidden,
|
||||
});
|
||||
|
||||
let content = null;
|
||||
let content: JSX.Element | undefined;
|
||||
if (this.state.roomsLoading) {
|
||||
content = <div className="mx_RoomSublist_skeletonUI" />;
|
||||
} else if (visibleTiles.length > 0 && this.props.forceExpanded) {
|
||||
|
@ -773,7 +769,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
// If we're hiding rooms, show a 'show more' button to the user. This button
|
||||
// floats above the resize handle, if we have one present. If the user has all
|
||||
// tiles visible, it becomes 'show less'.
|
||||
let showNButton = null;
|
||||
let showNButton: JSX.Element | undefined;
|
||||
const hasMoreSlidingSync =
|
||||
this.slidingSyncMode && RoomListStore.instance.getCount(this.props.tagId) > this.state.rooms.length;
|
||||
|
||||
|
@ -786,7 +782,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
numMissing = RoomListStore.instance.getCount(this.props.tagId) - amountFullyShown;
|
||||
}
|
||||
const label = _t("Show %(count)s more", { count: numMissing });
|
||||
let showMoreText = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
|
||||
let showMoreText: ReactNode = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
|
||||
if (this.props.isMinimized) showMoreText = null;
|
||||
showNButton = (
|
||||
<RovingAccessibleButton
|
||||
|
@ -804,7 +800,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
} else if (this.numTiles > this.layout.defaultVisibleTiles) {
|
||||
// we have all tiles visible - add a button to show less
|
||||
const label = _t("Show less");
|
||||
let showLessText = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
|
||||
let showLessText: ReactNode = <span className="mx_RoomSublist_showNButtonText">{label}</span>;
|
||||
if (this.props.isMinimized) showLessText = null;
|
||||
showNButton = (
|
||||
<RovingAccessibleButton
|
||||
|
|
|
@ -72,13 +72,13 @@ export default class SearchBar extends React.Component<IProps, IState> {
|
|||
};
|
||||
|
||||
private searchIfQuery(): void {
|
||||
if (this.searchTerm.current.value) {
|
||||
if (this.searchTerm.current?.value) {
|
||||
this.onSearch();
|
||||
}
|
||||
}
|
||||
|
||||
private onSearch = (): void => {
|
||||
if (!this.searchTerm.current.value.trim()) return;
|
||||
if (!this.searchTerm.current?.value.trim()) return;
|
||||
this.props.onSearch(this.searchTerm.current.value, this.state.scope);
|
||||
};
|
||||
|
||||
|
|
|
@ -368,7 +368,12 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation?.event_id : null;
|
||||
|
||||
let commandSuccessful: boolean;
|
||||
[content, commandSuccessful] = await runSlashCommand(cmd, args, this.props.room.roomId, threadId);
|
||||
[content, commandSuccessful] = await runSlashCommand(
|
||||
cmd,
|
||||
args,
|
||||
this.props.room.roomId,
|
||||
threadId ?? null,
|
||||
);
|
||||
if (!commandSuccessful) {
|
||||
return; // errored
|
||||
}
|
||||
|
@ -425,7 +430,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
|
||||
const prom = doMaybeLocalRoomAction(
|
||||
roomId,
|
||||
(actualRoomId: string) => this.props.mxClient.sendMessage(actualRoomId, threadId, content),
|
||||
(actualRoomId: string) => this.props.mxClient.sendMessage(actualRoomId, threadId ?? null, content!),
|
||||
this.props.mxClient,
|
||||
);
|
||||
if (replyToEvent) {
|
||||
|
@ -439,7 +444,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
}
|
||||
dis.dispatch({ action: "message_sent" });
|
||||
CHAT_EFFECTS.forEach((effect) => {
|
||||
if (containsEmoji(content, effect.emojis)) {
|
||||
if (containsEmoji(content!, effect.emojis)) {
|
||||
// For initial threads launch, chat effects are disabled
|
||||
// see #19731
|
||||
const isNotThread = this.props.relation?.rel_type !== THREAD_RELATION_TYPE.name;
|
||||
|
|
|
@ -52,9 +52,9 @@ interface IProps {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
imError: string;
|
||||
stickerpickerWidget: IWidgetEvent;
|
||||
widgetId: string;
|
||||
imError: string | null;
|
||||
stickerpickerWidget: IWidgetEvent | null;
|
||||
widgetId: string | null;
|
||||
}
|
||||
|
||||
export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
||||
|
@ -71,7 +71,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
private popoverWidth = 300;
|
||||
private popoverHeight = 300;
|
||||
// This is loaded by _acquireScalarClient on an as-needed basis.
|
||||
private scalarClient: ScalarAuthClient = null;
|
||||
private scalarClient: ScalarAuthClient | null = null;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
@ -82,13 +82,13 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
private acquireScalarClient(): Promise<void | ScalarAuthClient> {
|
||||
private async acquireScalarClient(): Promise<void | undefined | null | ScalarAuthClient> {
|
||||
if (this.scalarClient) return Promise.resolve(this.scalarClient);
|
||||
// TODO: Pick the right manager for the widget
|
||||
if (IntegrationManagers.sharedInstance().hasManager()) {
|
||||
this.scalarClient = IntegrationManagers.sharedInstance().getPrimaryManager().getScalarClient();
|
||||
this.scalarClient = IntegrationManagers.sharedInstance().getPrimaryManager()?.getScalarClient() ?? null;
|
||||
return this.scalarClient
|
||||
.connect()
|
||||
?.connect()
|
||||
.then(() => {
|
||||
this.forceUpdate();
|
||||
return this.scalarClient;
|
||||
|
@ -170,21 +170,14 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
private updateWidget = (): void => {
|
||||
const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets()[0];
|
||||
if (!stickerpickerWidget) {
|
||||
Stickerpicker.currentWidget = null;
|
||||
Stickerpicker.currentWidget = undefined;
|
||||
this.setState({ stickerpickerWidget: null, widgetId: null });
|
||||
return;
|
||||
}
|
||||
|
||||
const currentWidget = Stickerpicker.currentWidget;
|
||||
let currentUrl = null;
|
||||
if (currentWidget && currentWidget.content && currentWidget.content.url) {
|
||||
currentUrl = currentWidget.content.url;
|
||||
}
|
||||
|
||||
let newUrl = null;
|
||||
if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) {
|
||||
newUrl = stickerpickerWidget.content.url;
|
||||
}
|
||||
const currentUrl = currentWidget?.content?.url ?? null;
|
||||
const newUrl = stickerpickerWidget?.content?.url ?? null;
|
||||
|
||||
if (newUrl !== currentUrl) {
|
||||
// Destroy the existing frame so a new one can be created
|
||||
|
@ -238,7 +231,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
private sendVisibilityToWidget(visible: boolean): void {
|
||||
if (!this.state.stickerpickerWidget) return;
|
||||
const messaging = WidgetMessagingStore.instance.getMessagingForUid(
|
||||
WidgetUtils.calcWidgetUid(this.state.stickerpickerWidget.id, null),
|
||||
WidgetUtils.calcWidgetUid(this.state.stickerpickerWidget.id),
|
||||
);
|
||||
if (messaging && visible !== this.prevSentVisibility) {
|
||||
messaging.updateVisibility(visible).catch((err) => {
|
||||
|
@ -300,8 +293,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
room={this.props.room}
|
||||
threadId={this.props.threadId}
|
||||
fullWidth={true}
|
||||
userId={MatrixClientPeg.get().credentials.userId}
|
||||
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
|
||||
userId={MatrixClientPeg.get().credentials.userId!}
|
||||
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId!}
|
||||
waitForIframeLoad={true}
|
||||
showMenubar={true}
|
||||
onEditClick={this.launchManageIntegrations}
|
||||
|
@ -347,8 +340,8 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
private launchManageIntegrations = (): void => {
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
IntegrationManagers.sharedInstance()
|
||||
.getPrimaryManager()
|
||||
.open(this.props.room, `type_${WidgetType.STICKERPICKER.preferred}`, this.state.widgetId);
|
||||
?.getPrimaryManager()
|
||||
?.open(this.props.room, `type_${WidgetType.STICKERPICKER.preferred}`, this.state.widgetId ?? undefined);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
|
|
@ -45,19 +45,19 @@ interface IState {
|
|||
}
|
||||
|
||||
export default class ThirdPartyMemberInfo extends React.Component<IProps, IState> {
|
||||
private room: Room;
|
||||
private readonly room: Room | null;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.room = MatrixClientPeg.get().getRoom(this.props.event.getRoomId());
|
||||
const me = this.room.getMember(MatrixClientPeg.get().getUserId());
|
||||
const powerLevels = this.room.currentState.getStateEvents("m.room.power_levels", "");
|
||||
const me = this.room?.getMember(MatrixClientPeg.get().getUserId()!);
|
||||
const powerLevels = this.room?.currentState.getStateEvents("m.room.power_levels", "");
|
||||
|
||||
let kickLevel = powerLevels ? powerLevels.getContent().kick : 50;
|
||||
if (typeof kickLevel !== "number") kickLevel = 50;
|
||||
|
||||
const sender = this.room.getMember(this.props.event.getSender());
|
||||
const sender = this.room?.getMember(this.props.event.getSender());
|
||||
|
||||
this.state = {
|
||||
stateKey: this.props.event.getStateKey(),
|
||||
|
@ -121,7 +121,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
|||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let adminTools = null;
|
||||
let adminTools: JSX.Element | undefined;
|
||||
if (this.state.canKick && this.state.invited) {
|
||||
adminTools = (
|
||||
<div className="mx_MemberInfo_container">
|
||||
|
@ -135,8 +135,8 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
|||
);
|
||||
}
|
||||
|
||||
let scopeHeader;
|
||||
if (this.room.isSpaceRoom()) {
|
||||
let scopeHeader: JSX.Element | undefined;
|
||||
if (this.room?.isSpaceRoom()) {
|
||||
scopeHeader = (
|
||||
<div className="mx_RightPanel_scopeHeader">
|
||||
<RoomAvatar room={this.room} height={32} width={32} />
|
||||
|
|
|
@ -77,18 +77,18 @@ interface IPreviewProps {
|
|||
export const ThreadMessagePreview: React.FC<IPreviewProps> = ({ thread, showDisplayname = false }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
|
||||
const lastReply = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.replyToEvent);
|
||||
const lastReply = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.replyToEvent) ?? undefined;
|
||||
// track the content as a means to regenerate the thread message preview upon edits & decryption
|
||||
const [content, setContent] = useState<IContent>(lastReply?.getContent());
|
||||
const [content, setContent] = useState<IContent | undefined>(lastReply?.getContent());
|
||||
useTypedEventEmitter(lastReply, MatrixEventEvent.Replaced, () => {
|
||||
setContent(lastReply.getContent());
|
||||
setContent(lastReply!.getContent());
|
||||
});
|
||||
const awaitDecryption = lastReply?.shouldAttemptDecryption() || lastReply?.isBeingDecrypted();
|
||||
useTypedEventEmitter(awaitDecryption ? lastReply : null, MatrixEventEvent.Decrypted, () => {
|
||||
setContent(lastReply.getContent());
|
||||
useTypedEventEmitter(awaitDecryption ? lastReply : undefined, MatrixEventEvent.Decrypted, () => {
|
||||
setContent(lastReply!.getContent());
|
||||
});
|
||||
|
||||
const preview = useAsyncMemo(async (): Promise<string> => {
|
||||
const preview = useAsyncMemo(async (): Promise<string | undefined> => {
|
||||
if (!lastReply) return;
|
||||
await cli.decryptEventIfNeeded(lastReply);
|
||||
return MessagePreviewStore.instance.generatePreviewForEvent(lastReply);
|
||||
|
|
|
@ -20,8 +20,8 @@ import { _t } from "../../../languageHandler";
|
|||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
interface IProps {
|
||||
onScrollUpClick?: (e: React.MouseEvent) => void;
|
||||
onCloseClick?: (e: React.MouseEvent) => void;
|
||||
onScrollUpClick: (e: React.MouseEvent) => void;
|
||||
onCloseClick: (e: React.MouseEvent) => void;
|
||||
}
|
||||
|
||||
export default class TopUnreadMessagesBar extends React.PureComponent<IProps> {
|
||||
|
|
|
@ -48,7 +48,7 @@ import { createVoiceMessageContent } from "../../../utils/createVoiceMessageCont
|
|||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
relation?: IEventRelation;
|
||||
replyToEvent?: MatrixEvent;
|
||||
}
|
||||
|
@ -70,9 +70,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
recorder: null, // no recording started by default
|
||||
};
|
||||
this.state = {};
|
||||
|
||||
this.voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation);
|
||||
}
|
||||
|
@ -163,7 +161,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
await VoiceRecordingStore.instance.disposeRecording(this.voiceRecordingId);
|
||||
|
||||
// Reset back to no recording, which means no phase (ie: restart component entirely)
|
||||
this.setState({ recorder: null, recordingPhase: null, didUploadFail: false });
|
||||
this.setState({ recorder: undefined, recordingPhase: undefined, didUploadFail: false });
|
||||
}
|
||||
|
||||
private onCancel = async (): Promise<void> => {
|
||||
|
@ -220,7 +218,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
|
||||
try {
|
||||
// stop any noises which might be happening
|
||||
PlaybackManager.instance.pauseAllExcept(null);
|
||||
PlaybackManager.instance.pauseAllExcept();
|
||||
const recorder = VoiceRecordingStore.instance.startRecording(this.voiceRecordingId);
|
||||
await recorder.start();
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
|
|||
return WhoIsTypingTile.isVisible(this.state);
|
||||
};
|
||||
|
||||
private onRoomTimeline = (event: MatrixEvent, room: Room | null): void => {
|
||||
private onRoomTimeline = (event: MatrixEvent, room?: Room): void => {
|
||||
if (room?.roomId === this.props.room.roomId) {
|
||||
const userId = event.getSender();
|
||||
// remove user from usersTyping
|
||||
|
|
|
@ -45,7 +45,7 @@ export function setCursorPositionAtTheEnd(element: HTMLElement): void {
|
|||
const range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
range.collapse(false);
|
||||
const selection = document.getSelection();
|
||||
const selection = document.getSelection()!;
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue