Skip to content

Commit c0e4021

Browse files
authored
Apply strictNullChecks to src/stores/widgets/* (matrix-org#10324)
* Apply `strictNullChecks` to src/stores/widgets/* * Iterate * Iterate
1 parent 0c1c3f1 commit c0e4021

File tree

11 files changed

+59
-55
lines changed

11 files changed

+59
-55
lines changed

src/LegacyCallHandler.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ export default class LegacyCallHandler extends EventEmitter {
458458

459459
public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
460460
const room = MatrixClientPeg.get().getRoom(roomId);
461-
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
461+
if (room && WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
462462
// This checks if there is space for the call view in the aux panel
463463
// If there is no space any call should be displayed in PiP
464464
return this.getAllActiveCalls();

src/components/views/context_menus/WidgetContextMenu.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
6767
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
6868
const onStreamAudioClick = async (): Promise<void> => {
6969
try {
70-
await startJitsiAudioLivestream(widgetMessaging, roomId);
70+
await startJitsiAudioLivestream(widgetMessaging!, roomId);
7171
} catch (err) {
7272
logger.error("Failed to start livestream", err);
7373
// XXX: won't i18n well, but looks like widget api only support 'message'?
@@ -84,7 +84,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
8484
);
8585
}
8686

87-
const pinnedWidgets = WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top);
87+
const pinnedWidgets = room ? WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top) : [];
8888
const widgetIndex = pinnedWidgets.findIndex((widget) => widget.id === app.id);
8989

9090
let editButton;
@@ -196,6 +196,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
196196
let moveRightButton;
197197
if (showUnpin && widgetIndex < pinnedWidgets.length - 1) {
198198
const onClick = (): void => {
199+
if (!room) throw new Error("room must be defined");
199200
WidgetLayoutStore.instance.moveWithinContainer(room, Container.Top, app, 1);
200201
onFinished();
201202
};

src/components/views/elements/AppTile.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ interface IState {
9999
hasPermissionToLoad: boolean;
100100
// Wait for user profile load to display correct name
101101
isUserProfileReady: boolean;
102-
error: Error;
102+
error: Error | null;
103103
menuDisplayed: boolean;
104104
requiresClient: boolean;
105105
}
@@ -124,7 +124,7 @@ export default class AppTile extends React.Component<IProps, IState> {
124124
private iframe: HTMLIFrameElement; // ref to the iframe (callback style)
125125
private allowedWidgetsWatchRef: string;
126126
private persistKey: string;
127-
private sgWidget: StopGapWidget;
127+
private sgWidget: StopGapWidget | null;
128128
private dispatcherRef: string;
129129
private unmounted: boolean;
130130

@@ -202,7 +202,7 @@ export default class AppTile extends React.Component<IProps, IState> {
202202
private determineInitialRequiresClientState(): boolean {
203203
try {
204204
const mockWidget = new ElementWidget(this.props.app);
205-
const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room.roomId);
205+
const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room?.roomId);
206206
if (widgetApi) {
207207
// Load value from existing API to prevent resetting the requiresClient value on layout changes.
208208
return widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient);
@@ -310,9 +310,9 @@ export default class AppTile extends React.Component<IProps, IState> {
310310
}
311311

312312
private setupSgListeners(): void {
313-
this.sgWidget.on("preparing", this.onWidgetPreparing);
313+
this.sgWidget?.on("preparing", this.onWidgetPreparing);
314314
// emits when the capabilities have been set up or changed
315-
this.sgWidget.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
315+
this.sgWidget?.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
316316
}
317317

318318
private stopSgListeners(): void {
@@ -336,7 +336,7 @@ export default class AppTile extends React.Component<IProps, IState> {
336336
}
337337

338338
private startWidget(): void {
339-
this.sgWidget.prepare().then(() => {
339+
this.sgWidget?.prepare().then(() => {
340340
if (this.unmounted) return;
341341
this.setState({ initialising: false });
342342
});
@@ -406,7 +406,7 @@ export default class AppTile extends React.Component<IProps, IState> {
406406

407407
private onWidgetCapabilitiesNotified = (): void => {
408408
this.setState({
409-
requiresClient: this.sgWidget.widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient),
409+
requiresClient: !!this.sgWidget?.widgetApi?.hasCapability(ElementWidgetCapabilities.RequiresClient),
410410
});
411411
};
412412

@@ -415,7 +415,7 @@ export default class AppTile extends React.Component<IProps, IState> {
415415
case "m.sticker":
416416
if (
417417
payload.widgetId === this.props.app.id &&
418-
this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending)
418+
this.sgWidget?.widgetApi?.hasCapability(MatrixCapabilities.StickerSending)
419419
) {
420420
dis.dispatch({
421421
action: "post_sticker_message",
@@ -444,8 +444,8 @@ export default class AppTile extends React.Component<IProps, IState> {
444444
logger.info("Granting permission for widget to load: " + this.props.app.eventId);
445445
const current = SettingsStore.getValue("allowedWidgets", roomId);
446446
if (this.props.app.eventId !== undefined) current[this.props.app.eventId] = true;
447-
const level = SettingsStore.firstSupportedLevel("allowedWidgets");
448-
SettingsStore.setValue("allowedWidgets", roomId, level, current)
447+
const level = SettingsStore.firstSupportedLevel("allowedWidgets")!;
448+
SettingsStore.setValue("allowedWidgets", roomId ?? null, level, current)
449449
.then(() => {
450450
this.setState({ hasPermissionToLoad: true });
451451

@@ -501,7 +501,7 @@ export default class AppTile extends React.Component<IProps, IState> {
501501
this.resetWidget(this.props);
502502
this.startMessaging();
503503

504-
if (this.iframe) {
504+
if (this.iframe && this.sgWidget) {
505505
// Reload iframe
506506
this.iframe.src = this.sgWidget.embedUrl;
507507
}
@@ -519,7 +519,7 @@ export default class AppTile extends React.Component<IProps, IState> {
519519
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
520520
Object.assign(document.createElement("a"), {
521521
target: "_blank",
522-
href: this.sgWidget.popoutUrl,
522+
href: this.sgWidget?.popoutUrl,
523523
rel: "noreferrer noopener",
524524
}).click();
525525
};
@@ -676,7 +676,7 @@ export default class AppTile extends React.Component<IProps, IState> {
676676
if (this.state.menuDisplayed) {
677677
contextMenu = (
678678
<WidgetContextMenu
679-
{...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect(), null)}
679+
{...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect())}
680680
app={this.props.app}
681681
onFinished={this.closeContextMenu}
682682
showUnpin={!this.props.userWidget}

src/integrations/IntegrationManagerInstance.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class IntegrationManagerInstance {
4343

4444
public get name(): string {
4545
const parsed = url.parse(this.uiUrl);
46-
return parsed.host;
46+
return parsed.host ?? "";
4747
}
4848

4949
public get trimmedApiUrl(): string {

src/stores/ActiveWidgetStore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export default class ActiveWidgetStore extends EventEmitter {
7575
this.setWidgetPersistence(widgetId, roomId, false);
7676
}
7777

78-
public setWidgetPersistence(widgetId: string, roomId: string, val: boolean): void {
78+
public setWidgetPersistence(widgetId: string, roomId: string | null, val: boolean): void {
7979
const isPersisted = this.getWidgetPersistence(widgetId, roomId);
8080

8181
if (isPersisted && !val) {
@@ -88,7 +88,7 @@ export default class ActiveWidgetStore extends EventEmitter {
8888
this.emit(ActiveWidgetStoreEvent.Persistence);
8989
}
9090

91-
public getWidgetPersistence(widgetId: string, roomId: string): boolean {
91+
public getWidgetPersistence(widgetId: string, roomId: string | null): boolean {
9292
return this.persistentWidgetId === widgetId && this.persistentRoomId === roomId;
9393
}
9494

src/stores/widgets/StopGapWidget.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ export class StopGapWidget extends EventEmitter {
285285
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
286286
this.messaging.on("preparing", () => this.emit("preparing"));
287287
this.messaging.on("ready", () => {
288-
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging);
288+
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging!);
289289
this.emit("ready");
290290
});
291291
this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified"));
@@ -347,7 +347,7 @@ export class StopGapWidget extends EventEmitter {
347347
if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
348348
ActiveWidgetStore.instance.setWidgetPersistence(
349349
this.mockWidget.id,
350-
this.roomId,
350+
this.roomId ?? null,
351351
ev.detail.data.value,
352352
);
353353
ev.preventDefault();
@@ -393,14 +393,12 @@ export class StopGapWidget extends EventEmitter {
393393
const integType = data?.integType as string;
394394
const integId = <string>data?.integId;
395395

396+
const roomId = SdkContextClass.instance.roomViewStore.getRoomId();
397+
const room = roomId ? this.client.getRoom(roomId) : undefined;
398+
if (!room) return;
399+
396400
// noinspection JSIgnoredPromiseFromCall
397-
IntegrationManagers.sharedInstance()
398-
.getPrimaryManager()
399-
.open(
400-
this.client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()),
401-
`type_${integType}`,
402-
integId,
403-
);
401+
IntegrationManagers.sharedInstance()?.getPrimaryManager()?.open(room, `type_${integType}`, integId);
404402
},
405403
);
406404
}
@@ -434,7 +432,7 @@ export class StopGapWidget extends EventEmitter {
434432
if (managers.hasManager()) {
435433
// TODO: Pick the right manager for the widget
436434
const defaultManager = managers.getPrimaryManager();
437-
if (WidgetUtils.isScalarUrl(defaultManager.apiUrl)) {
435+
if (defaultManager && WidgetUtils.isScalarUrl(defaultManager.apiUrl)) {
438436
const scalar = defaultManager.getScalarClient();
439437
this.scalarToken = await scalar.getScalarToken();
440438
}
@@ -452,7 +450,10 @@ export class StopGapWidget extends EventEmitter {
452450
* @param opts
453451
*/
454452
public stopMessaging(opts = { forceDestroy: false }): void {
455-
if (!opts?.forceDestroy && ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId)) {
453+
if (
454+
!opts?.forceDestroy &&
455+
ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId ?? null)
456+
) {
456457
logger.log("Skipping destroy - persistent widget");
457458
return;
458459
}
@@ -500,9 +501,11 @@ export class StopGapWidget extends EventEmitter {
500501

501502
let isBeforeMark = true;
502503

504+
const room = this.client.getRoom(ev.getRoomId()!);
505+
if (!room) return;
503506
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events
504507
// to avoid overusing the CPU.
505-
const timeline = this.client.getRoom(ev.getRoomId()!).getLiveTimeline();
508+
const timeline = room.getLiveTimeline();
506509
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
507510

508511
for (const timelineEvent of events) {
@@ -533,7 +536,7 @@ export class StopGapWidget extends EventEmitter {
533536
}
534537

535538
const raw = ev.getEffectiveEvent();
536-
this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId).catch((e) => {
539+
this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId!).catch((e) => {
537540
logger.error("Error sending event to widget: ", e);
538541
});
539542
}

src/stores/widgets/StopGapWidgetDriver.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
113113
this.allowedCapabilities.add("visibility");
114114
} else if (
115115
virtual &&
116-
new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url).origin === this.forWidget.origin
116+
new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url!).origin === this.forWidget.origin
117117
) {
118118
// This is a trusted Element Call widget that we control
119119
this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen);
@@ -202,8 +202,8 @@ export class StopGapWidgetDriver extends WidgetDriver {
202202
widget: this.forWidget,
203203
widgetKind: this.forWidgetKind,
204204
}).finished;
205-
(result.approved || []).forEach((cap) => allowedSoFar.add(cap));
206-
rememberApproved = result.remember;
205+
result?.approved?.forEach((cap) => allowedSoFar.add(cap));
206+
rememberApproved = !!result?.remember;
207207
} catch (e) {
208208
logger.error("Non-fatal error getting capabilities: ", e);
209209
}
@@ -267,7 +267,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
267267
const client = MatrixClientPeg.get();
268268

