Apply strictNullChecks to src/components/views/context_menus/* (#10367)

This commit is contained in:
Michael Telatynski 2023-03-14 09:29:35 +00:00 committed by GitHub
parent 4c2b5df1f2
commit 7c2511a592
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 32 additions and 29 deletions

View file

@ -54,7 +54,7 @@ const DeviceContextMenuSection: React.FC<IDeviceContextMenuSectionProps> = ({ de
useEffect(() => { useEffect(() => {
const getDevices = async (): Promise<void> => { const getDevices = async (): Promise<void> => {
return setDevices((await MediaDeviceHandler.getDevices())[deviceKind]); return setDevices((await MediaDeviceHandler.getDevices())?.[deviceKind] ?? []);
}; };
getDevices(); getDevices();
}, [deviceKind]); }, [deviceKind]);

View file

@ -48,7 +48,7 @@ export const KebabContextMenu: React.FC<KebabContextMenuProps> = ({ options, tit
compact compact
rightAligned rightAligned
closeOnInteraction closeOnInteraction
{...contextMenuBelow(button.current.getBoundingClientRect())} {...contextMenuBelow(button.current!.getBoundingClientRect())}
> >
<IconizedContextMenuOptionList>{options}</IconizedContextMenuOptionList> <IconizedContextMenuOptionList>{options}</IconizedContextMenuOptionList>
</IconizedContextMenu> </IconizedContextMenu>

View file

@ -73,7 +73,7 @@ const ReplyInThreadButton: React.FC<IReplyInThreadButton> = ({ mxEvent, closeMen
if (mxEvent.getThread() && !mxEvent.isThreadRoot) { if (mxEvent.getThread() && !mxEvent.isThreadRoot) {
dis.dispatch<ShowThreadPayload>({ dis.dispatch<ShowThreadPayload>({
action: Action.ShowThread, action: Action.ShowThread,
rootEvent: mxEvent.getThread().rootEvent, rootEvent: mxEvent.getThread()!.rootEvent!,
initialEvent: mxEvent, initialEvent: mxEvent,
scroll_into_view: true, scroll_into_view: true,
highlighted: true, highlighted: true,
@ -163,12 +163,12 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
// to obliterate the room - https://github.com/matrix-org/synapse/issues/4042 // to obliterate the room - https://github.com/matrix-org/synapse/issues/4042
// Similarly for encryption events, since redacting them "breaks everything" // Similarly for encryption events, since redacting them "breaks everything"
const canRedact = const canRedact =
room.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.credentials.userId) && !!room?.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.getSafeUserId()) &&
this.props.mxEvent.getType() !== EventType.RoomServerAcl && this.props.mxEvent.getType() !== EventType.RoomServerAcl &&
this.props.mxEvent.getType() !== EventType.RoomEncryption; this.props.mxEvent.getType() !== EventType.RoomEncryption;
let canPin = let canPin =
room.currentState.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) && !!room?.currentState.mayClientSendStateEvent(EventType.RoomPinnedEvents, cli) &&
canPinEvent(this.props.mxEvent); canPinEvent(this.props.mxEvent);
// HACK: Intentionally say we can't pin if the user doesn't want to use the functionality // HACK: Intentionally say we can't pin if the user doesn't want to use the functionality
@ -249,9 +249,10 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onPinClick = (): void => { private onPinClick = (): void => {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.mxEvent.getRoomId()); const room = cli.getRoom(this.props.mxEvent.getRoomId());
if (!room) return;
const eventId = this.props.mxEvent.getId(); const eventId = this.props.mxEvent.getId();
const pinnedIds = room?.currentState?.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent().pinned || []; const pinnedIds = room.currentState?.getStateEvents(EventType.RoomPinnedEvents, "")?.getContent().pinned || [];
if (pinnedIds.includes(eventId)) { if (pinnedIds.includes(eventId)) {
pinnedIds.splice(pinnedIds.indexOf(eventId), 1); pinnedIds.splice(pinnedIds.indexOf(eventId), 1);
@ -261,7 +262,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
event_ids: [...(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids || []), eventId], event_ids: [...(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids || []), eventId],
}); });
} }
cli.sendStateEvent(this.props.mxEvent.getRoomId(), EventType.RoomPinnedEvents, { pinned: pinnedIds }, ""); cli.sendStateEvent(room.roomId, EventType.RoomPinnedEvents, { pinned: pinnedIds }, "");
this.closeMenu(); this.closeMenu();
}; };
@ -294,12 +295,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
private onCopyLinkClick = (e: ButtonEvent): void => { private onCopyLinkClick = (e: ButtonEvent): void => {
e.preventDefault(); // So that we don't open the permalink e.preventDefault(); // So that we don't open the permalink
if (!this.props.link) return;
copyPlaintext(this.props.link); copyPlaintext(this.props.link);
this.closeMenu(); this.closeMenu();
}; };
private onCollapseReplyChainClick = (): void => { private onCollapseReplyChainClick = (): void => {
this.props.collapseReplyChain(); this.props.collapseReplyChain?.();
this.closeMenu(); this.closeMenu();
}; };
@ -349,10 +351,12 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.mxEvent.getRoomId()); const room = cli.getRoom(this.props.mxEvent.getRoomId());
const eventId = this.props.mxEvent.getId(); const eventId = this.props.mxEvent.getId();
return room.getPendingEvents().filter((e) => { return (
const relation = e.getRelation(); room?.getPendingEvents().filter((e) => {
return relation?.rel_type === RelationType.Annotation && relation.event_id === eventId && filter(e); const relation = e.getRelation();
}); return relation?.rel_type === RelationType.Annotation && relation.event_id === eventId && filter(e);
}) ?? []
);
} }
private getUnsentReactions(): MatrixEvent[] { private getUnsentReactions(): MatrixEvent[] {
@ -380,7 +384,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
const eventStatus = mxEvent.status; const eventStatus = mxEvent.status;
const unsentReactionsCount = this.getUnsentReactions().length; const unsentReactionsCount = this.getUnsentReactions().length;
const contentActionable = isContentActionable(mxEvent); const contentActionable = isContentActionable(mxEvent);
const permalink = this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()); const permalink = this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()!);
// status is SENT before remote-echo, null after // status is SENT before remote-echo, null after
const isSent = !eventStatus || eventStatus === EventStatus.SENT; const isSent = !eventStatus || eventStatus === EventStatus.SENT;
const { timelineRenderingType, canReact, canSendMessages } = this.context; const { timelineRenderingType, canReact, canSendMessages } = this.context;

View file

@ -399,7 +399,7 @@ const RoomContextMenu: React.FC<IProps> = ({ room, onFinished, ...props }) => {
Modal.createDialog( Modal.createDialog(
DevtoolsDialog, DevtoolsDialog,
{ {
roomId: SdkContextClass.instance.roomViewStore.getRoomId(), roomId: room.roomId,
}, },
"mx_DevtoolsDialog_wrapper", "mx_DevtoolsDialog_wrapper",
); );

View file

@ -72,7 +72,7 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
if (permalinkCreator) { if (permalinkCreator) {
evt?.preventDefault(); evt?.preventDefault();
evt?.stopPropagation(); evt?.stopPropagation();
const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId()); const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId()!);
await copyPlaintext(matrixToUrl); await copyPlaintext(matrixToUrl);
closeThreadOptions(); closeThreadOptions();
} }
@ -84,9 +84,8 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
onMenuToggle?.(menuDisplayed); onMenuToggle?.(menuDisplayed);
}, [menuDisplayed, onMenuToggle]); }, [menuDisplayed, onMenuToggle]);
const isMainSplitTimelineShown = !WidgetLayoutStore.instance.hasMaximisedWidget( const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId());
MatrixClientPeg.get().getRoom(mxEvent.getRoomId()), const isMainSplitTimelineShown = !!room && !WidgetLayoutStore.instance.hasMaximisedWidget(room);
);
return ( return (
<React.Fragment> <React.Fragment>
<ContextMenuTooltipButton <ContextMenuTooltipButton
@ -104,7 +103,7 @@ const ThreadListContextMenu: React.FC<ThreadListContextMenuProps> = ({
className="mx_RoomTile_contextMenu" className="mx_RoomTile_contextMenu"
compact compact
rightAligned rightAligned
{...contextMenuBelow(button.current.getBoundingClientRect())} {...contextMenuBelow(button.current!.getBoundingClientRect())}
> >
<IconizedContextMenuOptionList> <IconizedContextMenuOptionList>
{isMainSplitTimelineShown && ( {isMainSplitTimelineShown && (

View file

@ -63,8 +63,8 @@ export const WidgetContextMenu: React.FC<IProps> = ({
const widgetMessaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(app)); const widgetMessaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(app));
const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId); const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId);
let streamAudioStreamButton; let streamAudioStreamButton: JSX.Element | undefined;
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) { if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
const onStreamAudioClick = async (): Promise<void> => { const onStreamAudioClick = async (): Promise<void> => {
try { try {
await startJitsiAudioLivestream(widgetMessaging!, roomId); await startJitsiAudioLivestream(widgetMessaging!, roomId);
@ -87,12 +87,12 @@ export const WidgetContextMenu: React.FC<IProps> = ({
const pinnedWidgets = room ? WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top) : []; const pinnedWidgets = room ? WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top) : [];
const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id); const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id);
let editButton; let editButton: JSX.Element | undefined;
if (canModify && WidgetUtils.isManagedByManager(app)) { if (canModify && WidgetUtils.isManagedByManager(app)) {
const _onEditClick = (): void => { const _onEditClick = (): void => {
if (onEditClick) { if (onEditClick) {
onEditClick(); onEditClick();
} else { } else if (room) {
WidgetUtils.editWidget(room, app); WidgetUtils.editWidget(room, app);
} }
onFinished(); onFinished();
@ -101,7 +101,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
editButton = <IconizedContextMenuOption onClick={_onEditClick} label={_t("Edit")} />; editButton = <IconizedContextMenuOption onClick={_onEditClick} label={_t("Edit")} />;
} }
let snapshotButton; let snapshotButton: JSX.Element | undefined;
const screenshotsEnabled = SettingsStore.getValue("enableWidgetScreenshots"); const screenshotsEnabled = SettingsStore.getValue("enableWidgetScreenshots");
if (screenshotsEnabled && widgetMessaging?.hasCapability(MatrixCapabilities.Screenshots)) { if (screenshotsEnabled && widgetMessaging?.hasCapability(MatrixCapabilities.Screenshots)) {
const onSnapshotClick = (): void => { const onSnapshotClick = (): void => {
@ -122,12 +122,12 @@ export const WidgetContextMenu: React.FC<IProps> = ({
snapshotButton = <IconizedContextMenuOption onClick={onSnapshotClick} label={_t("Take a picture")} />; snapshotButton = <IconizedContextMenuOption onClick={onSnapshotClick} label={_t("Take a picture")} />;
} }
let deleteButton; let deleteButton: JSX.Element | undefined;
if (onDeleteClick || canModify) { if (onDeleteClick || canModify) {
const _onDeleteClick = (): void => { const _onDeleteClick = (): void => {
if (onDeleteClick) { if (onDeleteClick) {
onDeleteClick(); onDeleteClick();
} else { } else if (roomId) {
// Show delete confirmation dialog // Show delete confirmation dialog
Modal.createDialog(QuestionDialog, { Modal.createDialog(QuestionDialog, {
title: _t("Delete Widget"), title: _t("Delete Widget"),
@ -159,7 +159,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
app.creatorUserId === cli.getUserId(); app.creatorUserId === cli.getUserId();
const isLocalWidget = WidgetType.JITSI.matches(app.type); const isLocalWidget = WidgetType.JITSI.matches(app.type);
let revokeButton; let revokeButton: JSX.Element | undefined;
if (!userWidget && !isLocalWidget && isAllowedWidget) { if (!userWidget && !isLocalWidget && isAllowedWidget) {
const opts: ApprovalOpts = { approved: undefined }; const opts: ApprovalOpts = { approved: undefined };
ModuleRunner.instance.invoke(WidgetLifecycle.PreLoadRequest, opts, new ElementWidget(app)); ModuleRunner.instance.invoke(WidgetLifecycle.PreLoadRequest, opts, new ElementWidget(app));
@ -182,7 +182,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
} }
} }
let moveLeftButton; let moveLeftButton: JSX.Element | undefined;
if (showUnpin && widgetIndex > 0) { if (showUnpin && widgetIndex > 0) {
const onClick = (): void => { const onClick = (): void => {
if (!room) throw new Error("room must be defined"); if (!room) throw new Error("room must be defined");
@ -193,7 +193,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
moveLeftButton = <IconizedContextMenuOption onClick={onClick} label={_t("Move left")} />; moveLeftButton = <IconizedContextMenuOption onClick={onClick} label={_t("Move left")} />;
} }
let moveRightButton; let moveRightButton: JSX.Element | undefined;
if (showUnpin && widgetIndex < pinnedWidgets.length - 1) { if (showUnpin && widgetIndex < pinnedWidgets.length - 1) {
const onClick = (): void => { const onClick = (): void => {
if (!room) throw new Error("room must be defined"); if (!room) throw new Error("room must be defined");