Apply strictNullChecks to src/stores/widgets/* (#10324)

* Apply `strictNullChecks` to src/stores/widgets/*

* Iterate

* Iterate
This commit is contained in:
Michael Telatynski 2023-03-08 11:48:58 +00:00 committed by GitHub
parent 0c1c3f1cde
commit c0e40217f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 59 additions and 55 deletions

View file

@ -458,7 +458,7 @@ export default class LegacyCallHandler extends EventEmitter {
public getAllActiveCallsForPip(roomId: string): MatrixCall[] { public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.get().getRoom(roomId);
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) { if (room && WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
// This checks if there is space for the call view in the aux panel // This checks if there is space for the call view in the aux panel
// If there is no space any call should be displayed in PiP // If there is no space any call should be displayed in PiP
return this.getAllActiveCalls(); return this.getAllActiveCalls();

View file

@ -67,7 +67,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) { if (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);
} catch (err) { } catch (err) {
logger.error("Failed to start livestream", err); logger.error("Failed to start livestream", err);
// XXX: won't i18n well, but looks like widget api only support 'message'? // XXX: won't i18n well, but looks like widget api only support 'message'?
@ -84,7 +84,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
); );
} }
const pinnedWidgets = 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;
@ -196,6 +196,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
let moveRightButton; let moveRightButton;
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");
WidgetLayoutStore.instance.moveWithinContainer(room, Container.Top, app, 1); WidgetLayoutStore.instance.moveWithinContainer(room, Container.Top, app, 1);
onFinished(); onFinished();
}; };

View file

@ -99,7 +99,7 @@ interface IState {
hasPermissionToLoad: boolean; hasPermissionToLoad: boolean;
// Wait for user profile load to display correct name // Wait for user profile load to display correct name
isUserProfileReady: boolean; isUserProfileReady: boolean;
error: Error; error: Error | null;
menuDisplayed: boolean; menuDisplayed: boolean;
requiresClient: boolean; requiresClient: boolean;
} }
@ -124,7 +124,7 @@ export default class AppTile extends React.Component<IProps, IState> {
private iframe: HTMLIFrameElement; // ref to the iframe (callback style) private iframe: HTMLIFrameElement; // ref to the iframe (callback style)
private allowedWidgetsWatchRef: string; private allowedWidgetsWatchRef: string;
private persistKey: string; private persistKey: string;
private sgWidget: StopGapWidget; private sgWidget: StopGapWidget | null;
private dispatcherRef: string; private dispatcherRef: string;
private unmounted: boolean; private unmounted: boolean;
@ -202,7 +202,7 @@ export default class AppTile extends React.Component<IProps, IState> {
private determineInitialRequiresClientState(): boolean { private determineInitialRequiresClientState(): boolean {
try { try {
const mockWidget = new ElementWidget(this.props.app); const mockWidget = new ElementWidget(this.props.app);
const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room.roomId); const widgetApi = WidgetMessagingStore.instance.getMessaging(mockWidget, this.props.room?.roomId);
if (widgetApi) { if (widgetApi) {
// Load value from existing API to prevent resetting the requiresClient value on layout changes. // Load value from existing API to prevent resetting the requiresClient value on layout changes.
return widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient); return widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient);
@ -310,9 +310,9 @@ export default class AppTile extends React.Component<IProps, IState> {
} }
private setupSgListeners(): void { private setupSgListeners(): void {
this.sgWidget.on("preparing", this.onWidgetPreparing); this.sgWidget?.on("preparing", this.onWidgetPreparing);
// emits when the capabilities have been set up or changed // emits when the capabilities have been set up or changed
this.sgWidget.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified); this.sgWidget?.on("capabilitiesNotified", this.onWidgetCapabilitiesNotified);
} }
private stopSgListeners(): void { private stopSgListeners(): void {
@ -336,7 +336,7 @@ export default class AppTile extends React.Component<IProps, IState> {
} }
private startWidget(): void { private startWidget(): void {
this.sgWidget.prepare().then(() => { this.sgWidget?.prepare().then(() => {
if (this.unmounted) return; if (this.unmounted) return;
this.setState({ initialising: false }); this.setState({ initialising: false });
}); });
@ -406,7 +406,7 @@ export default class AppTile extends React.Component<IProps, IState> {
private onWidgetCapabilitiesNotified = (): void => { private onWidgetCapabilitiesNotified = (): void => {
this.setState({ this.setState({
requiresClient: this.sgWidget.widgetApi.hasCapability(ElementWidgetCapabilities.RequiresClient), requiresClient: !!this.sgWidget?.widgetApi?.hasCapability(ElementWidgetCapabilities.RequiresClient),
}); });
}; };
@ -415,7 +415,7 @@ export default class AppTile extends React.Component<IProps, IState> {
case "m.sticker": case "m.sticker":
if ( if (
payload.widgetId === this.props.app.id && payload.widgetId === this.props.app.id &&
this.sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending) this.sgWidget?.widgetApi?.hasCapability(MatrixCapabilities.StickerSending)
) { ) {
dis.dispatch({ dis.dispatch({
action: "post_sticker_message", action: "post_sticker_message",
@ -444,8 +444,8 @@ export default class AppTile extends React.Component<IProps, IState> {
logger.info("Granting permission for widget to load: " + this.props.app.eventId); logger.info("Granting permission for widget to load: " + this.props.app.eventId);
const current = SettingsStore.getValue("allowedWidgets", roomId); const current = SettingsStore.getValue("allowedWidgets", roomId);
if (this.props.app.eventId !== undefined) current[this.props.app.eventId] = true; if (this.props.app.eventId !== undefined) current[this.props.app.eventId] = true;
const level = SettingsStore.firstSupportedLevel("allowedWidgets"); const level = SettingsStore.firstSupportedLevel("allowedWidgets")!;
SettingsStore.setValue("allowedWidgets", roomId, level, current) SettingsStore.setValue("allowedWidgets", roomId ?? null, level, current)
.then(() => { .then(() => {
this.setState({ hasPermissionToLoad: true }); this.setState({ hasPermissionToLoad: true });
@ -501,7 +501,7 @@ export default class AppTile extends React.Component<IProps, IState> {
this.resetWidget(this.props); this.resetWidget(this.props);
this.startMessaging(); this.startMessaging();
if (this.iframe) { if (this.iframe && this.sgWidget) {
// Reload iframe // Reload iframe
this.iframe.src = this.sgWidget.embedUrl; this.iframe.src = this.sgWidget.embedUrl;
} }
@ -519,7 +519,7 @@ export default class AppTile extends React.Component<IProps, IState> {
// window.open(this._getPopoutUrl(), '_blank', 'noopener=yes'); // window.open(this._getPopoutUrl(), '_blank', 'noopener=yes');
Object.assign(document.createElement("a"), { Object.assign(document.createElement("a"), {
target: "_blank", target: "_blank",
href: this.sgWidget.popoutUrl, href: this.sgWidget?.popoutUrl,
rel: "noreferrer noopener", rel: "noreferrer noopener",
}).click(); }).click();
}; };
@ -676,7 +676,7 @@ export default class AppTile extends React.Component<IProps, IState> {
if (this.state.menuDisplayed) { if (this.state.menuDisplayed) {
contextMenu = ( contextMenu = (
<WidgetContextMenu <WidgetContextMenu
{...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect(), null)} {...aboveLeftOf(this.contextMenuButton.current.getBoundingClientRect())}
app={this.props.app} app={this.props.app}
onFinished={this.closeContextMenu} onFinished={this.closeContextMenu}
showUnpin={!this.props.userWidget} showUnpin={!this.props.userWidget}

View file

@ -43,7 +43,7 @@ export class IntegrationManagerInstance {
public get name(): string { public get name(): string {
const parsed = url.parse(this.uiUrl); const parsed = url.parse(this.uiUrl);
return parsed.host; return parsed.host ?? "";
} }
public get trimmedApiUrl(): string { public get trimmedApiUrl(): string {

View file

@ -75,7 +75,7 @@ export default class ActiveWidgetStore extends EventEmitter {
this.setWidgetPersistence(widgetId, roomId, false); this.setWidgetPersistence(widgetId, roomId, false);
} }
public setWidgetPersistence(widgetId: string, roomId: string, val: boolean): void { public setWidgetPersistence(widgetId: string, roomId: string | null, val: boolean): void {
const isPersisted = this.getWidgetPersistence(widgetId, roomId); const isPersisted = this.getWidgetPersistence(widgetId, roomId);
if (isPersisted && !val) { if (isPersisted && !val) {
@ -88,7 +88,7 @@ export default class ActiveWidgetStore extends EventEmitter {
this.emit(ActiveWidgetStoreEvent.Persistence); this.emit(ActiveWidgetStoreEvent.Persistence);
} }
public getWidgetPersistence(widgetId: string, roomId: string): boolean { public getWidgetPersistence(widgetId: string, roomId: string | null): boolean {
return this.persistentWidgetId === widgetId && this.persistentRoomId === roomId; return this.persistentWidgetId === widgetId && this.persistentRoomId === roomId;
} }

View file

@ -285,7 +285,7 @@ export class StopGapWidget extends EventEmitter {
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver); this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
this.messaging.on("preparing", () => this.emit("preparing")); this.messaging.on("preparing", () => this.emit("preparing"));
this.messaging.on("ready", () => { this.messaging.on("ready", () => {
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging); WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.roomId, this.messaging!);
this.emit("ready"); this.emit("ready");
}); });
this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified")); this.messaging.on("capabilitiesNotified", () => this.emit("capabilitiesNotified"));
@ -347,7 +347,7 @@ export class StopGapWidget extends EventEmitter {
if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) { if (this.messaging?.hasCapability(MatrixCapabilities.AlwaysOnScreen)) {
ActiveWidgetStore.instance.setWidgetPersistence( ActiveWidgetStore.instance.setWidgetPersistence(
this.mockWidget.id, this.mockWidget.id,
this.roomId, this.roomId ?? null,
ev.detail.data.value, ev.detail.data.value,
); );
ev.preventDefault(); ev.preventDefault();
@ -393,14 +393,12 @@ export class StopGapWidget extends EventEmitter {
const integType = data?.integType as string; const integType = data?.integType as string;
const integId = <string>data?.integId; const integId = <string>data?.integId;
const roomId = SdkContextClass.instance.roomViewStore.getRoomId();
const room = roomId ? this.client.getRoom(roomId) : undefined;
if (!room) return;
// noinspection JSIgnoredPromiseFromCall // noinspection JSIgnoredPromiseFromCall
IntegrationManagers.sharedInstance() IntegrationManagers.sharedInstance()?.getPrimaryManager()?.open(room, `type_${integType}`, integId);
.getPrimaryManager()
.open(
this.client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()),
`type_${integType}`,
integId,
);
}, },
); );
} }
@ -434,7 +432,7 @@ export class StopGapWidget extends EventEmitter {
if (managers.hasManager()) { if (managers.hasManager()) {
// TODO: Pick the right manager for the widget // TODO: Pick the right manager for the widget
const defaultManager = managers.getPrimaryManager(); const defaultManager = managers.getPrimaryManager();
if (WidgetUtils.isScalarUrl(defaultManager.apiUrl)) { if (defaultManager && WidgetUtils.isScalarUrl(defaultManager.apiUrl)) {
const scalar = defaultManager.getScalarClient(); const scalar = defaultManager.getScalarClient();
this.scalarToken = await scalar.getScalarToken(); this.scalarToken = await scalar.getScalarToken();
} }
@ -452,7 +450,10 @@ export class StopGapWidget extends EventEmitter {
* @param opts * @param opts
*/ */
public stopMessaging(opts = { forceDestroy: false }): void { public stopMessaging(opts = { forceDestroy: false }): void {
if (!opts?.forceDestroy && ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId)) { if (
!opts?.forceDestroy &&
ActiveWidgetStore.instance.getWidgetPersistence(this.mockWidget.id, this.roomId ?? null)
) {
logger.log("Skipping destroy - persistent widget"); logger.log("Skipping destroy - persistent widget");
return; return;
} }
@ -500,9 +501,11 @@ export class StopGapWidget extends EventEmitter {
let isBeforeMark = true; let isBeforeMark = true;
const room = this.client.getRoom(ev.getRoomId()!);
if (!room) return;
// Timelines are most recent last, so reverse the order and limit ourselves to 100 events // Timelines are most recent last, so reverse the order and limit ourselves to 100 events
// to avoid overusing the CPU. // to avoid overusing the CPU.
const timeline = this.client.getRoom(ev.getRoomId()!).getLiveTimeline(); const timeline = room.getLiveTimeline();
const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100); const events = arrayFastClone(timeline.getEvents()).reverse().slice(0, 100);
for (const timelineEvent of events) { for (const timelineEvent of events) {
@ -533,7 +536,7 @@ export class StopGapWidget extends EventEmitter {
} }
const raw = ev.getEffectiveEvent(); const raw = ev.getEffectiveEvent();
this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId).catch((e) => { this.messaging.feedEvent(raw as IRoomEvent, this.eventListenerRoomId!).catch((e) => {
logger.error("Error sending event to widget: ", e); logger.error("Error sending event to widget: ", e);
}); });
} }