269269
if (encrypted) {
270-
const deviceInfoMap = await client.crypto.deviceList.downloadKeys(Object.keys(contentMap), false);
270+
const deviceInfoMap = await client.crypto!.deviceList.downloadKeys(Object.keys(contentMap), false);
271271

272272
await Promise.all(
273273
Object.entries(contentMap).flatMap(([userId, userContentMap]) =>
@@ -313,7 +313,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
313313
? roomIds.includes(Symbols.AnyRoom)
314314
? client.getVisibleRooms()
315315
: roomIds.map((r) => client.getRoom(r))
316-
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId())];
316+
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()!)];
317317
return targetRooms.filter((r) => !!r) as Room[];
318318
}
319319

@@ -356,7 +356,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
356356
const allResults: IRoomEvent[] = [];
357357
for (const room of rooms) {
358358
const results: MatrixEvent[] = [];
359-
const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType);
359+
const state = room.currentState.events.get(eventType);
360360
if (state) {
361361
if (stateKey === "" || !!stateKey) {
362362
const forKey = state.get(stateKey);

src/stores/widgets/WidgetLayoutStore.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import { Room } from "matrix-js-sdk/src/models/room";
1818
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
1919
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
20-
import { Optional } from "matrix-events-sdk";
2120
import { compare } from "matrix-js-sdk/src/utils";
2221

2322
import SettingsStore from "../../settings/SettingsStore";
@@ -63,7 +62,7 @@ export interface IStoredLayout {
6362
// this only applies to the top container currently, and that container
6463
// will take the highest value among widgets in the container. Clamped
6564
// to 0-100 and may have minimums imposed on it.
66-
height?: number;
65+
height?: number | null;
6766

6867
// TODO: [Deferred] Maximizing (fullscreen) widgets by default.
6968
}
@@ -147,6 +146,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
147146
}
148147

149148
private updateAllRooms = (): void => {
149+
if (!this.matrixClient) return;
150150
this.byRoom = {};
151151
for (const room of this.matrixClient.getVisibleRooms()) {
152152
this.recalculateRoom(room);
@@ -267,7 +267,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
267267
const userWidgetLayout = userLayout?.widgets?.[widget.id];
268268

269269
if (Number.isFinite(userWidgetLayout?.width) || Number.isFinite(widgetLayout?.width)) {
270-
const val = userWidgetLayout?.width || widgetLayout?.width;
270+
const val = (userWidgetLayout?.width || widgetLayout?.width)!;
271271
const normalized = clamp(val, MIN_WIDGET_WIDTH_PCT, 100);
272272
widths.push(normalized);
273273
doAutobalance = false; // a manual width was specified
@@ -278,7 +278,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
278278
if (widgetLayout?.height || userWidgetLayout?.height) {
279279
const defRoomHeight = defaultNumber(widgetLayout?.height, MIN_WIDGET_HEIGHT_PCT);
280280
const h = defaultNumber(userWidgetLayout?.height, defRoomHeight);
281-
maxHeight = Math.max(maxHeight, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100));
281+
maxHeight = Math.max(maxHeight ?? 0, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100));
282282
}
283283
}
284284
if (doAutobalance) {
@@ -346,11 +346,11 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
346346
}
347347
}
348348

