Conform more code to strict null checking (#10153)
* Conform more code to strict null checking * Conform more code to strict null checking * Iterate * Iterate
This commit is contained in:
committed by
GitHub
parent
a4ff959aa1
commit
145a5a8a8d
@@ -33,6 +33,7 @@ import {
|
||||
WidgetApiFromWidgetAction,
|
||||
WidgetKind,
|
||||
} from "matrix-widget-api";
|
||||
import { Optional } from "matrix-events-sdk";
|
||||
import { EventEmitter } from "events";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/models/event";
|
||||
@@ -156,7 +157,7 @@ export class ElementWidget extends Widget {
|
||||
|
||||
export class StopGapWidget extends EventEmitter {
|
||||
private client: MatrixClient;
|
||||
private messaging: ClientWidgetApi;
|
||||
private messaging: ClientWidgetApi | null;
|
||||
private mockWidget: ElementWidget;
|
||||
private scalarToken: string;
|
||||
private roomId?: string;
|
||||
@@ -172,7 +173,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
// Backwards compatibility: not all old widgets have a creatorUserId
|
||||
if (!app.creatorUserId) {
|
||||
app = objectShallowClone(app); // clone to prevent accidental mutation
|
||||
app.creatorUserId = this.client.getUserId();
|
||||
app.creatorUserId = this.client.getUserId()!;
|
||||
}
|
||||
|
||||
this.mockWidget = new ElementWidget(app);
|
||||
@@ -181,7 +182,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
this.virtual = app.eventId === undefined;
|
||||
}
|
||||
|
||||
private get eventListenerRoomId(): string {
|
||||
private get eventListenerRoomId(): Optional<string> {
|
||||
// When widgets are listening to events, we need to make sure they're only
|
||||
// receiving events for the right room. In particular, room widgets get locked
|
||||
// to the room they were added in while account widgets listen to the currently
|
||||
@@ -192,7 +193,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
return SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
}
|
||||
|
||||
public get widgetApi(): ClientWidgetApi {
|
||||
public get widgetApi(): ClientWidgetApi | null {
|
||||
return this.messaging;
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
const fromCustomisation = WidgetVariableCustomisations?.provideVariables?.() ?? {};
|
||||
const defaults: ITemplateParams = {
|
||||
widgetRoomId: this.roomId,
|
||||
currentUserId: this.client.getUserId(),
|
||||
currentUserId: this.client.getUserId()!,
|
||||
userDisplayName: OwnProfileStore.instance.displayName,
|
||||
userHttpAvatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(),
|
||||
clientId: ELEMENT_CLIENT_ID,
|
||||
@@ -256,9 +257,9 @@ export class StopGapWidget extends EventEmitter {
|
||||
ev.preventDefault();
|
||||
if (ModalWidgetStore.instance.canOpenModalWidget()) {
|
||||
ModalWidgetStore.instance.openModalWidget(ev.detail.data, this.mockWidget, this.roomId);
|
||||
this.messaging.transport.reply(ev.detail, {}); // ack
|
||||
this.messaging?.transport.reply(ev.detail, {}); // ack
|
||||
} else {
|
||||
this.messaging.transport.reply(ev.detail, {
|
||||
this.messaging?.transport.reply(ev.detail, {
|
||||
error: {
|
||||
message: "Unable to open modal at this time",
|
||||
},
|
||||
@@ -301,14 +302,14 @@ export class StopGapWidget extends EventEmitter {
|
||||
// Check up front if this is even a valid request
|
||||
const targetRoomId = (ev.detail.data || {}).room_id;
|
||||
if (!targetRoomId) {
|
||||
return this.messaging.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
|
||||
return this.messaging?.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
|
||||
error: { message: "Room ID not supplied." },
|
||||
});
|
||||
}
|
||||
|
||||
// Check the widget's permission
|
||||
if (!this.messaging.hasCapability(ElementWidgetCapabilities.CanChangeViewedRoom)) {
|
||||
return this.messaging.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
|
||||
if (!this.messaging?.hasCapability(ElementWidgetCapabilities.CanChangeViewedRoom)) {
|
||||
return this.messaging?.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
|
||||
error: { message: "This widget does not have permission for this action (denied)." },
|
||||
});
|
||||
}
|
||||
@@ -332,7 +333,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
const events = room.getLiveTimeline()?.getEvents() || [];
|
||||
const roomEvent = events[events.length - 1];
|
||||
if (!roomEvent) continue; // force later code to think the room is fresh
|
||||
this.readUpToMap[room.roomId] = roomEvent.getId();
|
||||
this.readUpToMap[room.roomId] = roomEvent.getId()!;
|
||||
}
|
||||
|
||||
// Attach listeners for feeding events - the underlying widget classes handle permissions for us
|
||||
@@ -343,7 +344,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
this.messaging.on(
|
||||
`action:${WidgetApiFromWidgetAction.UpdateAlwaysOnScreen}`,
|
||||
(ev: CustomEvent<IStickyActionRequest>) => {
|
||||
if (this.messaging.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
|
||||
if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
|
||||
ActiveWidgetStore.instance.setWidgetPersistence(
|
||||
this.mockWidget.id,
|
||||
this.roomId,
|
||||
@@ -360,7 +361,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
this.messaging.on(
|
||||
`action:${WidgetApiFromWidgetAction.SendSticker}`,
|
||||
(ev: CustomEvent<IStickerActionRequest>) => {
|
||||
if (this.messaging.hasCapability(MatrixCapabilities.StickerSending)) {
|
||||
if (this.messaging?.hasCapability(MatrixCapabilities.StickerSending)) {
|
||||
// Acknowledge first
|
||||
ev.preventDefault();
|
||||
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||
@@ -381,7 +382,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
(ev: CustomEvent<IWidgetApiRequest>) => {
|
||||
// Acknowledge first
|
||||
ev.preventDefault();
|
||||
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||
this.messaging?.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||
|
||||
// First close the stickerpicker
|
||||
defaultDispatcher.dispatch({ action: "stickerpicker_close" });
|
||||
@@ -415,7 +416,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
}),
|
||||
});
|
||||
}
|
||||
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||
this.messaging?.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -478,7 +479,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
private onToDeviceEvent = async (ev: MatrixEvent): Promise<void> => {
|
||||
await this.client.decryptEventIfNeeded(ev);
|
||||
if (ev.isDecryptionFailure()) return;
|
||||
await this.messaging.feedToDevice(ev.getEffectiveEvent() as IRoomEvent, ev.isEncrypted());
|
||||
await this.messaging?.feedToDevice(ev.getEffectiveEvent() as IRoomEvent, ev.isEncrypted());
|
||||
};
|
||||
|
||||
private feedEvent(ev: MatrixEvent): void {
|
||||
@@ -490,7 +491,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
//
|
||||
// This approach of "read up to" prevents widgets receiving decryption spam from startup or
|
||||
// receiving out-of-order events from backfill and such.
|
||||
const upToEventId = this.readUpToMap[ev.getRoomId()];
|
||||
const upToEventId = this.readUpToMap[ev.getRoomId()!];
|
||||
if (upToEventId) {
|
||||
// Small optimization for exact match (prevent search)
|
||||
if (upToEventId === ev.getId()) {
|
||||
@@ -501,7 +502,7 @@ export class StopGapWidget extends EventEmitter {
|
||||
|
||||
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events
|
||||
// to avoid overusing the CPU.
|
||||
const timeline = this.client.getRoom(ev.getRoomId()).getLiveTimeline();
|
||||
const timeline = this.client.getRoom(ev.getRoomId()!).getLiveTimeline();
|
||||
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
|
||||
|
||||
for (const timelineEvent of events) {
|
||||
|
||||
@@ -131,7 +131,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
protected async onReady(): Promise<void> {
|
||||
this.updateAllRooms();
|
||||
|
||||
this.matrixClient.on(RoomStateEvent.Events, this.updateRoomFromState);
|
||||
this.matrixClient?.on(RoomStateEvent.Events, this.updateRoomFromState);
|
||||
this.pinnedRef = SettingsStore.watchSetting("Widgets.pinned", null, this.updateFromSettings);
|
||||
this.layoutRef = SettingsStore.watchSetting("Widgets.layout", null, this.updateFromSettings);
|
||||
WidgetStore.instance.on(UPDATE_EVENT, this.updateFromWidgetStore);
|
||||
@@ -155,7 +155,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
|
||||
private updateFromWidgetStore = (roomId?: string): void => {
|
||||
if (roomId) {
|
||||
const room = this.matrixClient.getRoom(roomId);
|
||||
const room = this.matrixClient?.getRoom(roomId);
|
||||
if (room) this.recalculateRoom(room);
|
||||
} else {
|
||||
this.updateAllRooms();
|
||||
@@ -164,13 +164,13 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
|
||||
private updateRoomFromState = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() !== WIDGET_LAYOUT_EVENT_TYPE) return;
|
||||
const room = this.matrixClient.getRoom(ev.getRoomId());
|
||||
const room = this.matrixClient?.getRoom(ev.getRoomId());
|
||||
if (room) this.recalculateRoom(room);
|
||||
};
|
||||
|
||||
private updateFromSettings = (settingName: string, roomId: string /* and other stuff */): void => {
|
||||
if (roomId) {
|
||||
const room = this.matrixClient.getRoom(roomId);
|
||||
const room = this.matrixClient?.getRoom(roomId);
|
||||
if (room) this.recalculateRoom(room);
|
||||
} else {
|
||||
this.updateAllRooms();
|
||||
@@ -189,7 +189,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
|
||||
const layoutEv = room.currentState.getStateEvents(WIDGET_LAYOUT_EVENT_TYPE, "");
|
||||
const legacyPinned = SettingsStore.getValue("Widgets.pinned", room.roomId);
|
||||
let userLayout = SettingsStore.getValue<ILayoutSettings>("Widgets.layout", room.roomId);
|
||||
let userLayout = SettingsStore.getValue<ILayoutSettings | null>("Widgets.layout", room.roomId);
|
||||
|
||||
if (layoutEv && userLayout && userLayout.overrides !== layoutEv.getId()) {
|
||||
// For some other layout that we don't really care about. The user can reset this
|
||||
@@ -197,7 +197,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
userLayout = null;
|
||||
}
|
||||
|
||||
const roomLayout: ILayoutStateEvent = layoutEv ? layoutEv.getContent() : null;
|
||||
const roomLayout = layoutEv?.getContent<ILayoutStateEvent>() ?? null;
|
||||
// We filter for the center container first.
|
||||
// (An error is raised, if there are multiple widgets marked for the center container)
|
||||
// For the right and top container multiple widgets are allowed.
|
||||
@@ -218,9 +218,9 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
// The widget won't need to be put in any other container.
|
||||
continue;
|
||||
}
|
||||
let targetContainer = defaultContainer;
|
||||
let targetContainer: Container = defaultContainer;
|
||||
if (!!manualContainer || !!stateContainer) {
|
||||
targetContainer = manualContainer ? manualContainer : stateContainer;
|
||||
targetContainer = manualContainer ?? stateContainer!;
|
||||
} else if (isLegacyPinned && !stateContainer) {
|
||||
// Special legacy case
|
||||
targetContainer = Container.Top;
|
||||
@@ -259,7 +259,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
|
||||
// Determine width distribution and height of the top container now (the only relevant one)
|
||||
const widths: number[] = [];
|
||||
let maxHeight = null; // null == default
|
||||
let maxHeight: number | null = null; // null == default
|
||||
let doAutobalance = true;
|
||||
for (let i = 0; i < topWidgets.length; i++) {
|
||||
const widget = topWidgets[i];
|
||||
@@ -487,7 +487,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
|
||||
public canCopyLayoutToRoom(room: Room): boolean {
|
||||
if (!this.matrixClient) return false; // not ready yet
|
||||
return room.currentState.maySendStateEvent(WIDGET_LAYOUT_EVENT_TYPE, this.matrixClient.getUserId());
|
||||
return room.currentState.maySendStateEvent(WIDGET_LAYOUT_EVENT_TYPE, this.matrixClient.getUserId()!);
|
||||
}
|
||||
|
||||
public copyLayoutToRoom(room: Room): void {
|
||||
@@ -508,7 +508,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
};
|
||||
}
|
||||
}
|
||||
this.matrixClient.sendStateEvent(room.roomId, WIDGET_LAYOUT_EVENT_TYPE, evContent, "");
|
||||
this.matrixClient?.sendStateEvent(room.roomId, WIDGET_LAYOUT_EVENT_TYPE, evContent, "");
|
||||
}
|
||||
|
||||
private getAllWidgets(room: Room): [IApp, Container][] {
|
||||
@@ -516,7 +516,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
|
||||
if (!containers) return [];
|
||||
|
||||
const ret: [IApp, Container][] = [];
|
||||
for (const container of Object.keys(containers)) {
|
||||
for (const container in containers) {
|
||||
const widgets = containers[container as Container].ordered;
|
||||
for (const widget of widgets) {
|
||||
ret.push([widget, container as Container]);
|
||||
|
||||
@@ -32,7 +32,7 @@ export class WidgetPermissionStore {
|
||||
// TODO (all functions here): Merge widgetKind with the widget definition
|
||||
|
||||
private packSettingKey(widget: Widget, kind: WidgetKind, roomId?: string): string {
|
||||
let location = roomId;
|
||||
let location: string | null | undefined = roomId;
|
||||
if (kind !== WidgetKind.Room) {
|
||||
location = this.context.client?.getUserId();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user