View file

@ -113,7 +113,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
this.allowedCapabilities.add("visibility"); this.allowedCapabilities.add("visibility");
} else if ( } else if (
virtual && virtual &&
new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url).origin === this.forWidget.origin new URL(SdkConfig.get("element_call").url ?? DEFAULTS.element_call.url!).origin === this.forWidget.origin
) { ) {
// This is a trusted Element Call widget that we control // This is a trusted Element Call widget that we control
this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen); this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen);
@ -202,8 +202,8 @@ export class StopGapWidgetDriver extends WidgetDriver {
widget: this.forWidget, widget: this.forWidget,
widgetKind: this.forWidgetKind, widgetKind: this.forWidgetKind,
}).finished; }).finished;
(result.approved || []).forEach((cap) => allowedSoFar.add(cap)); result?.approved?.forEach((cap) => allowedSoFar.add(cap));
rememberApproved = result.remember; rememberApproved = !!result?.remember;
} catch (e) { } catch (e) {
logger.error("Non-fatal error getting capabilities: ", e); logger.error("Non-fatal error getting capabilities: ", e);
} }
@ -267,7 +267,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
if (encrypted) { if (encrypted) {
const deviceInfoMap = await client.crypto.deviceList.downloadKeys(Object.keys(contentMap), false); const deviceInfoMap = await client.crypto!.deviceList.downloadKeys(Object.keys(contentMap), false);
await Promise.all( await Promise.all(
Object.entries(contentMap).flatMap(([userId, userContentMap]) => Object.entries(contentMap).flatMap(([userId, userContentMap]) =>
@ -313,7 +313,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
? roomIds.includes(Symbols.AnyRoom) ? roomIds.includes(Symbols.AnyRoom)
? client.getVisibleRooms() ? client.getVisibleRooms()
: roomIds.map((r) => client.getRoom(r)) : roomIds.map((r) => client.getRoom(r))
: [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId())]; : [client.getRoom(SdkContextClass.instance.roomViewStore.getRoomId()!)];
return targetRooms.filter((r) => !!r) as Room[]; return targetRooms.filter((r) => !!r) as Room[];
} }
@ -356,7 +356,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
const allResults: IRoomEvent[] = []; const allResults: IRoomEvent[] = [];
for (const room of rooms) { for (const room of rooms) {
const results: MatrixEvent[] = []; const results: MatrixEvent[] = [];
const state: Map<string, MatrixEvent> = room.currentState.events.get(eventType); const state = room.currentState.events.get(eventType);
if (state) { if (state) {
if (stateKey === "" || !!stateKey) { if (stateKey === "" || !!stateKey) {
const forKey = state.get(stateKey); const forKey = state.get(stateKey);

View file

@ -17,7 +17,6 @@
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { Optional } from "matrix-events-sdk";
import { compare } from "matrix-js-sdk/src/utils"; import { compare } from "matrix-js-sdk/src/utils";
import SettingsStore from "../../settings/SettingsStore"; import SettingsStore from "../../settings/SettingsStore";
@ -63,7 +62,7 @@ export interface IStoredLayout {
// this only applies to the top container currently, and that container // this only applies to the top container currently, and that container
// will take the highest value among widgets in the container. Clamped // will take the highest value among widgets in the container. Clamped
// to 0-100 and may have minimums imposed on it. // to 0-100 and may have minimums imposed on it.
height?: number; height?: number | null;
// TODO: [Deferred] Maximizing (fullscreen) widgets by default. // TODO: [Deferred] Maximizing (fullscreen) widgets by default.
} }
@ -147,6 +146,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
} }
private updateAllRooms = (): void => { private updateAllRooms = (): void => {
if (!this.matrixClient) return;
this.byRoom = {}; this.byRoom = {};
for (const room of this.matrixClient.getVisibleRooms()) { for (const room of this.matrixClient.getVisibleRooms()) {
this.recalculateRoom(room); this.recalculateRoom(room);
@ -267,7 +267,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
const userWidgetLayout = userLayout?.widgets?.[widget.id]; const userWidgetLayout = userLayout?.widgets?.[widget.id];
if (Number.isFinite(userWidgetLayout?.width) || Number.isFinite(widgetLayout?.width)) { if (Number.isFinite(userWidgetLayout?.width) || Number.isFinite(widgetLayout?.width)) {
const val = userWidgetLayout?.width || widgetLayout?.width; const val = (userWidgetLayout?.width || widgetLayout?.width)!;
const normalized = clamp(val, MIN_WIDGET_WIDTH_PCT, 100); const normalized = clamp(val, MIN_WIDGET_WIDTH_PCT, 100);
widths.push(normalized); widths.push(normalized);
doAutobalance = false; // a manual width was specified doAutobalance = false; // a manual width was specified
@ -278,7 +278,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
if (widgetLayout?.height || userWidgetLayout?.height) { if (widgetLayout?.height || userWidgetLayout?.height) {
const defRoomHeight = defaultNumber(widgetLayout?.height, MIN_WIDGET_HEIGHT_PCT); const defRoomHeight = defaultNumber(widgetLayout?.height, MIN_WIDGET_HEIGHT_PCT);
const h = defaultNumber(userWidgetLayout?.height, defRoomHeight); const h = defaultNumber(userWidgetLayout?.height, defRoomHeight);
maxHeight = Math.max(maxHeight, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100)); maxHeight = Math.max(maxHeight ?? 0, clamp(h, MIN_WIDGET_HEIGHT_PCT, 100));
} }
} }
if (doAutobalance) { if (doAutobalance) {
@ -346,11 +346,11 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
} }
} }
public getContainerWidgets(room: Optional<Room>, container: Container): IApp[] { public getContainerWidgets(room: Room, container: Container): IApp[] {
return this.byRoom[room?.roomId]?.[container]?.ordered || []; return this.byRoom[room.roomId]?.[container]?.ordered || [];
} }
public isInContainer(room: Optional<Room>, widget: IApp, container: Container): boolean { public isInContainer(room: Room, widget: IApp, container: Container): boolean {
return this.getContainerWidgets(room, container).some((w) => w.id === widget.id); return this.getContainerWidgets(room, container).some((w) => w.id === widget.id);
} }
@ -406,7 +406,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
return this.byRoom[room.roomId]?.[container]?.height ?? null; // let the default get returned if needed return this.byRoom[room.roomId]?.[container]?.height ?? null; // let the default get returned if needed
} }
public setContainerHeight(room: Room, container: Container, height?: number): void { public setContainerHeight(room: Room, container: Container, height?: number | null): void {
const widgets = this.getContainerWidgets(room, container); const widgets = this.getContainerWidgets(room, container);
const widths = this.byRoom[room.roomId]?.[container]?.distributions; const widths = this.byRoom[room.roomId]?.[container]?.distributions;
const localLayout: Record<string, IStoredLayout> = {}; const localLayout: Record<string, IStoredLayout> = {};
@ -438,7 +438,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
container: container, container: container,
width: widths?.[i], width: widths?.[i],
index: i, index: i,
height: height, height,
}; };
}); });
this.updateUserLayout(room, localLayout); this.updateUserLayout(room, localLayout);
@ -477,7 +477,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
this.updateUserLayout(room, newLayout); this.updateUserLayout(room, newLayout);
} }
public hasMaximisedWidget(room?: Room): boolean { public hasMaximisedWidget(room: Room): boolean {
return this.getContainerWidgets(room, Container.Center).length > 0; return this.getContainerWidgets(room, Container.Center).length > 0;
} }
@ -517,7 +517,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
const ret: [IApp, Container][] = []; const ret: [IApp, Container][] = [];
for (const container in containers) { for (const container in containers) {
const widgets = containers[container as Container].ordered; const widgets = containers[container as Container]!.ordered;
for (const widget of widgets) { for (const widget of widgets) {
ret.push([widget, container as Container]); ret.push([widget, container as Container]);
} }

View file

@ -58,7 +58,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
this.widgetMap.clear(); this.widgetMap.clear();
} }
public storeMessaging(widget: Widget, roomId: string, widgetApi: ClientWidgetApi): void { public storeMessaging(widget: Widget, roomId: string | undefined, widgetApi: ClientWidgetApi): void {
this.stopMessaging(widget, roomId); this.stopMessaging(widget, roomId);
const uid = WidgetUtils.calcWidgetUid(widget.id, roomId); const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
this.widgetMap.set(uid, widgetApi); this.widgetMap.set(uid, widgetApi);
@ -66,11 +66,11 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
this.emit(WidgetMessagingStoreEvent.StoreMessaging, uid, widgetApi); this.emit(WidgetMessagingStoreEvent.StoreMessaging, uid, widgetApi);
} }
public stopMessaging(widget: Widget, roomId: string): void { public stopMessaging(widget: Widget, roomId: string | undefined): void {
this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId)); this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
} }
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi { public getMessaging(widget: Widget, roomId: string | undefined): ClientWidgetApi | undefined {
return this.widgetMap.get(WidgetUtils.calcWidgetUid(widget.id, roomId)); return this.widgetMap.get(WidgetUtils.calcWidgetUid(widget.id, roomId));
} }
@ -88,7 +88,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
* @param {string} widgetUid The widget UID. * @param {string} widgetUid The widget UID.
* @returns {ClientWidgetApi} The widget API, or a falsy value if not found. * @returns {ClientWidgetApi} The widget API, or a falsy value if not found.
*/ */
public getMessagingForUid(widgetUid: string): ClientWidgetApi { public getMessagingForUid(widgetUid: string): ClientWidgetApi | undefined {
return this.widgetMap.get(widgetUid); return this.widgetMap.get(widgetUid);
} }
} }

View file

@ -57,7 +57,7 @@ export default class WidgetUtils {
* @return Boolean -- true if the user can modify widgets in this room * @return Boolean -- true if the user can modify widgets in this room
* @throws Error -- specifies the error reason * @throws Error -- specifies the error reason
*/ */
public static canUserModifyWidgets(roomId: string): boolean { public static canUserModifyWidgets(roomId?: string): boolean {
if (!roomId) { if (!roomId) {
logger.warn("No room ID specified"); logger.warn("No room ID specified");
return false; return false;

View file

@ -541,7 +541,7 @@ describe("RoomHeader", () => {
await withCall(async (call) => { await withCall(async (call) => {
await call.connect(); await call.connect();
const messaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(call.widget)); const messaging = WidgetMessagingStore.instance.getMessagingForUid(WidgetUtils.getWidgetUid(call.widget))!;
renderHeader({ viewingCall: true, activeCall: call }); renderHeader({ viewingCall: true, activeCall: call });
// Should start with Freedom selected // Should start with Freedom selected