349-
public getContainerWidgets(room: Optional<Room>, container: Container): IApp[] {
350-
return this.byRoom[room?.roomId]?.[container]?.ordered || [];
349+
public getContainerWidgets(room: Room, container: Container): IApp[] {
350+
return this.byRoom[room.roomId]?.[container]?.ordered || [];
351351
}
352352

353-
public isInContainer(room: Optional<Room>, widget: IApp, container: Container): boolean {
353+
public isInContainer(room: Room, widget: IApp, container: Container): boolean {
354354
return this.getContainerWidgets(room, container).some((w) => w.id === widget.id);
355355
}
356356

@@ -406,7 +406,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
406406
return this.byRoom[room.roomId]?.[container]?.height ?? null; // let the default get returned if needed
407407
}
408408

409-
public setContainerHeight(room: Room, container: Container, height?: number): void {
409+
public setContainerHeight(room: Room, container: Container, height?: number | null): void {
410410
const widgets = this.getContainerWidgets(room, container);
411411
const widths = this.byRoom[room.roomId]?.[container]?.distributions;
412412
const localLayout: Record<string, IStoredLayout> = {};
@@ -438,7 +438,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
438438
container: container,
439439
width: widths?.[i],
440440
index: i,
441-
height: height,
441+
height,
442442
};
443443
});
444444
this.updateUserLayout(room, localLayout);
@@ -477,7 +477,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
477477
this.updateUserLayout(room, newLayout);
478478
}
479479

480-
public hasMaximisedWidget(room?: Room): boolean {
480+
public hasMaximisedWidget(room: Room): boolean {
481481
return this.getContainerWidgets(room, Container.Center).length > 0;
482482
}
483483

@@ -517,7 +517,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
517517

518518
const ret: [IApp, Container][] = [];
519519
for (const container in containers) {
520-
const widgets = containers[container as Container].ordered;
520+
const widgets = containers[container as Container]!.ordered;
521521
for (const widget of widgets) {
522522
ret.push([widget, container as Container]);
523523
}

0 commit comments

Comments
 (0)