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
@@ -92,7 +92,7 @@ export abstract class AsyncStore<T extends Object> extends EventEmitter {
|
||||
* @param {T|*} newState The new state of the store.
|
||||
* @param {boolean} quiet If true, the function will not raise an UPDATE_EVENT.
|
||||
*/
|
||||
protected async reset(newState: T | Object = null, quiet = false): Promise<void> {
|
||||
protected async reset(newState: T | Object | null = null, quiet = false): Promise<void> {
|
||||
await this.lock.acquireAsync();
|
||||
try {
|
||||
this.storeState = Object.freeze(<T>(newState || {}));
|
||||
|
||||
@@ -19,7 +19,7 @@ import { AsyncStore } from "./AsyncStore";
|
||||
import { ActionPayload } from "../dispatcher/payloads";
|
||||
|
||||
interface IState {
|
||||
hostSignupActive?: boolean;
|
||||
hostSignupActive: boolean;
|
||||
}
|
||||
|
||||
export class HostSignupStore extends AsyncStore<IState> {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { ActionPayload } from "../dispatcher/payloads";
|
||||
import { DoAfterSyncPreparedPayload } from "../dispatcher/payloads/DoAfterSyncPreparedPayload";
|
||||
|
||||
interface IState {
|
||||
deferredAction: ActionPayload;
|
||||
deferredAction: ActionPayload | null;
|
||||
}
|
||||
|
||||
const INITIAL_STATE: IState = {
|
||||
@@ -83,8 +83,8 @@ class LifecycleStore extends Store<ActionPayload> {
|
||||
}
|
||||
}
|
||||
|
||||
let singletonLifecycleStore = null;
|
||||
let singletonLifecycleStore: LifecycleStore | null = null;
|
||||
if (!singletonLifecycleStore) {
|
||||
singletonLifecycleStore = new LifecycleStore();
|
||||
}
|
||||
export default singletonLifecycleStore;
|
||||
export default singletonLifecycleStore!;
|
||||
|
||||
@@ -110,15 +110,15 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
* ordered by creation time descending
|
||||
*/
|
||||
private liveBeaconIds: BeaconIdentifier[] = [];
|
||||
private locationInterval: number;
|
||||
private geolocationError: GeolocationError | undefined;
|
||||
private clearPositionWatch: ClearWatchCallback | undefined;
|
||||
private locationInterval?: number;
|
||||
private geolocationError?: GeolocationError;
|
||||
private clearPositionWatch?: ClearWatchCallback;
|
||||
/**
|
||||
* Track when the last position was published
|
||||
* So we can manually get position on slow interval
|
||||
* when the target is stationary
|
||||
*/
|
||||
private lastPublishedPositionTimestamp: number | undefined;
|
||||
private lastPublishedPositionTimestamp?: number;
|
||||
|
||||
public constructor() {
|
||||
super(defaultDispatcher);
|
||||
@@ -231,7 +231,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
*/
|
||||
|
||||
private onNewBeacon = (_event: MatrixEvent, beacon: Beacon): void => {
|
||||
if (!isOwnBeacon(beacon, this.matrixClient.getUserId())) {
|
||||
if (!isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
|
||||
return;
|
||||
}
|
||||
this.addBeacon(beacon);
|
||||
@@ -242,7 +242,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
* This will be called when a beacon is replaced
|
||||
*/
|
||||
private onUpdateBeacon = (_event: MatrixEvent, beacon: Beacon): void => {
|
||||
if (!isOwnBeacon(beacon, this.matrixClient.getUserId())) {
|
||||
if (!isOwnBeacon(beacon, this.matrixClient.getUserId()!)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
}
|
||||
|
||||
private initialiseBeaconState = (): void => {
|
||||
const userId = this.matrixClient.getUserId();
|
||||
const userId = this.matrixClient.getUserId()!;
|
||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
||||
|
||||
visibleRooms.forEach((room) => {
|
||||
@@ -329,7 +329,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
this.beaconsByRoomId.set(beacon.roomId, new Set<string>());
|
||||
}
|
||||
|
||||
this.beaconsByRoomId.get(beacon.roomId).add(beacon.identifier);
|
||||
this.beaconsByRoomId.get(beacon.roomId)!.add(beacon.identifier);
|
||||
|
||||
beacon.monitorLiveness();
|
||||
};
|
||||
@@ -343,7 +343,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
if (!this.beacons.has(beaconId)) {
|
||||
return;
|
||||
}
|
||||
this.beacons.get(beaconId).destroy();
|
||||
this.beacons.get(beaconId)!.destroy();
|
||||
this.beacons.delete(beaconId);
|
||||
|
||||
this.checkLiveness();
|
||||
|
||||
@@ -43,7 +43,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
return instance;
|
||||
})();
|
||||
|
||||
private monitoredUser: User;
|
||||
private monitoredUser: User | null;
|
||||
|
||||
private constructor() {
|
||||
// seed from localstorage because otherwise we won't get these values until a whole network
|
||||
@@ -62,7 +62,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
/**
|
||||
* Gets the display name for the user, or null if not present.
|
||||
*/
|
||||
public get displayName(): string {
|
||||
public get displayName(): string | null {
|
||||
if (!this.matrixClient) return this.state.displayName || null;
|
||||
|
||||
if (this.matrixClient.isGuest()) {
|
||||
@@ -81,7 +81,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
/**
|
||||
* Gets the MXC URI of the user's avatar, or null if not present.
|
||||
*/
|
||||
public get avatarMxc(): string {
|
||||
public get avatarMxc(): string | null {
|
||||
return this.state.avatarUrl || null;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
* will be returned as an HTTP URL.
|
||||
* @returns The HTTP URL of the user's avatar
|
||||
*/
|
||||
public getHttpAvatarUrl(size = 0): string {
|
||||
public getHttpAvatarUrl(size = 0): string | null {
|
||||
if (!this.avatarMxc) return null;
|
||||
const media = mediaFromMxc(this.avatarMxc);
|
||||
if (!size || size <= 0) {
|
||||
@@ -112,7 +112,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
}
|
||||
|
||||
protected async onReady(): Promise<void> {
|
||||
const myUserId = this.matrixClient.getUserId();
|
||||
const myUserId = this.matrixClient.getUserId()!;
|
||||
this.monitoredUser = this.matrixClient.getUser(myUserId);
|
||||
if (this.monitoredUser) {
|
||||
this.monitoredUser.on(UserEvent.DisplayName, this.onProfileUpdate);
|
||||
@@ -134,7 +134,7 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||
async (): Promise<void> => {
|
||||
// We specifically do not use the User object we stored for profile info as it
|
||||
// could easily be wrong (such as per-room instead of global profile).
|
||||
const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId());
|
||||
const profileInfo = await this.matrixClient.getProfileInfo(this.matrixClient.getUserId()!);
|
||||
if (profileInfo.displayname) {
|
||||
window.localStorage.setItem(KEY_DISPLAY_NAME, profileInfo.displayname);
|
||||
} else {
|
||||
|
||||
@@ -44,10 +44,12 @@ export enum Phase {
|
||||
export class SetupEncryptionStore extends EventEmitter {
|
||||
private started: boolean;
|
||||
public phase: Phase;
|
||||
public verificationRequest: VerificationRequest;
|
||||
public backupInfo: IKeyBackupInfo;
|
||||
public keyId: string;
|
||||
public keyInfo: ISecretStorageKeyInfo;
|
||||
public verificationRequest: VerificationRequest | null = null;
|
||||
public backupInfo: IKeyBackupInfo | null = null;
|
||||
// ID of the key that the secrets we want are encrypted with
|
||||
public keyId: string | null = null;
|
||||
// Descriptor of the key that the secrets we want are encrypted with
|
||||
public keyInfo: ISecretStorageKeyInfo | null = null;
|
||||
public hasDevicesToVerifyAgainst: boolean;
|
||||
|
||||
public static sharedInstance(): SetupEncryptionStore {
|
||||
@@ -61,19 +63,12 @@ export class SetupEncryptionStore extends EventEmitter {
|
||||
}
|
||||
this.started = true;
|
||||
this.phase = Phase.Loading;
|
||||
this.verificationRequest = null;
|
||||
this.backupInfo = null;
|
||||
|
||||
// ID of the key that the secrets we want are encrypted with
|
||||
this.keyId = null;
|
||||
// Descriptor of the key that the secrets we want are encrypted with
|
||||
this.keyInfo = null;
|
||||
|
||||
const cli = MatrixClientPeg.get();
|
||||
cli.on(CryptoEvent.VerificationRequest, this.onVerificationRequest);
|
||||
cli.on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
|
||||
|
||||
const requestsInProgress = cli.getVerificationRequestsToDeviceInProgress(cli.getUserId());
|
||||
const requestsInProgress = cli.getVerificationRequestsToDeviceInProgress(cli.getUserId()!);
|
||||
if (requestsInProgress.length) {
|
||||
// If there are multiple, we take the most recent. Equally if the user sends another request from
|
||||
// another device after this screen has been shown, we'll switch to the new one, so this
|
||||
@@ -111,7 +106,7 @@ export class SetupEncryptionStore extends EventEmitter {
|
||||
|
||||
// do we have any other verified devices which are E2EE which we can verify against?
|
||||
const dehydratedDevice = await cli.getDehydratedDevice();
|
||||
const ownUserId = cli.getUserId();
|
||||
const ownUserId = cli.getUserId()!;
|
||||
const crossSigningInfo = cli.getStoredCrossSigningForUser(ownUserId);
|
||||
this.hasDevicesToVerifyAgainst = cli
|
||||
.getStoredDevicesForUser(ownUserId)
|
||||
@@ -119,7 +114,7 @@ export class SetupEncryptionStore extends EventEmitter {
|
||||
(device) =>
|
||||
device.getIdentityKey() &&
|
||||
(!dehydratedDevice || device.deviceId != dehydratedDevice.device_id) &&
|
||||
crossSigningInfo.checkDeviceTrust(crossSigningInfo, device, false, true).isCrossSigningVerified(),
|
||||
crossSigningInfo?.checkDeviceTrust(crossSigningInfo, device, false, true).isCrossSigningVerified(),
|
||||
);
|
||||
|
||||
this.phase = Phase.Intro;
|
||||
@@ -183,11 +178,11 @@ export class SetupEncryptionStore extends EventEmitter {
|
||||
};
|
||||
|
||||
public onVerificationRequestChange = (): void => {
|
||||
if (this.verificationRequest.cancelled) {
|
||||
if (this.verificationRequest?.cancelled) {
|
||||
this.verificationRequest.off(VerificationRequestEvent.Change, this.onVerificationRequestChange);
|
||||
this.verificationRequest = null;
|
||||
this.emit("update");
|
||||
} else if (this.verificationRequest.phase === VERIF_PHASE_DONE) {
|
||||
} else if (this.verificationRequest?.phase === VERIF_PHASE_DONE) {
|
||||
this.verificationRequest.off(VerificationRequestEvent.Change, this.onVerificationRequestChange);
|
||||
this.verificationRequest = null;
|
||||
// At this point, the verification has finished, we just need to wait for
|
||||
@@ -259,7 +254,7 @@ export class SetupEncryptionStore extends EventEmitter {
|
||||
this.phase = Phase.Finished;
|
||||
this.emit("update");
|
||||
// async - ask other clients for keys, if necessary
|
||||
MatrixClientPeg.get().crypto.cancelAndResendAllOutgoingKeyRequests();
|
||||
MatrixClientPeg.get().crypto?.cancelAndResendAllOutgoingKeyRequests();
|
||||
}
|
||||
|
||||
private async setActiveVerificationRequest(request: VerificationRequest): Promise<void> {
|
||||
|
||||
@@ -104,9 +104,9 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
|
||||
private generateApps(room: Room): IApp[] {
|
||||
return WidgetEchoStore.getEchoedRoomWidgets(room.roomId, WidgetUtils.getRoomWidgets(room)).map((ev) => {
|
||||
return WidgetUtils.makeAppConfig(
|
||||
ev.getStateKey(),
|
||||
ev.getStateKey()!,
|
||||
ev.getContent(),
|
||||
ev.getSender(),
|
||||
ev.getSender()!,
|
||||
ev.getRoomId(),
|
||||
ev.getId(),
|
||||
);
|
||||
@@ -172,7 +172,7 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
|
||||
|
||||
private onRoomStateEvents = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() !== "im.vector.modular.widgets") return; // TODO: Support m.widget too
|
||||
const roomId = ev.getRoomId();
|
||||
const roomId = ev.getRoomId()!;
|
||||
this.initRoom(roomId);
|
||||
this.loadRoomWidgets(this.matrixClient.getRoom(roomId));
|
||||
this.emit(UPDATE_EVENT, roomId);
|
||||
|
||||
@@ -37,7 +37,7 @@ export abstract class EchoContext extends Whenable<ContextTransactionState> impl
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public get firstFailedTime(): Date {
|
||||
public get firstFailedTime(): Date | null {
|
||||
const failedTxn = this.transactions.find((t) => t.didPreviouslyFail || t.status === TransactionStatus.Error);
|
||||
if (failedTxn) return failedTxn.startTime;
|
||||
return null;
|
||||
|
||||
@@ -28,19 +28,19 @@ export const PROPERTY_UPDATED = "property_updated";
|
||||
|
||||
export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends EventEmitter {
|
||||
private cache = new Map<K, { txn: EchoTransaction; val: V }>();
|
||||
protected matrixClient: MatrixClient;
|
||||
protected matrixClient: MatrixClient | null;
|
||||
|
||||
protected constructor(public readonly context: C, private lookupFn: (key: K) => V) {
|
||||
super();
|
||||
}
|
||||
|
||||
public setClient(client: MatrixClient): void {
|
||||
public setClient(client: MatrixClient | null): void {
|
||||
const oldClient = this.matrixClient;
|
||||
this.matrixClient = client;
|
||||
this.onClientChanged(oldClient, client);
|
||||
}
|
||||
|
||||
protected abstract onClientChanged(oldClient: MatrixClient, newClient: MatrixClient): void;
|
||||
protected abstract onClientChanged(oldClient: MatrixClient | null, newClient: MatrixClient | null): void;
|
||||
|
||||
/**
|
||||
* Gets a value. If the key is in flight, the cached value will be returned. If
|
||||
@@ -50,7 +50,7 @@ export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends Ev
|
||||
* @returns The value for the key.
|
||||
*/
|
||||
public getValue(key: K): V {
|
||||
return this.cache.has(key) ? this.cache.get(key).val : this.lookupFn(key);
|
||||
return this.cache.has(key) ? this.cache.get(key)!.val : this.lookupFn(key);
|
||||
}
|
||||
|
||||
private cacheVal(key: K, val: V, txn: EchoTransaction): void {
|
||||
@@ -60,7 +60,7 @@ export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends Ev
|
||||
|
||||
private decacheKey(key: K): void {
|
||||
if (this.cache.has(key)) {
|
||||
this.context.disownTransaction(this.cache.get(key).txn);
|
||||
this.context.disownTransaction(this.cache.get(key)!.txn);
|
||||
this.cache.delete(key);
|
||||
this.emit(PROPERTY_UPDATED, key);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends Ev
|
||||
|
||||
protected markEchoReceived(key: K): void {
|
||||
if (this.cache.has(key)) {
|
||||
const txn = this.cache.get(key).txn;
|
||||
const txn = this.cache.get(key)!.txn;
|
||||
this.context.disownTransaction(txn);
|
||||
txn.cancel();
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends Ev
|
||||
public setValue(auditName: string, key: K, targetVal: V, runFn: RunFn, revertFn: RunFn): void {
|
||||
// Cancel any pending transactions for the same key
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.get(key).txn.cancel();
|
||||
this.cache.get(key)!.txn.cancel();
|
||||
}
|
||||
|
||||
const ctxn = this.context.beginTransaction(auditName, runFn);
|
||||
|
||||
@@ -34,7 +34,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
|
||||
super(context, (k) => this.properties.get(k));
|
||||
}
|
||||
|
||||
protected onClientChanged(oldClient: MatrixClient, newClient: MatrixClient): void {
|
||||
protected onClientChanged(oldClient: MatrixClient | null, newClient: MatrixClient | null): void {
|
||||
this.properties.clear();
|
||||
oldClient?.removeListener(ClientEvent.AccountData, this.onAccountData);
|
||||
if (newClient) {
|
||||
@@ -57,7 +57,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
|
||||
};
|
||||
|
||||
private updateNotificationVolume(): void {
|
||||
const state = getRoomNotifsState(this.matrixClient, this.context.room.roomId);
|
||||
const state = this.matrixClient ? getRoomNotifsState(this.matrixClient, this.context.room.roomId) : null;
|
||||
if (state) this.properties.set(CachedRoomKey.NotificationVolume, state);
|
||||
else this.properties.delete(CachedRoomKey.NotificationVolume);
|
||||
this.markEchoReceived(CachedRoomKey.NotificationVolume);
|
||||
|
||||
@@ -62,7 +62,7 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
|
||||
*/
|
||||
public getListState(tagId: TagID): ListNotificationState {
|
||||
if (this.listMap.has(tagId)) {
|
||||
return this.listMap.get(tagId);
|
||||
return this.listMap.get(tagId)!;
|
||||
}
|
||||
|
||||
// TODO: Update if/when invites move out of the room list.
|
||||
@@ -86,14 +86,14 @@ export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
|
||||
if (!this.roomMap.has(room)) {
|
||||
this.roomMap.set(room, new RoomNotificationState(room));
|
||||
}
|
||||
return this.roomMap.get(room);
|
||||
return this.roomMap.get(room)!;
|
||||
}
|
||||
|
||||
public static get instance(): RoomNotificationStateStore {
|
||||
return RoomNotificationStateStore.internalInstance;
|
||||
}
|
||||
|
||||
private onSync = (state: SyncState, prevState?: SyncState, data?: ISyncStateData): void => {
|
||||
private onSync = (state: SyncState, prevState: SyncState | null, data?: ISyncStateData): void => {
|
||||
// Only count visible rooms to not torment the user with notification counts in rooms they can't see.
|
||||
// This will include highlights from the previous version of the room internally
|
||||
const globalState = new SummarizedNotificationState();
|
||||
|
||||
@@ -58,20 +58,20 @@ export default class RightPanelStore extends ReadyWatchingStore {
|
||||
* Resets the store. Intended for test usage only.
|
||||
*/
|
||||
public reset(): void {
|
||||
this.global = null;
|
||||
this.global = undefined;
|
||||
this.byRoom = {};
|
||||
this.viewedRoomId = null;
|
||||
}
|
||||
|
||||
protected async onReady(): Promise<any> {
|
||||
this.viewedRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
this.matrixClient.on(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
|
||||
this.matrixClient?.on(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
|
||||
this.loadCacheFromSettings();
|
||||
this.emitAndUpdateSettings();
|
||||
}
|
||||
|
||||
protected async onNotReady(): Promise<any> {
|
||||
this.matrixClient.off(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
|
||||
this.matrixClient?.off(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
|
||||
}
|
||||
|
||||
protected onDispatcherAction(payload: ActionPayload): void {
|
||||
@@ -376,7 +376,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
|
||||
// the room member list.
|
||||
if (SettingsStore.getValue("feature_right_panel_default_open") && !this.byRoom[this.viewedRoomId]?.isOpen) {
|
||||
const history = [{ phase: RightPanelPhases.RoomMemberList }];
|
||||
const room = this.viewedRoomId && this.mxClient?.getRoom(this.viewedRoomId);
|
||||
const room = this.viewedRoomId ? this.mxClient?.getRoom(this.viewedRoomId) : undefined;
|
||||
if (!room?.isSpaceRoom()) {
|
||||
history.unshift({ phase: RightPanelPhases.RoomSummary });
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
||||
* @param inTagId The tag ID in which the room resides
|
||||
* @returns The preview, or null if none present.
|
||||
*/
|
||||
public async getPreviewForRoom(room: Room, inTagId: TagID): Promise<string> {
|
||||
public async getPreviewForRoom(room: Room, inTagId: TagID): Promise<string | null> {
|
||||
if (!room) return null; // invalid room, just return nothing
|
||||
|
||||
if (!this.previews.has(room.roomId)) await this.generatePreview(room, inTagId);
|
||||
@@ -132,14 +132,14 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
||||
if (!previews) return null;
|
||||
|
||||
if (!previews.has(inTagId)) {
|
||||
return previews.get(TAG_ANY);
|
||||
return previews.get(TAG_ANY)!;
|
||||
}
|
||||
return previews.get(inTagId);
|
||||
return previews.get(inTagId) ?? null;
|
||||
}
|
||||
|
||||
public generatePreviewForEvent(event: MatrixEvent): string {
|
||||
const previewDef = PREVIEWS[event.getType()];
|
||||
return previewDef?.previewer.getTextFor(event, null, true) ?? "";
|
||||
return previewDef?.previewer.getTextFor(event, undefined, true) ?? "";
|
||||
}
|
||||
|
||||
private async generatePreview(room: Room, tagId?: TagID): Promise<void> {
|
||||
@@ -171,7 +171,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
||||
if (!previewDef) continue;
|
||||
if (previewDef.isState && isNullOrUndefined(event.getStateKey())) continue;
|
||||
|
||||
const anyPreview = previewDef.previewer.getTextFor(event, null);
|
||||
const anyPreview = previewDef.previewer.getTextFor(event);
|
||||
if (!anyPreview) continue; // not previewable for some reason
|
||||
|
||||
changed = changed || anyPreview !== map.get(TAG_ANY);
|
||||
@@ -179,7 +179,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
||||
|
||||
const tagsToGenerate = Array.from(map.keys()).filter((t) => t !== TAG_ANY); // we did the any tag above
|
||||
for (const genTagId of tagsToGenerate) {
|
||||
const realTagId: TagID = genTagId === TAG_ANY ? null : genTagId;
|
||||
const realTagId = genTagId === TAG_ANY ? undefined : genTagId;
|
||||
const preview = previewDef.previewer.getTextFor(event, realTagId);
|
||||
if (preview === anyPreview) {
|
||||
changed = changed || anyPreview !== map.get(genTagId);
|
||||
|
||||
@@ -116,7 +116,7 @@ export class Algorithm extends EventEmitter {
|
||||
* Awaitable version of the sticky room setter.
|
||||
* @param val The new room to sticky.
|
||||
*/
|
||||
public setStickyRoom(val: Room): void {
|
||||
public setStickyRoom(val: Room | null): void {
|
||||
try {
|
||||
this.updateStickyRoom(val);
|
||||
} catch (e) {
|
||||
|
||||
@@ -29,7 +29,7 @@ export class PollStartEventPreview implements IPreview {
|
||||
public static contextType = MatrixClientContext;
|
||||
public context!: React.ContextType<typeof MatrixClientContext>;
|
||||
|
||||
public getTextFor(event: MatrixEvent, tagId?: TagID, isThread?: boolean): string {
|
||||
public getTextFor(event: MatrixEvent, tagId?: TagID, isThread?: boolean): string | null {
|
||||
let eventContent = event.getContent();
|
||||
|
||||
if (event.isRelation("m.replace")) {
|
||||
@@ -51,7 +51,7 @@ export class PollStartEventPreview implements IPreview {
|
||||
let question = poll.question.text.trim();
|
||||
question = sanitizeForTranslation(question);
|
||||
|
||||
if (isThread || isSelf(event) || !shouldPrefixMessagesIn(event.getRoomId(), tagId)) {
|
||||
if (isThread || isSelf(event) || !shouldPrefixMessagesIn(event.getRoomId()!, tagId)) {
|
||||
return question;
|
||||
} else {
|
||||
return _t("%(senderName)s: %(message)s", { senderName: getSenderName(event), message: question });
|
||||
|
||||
@@ -22,11 +22,11 @@ import { getSenderName, isSelf, shouldPrefixMessagesIn } from "./utils";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
export class StickerEventPreview implements IPreview {
|
||||
public getTextFor(event: MatrixEvent, tagId?: TagID, isThread?: boolean): string {
|
||||
public getTextFor(event: MatrixEvent, tagId?: TagID, isThread?: boolean): string | null {
|
||||
const stickerName = event.getContent()["body"];
|
||||
if (!stickerName) return null;
|
||||
|
||||
if (isThread || isSelf(event) || !shouldPrefixMessagesIn(event.getRoomId(), tagId)) {
|
||||
if (isThread || isSelf(event) || !shouldPrefixMessagesIn(event.getRoomId()!, tagId)) {
|
||||
return stickerName;
|
||||
} else {
|
||||
return _t("%(senderName)s: %(stickerName)s", { senderName: getSenderName(event), stickerName });
|
||||
|
||||
@@ -78,7 +78,7 @@ const getSpaceContextKey = (space: SpaceKey): string => `mx_space_context_${spac
|
||||
|
||||
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => {
|
||||
// [spaces, rooms]
|
||||
return arr.reduce(
|
||||
return arr.reduce<[Room[], Room[]]>(
|
||||
(result, room: Room) => {
|
||||
result[room.isSpaceRoom() ? 0 : 1].push(room);
|
||||
return result;
|
||||
@@ -165,7 +165,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
return this.rootSpaces;
|
||||
}
|
||||
|
||||
public get activeSpace(): SpaceKey {
|
||||
public get activeSpace(): SpaceKey | undefined {
|
||||
return this._activeSpace;
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
public setActiveSpace(space: SpaceKey, contextSwitch = true): void {
|
||||
if (!space || !this.matrixClient || space === this.activeSpace) return;
|
||||
|
||||
let cliSpace: Room;
|
||||
let cliSpace: Room | null = null;
|
||||
if (!isMetaSpace(space)) {
|
||||
cliSpace = this.matrixClient.getRoom(space);
|
||||
if (!cliSpace?.isSpaceRoom()) return;
|
||||
@@ -246,6 +246,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
// else if the last viewed room in this space is joined then view that
|
||||
// else view space home or home depending on what is being clicked on
|
||||
if (
|
||||
roomId &&
|
||||
cliSpace?.getMyMembership() !== "invite" &&
|
||||
this.matrixClient.getRoom(roomId)?.getMyMembership() === "join" &&
|
||||
this.isRoomInSpace(space, roomId)
|
||||
@@ -348,10 +349,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
.filter((ev) => ev.getContent()?.via);
|
||||
return (
|
||||
sortBy(childEvents, (ev) => {
|
||||
return getChildOrder(ev.getContent().order, ev.getTs(), ev.getStateKey());
|
||||
return getChildOrder(ev.getContent().order, ev.getTs(), ev.getStateKey()!);
|
||||
})
|
||||
.map((ev) => {
|
||||
const history = this.matrixClient.getRoomUpgradeHistory(ev.getStateKey(), true);
|
||||
const history = this.matrixClient.getRoomUpgradeHistory(ev.getStateKey()!, true);
|
||||
return history[history.length - 1];
|
||||
})
|
||||
.filter((room) => {
|
||||
@@ -373,7 +374,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
const userId = this.matrixClient?.getUserId();
|
||||
const room = this.matrixClient?.getRoom(roomId);
|
||||
return (
|
||||
room?.currentState
|
||||
(room?.currentState
|
||||
.getStateEvents(EventType.SpaceParent)
|
||||
.map((ev) => {
|
||||
const content = ev.getContent();
|
||||
@@ -396,7 +397,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
|
||||
return parent;
|
||||
})
|
||||
.filter(Boolean) || []
|
||||
.filter(Boolean) as Room[]) || []
|
||||
);
|
||||
}
|
||||
|
||||
@@ -467,7 +468,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
space: SpaceKey,
|
||||
includeDescendantSpaces = true,
|
||||
useCache = true,
|
||||
): Set<string> => {
|
||||
): Set<string> | undefined => {
|
||||
if (space === MetaSpace.Home && this.allRoomsInHome) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -490,7 +491,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
private markTreeChildren = (rootSpace: Room, unseen: Set<Room>): void => {
|
||||
const stack = [rootSpace];
|
||||
while (stack.length) {
|
||||
const space = stack.pop();
|
||||
const space = stack.pop()!;
|
||||
unseen.delete(space);
|
||||
this.getChildSpaces(space.roomId).forEach((space) => {
|
||||
if (unseen.has(space)) {
|
||||
@@ -646,7 +647,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
const enabledMetaSpaces = new Set(this.enabledMetaSpaces);
|
||||
const visibleRooms = this.matrixClient.getVisibleRooms();
|
||||
|
||||
let dmBadgeSpace: MetaSpace;
|
||||
let dmBadgeSpace: MetaSpace | undefined;
|
||||
// only show badges on dms on the most relevant space if such exists
|
||||
if (enabledMetaSpaces.has(MetaSpace.People)) {
|
||||
dmBadgeSpace = MetaSpace.People;
|
||||
@@ -702,8 +703,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
); // put all invites in the Home Space
|
||||
};
|
||||
|
||||
private static isInSpace(member: RoomMember): boolean {
|
||||
return member.membership === "join" || member.membership === "invite";
|
||||
private static isInSpace(member?: RoomMember | null): boolean {
|
||||
return member?.membership === "join" || member?.membership === "invite";
|
||||
}
|
||||
|
||||
// Method for resolving the impact of a single user's membership change in the given Space and its hierarchy
|
||||
@@ -755,11 +756,14 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
this.rootSpaces.forEach((s) => {
|
||||
// traverse each space tree in DFS to build up the supersets as you go up,
|
||||
// reusing results from like subtrees.
|
||||
const traverseSpace = (spaceId: string, parentPath: Set<string>): [Set<string>, Set<string>] => {
|
||||
const traverseSpace = (
|
||||
spaceId: string,
|
||||
parentPath: Set<string>,
|
||||
): [Set<string>, Set<string>] | undefined => {
|
||||
if (parentPath.has(spaceId)) return; // prevent cycles
|
||||
// reuse existing results if multiple similar branches exist
|
||||
if (this.roomIdsBySpace.has(spaceId) && this.userIdsBySpace.has(spaceId)) {
|
||||
return [this.roomIdsBySpace.get(spaceId), this.userIdsBySpace.get(spaceId)];
|
||||
return [this.roomIdsBySpace.get(spaceId)!, this.userIdsBySpace.get(spaceId)!];
|
||||
}
|
||||
|
||||
const [childSpaces, childRooms] = partitionSpacesAndRooms(this.getChildren(spaceId));
|
||||
@@ -865,7 +869,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
||||
if (this.suggestedRooms.find((r) => r.room_id === roomId)) return;
|
||||
|
||||
// try to find the canonical parent first
|
||||
let parent: SpaceKey = this.getCanonicalParent(roomId)?.roomId;
|
||||
let parent: SpaceKey | undefined = this.getCanonicalParent(roomId)?.roomId;
|
||||
|
||||
// otherwise, try to find a root space which contains this room
|
||||
if (!parent) {
|
||||
|
||||
@@ -54,7 +54,7 @@ export interface ISuggestedRoom extends IHierarchyRoom {
|
||||
viaServers: string[];
|
||||
}
|
||||
|
||||
export function isMetaSpace(spaceKey: SpaceKey): boolean {
|
||||
export function isMetaSpace(spaceKey?: SpaceKey): boolean {
|
||||
return (
|
||||
spaceKey === MetaSpace.Home ||
|
||||
spaceKey === MetaSpace.Favourites ||
|
||||
|
||||
@@ -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