Enable more oxlint rules (#34189)
* Fix type imports * Fix jsdoc * Fixup types * Fix stray awaits on non-thenables * Fixup imports * Fix splats * Fix this-context on callbacks * Memoise react contexts * Prefer find/flatMap * Make oxlint happier about our React keys * Avoid unsafe default function params * Fixup jsdoc * Fixup contexts * Switch from eslint to oxlint * Some oxlint-related tweaks * Iterate * Partial revert to defer some changes and shrink diff * Iterate * Add eslint-plugin-element-call and enable the copyright rule * Set strictStorePkgContentCheck * Iterate * Enable forwardRef oxlint rule * Enable no-unused-vars oxlint rule * Enable no-implied-eval oxlint rule * Enable no-duplicate-type-constituents oxlint rule * Enable explicit-length-check oxlint rule * Enable prefer-number-properties oxlint rule * Enable no-callback-in-promise oxlint rule * Enable no-require-imports oxlint rule * Remove disablement of most unicorn oxlint rules * Enable no-conditional-tests oxlint rule * Enable promise-valid-params oxlint rule * Enable require-unicode-regexp oxlint rule * Remove max-len comments as we use oxfmt for formatting * Enable majority of oxlint `suspicious` rules * Iterate * Fix oxlint type-aware lint running without dependencies built
This commit is contained in:
@@ -75,7 +75,7 @@ if (process.env.VARIANT_PATH) {
|
||||
console.log(`Using variant configuration from '${process.env.VARIANT_PATH}':`);
|
||||
variant = {
|
||||
...variant,
|
||||
...JSON.parse(fs.readFileSync(`${process.env.VARIANT_PATH}`, "utf8")),
|
||||
...JSON.parse(fs.readFileSync(process.env.VARIANT_PATH, "utf8")),
|
||||
};
|
||||
} else {
|
||||
console.warn(`No VARIANT_PATH specified, using default variant configuration '${DEFAULT_VARIANT}':`);
|
||||
|
||||
@@ -48,8 +48,9 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
|
||||
"` " +
|
||||
"or your package manager if not using `rustup`",
|
||||
);
|
||||
return;
|
||||
}
|
||||
fsProm.unlink("tmp").then(resolve);
|
||||
resolve(fsProm.unlink("tmp"));
|
||||
},
|
||||
);
|
||||
rustc.stdin!.write("fn main() {}");
|
||||
|
||||
@@ -27,7 +27,7 @@ export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
if (moduleInfo.moduleBuildDirs.length > 1) {
|
||||
if (!hakEnv.isMac()) {
|
||||
console.error(
|
||||
"You asked me to copy multiple targets but I've only been taught " + "how to do that on macOS.",
|
||||
"You asked me to copy multiple targets but I've only been taught how to do that on macOS.",
|
||||
);
|
||||
throw new Error("Can't copy multiple targets on this platform");
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ async function main(): Promise<void> {
|
||||
for (const mod of modules) {
|
||||
const depInfo = deps[mod];
|
||||
if (depInfo === undefined) {
|
||||
console.log("Module " + mod + " not found - is it in hakDependencies " + "in your package.json?");
|
||||
console.log(`Module ${mod} not found - is it in hakDependencies in your package.json?`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log("hak " + cmd + ": " + mod);
|
||||
|
||||
@@ -42,12 +42,10 @@ describe("buildMenuTemplate", () => {
|
||||
({ buildMenuTemplate } = await import("./vectormenu.js"));
|
||||
});
|
||||
|
||||
if (platform === "darwin") {
|
||||
it("should have an app-named item first", () => {
|
||||
const menu = buildMenuTemplate();
|
||||
expect(menu.items[0].label).toBe("ChatApp");
|
||||
});
|
||||
}
|
||||
it.runIf(platform === "darwin")("should have an app-named item first", () => {
|
||||
const menu = buildMenuTemplate();
|
||||
expect(menu.items[0].label).toBe("ChatApp");
|
||||
});
|
||||
|
||||
it("should include expected `help` menu", () => {
|
||||
const menu = buildMenuTemplate();
|
||||
@@ -55,8 +53,8 @@ describe("buildMenuTemplate", () => {
|
||||
const helpMenu = menu.items.at(-1)!;
|
||||
expect(helpMenu.label).toBe("common|help");
|
||||
const helpSubmenu = helpMenu.submenu as unknown as MenuItemConstructorOptions[];
|
||||
expect(helpSubmenu[0]!.label).toBe("common|brand_help");
|
||||
helpSubmenu[0]!.click!(menu.items.at(-1)!, undefined, new Event("click") as KeyboardEvent);
|
||||
expect(helpSubmenu[0].label).toBe("common|brand_help");
|
||||
helpSubmenu[0].click!(menu.items.at(-1)!, undefined, new Event("click") as KeyboardEvent);
|
||||
expect(shell.openExternal).toHaveBeenCalledWith("https://i.need.help");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ declare module "webpack-version-file-plugin" {
|
||||
extras?: Record<string, string>;
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export default class VersionFilePlugin {
|
||||
public constructor(opts: Opts);
|
||||
}
|
||||
|
||||
@@ -609,7 +609,7 @@ class Helpers {
|
||||
const roomListContainer = this.page.getByTestId("room-list");
|
||||
const roomTiles = roomListContainer.getByRole("option");
|
||||
for (const [i, room] of rooms.entries()) {
|
||||
await expect(roomTiles.nth(i)).toHaveAccessibleName(new RegExp(`${room.name}`));
|
||||
await expect(roomTiles.nth(i)).toHaveAccessibleName(new RegExp(room.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,11 +120,11 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await sendUnthreadedReadReceipt(app, main2);
|
||||
|
||||
// (So the room has no unreads)
|
||||
await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(otherRoomName)).toBeVisible();
|
||||
|
||||
// And we persuade the app to persist its state to indexeddb by reloading and waiting
|
||||
await page.reload();
|
||||
await expect(page.getByLabel(`${selectedRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(selectedRoomName)).toBeVisible();
|
||||
|
||||
// And we reload again, fetching the persisted state FROM indexeddb
|
||||
await page.reload();
|
||||
@@ -132,7 +132,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
// Then the room is read, because the persisted state correctly remembers both
|
||||
// receipts. (In #24629, the unthreaded receipt overwrote the main thread one,
|
||||
// meaning that the room still said it had unread messages.)
|
||||
await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(otherRoomName)).toBeVisible();
|
||||
await expect(page.getByLabel(`${otherRoomName} Unread messages.`)).not.toBeVisible();
|
||||
});
|
||||
|
||||
@@ -172,7 +172,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await sendThreadedReadReceipt(app, main3);
|
||||
|
||||
// Then the room has no unreads
|
||||
await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(otherRoomName)).toBeVisible();
|
||||
});
|
||||
|
||||
test("Recognises unread messages on other thread after receiving a receipt for earlier ones", async ({
|
||||
@@ -210,7 +210,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await sendThreadedReadReceipt(app, thread1b, main1);
|
||||
|
||||
// Then the room has no unreads
|
||||
await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(otherRoomName)).toBeVisible();
|
||||
await util.goTo({ name: otherRoomName, roomId: otherRoomId });
|
||||
await util.assertReadThread("Message 1");
|
||||
});
|
||||
@@ -235,7 +235,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
// thread. The one in main is read because the unthreaded
|
||||
// receipt is for a later event. The room should therefore be
|
||||
// read, and the thread unread.
|
||||
await expect(page.getByLabel(`${otherRoomName}`)).toBeVisible();
|
||||
await expect(page.getByLabel(otherRoomName)).toBeVisible();
|
||||
await util.goTo({ name: otherRoomName, roomId: otherRoomId });
|
||||
await util.assertUnreadThread("Message 1");
|
||||
});
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
},
|
||||
"dependsOn": ["^build", "^build:playwright"]
|
||||
},
|
||||
"lint:prepare": {
|
||||
"executor": "nx:noop",
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"test:unit:prepare": {
|
||||
"executor": "nx:noop",
|
||||
"dependsOn": ["^build"]
|
||||
|
||||
@@ -459,7 +459,7 @@ export function bodyToNode(content: IContent, highlights?: string[], opts: Event
|
||||
// This has to be done after the emojiBody check as to not break big emoji on replies
|
||||
formattedBody = formatEmojis(eventInfo.safeBody, true).join("");
|
||||
} else {
|
||||
emojiBodyElements = formatEmojis(eventInfo.strippedBody, false) as JSX.Element[];
|
||||
emojiBodyElements = formatEmojis(eventInfo.strippedBody, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ export default class Notifier extends TypedEventEmitter<keyof EmittedEvents, Emi
|
||||
avatarUrl = Avatar.avatarUrlForMember(ev.sender, 40, 40, "crop");
|
||||
}
|
||||
|
||||
const notif = plaf.displayNotification(title, msg!, avatarUrl, room, ev);
|
||||
const notif = plaf.displayNotification(title, msg, avatarUrl, room, ev);
|
||||
|
||||
// if displayNotification returns non-null, the platform supports
|
||||
// clearing notifications later, so keep track of this.
|
||||
|
||||
@@ -11,6 +11,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import dis from "./dispatcher/dispatcher";
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export default class Resend {
|
||||
public static resendUnsentEvents(room: Room): Promise<void[]> {
|
||||
return Promise.all(
|
||||
|
||||
@@ -117,7 +117,7 @@ export function showAnyInviteErrors(
|
||||
(avatarUrl && mediaFromMxc(avatarUrl).getSquareThumbnailHttp(24)) ??
|
||||
undefined
|
||||
}
|
||||
name={name!}
|
||||
name={name}
|
||||
idName={user?.userId}
|
||||
size="36px"
|
||||
/>
|
||||
|
||||
@@ -237,7 +237,7 @@ function isRuleRoomMuteRuleForRoomId(roomId: string, rule: IPushRule): boolean {
|
||||
return false;
|
||||
}
|
||||
// isRuleMaybeRoomMuteRule checks this condition exists
|
||||
const cond = rule.conditions![0]!;
|
||||
const cond = rule.conditions![0];
|
||||
return cond.pattern === roomId;
|
||||
}
|
||||
|
||||
|
||||
@@ -316,14 +316,14 @@ enum Action {
|
||||
ReadEvents = "read_events",
|
||||
}
|
||||
|
||||
function sendResponse(event: MessageEvent<any>, res: any): void {
|
||||
function sendResponse(event: MessageEvent, res: any): void {
|
||||
const data = objectClone(event.data);
|
||||
data.response = res;
|
||||
// @ts-ignore
|
||||
event.source.postMessage(data, event.origin);
|
||||
}
|
||||
|
||||
function sendError(event: MessageEvent<any>, msg: string, nestedError?: Error): void {
|
||||
function sendError(event: MessageEvent, msg: string, nestedError?: Error): void {
|
||||
logger.error("Action:" + event.data.action + " failed with message: " + msg);
|
||||
const data = objectClone(event.data);
|
||||
data.response = {
|
||||
@@ -338,7 +338,7 @@ function sendError(event: MessageEvent<any>, msg: string, nestedError?: Error):
|
||||
event.source.postMessage(data, event.origin);
|
||||
}
|
||||
|
||||
function inviteUser(event: MessageEvent<any>, roomId: string, userId: string): void {
|
||||
function inviteUser(event: MessageEvent, roomId: string, userId: string): void {
|
||||
logger.log(`Received request to invite ${userId} into room ${roomId}`);
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
@@ -372,7 +372,7 @@ function inviteUser(event: MessageEvent<any>, roomId: string, userId: string): v
|
||||
);
|
||||
}
|
||||
|
||||
function kickUser(event: MessageEvent<any>, roomId: string, userId: string): void {
|
||||
function kickUser(event: MessageEvent, roomId: string, userId: string): void {
|
||||
logger.log(`Received request to kick ${userId} from room ${roomId}`);
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
@@ -404,7 +404,7 @@ function kickUser(event: MessageEvent<any>, roomId: string, userId: string): voi
|
||||
});
|
||||
}
|
||||
|
||||
function setWidget(event: MessageEvent<any>, roomId: string | null): void {
|
||||
function setWidget(event: MessageEvent, roomId: string | null): void {
|
||||
const client = MatrixClientPeg.safeGet();
|
||||
const widgetId = event.data.widget_id;
|
||||
let widgetType = event.data.type;
|
||||
@@ -488,7 +488,7 @@ function setWidget(event: MessageEvent<any>, roomId: string | null): void {
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgets(event: MessageEvent<any>, roomId: string | null): void {
|
||||
function getWidgets(event: MessageEvent, roomId: string | null): void {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("widget|error_need_to_be_logged_in"));
|
||||
@@ -514,7 +514,7 @@ function getWidgets(event: MessageEvent<any>, roomId: string | null): void {
|
||||
sendResponse(event, widgetStateEvents);
|
||||
}
|
||||
|
||||
async function getRoomEncState(event: MessageEvent<any>, roomId: string): Promise<void> {
|
||||
async function getRoomEncState(event: MessageEvent, roomId: string): Promise<void> {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("widget|error_need_to_be_logged_in"));
|
||||
@@ -530,7 +530,7 @@ async function getRoomEncState(event: MessageEvent<any>, roomId: string): Promis
|
||||
sendResponse(event, roomIsEncrypted);
|
||||
}
|
||||
|
||||
function setPlumbingState(event: MessageEvent<any>, roomId: string, status: string): void {
|
||||
function setPlumbingState(event: MessageEvent, roomId: string, status: string): void {
|
||||
if (typeof status !== "string") {
|
||||
throw new Error("Plumbing state status should be a string");
|
||||
}
|
||||
@@ -552,7 +552,7 @@ function setPlumbingState(event: MessageEvent<any>, roomId: string, status: stri
|
||||
);
|
||||
}
|
||||
|
||||
function setBotOptions(event: MessageEvent<any>, roomId: string, userId: string): void {
|
||||
function setBotOptions(event: MessageEvent, roomId: string, userId: string): void {
|
||||
logger.log(`Received request to set options for bot ${userId} in room ${roomId}`);
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
@@ -572,7 +572,7 @@ function setBotOptions(event: MessageEvent<any>, roomId: string, userId: string)
|
||||
}
|
||||
|
||||
async function setBotPower(
|
||||
event: MessageEvent<any>,
|
||||
event: MessageEvent,
|
||||
roomId: string,
|
||||
userId: string,
|
||||
level: number,
|
||||
@@ -613,22 +613,22 @@ async function setBotPower(
|
||||
}
|
||||
}
|
||||
|
||||
function getMembershipState(event: MessageEvent<any>, roomId: string, userId: string): void {
|
||||
function getMembershipState(event: MessageEvent, roomId: string, userId: string): void {
|
||||
logger.log(`membership_state of ${userId} in room ${roomId} requested.`);
|
||||
returnStateEvent(event, roomId, "m.room.member", userId);
|
||||
}
|
||||
|
||||
function getJoinRules(event: MessageEvent<any>, roomId: string): void {
|
||||
function getJoinRules(event: MessageEvent, roomId: string): void {
|
||||
logger.log(`join_rules of ${roomId} requested.`);
|
||||
returnStateEvent(event, roomId, "m.room.join_rules", "");
|
||||
}
|
||||
|
||||
function botOptions(event: MessageEvent<any>, roomId: string, userId: string): void {
|
||||
function botOptions(event: MessageEvent, roomId: string, userId: string): void {
|
||||
logger.log(`bot_options of ${userId} in room ${roomId} requested.`);
|
||||
returnStateEvent(event, roomId, "m.room.bot.options", "_" + userId);
|
||||
}
|
||||
|
||||
function getMembershipCount(event: MessageEvent<any>, roomId: string): void {
|
||||
function getMembershipCount(event: MessageEvent, roomId: string): void {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("widget|error_need_to_be_logged_in"));
|
||||
@@ -643,7 +643,7 @@ function getMembershipCount(event: MessageEvent<any>, roomId: string): void {
|
||||
sendResponse(event, count);
|
||||
}
|
||||
|
||||
function canSendEvent(event: MessageEvent<any>, roomId: string): void {
|
||||
function canSendEvent(event: MessageEvent, roomId: string): void {
|
||||
const evType = "" + event.data.event_type; // force stringify
|
||||
const isState = Boolean(event.data.is_state);
|
||||
const client = MatrixClientPeg.get();
|
||||
@@ -677,7 +677,7 @@ function canSendEvent(event: MessageEvent<any>, roomId: string): void {
|
||||
sendResponse(event, true);
|
||||
}
|
||||
|
||||
function returnStateEvent(event: MessageEvent<any>, roomId: string, eventType: string, stateKey: string): void {
|
||||
function returnStateEvent(event: MessageEvent, roomId: string, eventType: string, stateKey: string): void {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!client) {
|
||||
sendError(event, _t("widget|error_need_to_be_logged_in"));
|
||||
@@ -696,7 +696,7 @@ function returnStateEvent(event: MessageEvent<any>, roomId: string, eventType: s
|
||||
sendResponse(event, stateEvent.getContent());
|
||||
}
|
||||
|
||||
async function getOpenIdToken(event: MessageEvent<any>): Promise<void> {
|
||||
async function getOpenIdToken(event: MessageEvent): Promise<void> {
|
||||
try {
|
||||
const tokenObject = await MatrixClientPeg.safeGet().getOpenIdToken();
|
||||
sendResponse(event, tokenObject);
|
||||
@@ -841,7 +841,7 @@ async function readEvents(
|
||||
}
|
||||
}
|
||||
|
||||
const onMessage = function (event: MessageEvent<any>): void {
|
||||
const onMessage = function (event: MessageEvent): void {
|
||||
if (!event.origin) {
|
||||
// @ts-ignore - stupid chrome
|
||||
event.origin = event.originalEvent.origin;
|
||||
@@ -987,7 +987,7 @@ export function stopListening(): void {
|
||||
}
|
||||
if (listenerCount < 0) {
|
||||
// Make an error so we get a stack trace
|
||||
const e = new Error("ScalarMessaging: mismatched startListening / stopListening detected." + " Negative count");
|
||||
const e = new Error("ScalarMessaging: mismatched startListening / stopListening detected. Negative count");
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ type ObjectType<K extends keyof IConfigOptions> = IConfigOptions[K] extends obje
|
||||
? SnakedObject<NonNullable<IConfigOptions[K]>>
|
||||
: SnakedObject<NonNullable<IConfigOptions[K]>> | null | undefined;
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export default class SdkConfig {
|
||||
private static instance: DeepReadonly<IConfigOptions>;
|
||||
private static fallback: SnakedObject<DeepReadonly<IConfigOptions>>;
|
||||
|
||||
@@ -49,7 +49,7 @@ function getRoomMemberDisplayname(client: MatrixClient, event: MatrixEvent, user
|
||||
}
|
||||
|
||||
function textForCallEvent(event: MatrixEvent, client: MatrixClient): () => string {
|
||||
const roomName = client.getRoom(event.getRoomId()!)?.name;
|
||||
const roomName = client.getRoom(event.getRoomId())?.name;
|
||||
const isSupported = client.supportsVoip();
|
||||
|
||||
return isSupported
|
||||
|
||||
@@ -96,7 +96,7 @@ export const getKeyboardShortcuts = (): IKeyboardShortcuts => {
|
||||
return true;
|
||||
})
|
||||
.reduce((o, key) => {
|
||||
o[key as KeyBindingAction] = KEYBOARD_SHORTCUTS[key as KeyBindingAction];
|
||||
o[key] = KEYBOARD_SHORTCUTS[key];
|
||||
return o;
|
||||
}, {} as IKeyboardShortcuts);
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ const ORDERED_LANDMARKS = [
|
||||
* The landmarks are cycled through in the following order:
|
||||
* ACTIVE_SPACE_BUTTON <-> ROOM_SEARCH <-> ROOM_LIST <-> MESSAGE_COMPOSER/HOME <-> ACTIVE_SPACE_BUTTON
|
||||
*/
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class LandmarkNavigation {
|
||||
/**
|
||||
* Get the next/previous landmark that must be focused from a given landmark
|
||||
|
||||
@@ -18,6 +18,7 @@ import { type AsyncActionPayload } from "../dispatcher/payloads";
|
||||
import { DefaultTagID, type TagID } from "../stores/room-list-v3/skip-list/tag";
|
||||
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export default class RoomListActions {
|
||||
/**
|
||||
* Creates an action thunk that will do an asynchronous request to
|
||||
|
||||
@@ -62,16 +62,16 @@ class MxVoiceWorklet extends AudioWorkletProcessor {
|
||||
const maxVal = Math.max(...monoChan);
|
||||
const amplitude = percentageOf(maxVal, -1, 1) - percentageOf(minVal, -1, 1);
|
||||
|
||||
this.port.postMessage(<IAmplitudePayload>{
|
||||
this.port.postMessage({
|
||||
ev: PayloadEvent.AmplitudeMark,
|
||||
amplitude: amplitude,
|
||||
forIndex: this.amplitudeIndex++,
|
||||
});
|
||||
} satisfies IAmplitudePayload);
|
||||
this.nextAmplitudeSecond = nextTimeForTargetFreq(currentSecond);
|
||||
}
|
||||
|
||||
// We mostly use this worklet to fire regular clock updates through to components
|
||||
this.port.postMessage(<ITimingPayload>{ ev: PayloadEvent.Timekeep, timeSeconds: currentTime });
|
||||
this.port.postMessage({ ev: PayloadEvent.Timekeep, timeSeconds: currentTime } satisfies ITimingPayload);
|
||||
|
||||
// We're supposed to return false when we're "done" with the audio clip, but seeing as
|
||||
// we are acting as a passive processor we are never truly "done". The browser will clean
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class NotifProvider extends AutocompleteProvider {
|
||||
if (
|
||||
command?.[0] &&
|
||||
command[0].length > 1 &&
|
||||
["@room", "@channel", "@everyone", "@here"].some((c) => c.startsWith(command![0]))
|
||||
["@room", "@channel", "@everyone", "@here"].some((c) => c.startsWith(command[0]))
|
||||
) {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -228,7 +228,7 @@ export default class ContextMenu extends React.PureComponent<React.PropsWithChil
|
||||
}
|
||||
|
||||
// When an <input> is focused, only handle the Escape key
|
||||
if (checkInputableElement(ev.target as HTMLElement) && action !== KeyBindingAction.Escape) {
|
||||
if (checkInputableElement(ev.target) && action !== KeyBindingAction.Escape) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ export function GenericDropdownMenu<T>({
|
||||
className,
|
||||
AdditionalOptions,
|
||||
}: IProps<T>): JSX.Element {
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>();
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
|
||||
const valueKey = calculateKey(value, toKey);
|
||||
const selected: GenericDropdownMenuItem<T> | undefined = options
|
||||
|
||||
@@ -1264,7 +1264,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
if (isOnlyAdmin(roomToLeave)) {
|
||||
const userLevelValues = roomToLeave.getJoinedMembers().map((m) => m.powerLevel);
|
||||
|
||||
const maxUserLevel = Math.max(...(userLevelValues as number[]));
|
||||
const maxUserLevel = Math.max(...userLevelValues);
|
||||
|
||||
const warning =
|
||||
maxUserLevel >= 100
|
||||
|
||||
@@ -31,7 +31,7 @@ export type CreatePipChildren = (options: IChildrenOptions) => JSX.Element;
|
||||
|
||||
interface IChildrenOptions {
|
||||
// a callback which is called when a mouse event (most likely mouse down) occurs at start of moving the pip around
|
||||
onStartMoving: (event: React.MouseEvent<Element, MouseEvent>) => void;
|
||||
onStartMoving: (event: React.MouseEvent) => void;
|
||||
// a callback which is called when the content fo the pip changes in a way that is likely to cause a resize
|
||||
onResize: (event: Event) => void;
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ export default class RightPanel extends React.Component<Props, IState> {
|
||||
<RoomSummaryCardView
|
||||
room={this.props.room}
|
||||
// whenever RightPanel is passed a room it is passed a permalinkcreator
|
||||
permalinkCreator={this.props.permalinkCreator!}
|
||||
permalinkCreator={this.props.permalinkCreator}
|
||||
onSearchChange={this.props.onSearchChange}
|
||||
onSearchCancel={this.props.onSearchCancel}
|
||||
searchTerm={this.props.searchTerm}
|
||||
|
||||
@@ -1523,8 +1523,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
this.setState({ membersLoaded: true });
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage =
|
||||
`Fetching room members for ${room.roomId} failed.` + " Room members will appear incomplete.";
|
||||
const errorMessage = `Fetching room members for ${room.roomId} failed. Room members will appear incomplete.`;
|
||||
logger.error(errorMessage);
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
this.unfillDebouncer = window.setTimeout(() => {
|
||||
this.unfillDebouncer = null;
|
||||
debuglog("unfilling now", { backwards, origExcessHeight });
|
||||
this.props.onUnfillRequest?.(backwards, markerScrollToken!);
|
||||
this.props.onUnfillRequest?.(backwards, markerScrollToken);
|
||||
}, UNFILL_REQUEST_DEBOUNCE_MS);
|
||||
}
|
||||
}
|
||||
@@ -666,7 +666,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
debuglog("unable to save scroll state: found no children in the viewport");
|
||||
return;
|
||||
}
|
||||
const scrollToken = node!.dataset.scrollTokens?.split(",")[0];
|
||||
const scrollToken = node.dataset.scrollTokens?.split(",")[0];
|
||||
debuglog("saving anchored scroll state to message", scrollToken);
|
||||
const bottomOffset = this.topFromBottom(node);
|
||||
this.scrollState = {
|
||||
@@ -788,7 +788,7 @@ export default class ScrollPanel extends React.Component<IProps> {
|
||||
const m = messages[i] as HTMLElement;
|
||||
// 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens
|
||||
// There might only be one scroll token
|
||||
if (scrollToken && m.dataset.scrollTokens?.split(",").includes(scrollToken!)) {
|
||||
if (scrollToken && m.dataset.scrollTokens?.split(",").includes(scrollToken)) {
|
||||
node = m;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ import { Action } from "../../dispatcher/actions";
|
||||
import { type IState, RovingTabIndexProvider, useRovingTabIndex } from "../../accessibility/RovingTabIndex";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import { useTypedEventEmitterState } from "../../hooks/useEventEmitter";
|
||||
import { type IOOBData } from "../../stores/ThreepidInviteStore";
|
||||
import { awaitRoomDownSync } from "../../utils/RoomUpgrade";
|
||||
import { type ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { type JoinRoomReadyPayload } from "../../dispatcher/payloads/JoinRoomReadyPayload";
|
||||
@@ -400,7 +399,7 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
|
||||
// XXX: This logic is duplicated from the JS SDK which would normally decide what the name is.
|
||||
name: room?.name || roomAlias || _t("common|unnamed_room"),
|
||||
roomType,
|
||||
} as IOOBData,
|
||||
},
|
||||
metricsTrigger: "RoomDirectory",
|
||||
});
|
||||
};
|
||||
|
||||
@@ -617,7 +617,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||
|
||||
if (showSetup) {
|
||||
phase =
|
||||
this.props.justCreatedOpts!.createOpts?.preset === Preset.PublicChat
|
||||
this.props.justCreatedOpts.createOpts?.preset === Preset.PublicChat
|
||||
? Phase.PublicCreateRooms
|
||||
: Phase.PrivateScope;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export const ThreadPanelHeader: React.FC<{
|
||||
}> = ({ filterOption, setFilterOption }) => {
|
||||
const mxClient = useMatrixClientContext();
|
||||
const roomContext = useScopedRoomContext("room");
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu<HTMLElement>();
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
const options: readonly ThreadPanelHeaderOption[] = [
|
||||
{
|
||||
label: _t("threads|all_threads"),
|
||||
|
||||
@@ -272,7 +272,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
this.timelinePanel.current?.refreshTimeline(this.props.initialEvent?.getId());
|
||||
}
|
||||
|
||||
private setupThreadListeners(thread?: Thread | undefined, oldThread?: Thread | undefined): void {
|
||||
private setupThreadListeners(thread?: Thread, oldThread?: Thread): void {
|
||||
if (oldThread) {
|
||||
this.state.thread?.off(ThreadEvent.NewReply, this.updateThreadRelation);
|
||||
this.props.room.off(RoomEvent.LocalEchoUpdated, this.updateThreadRelation);
|
||||
|
||||
@@ -1532,6 +1532,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
description,
|
||||
});
|
||||
if (onFinished) {
|
||||
// oxlint-disable-next-line promise/no-promise-in-callback
|
||||
finished.then(onFinished);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class UploadBar extends React.PureComponent<IProps, IState> {
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
dis.unregister(this.dispatcherRef!);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
private getUploadsInRoom(): RoomUpload[] {
|
||||
|
||||
@@ -339,7 +339,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
|
||||
homeserver={this.props.serverConfig.hsName}
|
||||
loading={this.state.phase === Phase.SendingEmail}
|
||||
onInputChanged={this.onInputChanged}
|
||||
onLoginClick={this.props.onLoginClick!} // set by default props
|
||||
onLoginClick={this.props.onLoginClick} // set by default props
|
||||
onSubmitForm={this.onSubmitForm}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -89,7 +89,7 @@ export default class LegacySeekBar extends React.PureComponent<IProps, IState> {
|
||||
this.props.playback.skipTo(Number(ev.target.value) * this.props.playback.durationSeconds);
|
||||
};
|
||||
|
||||
private onMouseDown = (event: React.MouseEvent<Element, MouseEvent>): void => {
|
||||
private onMouseDown = (event: React.MouseEvent): void => {
|
||||
// do not propagate mouse down events, because these should be handled by the seekbar
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -286,9 +286,7 @@ export default class LoginWithQR extends React.Component<Props, IState> {
|
||||
} catch (e: RendezvousError | unknown) {
|
||||
if (abortController.signal.aborted) return;
|
||||
logger.error("Error whilst approving login", e);
|
||||
await rendezvous.cancel(
|
||||
e instanceof RendezvousError ? (e.code as MSC4108FailureReason) : ClientRendezvousFailureReason.Unknown,
|
||||
);
|
||||
await rendezvous.cancel(e instanceof RendezvousError ? e.code : ClientRendezvousFailureReason.Unknown);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ export default class BugReportDialog extends React.Component<BugReportDialogProp
|
||||
this.setState({
|
||||
downloadBusy: false,
|
||||
downloadProgress:
|
||||
_t("bug_reporting|failed_download_logs") + `${err instanceof Error ? err.message : ""}`,
|
||||
_t("bug_reporting|failed_download_logs") + (err instanceof Error ? err.message : ""),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export default class ChangelogDialog extends React.Component<IProps, State> {
|
||||
msg: this.state[repo],
|
||||
});
|
||||
} else {
|
||||
content = (this.state[repo] as Commit[]).map(this.elementsForCommit);
|
||||
content = this.state[repo].map(this.elementsForCommit);
|
||||
}
|
||||
return (
|
||||
<div key={repo}>
|
||||
|
||||
@@ -381,7 +381,7 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
|
||||
className="mx_ExportDialog_attachments-checkbox"
|
||||
id="include-attachments"
|
||||
checked={includeAttachments}
|
||||
onChange={(e) => setAttachments((e.target as HTMLInputElement).checked)}
|
||||
onChange={(e) => setAttachments(e.target.checked)}
|
||||
>
|
||||
{_t("export_chat|include_attachments")}
|
||||
</StyledCheckbox>
|
||||
|
||||
@@ -78,10 +78,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||
}}
|
||||
autoFocus={true}
|
||||
/>
|
||||
<StyledCheckbox
|
||||
checked={canContact}
|
||||
onChange={(e) => setCanContact((e.target as HTMLInputElement).checked)}
|
||||
>
|
||||
<StyledCheckbox checked={canContact} onChange={(e) => setCanContact(e.target.checked)}>
|
||||
{_t("feedback|can_contact_label")}
|
||||
</StyledCheckbox>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -323,10 +323,10 @@ describe("InviteDialog", () => {
|
||||
|
||||
const input = screen.getByTestId("invite-dialog-input");
|
||||
input.focus();
|
||||
await userEvent.paste(`${bobbob}`);
|
||||
await userEvent.paste(bobbob);
|
||||
|
||||
await screen.findAllByText(bobId);
|
||||
expect(input).toHaveValue(`${bobbob}`);
|
||||
expect(input).toHaveValue(bobbob);
|
||||
});
|
||||
|
||||
it("should allow to invite multiple emails to a room", async () => {
|
||||
@@ -409,9 +409,9 @@ describe("InviteDialog", () => {
|
||||
|
||||
const input = screen.getByTestId("invite-dialog-input");
|
||||
input.focus();
|
||||
await userEvent.paste(`${bobId}`);
|
||||
await userEvent.paste(`${bobId}`);
|
||||
await userEvent.paste(`${bobId}`);
|
||||
await userEvent.paste(bobId);
|
||||
await userEvent.paste(bobId);
|
||||
await userEvent.paste(bobId);
|
||||
|
||||
expect(input).toHaveValue("");
|
||||
await expect(screen.findAllByText(bobId, { selector: "a" })).resolves.toHaveLength(1);
|
||||
@@ -422,7 +422,7 @@ describe("InviteDialog", () => {
|
||||
|
||||
const input = screen.getByTestId("invite-dialog-input");
|
||||
input.focus();
|
||||
await userEvent.keyboard(`${aliceId}`);
|
||||
await userEvent.keyboard(aliceId);
|
||||
|
||||
const btn = await screen.findByRole("option", { name: aliceId });
|
||||
fireEvent.click(btn);
|
||||
|
||||
@@ -116,7 +116,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
||||
if (isClose || !this.possibleButtons.includes(ev.detail.data.button)) {
|
||||
return this.state.messaging?.transport.reply(ev.detail, {
|
||||
error: { message: "Invalid button" },
|
||||
} as IWidgetApiErrorResponseData);
|
||||
} satisfies IWidgetApiErrorResponseData);
|
||||
}
|
||||
|
||||
let buttonIds: ModalButtonID[];
|
||||
@@ -129,7 +129,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
||||
buttonIds = Array.from(tempSet);
|
||||
}
|
||||
this.setState({ disabledButtonIds: buttonIds });
|
||||
this.state.messaging?.transport.reply(ev.detail, {} as IWidgetApiAcknowledgeResponseData);
|
||||
this.state.messaging?.transport.reply(ev.detail, {} satisfies IWidgetApiAcknowledgeResponseData);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
@@ -207,6 +207,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
||||
<iframe
|
||||
title={this.widget.name ?? undefined}
|
||||
ref={this.appFrame}
|
||||
// oxlint-disable-next-line react/iframe-missing-sandbox
|
||||
sandbox="allow-forms allow-scripts allow-same-origin"
|
||||
src={widgetUrl}
|
||||
onLoad={this.onLoad}
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { createRef, type RefObject } from "react";
|
||||
import React, { createRef } from "react";
|
||||
import { type DialogContent, type DialogProps } from "@matrix-org/react-sdk-module-api/lib/components/DialogContent";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { type ModuleApi } from "@matrix-org/react-sdk-module-api/lib/ModuleApi";
|
||||
@@ -75,10 +75,6 @@ export class ModuleUiDialog<
|
||||
} as unknown as P;
|
||||
|
||||
// XXX: we have to fudge the types here a little as the react-sdk-module-api lacks React 19 support
|
||||
return (
|
||||
<div className="mx_ModuleUiDialog">
|
||||
{this.props.contentFactory(contentProps, this.contentRef as RefObject<C>)}
|
||||
</div>
|
||||
);
|
||||
return <div className="mx_ModuleUiDialog">{this.props.contentFactory(contentProps, this.contentRef)}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export class DMRoomTile extends React.PureComponent<IDMRoomTileProps> {
|
||||
<BaseAvatar
|
||||
url={
|
||||
this.props.member.getMxcAvatarUrl()
|
||||
? mediaFromMxc(this.props.member.getMxcAvatarUrl()!).getSquareThumbnailHttp(
|
||||
? mediaFromMxc(this.props.member.getMxcAvatarUrl()).getSquareThumbnailHttp(
|
||||
parseInt(avatarSize, 10),
|
||||
)
|
||||
: null
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Tooltip } from "@vector-im/compound-web";
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
|
||||
export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Element> | React.FormEvent<Element>;
|
||||
export type ButtonEvent = React.MouseEvent | React.KeyboardEvent | React.FormEvent;
|
||||
|
||||
/**
|
||||
* The kind of button, similar to how Bootstrap works.
|
||||
|
||||
@@ -306,8 +306,8 @@ export default class EventListSummary extends React.Component<Props, State> {
|
||||
|
||||
let transition = t;
|
||||
|
||||
if (i < transitions.length - 1 && modMap[t] && modMap[t]!.after === t2) {
|
||||
transition = modMap[t]!.newTransition;
|
||||
if (i < transitions.length - 1 && modMap[t] && modMap[t].after === t2) {
|
||||
transition = modMap[t].newTransition;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ export default class ImageView extends React.Component<IProps, IState> {
|
||||
|
||||
let info: JSX.Element | undefined;
|
||||
if (showEventMeta) {
|
||||
const mxEvent = this.props.mxEvent!;
|
||||
const mxEvent = this.props.mxEvent;
|
||||
const showTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
|
||||
let permalink = "#";
|
||||
if (this.props.permalinkCreator) {
|
||||
|
||||
@@ -163,7 +163,7 @@ const MapComponent: React.FC<MapProps> = ({
|
||||
}) => {
|
||||
const { map, bodyId } = useMapWithStyle({ centerGeoUri, onError, id, interactive, bounds, allowGeolocate });
|
||||
|
||||
const onMapClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
|
||||
const onMapClick = (event: React.MouseEvent<HTMLDivElement>): void => {
|
||||
// Eat click events when clicking the attribution button
|
||||
const target = event.target as Element;
|
||||
if (target.classList.contains("maplibregl-ctrl-attrib-button")) {
|
||||
|
||||
@@ -39,7 +39,7 @@ const OptionalTooltip: React.FC<{
|
||||
|
||||
const show = (): void => setIsVisible(true);
|
||||
const hide = (): void => setIsVisible(false);
|
||||
const toggleVisibility = (e: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
|
||||
const toggleVisibility = (e: React.MouseEvent<HTMLDivElement>): void => {
|
||||
// stop map from zooming in on click
|
||||
e.stopPropagation();
|
||||
setIsVisible(!isVisible);
|
||||
|
||||
@@ -25,7 +25,7 @@ import { type Media, mediaFromContent } from "../../../customisations/Media";
|
||||
import { BLURHASH_FIELD, createThumbnail } from "../../../utils/image-media";
|
||||
import ImageView from "../elements/ImageView";
|
||||
import { type IBodyProps } from "./IBodyProps";
|
||||
import { type ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";
|
||||
import { suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import { blobIsAnimated, mayBeAnimated } from "../../../utils/Image";
|
||||
@@ -409,7 +409,7 @@ export class ImageBodyBaseInner extends React.Component<ImageBodyBaseProps, ISta
|
||||
}
|
||||
|
||||
const { w: maxWidth, h: maxHeight } = suggestedImageSize(
|
||||
SettingsStore.getValue("Images.size") as ImageSize,
|
||||
SettingsStore.getValue("Images.size"),
|
||||
{ w: infoWidth, h: infoHeight },
|
||||
forcedHeight ?? this.props.maxImageHeight,
|
||||
);
|
||||
|
||||
@@ -409,8 +409,8 @@ export function allVotes(voteRelations: Relations): Array<UserVote> {
|
||||
*/
|
||||
export function collectUserVotes(
|
||||
userResponses: Array<UserVote>,
|
||||
userId?: string | null | undefined,
|
||||
selected?: string | null | undefined,
|
||||
userId?: string | null,
|
||||
selected?: string | null,
|
||||
): Map<string, UserVote> {
|
||||
const userVotes: Map<string, UserVote> = new Map();
|
||||
|
||||
|
||||
@@ -129,13 +129,13 @@ export const PollHistoryList: React.FC<PollHistoryListProps> = ({
|
||||
{pollStartEvents.map((pollStartEvent) =>
|
||||
filter === "ACTIVE" ? (
|
||||
<PollListItem
|
||||
key={pollStartEvent.getId()!}
|
||||
key={pollStartEvent.getId()}
|
||||
event={pollStartEvent}
|
||||
onClick={() => onItemClick(pollStartEvent.getId()!)}
|
||||
/>
|
||||
) : (
|
||||
<PollListItemEnded
|
||||
key={pollStartEvent.getId()!}
|
||||
key={pollStartEvent.getId()}
|
||||
event={pollStartEvent}
|
||||
poll={polls.get(pollStartEvent.getId()!)!}
|
||||
onClick={() => onItemClick(pollStartEvent.getId()!)}
|
||||
|
||||
@@ -195,14 +195,14 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
|
||||
let content: JSX.Element | undefined;
|
||||
switch (phase) {
|
||||
case RightPanelPhases.MemberInfo:
|
||||
content = <UserInfoBasicView room={room as Room} member={member as User} />;
|
||||
content = <UserInfoBasicView room={room as Room} member={member} />;
|
||||
break;
|
||||
case RightPanelPhases.EncryptionPanel:
|
||||
classes.push("mx_UserInfo_smallAvatar");
|
||||
content = (
|
||||
<EncryptionPanel
|
||||
{...(props as React.ComponentProps<typeof EncryptionPanel>)}
|
||||
member={member as User | RoomMember}
|
||||
member={member}
|
||||
onClose={onEncryptionPanelClose}
|
||||
isRoomEncrypted={Boolean(isRoomEncrypted)}
|
||||
/>
|
||||
|
||||
@@ -240,11 +240,11 @@ export default class AliasSettings extends React.Component<IProps, IState> {
|
||||
.createAlias(alias, this.props.roomId)
|
||||
.then(() => {
|
||||
this.setState({
|
||||
localAliases: this.state.localAliases.concat(alias!),
|
||||
localAliases: this.state.localAliases.concat(alias),
|
||||
newAlias: undefined,
|
||||
});
|
||||
if (!this.state.canonicalAlias) {
|
||||
this.changeCanonicalAlias(alias!);
|
||||
this.changeCanonicalAlias(alias);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { type AriaRole, useContext } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Resizable, type Size } from "re-resizable";
|
||||
import { Resizable } from "re-resizable";
|
||||
import { type Room } from "matrix-js-sdk/src/matrix";
|
||||
import { type IWidget } from "matrix-widget-api";
|
||||
import { clamp, percentageOf, percentageWithin } from "@element-hq/web-shared-components";
|
||||
@@ -340,7 +340,7 @@ const PersistentVResizer: React.FC<IPersistentResizerProps> = ({
|
||||
<Resizable
|
||||
// types do not support undefined height/width
|
||||
// but resizable code checks specifically for undefined on Size prop
|
||||
size={{ height: Math.min(defaultHeight, maxHeight), width: undefined } as unknown as Size}
|
||||
size={{ height: Math.min(defaultHeight, maxHeight), width: undefined }}
|
||||
minHeight={minHeight}
|
||||
maxHeight={maxHeight}
|
||||
onResizeStart={() => {
|
||||
@@ -350,7 +350,7 @@ const PersistentVResizer: React.FC<IPersistentResizerProps> = ({
|
||||
resizeNotifier.notifyTimelineHeightChanged();
|
||||
}}
|
||||
onResizeStop={(e, dir, ref, d) => {
|
||||
let newHeight = defaultHeight! + d.height;
|
||||
let newHeight = defaultHeight + d.height;
|
||||
newHeight = percentageOf(newHeight, minHeight, maxHeight) * 100;
|
||||
|
||||
sdkContext.widgetLayoutStore.setContainerHeight(room, "top", newHeight);
|
||||
|
||||
@@ -668,7 +668,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
|
||||
private readonly onFocusWithin = (event: FocusEvent<HTMLElement>): void => {
|
||||
// Show the action toolbar for keyboard-visible focus, with what-input as a fallback signal.
|
||||
const target = event.target as HTMLElement;
|
||||
const target = event.target;
|
||||
const showActionBarFromFocus =
|
||||
target.matches(":focus-visible") || document.body.dataset["data-whatinput"] === "keyboard";
|
||||
this.setState((prevState) => ({
|
||||
|
||||
@@ -179,7 +179,7 @@ const NewRoomIntro: React.FC = () => {
|
||||
let parentSpace: Room | undefined;
|
||||
if (
|
||||
sdkContext.spaceStore.activeSpaceRoom?.canInvite(cli.getSafeUserId()) &&
|
||||
sdkContext.spaceStore.isRoomInSpace(sdkContext.spaceStore.activeSpace!, room.roomId)
|
||||
sdkContext.spaceStore.isRoomInSpace(sdkContext.spaceStore.activeSpace, room.roomId)
|
||||
) {
|
||||
parentSpace = sdkContext.spaceStore.activeSpaceRoom;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ const NewRoomIntro: React.FC = () => {
|
||||
className="mx_NewRoomIntro_inviteButton"
|
||||
kind="primary"
|
||||
onClick={() => {
|
||||
showSpaceInvite(parentSpace!);
|
||||
showSpaceInvite(parentSpace);
|
||||
}}
|
||||
>
|
||||
<UserAddIcon />
|
||||
|
||||
@@ -38,7 +38,7 @@ export const RoomListPanel: React.FC<RoomListPanelProps> = ({ activeSpace }) =>
|
||||
const [focusedElement, setFocusedElement] = useState<Element | null>(null);
|
||||
|
||||
const onFocus = useCallback((ev: React.FocusEvent): void => {
|
||||
setFocusedElement(ev.target as Element);
|
||||
setFocusedElement(ev.target);
|
||||
}, []);
|
||||
|
||||
const onBlur = useCallback((): void => {
|
||||
|
||||
@@ -218,7 +218,7 @@ class RoomPreviewBar extends React.Component<IProps, IState> {
|
||||
}
|
||||
return MessageCase.Invite;
|
||||
} else if (this.props.error) {
|
||||
if ((this.props.error as MatrixError).errcode == "M_NOT_FOUND") {
|
||||
if (this.props.error.errcode === "M_NOT_FOUND") {
|
||||
return MessageCase.RoomNotFound;
|
||||
} else {
|
||||
return MessageCase.OtherError;
|
||||
|
||||
@@ -610,7 +610,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
||||
// Fallback to internal onPaste handler
|
||||
return false;
|
||||
}
|
||||
const imgSrc = imgDoc!.querySelector("img")!.src;
|
||||
const imgSrc = imgDoc.querySelector("img")!.src;
|
||||
|
||||
fetch(imgSrc).then(
|
||||
(response) => {
|
||||
|
||||
@@ -66,7 +66,7 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
|
||||
client.removeListener(RoomMemberEvent.Typing, this.onRoomMemberTyping);
|
||||
client.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
}
|
||||
Object.values(this.state.delayedStopTypingTimers).forEach((t) => (t as Timer).abort());
|
||||
Object.values(this.state.delayedStopTypingTimers).forEach((t) => t.abort());
|
||||
}
|
||||
|
||||
private static isVisible(state: IState): boolean {
|
||||
|
||||
@@ -133,7 +133,7 @@ export async function sendMessage(
|
||||
|
||||
const prom = doMaybeLocalRoomAction(
|
||||
roomId,
|
||||
(actualRoomId: string) => mxClient.sendMessage(actualRoomId, threadId, content!),
|
||||
(actualRoomId: string) => mxClient.sendMessage(actualRoomId, threadId, content),
|
||||
mxClient,
|
||||
);
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ const ExistingThreepid: React.FC<ExistingThreepidProps> = ({ mode, threepid, onC
|
||||
threepid.medium === "email"
|
||||
? _t("settings|general|error_revoke_email_discovery")
|
||||
: _t("settings|general|error_revoke_msisdn_discovery"),
|
||||
}).then();
|
||||
});
|
||||
},
|
||||
[changeBinding, threepid.medium],
|
||||
);
|
||||
@@ -143,7 +143,7 @@ const ExistingThreepid: React.FC<ExistingThreepidProps> = ({ mode, threepid, onC
|
||||
threepid.medium === "email"
|
||||
? _t("settings|general|error_share_email_discovery")
|
||||
: _t("settings|general|error_share_msisdn_discovery"),
|
||||
}).then();
|
||||
});
|
||||
},
|
||||
[changeBinding, threepid.medium],
|
||||
);
|
||||
|
||||
@@ -96,6 +96,7 @@ export default class IntegrationManager extends React.Component<IProps, IState>
|
||||
);
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line react/iframe-missing-sandbox
|
||||
return <iframe title={_t("common|integration_manager")} src={this.props.url} onError={this.onError} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
|
||||
}
|
||||
|
||||
private async refreshRules(): Promise<Partial<IState>> {
|
||||
const ruleSets = await MatrixClientPeg.safeGet().getPushRules()!;
|
||||
const ruleSets = await MatrixClientPeg.safeGet().getPushRules();
|
||||
const categories: Record<string, RuleClass> = {
|
||||
[RuleId.Master]: RuleClass.Master,
|
||||
|
||||
@@ -353,7 +353,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
|
||||
for (const rule of defaultRules[category]) {
|
||||
const definition: VectorPushRuleDefinition = VectorPushRulesDefinitions[rule.rule_id];
|
||||
const vectorState = definition.ruleToVectorState(rule)!;
|
||||
preparedNewState.vectorPushRules[category]!.push({
|
||||
preparedNewState.vectorPushRules[category].push({
|
||||
ruleId: rule.rule_id,
|
||||
rule,
|
||||
vectorState,
|
||||
@@ -363,7 +363,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
|
||||
}
|
||||
|
||||
// Quickly sort the rules for display purposes
|
||||
preparedNewState.vectorPushRules[category]!.sort((a, b) => {
|
||||
preparedNewState.vectorPushRules[category].sort((a, b) => {
|
||||
let idxA = RULE_DISPLAY_ORDER.indexOf(a.ruleId);
|
||||
let idxB = RULE_DISPLAY_ORDER.indexOf(b.ruleId);
|
||||
|
||||
@@ -375,7 +375,7 @@ export default class Notifications extends React.PureComponent<EmptyObject, ISta
|
||||
});
|
||||
|
||||
if (category === KEYWORD_RULE_CATEGORY) {
|
||||
preparedNewState.vectorPushRules[category]!.push({
|
||||
preparedNewState.vectorPushRules[category].push({
|
||||
ruleId: KEYWORD_RULE_ID,
|
||||
description: _t("settings|notifications|messages_containing_keywords"),
|
||||
vectorState: preparedNewState.vectorKeywordRuleInfo.vectorState,
|
||||
|
||||
@@ -68,15 +68,7 @@ export const UserPersonalInfoSettings: React.FC<UserPersonalInfoSettingsProps> =
|
||||
}, [client]);
|
||||
|
||||
useEffect(() => {
|
||||
updateThreepids().then();
|
||||
}, [updateThreepids]);
|
||||
|
||||
const onEmailsChange = useCallback(() => {
|
||||
updateThreepids().then();
|
||||
}, [updateThreepids]);
|
||||
|
||||
const onMsisdnsChange = useCallback(() => {
|
||||
updateThreepids().then();
|
||||
updateThreepids();
|
||||
}, [updateThreepids]);
|
||||
|
||||
if (!SettingsStore.getValue(UIFeature.ThirdPartyID)) return null;
|
||||
@@ -96,7 +88,7 @@ export const UserPersonalInfoSettings: React.FC<UserPersonalInfoSettingsProps> =
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Email}
|
||||
threepids={emails!}
|
||||
onChange={onEmailsChange}
|
||||
onChange={updateThreepids}
|
||||
disabled={!canMake3pidChanges}
|
||||
isLoading={loadingState === "loading"}
|
||||
/>
|
||||
@@ -116,7 +108,7 @@ export const UserPersonalInfoSettings: React.FC<UserPersonalInfoSettingsProps> =
|
||||
mode="hs"
|
||||
medium={ThreepidMedium.Phone}
|
||||
threepids={phoneNumbers!}
|
||||
onChange={onMsisdnsChange}
|
||||
onChange={updateThreepids}
|
||||
disabled={!canMake3pidChanges}
|
||||
isLoading={loadingState === "loading"}
|
||||
/>
|
||||
|
||||
@@ -299,7 +299,7 @@ export const FilteredDeviceList = ({
|
||||
];
|
||||
|
||||
const onFilterOptionChange = (filterId: DeviceFilterKey): void => {
|
||||
onFilterChange(filterId === ALL_FILTER_ID ? undefined : (filterId as FilterVariation));
|
||||
onFilterChange(filterId === ALL_FILTER_ID ? undefined : filterId);
|
||||
};
|
||||
|
||||
const isAllSelected = selectedDeviceIds.length >= sortedDevices.length;
|
||||
|
||||
@@ -73,7 +73,7 @@ export const DiscoverySettings: React.FC = () => {
|
||||
if (payload.action === "id_server_changed") {
|
||||
setIdServerName(abbreviateUrl(client.getIdentityServerUrl()));
|
||||
|
||||
getThreepidState().then();
|
||||
getThreepidState();
|
||||
}
|
||||
},
|
||||
[client, getThreepidState],
|
||||
@@ -113,9 +113,7 @@ export const DiscoverySettings: React.FC = () => {
|
||||
// User accepted all terms
|
||||
setMustAgreeToTerms(false);
|
||||
} catch (e) {
|
||||
logger.warn(
|
||||
`Unable to reach identity server at ${idServerUrl} to check ` + `for terms in Settings`,
|
||||
);
|
||||
logger.warn(`Unable to reach identity server at ${idServerUrl} to check for terms in Settings`);
|
||||
logger.warn(e);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
@@ -99,7 +99,7 @@ export default function NotificationSettings2(): JSX.Element {
|
||||
<SettingsBanner
|
||||
icon={<img src={NewAndImprovedIcon} alt="" width={12} />}
|
||||
action={_t("action|proceed")}
|
||||
onAction={() => reconcile(model!)}
|
||||
onAction={() => reconcile(model)}
|
||||
>
|
||||
{_t(
|
||||
"settings|notifications|labs_notice_prompt",
|
||||
|
||||
@@ -46,7 +46,7 @@ interface IProps {
|
||||
pipMode?: boolean;
|
||||
|
||||
// Used for dragging the PiP LegacyCallView
|
||||
onMouseDownOnHeader?: (event: React.MouseEvent<Element, MouseEvent>) => void;
|
||||
onMouseDownOnHeader?: (event: React.MouseEvent) => void;
|
||||
|
||||
showApps?: boolean;
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ const SecondaryCallInfo: React.FC<ISecondaryCallInfoProps> = ({ callRoom }) => {
|
||||
interface LegacyCallViewHeaderProps {
|
||||
pipMode?: boolean;
|
||||
callRooms: [Room, Room | null];
|
||||
onPipMouseDown?: (event: React.MouseEvent<Element, MouseEvent>) => void;
|
||||
onPipMouseDown?: (event: React.MouseEvent) => void;
|
||||
onExpand?: () => void;
|
||||
onPin?: () => void;
|
||||
onMaximize?: () => void;
|
||||
|
||||
@@ -25,4 +25,4 @@ function getDisplayUserIdentifier(
|
||||
// customisation points that make up `IUserIdentifierCustomisations`.
|
||||
export default {
|
||||
getDisplayUserIdentifier,
|
||||
} as UserIdentifierCustomisations;
|
||||
} satisfies UserIdentifierCustomisations;
|
||||
|
||||
@@ -220,7 +220,7 @@ export function formatRangeAsLink(range: Range, text?: string): void {
|
||||
replaceRangeAndMoveCaret(range, newParts, 0);
|
||||
} else {
|
||||
// We set offset to -1 here so that the caret lands between the brackets
|
||||
replaceRangeAndMoveCaret(range, [partCreator.plain("[" + range.text + "]" + "(" + (text ?? "") + ")")], -1);
|
||||
replaceRangeAndMoveCaret(range, [partCreator.plain(`[${range.text}](${text ?? ""})`)], -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@ function reconcileLine(lineContainer: ChildNode, parts: Part[]): void {
|
||||
currentNode = isFirst ? lineContainer.firstChild : currentNode!.nextSibling;
|
||||
|
||||
if (needsCaretNodeBefore(part, prevPart)) {
|
||||
if (isCaretNode(currentNode as Element)) {
|
||||
updateCaretNode(currentNode!);
|
||||
currentNode = currentNode!.nextSibling;
|
||||
if (isCaretNode(currentNode)) {
|
||||
updateCaretNode(currentNode);
|
||||
currentNode = currentNode.nextSibling;
|
||||
} else {
|
||||
lineContainer.insertBefore(createCaretNode(), currentNode);
|
||||
}
|
||||
@@ -106,9 +106,9 @@ function reconcileLine(lineContainer: ChildNode, parts: Part[]): void {
|
||||
}
|
||||
|
||||
if (needsCaretNodeAfter(part, part === lastPart)) {
|
||||
if (isCaretNode(currentNode?.nextSibling as Element)) {
|
||||
currentNode = currentNode!.nextSibling;
|
||||
updateCaretNode(currentNode as HTMLElement);
|
||||
if (isCaretNode(currentNode?.nextSibling)) {
|
||||
currentNode = currentNode.nextSibling;
|
||||
updateCaretNode(currentNode);
|
||||
} else {
|
||||
const caretNode = createCaretNode();
|
||||
insertAfter(currentNode as HTMLElement, caretNode);
|
||||
|
||||
@@ -177,9 +177,9 @@ export function textSerialize(model: EditorModel): string {
|
||||
case Type.RoomPill:
|
||||
// Here we use the resourceId for compatibility with non-rich text clients
|
||||
// See https://github.com/vector-im/element-web/issues/16660
|
||||
return text + `${part.resourceId}`;
|
||||
return text + part.resourceId;
|
||||
case Type.UserPill:
|
||||
return text + `${part.text}`;
|
||||
return text + part.text;
|
||||
}
|
||||
}, "");
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ export class BadgeOverlayRenderer extends IconRenderer {
|
||||
(blob) => {
|
||||
if (blob) {
|
||||
resolve(blob.arrayBuffer());
|
||||
return;
|
||||
}
|
||||
reject(new Error("Could not render badge overlay as blob"));
|
||||
},
|
||||
|
||||
@@ -189,4 +189,5 @@ export function useEventEmitterAsyncState<T, Events extends string, Arguments ex
|
||||
/**
|
||||
* Indicates that the callback for `useEventEmitterAsyncState` is not changing the value of the state.
|
||||
*/
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class NoChange {}
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function isRoomEncrypted(room: Room, cryptoApi: CryptoApi): Promise
|
||||
if (room instanceof LocalRoom) {
|
||||
// For local room check the state.
|
||||
// The crypto check fails because the room ID is not valid (it is a local id)
|
||||
return (room as LocalRoom).isEncryptionEnabled();
|
||||
return room.isEncryptionEnabled();
|
||||
}
|
||||
|
||||
return await cryptoApi.isEncryptionEnabledInRoom(room.roomId);
|
||||
|
||||
@@ -29,6 +29,7 @@ export const useSpaceResults = (space: Room | undefined, query: string): [Hierar
|
||||
let unmounted = false;
|
||||
|
||||
(async (): Promise<void> => {
|
||||
// oxlint-disable-next-line no-unmodified-loop-condition
|
||||
while (hierarchy?.canLoadMore && !unmounted && space === hierarchy.root) {
|
||||
await hierarchy.load();
|
||||
if (hierarchy.canLoadMore) hierarchy.load(); // start next load so that the loading attribute is right
|
||||
|
||||
@@ -458,6 +458,7 @@ export default class EventIndex extends EventEmitter {
|
||||
|
||||
let idle = false;
|
||||
|
||||
// oxlint-disable-next-line no-unmodified-loop-condition
|
||||
while (!cancelled) {
|
||||
let sleepTime = SettingsStore.getValueAt(SettingLevel.DEVICE, "crawlerSleepTime");
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ export abstract class Call extends TypedEventEmitter<CallEvent, CallEventHandler
|
||||
// The widget might still be initializing, so wait for it in an async
|
||||
// event loop. We need the messaging to be both present and started
|
||||
// (have a connected widget API), so register listeners for both cases.
|
||||
// oxlint-disable-next-line no-unmodified-loop-condition
|
||||
while (!messaging?.widgetApi) {
|
||||
if (messaging) logger.debug(`Messaging present but not yet started for ${this.widgetUid}`);
|
||||
else logger.debug(`No messaging yet for ${this.widgetUid}`);
|
||||
@@ -430,7 +431,7 @@ export class JitsiCall extends Call {
|
||||
const event = this.room.currentState.getStateEvents(JitsiCall.MEMBER_EVENT_TYPE, this.client.getUserId()!);
|
||||
const content = event?.getContent<JitsiCallMemberContent>();
|
||||
const expiresAt = typeof content?.expires_ts === "number" ? content.expires_ts : -Infinity;
|
||||
const devices = expiresAt > Date.now() && Array.isArray(content?.devices) ? content!.devices : [];
|
||||
const devices = expiresAt > Date.now() && Array.isArray(content?.devices) ? content.devices : [];
|
||||
const newDevices = fn(devices);
|
||||
|
||||
if (newDevices !== null) {
|
||||
|
||||
@@ -13,7 +13,7 @@ export class ConfigApi implements IConfigApi {
|
||||
public get<K extends keyof Config>(key: K): Config[K];
|
||||
public get<K extends keyof Config = never>(key?: K): Config | Config[K] {
|
||||
if (key === undefined) {
|
||||
return SdkConfig.get() as Config;
|
||||
return SdkConfig.get();
|
||||
}
|
||||
return SdkConfig.get(key);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ export class ProxiedModuleApi implements ModuleApi {
|
||||
|
||||
return {
|
||||
homeserverUrl: hsUrl,
|
||||
userId: creds.user_id!,
|
||||
userId: creds.user_id,
|
||||
deviceId: creds.device_id!,
|
||||
accessToken: creds.access_token!,
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface IContentRules {
|
||||
externalRules: IAnnotatedPushRule[];
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class ContentRules {
|
||||
/**
|
||||
* Extract the keyword rules from a list of rules, and parse them
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface PushRuleActions {
|
||||
highlight?: boolean;
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class NotificationUtils {
|
||||
// Encodes a dictionary of {
|
||||
// "notify": true/false,
|
||||
|
||||
@@ -21,6 +21,7 @@ export enum VectorState {
|
||||
Loud = "loud",
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class PushRuleVectorState {
|
||||
// Backwards compatibility (things should probably be using the enum above instead)
|
||||
public static OFF = VectorState.Off;
|
||||
|
||||
@@ -13,6 +13,7 @@ import { NotificationUtils } from "./NotificationUtils";
|
||||
|
||||
const encodeActions = NotificationUtils.encodeActions;
|
||||
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export class StandardActions {
|
||||
public static ACTION_NOTIFY = encodeActions({ notify: true });
|
||||
public static ACTION_NOTIFY_DEFAULT_SOUND = encodeActions({ notify: true, sound: "default" });
|
||||
|
||||
@@ -421,7 +421,7 @@ export class IndexedDBLogStore {
|
||||
resolve();
|
||||
};
|
||||
txn.onerror = () => {
|
||||
reject(new Error("Failed to delete logs for " + `'${id}' : ${query.error?.message}`));
|
||||
reject(new Error(`Failed to delete logs for '${id}' : ${query.error?.message}`));
|
||||
};
|
||||
// delete last modified entries
|
||||
const lastModStore = txn.objectStore("logslastmod");
|
||||
|
||||
@@ -22,7 +22,7 @@ export const ambiguousLinkTooltipRenderer: RendererMap = {
|
||||
|
||||
const href = anchor.attribs["href"];
|
||||
if (href && href !== getSingleTextContentNode(anchor)) {
|
||||
let tooltip = href as string;
|
||||
let tooltip = href;
|
||||
try {
|
||||
tooltip = new URL(href, window.location.href).toString();
|
||||
} catch {
|
||||
|
||||
@@ -125,6 +125,7 @@ type HandlerMap = Partial<{
|
||||
* feature may be reported as disabled even though a user has specifically requested it
|
||||
* be enabled).
|
||||
*/
|
||||
// oxlint-disable-next-line typescript/no-extraneous-class
|
||||
export default class SettingsStore {
|
||||
// We support watching settings for changes, and do this by tracking which callbacks have
|
||||
// been given to us. We end up returning the callbackRef to the caller so they can unsubscribe
|
||||
@@ -263,7 +264,7 @@ export default class SettingsStore {
|
||||
if (roomId === null) {
|
||||
// Unregister all existing watchers and register the new one
|
||||
rooms.forEach((roomId) => {
|
||||
SettingsStore.unwatchSetting(this.monitors.get(settingName)!.get(roomId)!);
|
||||
SettingsStore.unwatchSetting(this.monitors.get(settingName)!.get(roomId));
|
||||
});
|
||||
this.monitors.get(settingName)!.clear();
|
||||
registerWatcher();
|
||||
@@ -334,10 +335,10 @@ export default class SettingsStore {
|
||||
SettingsStore.isFeature(settingName) &&
|
||||
SettingsStore.getValueAt(SettingLevel.CONFIG, settingName, null, true, true) !== false
|
||||
) {
|
||||
const betaInfo = SETTINGS[settingName]!.betaInfo;
|
||||
const betaInfo = SETTINGS[settingName].betaInfo;
|
||||
if (betaInfo) {
|
||||
betaInfo.requiresRefresh =
|
||||
betaInfo.requiresRefresh ?? SETTINGS[settingName]!.controller instanceof ReloadOnChangeController;
|
||||
betaInfo.requiresRefresh ?? SETTINGS[settingName].controller instanceof ReloadOnChangeController;
|
||||
}
|
||||
return betaInfo;
|
||||
}
|
||||
@@ -868,8 +869,7 @@ export default class SettingsStore {
|
||||
|
||||
private static getHandler(settingName: SettingKey, level: SettingLevel): SettingsHandler | null {
|
||||
const handlers = SettingsStore.getHandlers(settingName);
|
||||
if (!handlers[level]) return null;
|
||||
return handlers[level]!;
|
||||
return handlers[level] ?? null;
|
||||
}
|
||||
|
||||
private static getHandlers(settingName: SettingKey): HandlerMap {
|
||||
|
||||
@@ -56,7 +56,7 @@ export default class MediaPreviewConfigController extends MatrixClientBackedCont
|
||||
|
||||
// Save an account data fetch if we have all the values.
|
||||
if (calculatedConfig.invite_avatars && calculatedConfig.media_previews) {
|
||||
return calculatedConfig as MediaPreviewConfig;
|
||||
return calculatedConfig;
|
||||
}
|
||||
|
||||
// We're missing some keys.
|
||||
|
||||
@@ -123,4 +123,4 @@ let singletonLifecycleStore: LifecycleStore | null = null;
|
||||
if (!singletonLifecycleStore) {
|
||||
singletonLifecycleStore = new LifecycleStore();
|
||||
}
|
||||
export default singletonLifecycleStore!;
|
||||
export default singletonLifecycleStore;
|
||||
|
||||
@@ -145,7 +145,7 @@ export class MemberListStore {
|
||||
return true;
|
||||
}
|
||||
const enablePresenceByHsUrl = SdkConfig.get("enable_presence_by_hs_url");
|
||||
return enablePresenceByHsUrl?.[this.stores.client!.baseUrl] ?? true;
|
||||
return enablePresenceByHsUrl?.[this.stores.client.baseUrl] ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -66,7 +66,7 @@ export class ModalWidgetStore extends AsyncStoreWithClient<IState> {
|
||||
/* priority = */ false,
|
||||
/* static = */ true,
|
||||
);
|
||||
this.modalInstance!.finished.then(([success, data]) => {
|
||||
this.modalInstance.finished.then(([success, data]) => {
|
||||
this.closeModalWidget(sourceWidget, widgetRoomId, success && data ? data : { "m.exited": true });
|
||||
|
||||
this.openSourceWidgetId = null;
|
||||
|
||||
@@ -512,6 +512,7 @@ export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
|
||||
|
||||
this.stopPollingLocation();
|
||||
// kill live beacons when location permissions are revoked
|
||||
// oxlint-disable-next-line promise/no-promise-in-callback
|
||||
await Promise.all(this.liveBeaconIds.map(this.stopBeacon));
|
||||
};
|
||||
|
||||
|
||||
@@ -45,4 +45,5 @@ export class RoomScrollStateStore {
|
||||
if (window.mxRoomScrollStateStore === undefined) {
|
||||
window.mxRoomScrollStateStore = new RoomScrollStateStore();
|
||||
}
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-assertion
|
||||
export default window.mxRoomScrollStateStore!;
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class ThreepidInviteStore extends EventEmitter {
|
||||
}
|
||||
|
||||
public storeInvite(roomId: string, wireInvite: IThreepidInviteWireFormat): IThreepidInvite {
|
||||
const invite = <IPersistedThreepidInvite>{ roomId, ...wireInvite };
|
||||
const invite: IPersistedThreepidInvite = { roomId, ...wireInvite };
|
||||
const id = this.generateIdOf(invite);
|
||||
localStorage.setItem(`${STORAGE_PREFIX}${id}`, JSON.stringify(invite));
|
||||
return this.translateInvite(invite);
|
||||
|
||||
@@ -107,4 +107,5 @@ let singletonWidgetEchoStore: WidgetEchoStore | null = null;
|
||||
if (!singletonWidgetEchoStore) {
|
||||
singletonWidgetEchoStore = new WidgetEchoStore();
|
||||
}
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-assertion
|
||||
export default singletonWidgetEchoStore!;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user