Switch from eslint to oxlint (#34166)
* 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 * Make sonar happy * Fix new lints
This commit is contained in:
@@ -1,97 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: ["matrix-org", "n"],
|
||||
extends: ["plugin:matrix-org/javascript"],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2021,
|
||||
project: ["tsconfig.json"],
|
||||
},
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
// we also have some browser code (ie. the preload script)
|
||||
browser: true,
|
||||
},
|
||||
// NOTE: These rules are frozen and new rules should not be added here.
|
||||
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
|
||||
rules: {
|
||||
"quotes": "off",
|
||||
"indent": "off",
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
|
||||
"n/file-extension-in-import": ["error", "always"],
|
||||
"unicorn/prefer-node-protocol": ["error"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["hak/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
parserOptions: {
|
||||
project: ["hak/tsconfig.json"],
|
||||
},
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
"n/file-extension-in-import": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["scripts/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
parserOptions: {
|
||||
project: ["scripts/tsconfig.json"],
|
||||
},
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
"n/file-extension-in-import": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["playwright/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
parserOptions: {
|
||||
project: ["playwright/tsconfig.json"],
|
||||
},
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["src/**/*.test.ts", "electron-builder.ts", "vitest.config.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
parserOptions: {
|
||||
project: ["tsconfig.node.json"],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"*": "oxfmt --no-error-on-unmatched-pattern",
|
||||
"*.(ts|tsx)": ["eslint --fix"]
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
|
||||
};
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as os from "node:os";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"lib": ["es2022"],
|
||||
"types": ["node"],
|
||||
"allowImportingTsExtensions": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"]
|
||||
}
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
"fetch": "pnpm run mkdirs && node scripts/fetch-package.ts",
|
||||
"asar-webapp": "asar p webapp webapp.asar",
|
||||
"start": "nx start",
|
||||
"lint": "pnpm lint:types && pnpm lint:js",
|
||||
"lint:js": "eslint --max-warnings 0 src hak playwright scripts",
|
||||
"lint:js-fix": "eslint --fix --max-warnings 0 src hak playwright scripts",
|
||||
"lint": "pnpm lint:types",
|
||||
"lint:types": "pnpm lint:types:src && pnpm lint:types:node && pnpm lint:types:test && pnpm lint:types:scripts && pnpm lint:types:hak",
|
||||
"lint:types:src": "tsc --noEmit",
|
||||
"lint:types:node": "tsc --noEmit -p tsconfig.node.json",
|
||||
@@ -75,14 +73,11 @@
|
||||
"@electron/asar": "4.2.0",
|
||||
"@electron/fuses": "^2.1.1",
|
||||
"@playwright/test": "catalog:",
|
||||
"@stylistic/eslint-plugin": "^5.0.0",
|
||||
"@types/auto-launch": "^5.0.1",
|
||||
"@types/counterpart": "^0.18.1",
|
||||
"@types/minimist": "^1.2.1",
|
||||
"@types/node": "catalog:",
|
||||
"@types/pacote": "^11.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"app-builder-lib": "26.15.3",
|
||||
"chokidar": "^5.0.0",
|
||||
"detect-libc": "^2.0.0",
|
||||
@@ -90,12 +85,6 @@
|
||||
"electron-builder": "26.15.3",
|
||||
"electron-builder-squirrel-windows": "26.15.3",
|
||||
"electron-devtools-installer": "^4.0.0",
|
||||
"eslint": "^8.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-matrix-org": "^3.0.0",
|
||||
"eslint-plugin-n": "^17.12.0",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"glob": "^13.0.0",
|
||||
"matrix-web-i18n": "catalog:",
|
||||
"memfs": "^4.57.2",
|
||||
@@ -112,8 +101,7 @@
|
||||
},
|
||||
"nx": {
|
||||
"includedScripts": [
|
||||
"lint:types",
|
||||
"lint:js"
|
||||
"lint:types"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
// copies resources into the lib directory.
|
||||
|
||||
import parseArgs from "minimist";
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import * as path from "node:path";
|
||||
import { createWriteStream, promises as fs } from "node:fs";
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Script to generate incremental Nightly build versions, based on the latest Nightly build version of that kind.
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Checks for the presence of a webapp, inspects its version and prints it
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Checks for the presence of a webapp, inspects its version and sets the
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"strict": true,
|
||||
"lib": ["es2022"],
|
||||
"types": ["node"],
|
||||
"allowImportingTsExtensions": true
|
||||
"allowImportingTsExtensions": true,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["../src/@types", "./**/*.ts"]
|
||||
}
|
||||
|
||||
@@ -385,11 +385,13 @@ app.on("ready", async () => {
|
||||
desktopCapturer
|
||||
.getSources({ types: ["screen", "window"] })
|
||||
.then((sources) => {
|
||||
// oxlint-disable-next-line promise/no-callback-in-promise
|
||||
callback({ video: sources[0] });
|
||||
})
|
||||
.catch((err) => {
|
||||
// If the user cancels the dialog an error occurs "Failed to get sources"
|
||||
console.error("Wayland: failed to get user-selected source:", err);
|
||||
// oxlint-disable-next-line promise/no-callback-in-promise
|
||||
callback({ video: { id: "", name: "" } }); // The promise does not return if no dummy is passed here as source
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -144,7 +144,7 @@ ipcMain.on("ipcCall", async function (_ev: IpcMainEvent, payload) {
|
||||
}));
|
||||
break;
|
||||
case "callDisplayMediaCallback":
|
||||
await getDisplayMediaCallback()?.({ video: args[0] });
|
||||
getDisplayMediaCallback()?.({ video: args[0] });
|
||||
setDisplayMediaCallback(null);
|
||||
ret = null;
|
||||
break;
|
||||
|
||||
@@ -113,7 +113,7 @@ export class AppLocalization {
|
||||
locales = [locales];
|
||||
}
|
||||
|
||||
const loadedLocales = locales.filter((locale) => {
|
||||
const chosenLocale = locales.find((locale) => {
|
||||
const translations = this.fetchTranslationJson(locale);
|
||||
if (translations !== null) {
|
||||
counterpart.registerTranslations(locale, translations);
|
||||
@@ -121,7 +121,7 @@ export class AppLocalization {
|
||||
return !!translations;
|
||||
});
|
||||
|
||||
counterpart.setLocale(loadedLocales[0]);
|
||||
counterpart.setLocale(chosenLocale!);
|
||||
this.store.set(AppLocalization.STORE_KEY, locales);
|
||||
|
||||
this.resetLocalizedUI();
|
||||
|
||||
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
// This file is compiled to CommonJS rather than ESM otherwise the browser chokes on the import statement.
|
||||
|
||||
import { ipcRenderer, contextBridge, IpcRendererEvent } from "electron";
|
||||
import { ipcRenderer, contextBridge, type IpcRendererEvent } from "electron";
|
||||
import type { ConfigOptions } from "./config.js" with { "resolution-mode": "import" };
|
||||
|
||||
// Expose only expected IPC wrapper APIs to the renderer process to avoid
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
src/vector/modernizr.cjs
|
||||
test/end-to-end-tests/node_modules/
|
||||
test/end-to-end-tests/element/
|
||||
test/end-to-end-tests/synapse/
|
||||
test/end-to-end-tests/lib/
|
||||
# Legacy skinning file that some people might still have
|
||||
src/component-index.js
|
||||
# Auto-generated file
|
||||
src/modules.ts
|
||||
src/modules.js
|
||||
# Test result files
|
||||
/playwright/test-results/
|
||||
/playwright/html-report/
|
||||
|
||||
# Shared components generated files
|
||||
/packages/shared-components/dist/
|
||||
/packages/shared-components/src/i18n/i18nKeys.d.ts
|
||||
/packages/shared-components/typedoc/
|
||||
@@ -1,349 +0,0 @@
|
||||
/*
|
||||
Copyright 2025 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
plugins: ["matrix-org", "eslint-plugin-react-compiler"],
|
||||
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"],
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
globals: {
|
||||
LANGUAGES_FILE: "readonly",
|
||||
},
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"no-constant-condition": "off",
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
"no-extra-boolean-cast": "off",
|
||||
|
||||
// Bind or arrow functions in props causes performance issues (but we
|
||||
// currently use them in some places).
|
||||
// It's disabled here, but we should using it sparingly.
|
||||
"react/jsx-no-bind": "off",
|
||||
"react/jsx-key": ["error"],
|
||||
|
||||
"no-restricted-properties": [
|
||||
"error",
|
||||
...buildRestrictedPropertiesOptions(
|
||||
["window.innerHeight", "window.innerWidth", "window.visualViewport"],
|
||||
"Use UIStore to access window dimensions instead.",
|
||||
),
|
||||
...buildRestrictedPropertiesOptions(
|
||||
["React.forwardRef", "*.forwardRef", "forwardRef"],
|
||||
"Use ref props instead.",
|
||||
),
|
||||
...buildRestrictedPropertiesOptions(
|
||||
["*.mxcUrlToHttp", "*.getHttpUriForMxc"],
|
||||
"Use Media helper instead to centralise access for customisation.",
|
||||
),
|
||||
...buildRestrictedPropertiesOptions(["window.setImmediate"], "Use setTimeout instead."),
|
||||
],
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
name: "setImmediate",
|
||||
message: "Use setTimeout instead.",
|
||||
},
|
||||
{
|
||||
name: "Buffer",
|
||||
message: "Buffer is not available in the web.",
|
||||
},
|
||||
],
|
||||
|
||||
"import/no-duplicates": ["error"],
|
||||
// Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell.
|
||||
// Ban compound-design-tokens raw svg imports in favour of their React component counterparts
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: "react",
|
||||
importNames: ["forwardRef"],
|
||||
message: "Use ref props instead.",
|
||||
},
|
||||
{
|
||||
name: "@testing-library/react",
|
||||
message: "Please use jest-matrix-react instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src/",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src/index",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "emojibase-regex",
|
||||
message:
|
||||
"This regex doesn't actually test for emoji. See the docs at https://emojibase.dev/docs/regex/ and prefer our own EMOJI_REGEX from HtmlUtils.",
|
||||
},
|
||||
],
|
||||
patterns: [
|
||||
{
|
||||
group: [
|
||||
"matrix-js-sdk/src/**",
|
||||
"!matrix-js-sdk/src/matrix",
|
||||
"!matrix-js-sdk/src/crypto-api",
|
||||
"!matrix-js-sdk/src/types",
|
||||
"!matrix-js-sdk/src/testing",
|
||||
"!matrix-js-sdk/src/utils/**",
|
||||
"matrix-js-sdk/src/utils/internal/**",
|
||||
"matrix-js-sdk/lib",
|
||||
"matrix-js-sdk/lib/",
|
||||
"matrix-js-sdk/lib/**",
|
||||
// XXX: Temporarily allow these as they are not available via the main export
|
||||
"!matrix-js-sdk/src/logger",
|
||||
"!matrix-js-sdk/src/errors",
|
||||
"!matrix-js-sdk/src/utils",
|
||||
"!matrix-js-sdk/src/version-support",
|
||||
"!matrix-js-sdk/src/randomstring",
|
||||
"!matrix-js-sdk/src/sliding-sync",
|
||||
"!matrix-js-sdk/src/browser-index",
|
||||
"!matrix-js-sdk/src/feature",
|
||||
"!matrix-js-sdk/src/NamespacedValue",
|
||||
"!matrix-js-sdk/src/ReEmitter",
|
||||
"!matrix-js-sdk/src/event-mapper",
|
||||
"!matrix-js-sdk/src/interactive-auth",
|
||||
"!matrix-js-sdk/src/secret-storage",
|
||||
"!matrix-js-sdk/src/room-hierarchy",
|
||||
"!matrix-js-sdk/src/rendezvous",
|
||||
"!matrix-js-sdk/src/indexeddb-worker",
|
||||
"!matrix-js-sdk/src/pushprocessor",
|
||||
"!matrix-js-sdk/src/extensible_events_v1",
|
||||
"!matrix-js-sdk/src/extensible_events_v1/PollStartEvent",
|
||||
"!matrix-js-sdk/src/extensible_events_v1/PollResponseEvent",
|
||||
"!matrix-js-sdk/src/extensible_events_v1/PollEndEvent",
|
||||
"!matrix-js-sdk/src/extensible_events_v1/InvalidEventError",
|
||||
"!matrix-js-sdk/src/webrtc",
|
||||
"!matrix-js-sdk/src/webrtc/call",
|
||||
"!matrix-js-sdk/src/webrtc/callFeed",
|
||||
"!matrix-js-sdk/src/webrtc/mediaHandler",
|
||||
"!matrix-js-sdk/src/webrtc/callEventTypes",
|
||||
"!matrix-js-sdk/src/webrtc/callEventHandler",
|
||||
"!matrix-js-sdk/src/webrtc/groupCallEventHandler",
|
||||
"!matrix-js-sdk/src/models",
|
||||
"!matrix-js-sdk/src/models/read-receipt",
|
||||
"!matrix-js-sdk/src/models/relations-container",
|
||||
"!matrix-js-sdk/src/models/related-relations",
|
||||
"!matrix-js-sdk/src/matrixrtc",
|
||||
],
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
group: ["emojibase-regex/emoji*"],
|
||||
message:
|
||||
"This regex doesn't actually test for emoji. See the docs at https://emojibase.dev/docs/regex/ and prefer our own EMOJI_REGEX from HtmlUtils.",
|
||||
},
|
||||
{
|
||||
group: ["@vector-im/compound-design-tokens/icons/*"],
|
||||
message: "Please use @vector-im/compound-design-tokens/assets/web/icons/* instead",
|
||||
},
|
||||
{
|
||||
group: ["**/packages/shared-components/**", "../packages/shared-components/**"],
|
||||
message: "Please use @element-hq/web-shared-components",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// There are too many a11y violations to fix at once
|
||||
// Turn violated rules off until they are fixed
|
||||
"jsx-a11y/aria-activedescendant-has-tabindex": "off",
|
||||
"jsx-a11y/click-events-have-key-events": "off",
|
||||
"jsx-a11y/interactive-supports-focus": "off",
|
||||
"jsx-a11y/media-has-caption": "off",
|
||||
"jsx-a11y/mouse-events-have-key-events": "off",
|
||||
"jsx-a11y/no-autofocus": "off",
|
||||
"jsx-a11y/no-noninteractive-element-interactions": "off",
|
||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": "off",
|
||||
"jsx-a11y/no-noninteractive-tabindex": "off",
|
||||
"jsx-a11y/no-static-element-interactions": "off",
|
||||
"jsx-a11y/role-supports-aria-props": "off",
|
||||
|
||||
"matrix-org/require-copyright-header": "error",
|
||||
|
||||
"react-compiler/react-compiler": "error",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "playwright/**/*.ts", "*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
|
||||
rules: {
|
||||
"@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{
|
||||
allowExpressions: true,
|
||||
},
|
||||
],
|
||||
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"no-extra-boolean-cast": "off",
|
||||
|
||||
// Remove Babel things manually due to override limitations
|
||||
"@babel/no-invalid-this": ["off"],
|
||||
|
||||
// We're okay being explicit at the moment
|
||||
"@typescript-eslint/no-empty-interface": "off",
|
||||
// We disable this while we're transitioning
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We'd rather not do this but we do
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-empty-object-type": [
|
||||
"error",
|
||||
{
|
||||
// We do this sometimes to brand interfaces
|
||||
allowInterfaces: "with-single-extends",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"src/**/*.test.{ts,tsx}",
|
||||
"src/test/**/*.{ts,tsx}",
|
||||
"src/**/__mocks__/*.{ts,tsx}",
|
||||
"test/**/*.{ts,tsx}",
|
||||
"playwright/**/*.ts",
|
||||
],
|
||||
extends: [],
|
||||
rules: {
|
||||
// We don't need super strict typing in test utilities
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
// These are fine in tests
|
||||
"no-restricted-globals": "off",
|
||||
"react-compiler/react-compiler": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["test/**/*.{ts,tsx}"],
|
||||
extends: ["plugin:matrix-org/jest"],
|
||||
rules: {
|
||||
// Disabled tests are a reality for now but as soon as all of the xits are
|
||||
// eliminated, we should enforce this.
|
||||
"jest/no-disabled-tests": "off",
|
||||
// Also treat "oldBackendOnly" as a test function.
|
||||
// Used in some crypto tests.
|
||||
"jest/no-standalone-expect": [
|
||||
"error",
|
||||
{
|
||||
additionalTestBlockFunctions: ["beforeAll", "beforeEach", "oldBackendOnly"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["playwright/**/*.ts"],
|
||||
parserOptions: {
|
||||
project: ["./playwright/tsconfig.json"],
|
||||
},
|
||||
rules: {
|
||||
"react-hooks/rules-of-hooks": ["off"],
|
||||
"@typescript-eslint/no-floating-promises": ["error"],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["module_system/**/*.{ts,tsx}"],
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.module_system.json"],
|
||||
},
|
||||
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
|
||||
// NOTE: These rules are frozen and new rules should not be added here.
|
||||
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
// We disable this while we're transitioning
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
|
||||
// Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell.
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: "matrix-js-sdk",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src/",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
{
|
||||
name: "matrix-js-sdk/src/index",
|
||||
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||
},
|
||||
],
|
||||
patterns: [
|
||||
{
|
||||
group: ["matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**"],
|
||||
message: "Please use matrix-js-sdk/src/* instead",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function buildRestrictedPropertiesOptions(properties, message) {
|
||||
return properties.map((prop) => {
|
||||
let [object, property] = prop.split(".");
|
||||
if (object === "*") {
|
||||
object = undefined;
|
||||
}
|
||||
return {
|
||||
object,
|
||||
property,
|
||||
message,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"*": "oxfmt --no-error-on-unmatched-pattern",
|
||||
"src/**/*.(ts|tsx)": ["eslint --fix"],
|
||||
"scripts/**/*.(ts|tsx)": ["eslint --fix"],
|
||||
"module_system/**/*.(ts|tsx)": ["eslint --fix"],
|
||||
"*.{js,jsx,ts,tsx,mjs,cjs}": "oxlint --no-error-on-unmatched-pattern",
|
||||
"*.pcss": ["stylelint --fix"]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
extends: ["stylelint-config-standard"],
|
||||
customSyntax: "postcss-scss",
|
||||
|
||||
@@ -62,7 +62,7 @@ export class I18nWebpackPlugin {
|
||||
}
|
||||
|
||||
const primaryPath = paths[0];
|
||||
const includeLangs = [...new Set([...(await fs.readdir(primaryPath))])]
|
||||
const includeLangs = [...new Set(await fs.readdir(primaryPath))]
|
||||
.filter((fn) => fn.endsWith(".json"))
|
||||
.map((f) => f.slice(0, -5));
|
||||
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = "css-file-stub";
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
// Yes, this is empty.
|
||||
module.exports = {};
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = "image-file-stub";
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
export const Icon = "div";
|
||||
export default "image-file-stub";
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
sourceMaps: true,
|
||||
presets: [
|
||||
|
||||
@@ -134,9 +134,9 @@ function getOptionalDepNames(pkgJsonStr: string): string[] {
|
||||
function findDepVersionInPackageJson(dep: string, pkgJsonStr: string): string {
|
||||
const pkgJson = JSON.parse(pkgJsonStr);
|
||||
const packages = {
|
||||
...(pkgJson["optionalDependencies"] ?? {}),
|
||||
...(pkgJson["devDependencies"] ?? {}),
|
||||
...(pkgJson["dependencies"] ?? {}),
|
||||
...pkgJson["optionalDependencies"],
|
||||
...pkgJson["devDependencies"],
|
||||
...pkgJson["dependencies"],
|
||||
};
|
||||
return packages[dep];
|
||||
}
|
||||
|
||||
+1
-19
@@ -24,9 +24,7 @@
|
||||
"vendor:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js",
|
||||
"dist": "./scripts/package.sh",
|
||||
"start": "nx start",
|
||||
"lint": "pnpm lint:types && pnpm lint:js && pnpm lint:style",
|
||||
"lint:js": "eslint --max-warnings 0 src test playwright module_system",
|
||||
"lint:js-fix": "eslint --fix src test playwright module_system",
|
||||
"lint": "pnpm lint:types && pnpm lint:style",
|
||||
"lint:types": "nx lint:types",
|
||||
"lint:style": "stylelint \"res/css/**/*.pcss\"",
|
||||
"test": "nx test:unit",
|
||||
@@ -109,8 +107,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/eslint-parser": "^7.12.10",
|
||||
"@babel/eslint-plugin": "^7.12.10",
|
||||
"@babel/plugin-proposal-decorators": "^7.25.9",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
@@ -134,7 +130,6 @@
|
||||
"@playwright/test": "catalog:",
|
||||
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
|
||||
"@sentry/webpack-plugin": "^5.0.0",
|
||||
"@stylistic/eslint-plugin": "^5.0.0",
|
||||
"@svgr/webpack": "^8.0.0",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.4.8",
|
||||
@@ -164,8 +159,6 @@
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/tar-js": "^0.3.5",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@typescript-eslint/eslint-plugin": "^8.19.0",
|
||||
"@typescript-eslint/parser": "^8.19.0",
|
||||
"@vitest/spy": "catalog:",
|
||||
"babel-jest": "^30.0.0",
|
||||
"babel-loader": "^10.0.0",
|
||||
@@ -175,17 +168,6 @@
|
||||
"css-loader": "^7.0.0",
|
||||
"css-minimizer-webpack-plugin": "^8.0.0",
|
||||
"dotenv": "^17.0.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-deprecate": "0.9.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^29.0.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-matrix-org": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-compiler": "^19.0.0-beta-df7b47d-20241124",
|
||||
"eslint-plugin-react-hooks": "^7.0.0",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"express": "^5.0.0",
|
||||
"fake-indexeddb": "^6.0.0",
|
||||
"file-loader": "^6.0.0",
|
||||
|
||||
@@ -52,7 +52,7 @@ test.describe("Custom Component API", () => {
|
||||
async ({ page, room, app }) => {
|
||||
await app.viewRoomById(room.roomId);
|
||||
await app.client.sendMessage(room.roomId, "Simple message");
|
||||
await expect(await page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
await expect(page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
"custom-component-tile.png",
|
||||
screenshotOptions(page),
|
||||
);
|
||||
@@ -64,7 +64,7 @@ test.describe("Custom Component API", () => {
|
||||
async ({ page, room, app }) => {
|
||||
await app.viewRoomById(room.roomId);
|
||||
await app.client.sendMessage(room.roomId, "Fall through here");
|
||||
await expect(await page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
await expect(page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
"custom-component-tile-fall-through.png",
|
||||
screenshotOptions(page),
|
||||
);
|
||||
@@ -76,7 +76,7 @@ test.describe("Custom Component API", () => {
|
||||
async ({ page, room, app }) => {
|
||||
await app.viewRoomById(room.roomId);
|
||||
await app.client.sendMessage(room.roomId, "Do not replace me");
|
||||
await expect(await page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
await expect(page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
"custom-component-tile-original.png",
|
||||
screenshotOptions(page),
|
||||
);
|
||||
@@ -87,7 +87,7 @@ test.describe("Custom Component API", () => {
|
||||
await app.client.sendMessage(room.roomId, "Do not show edits");
|
||||
await page.getByText("Do not show edits").hover();
|
||||
await expect(
|
||||
await page.getByRole("toolbar", { name: "Message Actions" }).getByRole("button", { name: "Edit" }),
|
||||
page.getByRole("toolbar", { name: "Message Actions" }).getByRole("button", { name: "Edit" }),
|
||||
).not.toBeVisible();
|
||||
});
|
||||
test("should disallow downloading media when the allowDownloading hint is set to false", async ({
|
||||
@@ -148,7 +148,7 @@ test.describe("Custom Component API", () => {
|
||||
async ({ page, room, app }) => {
|
||||
await app.viewRoomById(room.roomId);
|
||||
await app.client.sendMessage(room.roomId, "Crash the filter!");
|
||||
await expect(await page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
await expect(page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
"custom-component-crash-handle-filter.png",
|
||||
screenshotOptions(page),
|
||||
);
|
||||
@@ -160,7 +160,7 @@ test.describe("Custom Component API", () => {
|
||||
async ({ page, room, app }) => {
|
||||
await app.viewRoomById(room.roomId);
|
||||
await app.client.sendMessage(room.roomId, "Crash the renderer!");
|
||||
await expect(await page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
await expect(page.locator(".mx_EventTile_last")).toMatchScreenshot(
|
||||
"custom-component-crash-handle-renderer.png",
|
||||
screenshotOptions(page),
|
||||
);
|
||||
|
||||
@@ -193,7 +193,7 @@ test.describe("Read receipts", { tag: "@mergequeue" }, () => {
|
||||
await page.getByRole("button", { name: "React" }).click();
|
||||
await page.locator(".mx_EmojiPicker_body").getByText("😀").first().click();
|
||||
await page.locator(".mx_ThreadPanel").getByLabel("Mae reacted with 😀").click();
|
||||
await expect(await page.locator(".mx_ThreadPanel").getByLabel("Mae reacted with 😀")).not.toBeVisible();
|
||||
await expect(page.locator(".mx_ThreadPanel").getByLabel("Mae reacted with 😀")).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ test.describe("RightPanel", () => {
|
||||
test("should have padding under leave room", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
const leaveButton = await page.getByRole("menuitem", { name: "Leave Room" });
|
||||
const leaveButton = page.getByRole("menuitem", { name: "Leave Room" });
|
||||
await leaveButton.scrollIntoViewIfNeeded();
|
||||
|
||||
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-leave-room.png");
|
||||
@@ -177,7 +177,7 @@ test.describe("RightPanel", () => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Report room" }).click();
|
||||
const dialog = await page.getByRole("dialog", { name: "Report Room" });
|
||||
const dialog = page.getByRole("dialog", { name: "Report Room" });
|
||||
await dialog.getByLabel("reason").fill("This room should be reported");
|
||||
await expect(dialog).toMatchScreenshot("room-report-dialog.png");
|
||||
await dialog.getByRole("button", { name: "Send report" }).click();
|
||||
@@ -189,7 +189,7 @@ test.describe("RightPanel", () => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Report room" }).click();
|
||||
const dialog = await page.getByRole("dialog", { name: "Report room" });
|
||||
const dialog = page.getByRole("dialog", { name: "Report room" });
|
||||
await dialog.getByRole("switch", { name: "Leave room" }).click();
|
||||
await dialog.getByLabel("reason").fill("This room should be reported");
|
||||
await dialog.getByRole("button", { name: "Send report" }).click();
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ test.describe("Roles & Permissions room settings tab", () => {
|
||||
await combobox.selectOption("Moderator");
|
||||
|
||||
// Should display a modal to warn that we are demoting the only admin user
|
||||
const modal = await page.locator(".mx_Dialog", {
|
||||
const modal = page.locator(".mx_Dialog", {
|
||||
hasText: "Warning",
|
||||
});
|
||||
await expect(modal).toBeVisible();
|
||||
|
||||
@@ -126,7 +126,7 @@ test.describe("Roles & Permissions room settings tab", () => {
|
||||
// Element should have automatically set the room to "sharing" history visibility
|
||||
const errorDialog = page.getByRole("heading", { name: "Cannot make room private" });
|
||||
await expect(errorDialog).toBeVisible();
|
||||
await errorDialog.getByLabel("OK");
|
||||
errorDialog.getByLabel("OK");
|
||||
await expect(settingsGroupHistory.getByText("Anyone")).toBeChecked();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -30,6 +30,6 @@ test.describe("share from URL", () => {
|
||||
const lastMessage = page.locator(".mx_RoomView_MessageList .mx_EventTile_last");
|
||||
await expect(lastMessage).toBeVisible();
|
||||
const lastMessageText = await lastMessage.locator(".mx_EventTile_body").innerText();
|
||||
await expect(lastMessageText).toBe("Hello world");
|
||||
expect(lastMessageText).toBe("Hello world");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@ const sendImage = async (
|
||||
): Promise<ISendEventResponse> => {
|
||||
const upload = await client.uploadContent(pngBytes, { name: "image.png", type: "image/png" });
|
||||
return client.sendEvent(roomId, null, "m.room.message" as EventType, {
|
||||
...(additionalContent ?? {}),
|
||||
...additionalContent,
|
||||
|
||||
msgtype: "m.image" as MsgType,
|
||||
body: "image.png",
|
||||
|
||||
@@ -153,7 +153,7 @@ test.describe("Element Call", () => {
|
||||
await page.getByRole("menuitem", { name: "Element Call" }).click();
|
||||
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
// Ensure we set the correct parameters for ECall.
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
@@ -179,7 +179,7 @@ test.describe("Element Call", () => {
|
||||
await page.keyboard.up("Shift");
|
||||
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -204,7 +204,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -254,7 +254,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -283,7 +283,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -317,7 +317,7 @@ test.describe("Element Call", () => {
|
||||
await page.getByRole("menuitem", { name: "Element Call" }).click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -335,7 +335,7 @@ test.describe("Element Call", () => {
|
||||
await page.keyboard.up("Shift");
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -351,7 +351,7 @@ test.describe("Element Call", () => {
|
||||
await page.getByRole("menuitem", { name: "Element Call" }).click();
|
||||
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
|
||||
// The call should be presented in the picture-in-picture container, right in the room we started it
|
||||
// from, rather than taking over the room view.
|
||||
@@ -369,7 +369,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -409,7 +409,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -443,7 +443,7 @@ test.describe("Element Call", () => {
|
||||
// And test joining
|
||||
await button.click();
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
assertCommonCallParameters(url.searchParams, hash, user, room);
|
||||
@@ -475,7 +475,7 @@ test.describe("Element Call", () => {
|
||||
const roomId = new URL(page.url()).hash.slice("#/room/".length);
|
||||
|
||||
const frameUrlStr = await page.locator("iframe").getAttribute("src");
|
||||
await expect(frameUrlStr).toBeDefined();
|
||||
expect(frameUrlStr).toBeDefined();
|
||||
// Ensure we set the correct parameters for ECall.
|
||||
const url = new URL(frameUrlStr);
|
||||
const hash = new URLSearchParams(url.hash.slice(1));
|
||||
@@ -518,7 +518,7 @@ test.describe("Element Call", () => {
|
||||
await expect(callFrame.getByText("In call", { exact: true })).toBeVisible();
|
||||
|
||||
// Wait for Element Web to pickup the RTC session and update the room list entry.
|
||||
await expect(await page.getByTestId("notification-decoration")).toBeVisible();
|
||||
await expect(page.getByTestId("notification-decoration")).toBeVisible();
|
||||
}
|
||||
|
||||
test("should be able to switch rooms and have the call persist", async ({ page, user, room, app }) => {
|
||||
@@ -558,9 +558,9 @@ test.describe("Element Call", () => {
|
||||
await expect(pipContainer).not.toBeVisible();
|
||||
|
||||
// Wait for call to stop.
|
||||
await expect(await page.getByTestId("notification-decoration")).not.toBeVisible();
|
||||
await expect(page.getByTestId("notification-decoration")).not.toBeVisible();
|
||||
await app.viewRoomById(room.roomId);
|
||||
await expect(await page.getByTestId("join-call-button")).not.toBeVisible();
|
||||
await expect(page.getByTestId("join-call-button")).not.toBeVisible();
|
||||
|
||||
// Join the call again.
|
||||
await openAndJoinCall(page);
|
||||
@@ -590,8 +590,8 @@ test.describe("Element Call", () => {
|
||||
await expect(pipContainer).not.toBeVisible();
|
||||
|
||||
// Wait for call to stop.
|
||||
await expect(await page.getByTestId("notification-decoration")).not.toBeVisible();
|
||||
await expect(await page.getByTestId("join-call-button")).not.toBeVisible();
|
||||
await expect(page.getByTestId("notification-decoration")).not.toBeVisible();
|
||||
await expect(page.getByTestId("join-call-button")).not.toBeVisible();
|
||||
|
||||
// Join the call again, but from the other room.
|
||||
await openAndJoinCall(page);
|
||||
|
||||
@@ -202,7 +202,7 @@ export class Client {
|
||||
/**
|
||||
* Create a room with given options.
|
||||
* @param options the options to apply when creating the room
|
||||
* @return the ID of the newly created room
|
||||
* @returns the ID of the newly created room
|
||||
*/
|
||||
public async createRoom(options: ICreateRoomOpts): Promise<string> {
|
||||
const client = await this.prepareClient();
|
||||
@@ -217,7 +217,7 @@ export class Client {
|
||||
/**
|
||||
* Create a space with given options.
|
||||
* @param options the options to apply when creating the space
|
||||
* @return the ID of the newly created space (room)
|
||||
* @returns the ID of the newly created space (room)
|
||||
*/
|
||||
public async createSpace(options: ICreateRoomOpts): Promise<string> {
|
||||
return this.createRoom({
|
||||
@@ -412,8 +412,8 @@ export class Client {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {module:client.callback} callback Optional.
|
||||
* @return {Promise} Resolves: {} an empty object.
|
||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||
* @returns {Promise} Resolves: {} an empty object.
|
||||
* @returns {module:http-api.MatrixError} Rejects: with an error response.
|
||||
*/
|
||||
public async setDisplayName(name: string): Promise<EmptyObject> {
|
||||
const client = await this.prepareClient();
|
||||
@@ -423,8 +423,8 @@ export class Client {
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {module:client.callback} callback Optional.
|
||||
* @return {Promise} Resolves: {} an empty object.
|
||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||
* @returns {Promise} Resolves: {} an empty object.
|
||||
* @returns {module:http-api.MatrixError} Rejects: with an error response.
|
||||
*/
|
||||
public async setAvatarUrl(url: string): Promise<EmptyObject> {
|
||||
const client = await this.prepareClient();
|
||||
|
||||
@@ -41,7 +41,7 @@ export class Settings {
|
||||
* null.
|
||||
* @param {SettingLevel} level The level to change the value at.
|
||||
* @param {*} value The new value of the setting, may be null.
|
||||
* @return {Promise} Resolves when the setting has been changed.
|
||||
* @returns {Promise} Resolves when the setting has been changed.
|
||||
*/
|
||||
public async setValue(settingName: string, roomId: string | null, level: SettingLevel, value: any): Promise<void> {
|
||||
return this.page.evaluate<
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"allowImportingTsExtensions": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"types": ["node"]
|
||||
"types": ["node"],
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Quick-n-dirty algebraic datatypes.
|
||||
*
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
class StartupError extends Error {}
|
||||
|
||||
/*
|
||||
@@ -165,7 +172,7 @@ function BundlePicker() {
|
||||
setBundle(name);
|
||||
}
|
||||
}, console.log.bind(console));
|
||||
}, [baseUrl]);
|
||||
}, [baseUrl, bundle]);
|
||||
|
||||
/* ------------------------- */
|
||||
/* Follow user state changes */
|
||||
|
||||
Vendored
+2
-2
@@ -70,8 +70,8 @@ declare global {
|
||||
// so we don't accidentally use the methods on NodeJS.Timeout - they only exist in a subset of environments.
|
||||
// The overload for clear{Interval,Timeout} is resolved as expected.
|
||||
// We use `ReturnType<typeof setTimeout>` in the code to be agnostic of if this definition gets loaded.
|
||||
function setInterval(handler: TimerHandler, timeout: number, ...arguments: any[]): number;
|
||||
function setTimeout(handler: TimerHandler, timeout: number, ...arguments: any[]): number;
|
||||
function setInterval(handler: TimerHandler, timeout: number, ...args: any[]): number;
|
||||
function setTimeout(handler: TimerHandler, timeout: number, ...args: any[]): number;
|
||||
|
||||
interface Window {
|
||||
mxSendRageshake: (text: string, withLogs?: boolean) => Promise<void>;
|
||||
|
||||
@@ -69,7 +69,7 @@ export default class AddThreepid {
|
||||
* Attempt to add an email threepid to the homeserver.
|
||||
* This will trigger a side-effect of sending an email to the provided email address.
|
||||
* @param {string} emailAddress The email address to add
|
||||
* @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
||||
* @returns {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
||||
*/
|
||||
public async addEmailAddress(emailAddress: string): Promise<IRequestTokenResponse> {
|
||||
try {
|
||||
@@ -91,7 +91,7 @@ export default class AddThreepid {
|
||||
* Attempt to bind an email threepid on the identity server via the homeserver.
|
||||
* This will trigger a side-effect of sending an email to the provided email address.
|
||||
* @param {string} emailAddress The email address to add
|
||||
* @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
||||
* @returns {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
||||
*/
|
||||
public async bindEmailAddress(emailAddress: string): Promise<IRequestTokenResponse> {
|
||||
this.bind = true;
|
||||
@@ -122,7 +122,7 @@ export default class AddThreepid {
|
||||
* This will trigger a side-effect of sending an SMS to the provided phone number.
|
||||
* @param {string} phoneCountry The ISO 2 letter code of the country to resolve phoneNumber in
|
||||
* @param {string} phoneNumber The national or international formatted phone number to add
|
||||
* @return {Promise} Resolves when the text message has been sent. Then call haveMsisdnToken().
|
||||
* @returns {Promise} Resolves when the text message has been sent. Then call haveMsisdnToken().
|
||||
*
|
||||
* @throws {UserFriendlyError} An appropriate user-friendly error if the verification code could not be sent.
|
||||
*/
|
||||
@@ -155,7 +155,7 @@ export default class AddThreepid {
|
||||
* This will trigger a side-effect of sending an SMS to the provided phone number.
|
||||
* @param {string} phoneCountry The ISO 2 letter code of the country to resolve phoneNumber in
|
||||
* @param {string} phoneNumber The national or international formatted phone number to add
|
||||
* @return {Promise} Resolves when the text message has been sent. Then call haveMsisdnToken().
|
||||
* @returns {Promise} Resolves when the text message has been sent. Then call haveMsisdnToken().
|
||||
*/
|
||||
public async bindMsisdn(phoneCountry: string, phoneNumber: string): Promise<IRequestMsisdnTokenResponse> {
|
||||
this.bind = true;
|
||||
@@ -184,7 +184,7 @@ export default class AddThreepid {
|
||||
|
||||
/**
|
||||
* Checks if the email link has been clicked by attempting to add the threepid
|
||||
* @return {Promise} Resolves if the email address was added. Rejects with an object
|
||||
* @returns {Promise} Resolves if the email address was added. Rejects with an object
|
||||
* with a "message" property which contains a human-readable message detailing why
|
||||
* the request failed.
|
||||
*/
|
||||
@@ -254,7 +254,7 @@ export default class AddThreepid {
|
||||
|
||||
/**
|
||||
* @param {{type: string, session?: string}} auth UI auth object
|
||||
* @return {Promise<Object>} Response from /3pid/add call (in current spec, an empty object)
|
||||
* @returns {Promise<Object>} Response from /3pid/add call (in current spec, an empty object)
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
private makeAddThreepidOnlyRequest = (auth?: IAddThreePidOnlyBody["auth"] | null): Promise<{}> => {
|
||||
@@ -269,7 +269,7 @@ export default class AddThreepid {
|
||||
* Takes a phone number verification code as entered by the user and validates
|
||||
* it with the identity server, then if successful, adds the phone number.
|
||||
* @param {string} msisdnToken phone number verification code as entered by the user
|
||||
* @return {Promise} Resolves if the phone number was added. Rejects with an object
|
||||
* @returns {Promise} Resolves if the phone number was added. Rejects with an object
|
||||
* with a "message" property which contains a human-readable message detailing why
|
||||
* the request failed.
|
||||
*/
|
||||
|
||||
@@ -137,7 +137,7 @@ export function defaultAvatarUrlForString(s: string): string {
|
||||
* returns the first (non-sigil) character of 'name',
|
||||
* converted to uppercase
|
||||
* @param {string} name
|
||||
* @return {string} the first letter
|
||||
* @returns {string} the first letter
|
||||
*/
|
||||
export function getInitialLetter(name: string): string | undefined {
|
||||
if (!name) {
|
||||
|
||||
@@ -279,7 +279,7 @@ export default abstract class BasePlatform {
|
||||
/**
|
||||
* Get our platform specific EventIndexManager.
|
||||
*
|
||||
* @return {BaseEventIndexManager} The EventIndex manager for our platform,
|
||||
* @returns {BaseEventIndexManager} The EventIndex manager for our platform,
|
||||
* can be null if the platform doesn't support event indexing.
|
||||
*/
|
||||
public getEventIndexingManager(): BaseEventIndexManager | null {
|
||||
|
||||
@@ -77,7 +77,7 @@ interface IMediaConfig {
|
||||
* Load a file into a newly created image element.
|
||||
*
|
||||
* @param {File} imageFile The file to load in an image element.
|
||||
* @return {Promise} A promise that resolves with the html image element.
|
||||
* @returns {Promise} A promise that resolves with the html image element.
|
||||
*/
|
||||
async function loadImageElement(imageFile: File): Promise<{
|
||||
width: number;
|
||||
@@ -148,7 +148,7 @@ const ALWAYS_INCLUDE_THUMBNAIL = ["image/avif", "image/webp", "image/svg+xml"];
|
||||
* @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with.
|
||||
* @param {String} roomId The ID of the room the image will be uploaded in.
|
||||
* @param {File} imageFile The image to read and thumbnail.
|
||||
* @return {Promise} A promise that resolves with the attachment info.
|
||||
* @returns {Promise} A promise that resolves with the attachment info.
|
||||
*/
|
||||
async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imageFile: File): Promise<ImageInfo> {
|
||||
let thumbnailType = "image/png";
|
||||
@@ -196,7 +196,7 @@ async function infoForImageFile(matrixClient: MatrixClient, roomId: string, imag
|
||||
* Load a file into a newly created audio element and load the metadata
|
||||
*
|
||||
* @param {File} audioFile The file to load in an audio element.
|
||||
* @return {Promise} A promise that resolves with the audio element.
|
||||
* @returns {Promise} A promise that resolves with the audio element.
|
||||
*/
|
||||
function loadAudioElement(audioFile: File): Promise<HTMLAudioElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -228,7 +228,7 @@ function loadAudioElement(audioFile: File): Promise<HTMLAudioElement> {
|
||||
* Read the metadata for an audio file.
|
||||
*
|
||||
* @param {File} audioFile The audio to read.
|
||||
* @return {Promise} A promise that resolves with the attachment info.
|
||||
* @returns {Promise} A promise that resolves with the attachment info.
|
||||
*/
|
||||
async function infoForAudioFile(audioFile: File): Promise<AudioInfo> {
|
||||
const audio = await loadAudioElement(audioFile);
|
||||
@@ -240,7 +240,7 @@ async function infoForAudioFile(audioFile: File): Promise<AudioInfo> {
|
||||
* in an attempt to guarantee the first frame will be showing.
|
||||
*
|
||||
* @param {File} videoFile The file to load in a video element.
|
||||
* @return {Promise} A promise that resolves with the video element.
|
||||
* @returns {Promise} A promise that resolves with the video element.
|
||||
*/
|
||||
function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -286,7 +286,7 @@ function loadVideoElement(videoFile: File): Promise<HTMLVideoElement> {
|
||||
* @param {MatrixClient} matrixClient A matrixClient to upload the thumbnail with.
|
||||
* @param {String} roomId The ID of the room the video will be uploaded to.
|
||||
* @param {File} videoFile The video to read and thumbnail.
|
||||
* @return {Promise} A promise that resolves with the attachment info.
|
||||
* @returns {Promise} A promise that resolves with the attachment info.
|
||||
*/
|
||||
function infoForVideoFile(matrixClient: MatrixClient, roomId: string, videoFile: File): Promise<VideoInfo> {
|
||||
const thumbnailType = "image/jpeg";
|
||||
@@ -311,7 +311,7 @@ function infoForVideoFile(matrixClient: MatrixClient, roomId: string, videoFile:
|
||||
/**
|
||||
* Read the file as an ArrayBuffer.
|
||||
* @param {File} file The file to read
|
||||
* @return {Promise} A promise that resolves with an ArrayBuffer when the file
|
||||
* @returns {Promise} A promise that resolves with an ArrayBuffer when the file
|
||||
* is read.
|
||||
*/
|
||||
function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> {
|
||||
@@ -337,7 +337,7 @@ function readFileAsArrayBuffer(file: File | Blob): Promise<ArrayBuffer> {
|
||||
* @param {Function?} progressHandler optional callback to be called when a chunk of
|
||||
* data is uploaded.
|
||||
* @param {AbortController?} controller optional abortController to use for this upload.
|
||||
* @return {Promise} A promise that resolves with an object.
|
||||
* @returns {Promise} A promise that resolves with an object.
|
||||
* If the file is unencrypted then the object will have a "url" key.
|
||||
* If the file is encrypted then the object will have a "file" key.
|
||||
*/
|
||||
|
||||
@@ -79,7 +79,7 @@ function mightContainEmoji(str?: string): boolean {
|
||||
* Returns the shortcode for an emoji character.
|
||||
*
|
||||
* @param {String} char The emoji character
|
||||
* @return {String} The shortcode (such as :thumbup:)
|
||||
* @returns {String} The shortcode (such as :thumbup:)
|
||||
*/
|
||||
export function unicodeToShortcode(char: string): string {
|
||||
const shortcodes = getEmojiFromUnicode(char)?.shortcodes;
|
||||
@@ -119,7 +119,7 @@ export function getHtmlText(insaneHtml: string): string {
|
||||
* Note that the HTML sanitiser library has its own internal logic for
|
||||
* doing this, to which we pass the same list of schemes. This is used in
|
||||
* other places we need to sanitise URLs.
|
||||
* @return true if permitted, otherwise false
|
||||
* @returns true if permitted, otherwise false
|
||||
*/
|
||||
export function isUrlPermitted(inputUrl: string): boolean {
|
||||
try {
|
||||
@@ -497,7 +497,7 @@ export function bodyToHtml(content: IContent, highlights?: string[], opts: Event
|
||||
* @param htmlTopic optional html topic
|
||||
* @param ref React ref to attach to any React components returned
|
||||
* @param allowExtendedHtml whether to allow extended HTML tags such as headings and lists
|
||||
* @return The HTML-ified node.
|
||||
* @returns The HTML-ified node.
|
||||
*/
|
||||
export function topicToHtml(
|
||||
topic?: string,
|
||||
|
||||
@@ -54,7 +54,7 @@ export default class MediaDeviceHandler extends EventEmitter {
|
||||
* (https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API)
|
||||
* is ready for primetime, it might help make this simpler.
|
||||
*
|
||||
* @return Promise<IMediaDevices> The available media devices
|
||||
* @returns Promise<IMediaDevices> The available media devices
|
||||
*/
|
||||
public static async getDevices(): Promise<IMediaDevices | undefined> {
|
||||
try {
|
||||
|
||||
@@ -185,7 +185,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
* caused a chunk of tests to fail, so for now they continue to use this.
|
||||
*
|
||||
* @param reason either "backgroundClick" or undefined
|
||||
* @return whether a modal was closed
|
||||
* @returns whether a modal was closed
|
||||
*/
|
||||
public closeCurrentModal(reason?: ModalCloseReason): boolean {
|
||||
const modal = this.getCurrentModal();
|
||||
@@ -297,7 +297,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
/**
|
||||
* @callback onBeforeClose
|
||||
* @param {string?} reason either "backgroundClick" or null
|
||||
* @return {Promise<bool>} whether the dialog should close
|
||||
* @returns {Promise<bool>} whether the dialog should close
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -393,6 +393,7 @@ export default class Notifier extends TypedEventEmitter<keyof EmittedEvents, Emi
|
||||
return;
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line promise/no-callback-in-promise
|
||||
if (callback) callback();
|
||||
|
||||
this.sdkContext.posthogAnalytics.trackEvent<PermissionChangedEvent>({
|
||||
|
||||
@@ -73,7 +73,7 @@ export default class PasswordReset {
|
||||
/**
|
||||
* Checks if the email link has been clicked by attempting to change the password
|
||||
* for the mxid linked to the email.
|
||||
* @return {Promise} Resolves if the password was reset. Rejects with an object
|
||||
* @returns {Promise} Resolves if the password was reset. Rejects with an object
|
||||
* with a "message" property which contains a human-readable message detailing why
|
||||
* the reset failed, e.g. "There is no mapped matrix user ID for the given email address".
|
||||
*/
|
||||
|
||||
@@ -127,7 +127,7 @@ describe("PosthogAnalytics", () => {
|
||||
|
||||
it("Should not track events if anonymous", async () => {
|
||||
analytics.setAnonymity(Anonymity.Anonymous);
|
||||
await analytics.trackEvent<ITestEvent>({
|
||||
analytics.trackEvent<ITestEvent>({
|
||||
eventName: "TestEvents",
|
||||
foo: "bar",
|
||||
});
|
||||
|
||||
@@ -227,7 +227,7 @@ export default class ScalarAuthClient {
|
||||
* This can be useful to temporarily prevent purchased assets from being displayed.
|
||||
* @param {WidgetType} widgetType The Widget Type to disable assets for
|
||||
* @param {string} widgetId The widget ID to disable assets for
|
||||
* @return {Promise} Resolves on completion
|
||||
* @returns {Promise} Resolves on completion
|
||||
*/
|
||||
public async disableWidgetAssets(widgetType: WidgetType, widgetId: string): Promise<void> {
|
||||
const url = new URL(this.getStarterLink(this.apiUrl + "/widgets/set_assets_state"));
|
||||
|
||||
@@ -412,7 +412,7 @@ function combineEventSources(
|
||||
* index.
|
||||
* @param {object} serverEvents An unprocessed search result from the server.
|
||||
*
|
||||
* @return {object} A response object that combines the events from the
|
||||
* @returns {object} A response object that combines the events from the
|
||||
* different event sources.
|
||||
*
|
||||
*/
|
||||
@@ -476,7 +476,7 @@ function combineEvents(
|
||||
* index.
|
||||
* @param {object} serverEvents An unprocessed search result from the server.
|
||||
*
|
||||
* @return {object} A response object that combines the events from the
|
||||
* @returns {object} A response object that combines the events from the
|
||||
* different event sources.
|
||||
*/
|
||||
function combineResponses(
|
||||
|
||||
@@ -253,9 +253,9 @@ export class SlidingSyncManager {
|
||||
try {
|
||||
// if we only have range changes then call a different function so we don't nuke the list from before
|
||||
if (updateArgs.ranges && Object.keys(updateArgs).length === 1) {
|
||||
await this.slidingSync!.setListRanges(listKey, updateArgs.ranges);
|
||||
this.slidingSync!.setListRanges(listKey, updateArgs.ranges);
|
||||
} else {
|
||||
await this.slidingSync!.setList(listKey, list);
|
||||
this.slidingSync!.setList(listKey, list);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.debug("ensureListRegistered: update failed txn_id=", err);
|
||||
@@ -391,7 +391,7 @@ export class SlidingSyncManager {
|
||||
/**
|
||||
* Check if the server "natively" supports sliding sync (with an unstable endpoint).
|
||||
* @param client The MatrixClient to use
|
||||
* @return Whether the "native" (unstable) endpoint is supported
|
||||
* @returns Whether the "native" (unstable) endpoint is supported
|
||||
*/
|
||||
public async nativeSlidingSyncSupport(client: MatrixClient): Promise<boolean> {
|
||||
// Per https://github.com/matrix-org/matrix-spec-proposals/pull/3575/files#r1589542561
|
||||
|
||||
@@ -22,7 +22,6 @@ export function getUserTimezone(): string | undefined {
|
||||
|
||||
/**
|
||||
* Set in the settings the given timezone
|
||||
* @timezone
|
||||
*/
|
||||
export function setUserTimezone(timezone: string): Promise<void> {
|
||||
return SettingsStore.setValue(USER_TIMEZONE_KEY, null, SettingLevel.DEVICE, timezone);
|
||||
|
||||
@@ -299,7 +299,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||
|
||||
// Finally do our post-processing and clean up
|
||||
this.recording = false;
|
||||
await this.recorder!.close();
|
||||
this.recorder!.close();
|
||||
this.emit(RecordingState.Ended);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ export default abstract class AutocompleteProvider {
|
||||
* @param {string} query The query string
|
||||
* @param {ISelectionRange} selection Selection to search
|
||||
* @param {boolean} force True if the user is forcing completion
|
||||
* @return {object} { command, range } where both objects fields are null if no match
|
||||
* @returns {object} { command, range } where both objects fields are null if no match
|
||||
*/
|
||||
public getCurrentCommand(query: string, selection: ISelectionRange, force = false): Partial<ICommand> {
|
||||
let commandRegex = this.commandRegex;
|
||||
|
||||
@@ -6,8 +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, { type JSX } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
import React, { type JSX, useContext, useState } from "react";
|
||||
import { ChatSolidIcon, ExploreIcon, GroupIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import { AutoHideScrollbar } from "@element-hq/web-shared-components";
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit): void {
|
||||
const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
||||
if (error) {
|
||||
usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit;
|
||||
usageLimitEventContent = (syncError?.error as MatrixError)?.data as IUsageLimit;
|
||||
}
|
||||
|
||||
// usageLimitDismissed is true when the user has explicitly hidden the toast
|
||||
|
||||
@@ -691,7 +691,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
break;
|
||||
case "logout":
|
||||
this.stores.legacyCallHandler.hangupAllCalls();
|
||||
Promise.all([...[...CallStore.instance.connectedCalls].map((call) => call.disconnect())]).finally(() =>
|
||||
Promise.all([...CallStore.instance.connectedCalls].map((call) => call.disconnect())).finally(() =>
|
||||
Lifecycle.logout(),
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -25,7 +25,6 @@ interface ReleaseAnnouncementProps extends Omit<
|
||||
* @param feature - the feature to announce, should be listed in {@link Feature}
|
||||
* @param children
|
||||
* @param props
|
||||
* @constructor
|
||||
*/
|
||||
export function ReleaseAnnouncement({
|
||||
feature,
|
||||
|
||||
@@ -366,7 +366,7 @@ interface ILocalRoomCreateLoaderProps {
|
||||
* Room create loader view displaying a message and a spinner.
|
||||
*
|
||||
* @param {ILocalRoomCreateLoaderProps} props Room view props
|
||||
* @return {ReactElement}
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
function LocalRoomCreateLoader(props: ILocalRoomCreateLoaderProps): ReactElement {
|
||||
const text = _t("room|creating_room_text", { names: props.names });
|
||||
|
||||
@@ -798,7 +798,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
|
||||
|
||||
// Walk back up the tree to find all parents of the direct matches to show their place in the hierarchy
|
||||
const visited = new Set<string>();
|
||||
const queue = [...directMatches.map((r) => r.room_id)];
|
||||
const queue = directMatches.map((r) => r.room_id);
|
||||
while (queue.length) {
|
||||
const roomId = queue.pop()!;
|
||||
visited.add(roomId);
|
||||
|
||||
@@ -1728,7 +1728,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
* have been sent by the server, not
|
||||
* implicit ones generated by the JS
|
||||
* SDK.
|
||||
* @return {String} the event ID
|
||||
* @returns {String} the event ID
|
||||
*/
|
||||
private getCurrentReadReceipt(ignoreSynthesized = false): string | null {
|
||||
const client = MatrixClientPeg.get();
|
||||
@@ -1886,7 +1886,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||
* Iterate across all of the timelineSets and timelines inside to expose all of
|
||||
* the event IDs contained inside.
|
||||
*
|
||||
* @return An event ID list for every timeline in every timelineSet
|
||||
* @returns An event ID list for every timeline in every timelineSet
|
||||
*/
|
||||
function serializeEventIdsFromTimelineSets(timelineSets: EventTimelineSet[]): { [key: string]: string[] }[] {
|
||||
const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => {
|
||||
|
||||
@@ -116,6 +116,7 @@ export default class ViewSource extends React.Component<IProps, IState> {
|
||||
return (
|
||||
<MatrixClientContext.Consumer>
|
||||
{(cli) => (
|
||||
// oxlint-disable-next-line react/jsx-no-constructed-context-values
|
||||
<DevtoolsContext.Provider value={{ room: cli.getRoom(roomId)! }}>
|
||||
<StateEventEditor onBack={this.onBack} mxEvent={mxEvent} />
|
||||
</DevtoolsContext.Provider>
|
||||
@@ -127,6 +128,7 @@ export default class ViewSource extends React.Component<IProps, IState> {
|
||||
return (
|
||||
<MatrixClientContext.Consumer>
|
||||
{(cli) => (
|
||||
// oxlint-disable-next-line react/jsx-no-constructed-context-values
|
||||
<DevtoolsContext.Provider value={{ room: cli.getRoom(roomId)! }}>
|
||||
<TimelineEventEditor onBack={this.onBack} mxEvent={mxEvent} />
|
||||
</DevtoolsContext.Provider>
|
||||
|
||||
@@ -108,7 +108,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||
const loginViews = flows.map((f) => STATIC_FLOWS_TO_VIEWS[f.type]);
|
||||
|
||||
const isSocialSignOn = loginViews.includes(LoginView.Password) && loginViews.includes(LoginView.SSO);
|
||||
const firstView = loginViews.filter((f) => !!f)[0] || LoginView.Unsupported;
|
||||
const firstView = loginViews.find((f) => !!f) || LoginView.Unsupported;
|
||||
const chosenView = isSocialSignOn ? LoginView.PasswordWithSocialSignOn : firstView;
|
||||
this.setState({ flows, loginView: chosenView });
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { isEqual } from "lodash";
|
||||
import React, { type JSX, type ComponentProps, type PropsWithChildren, type Reducer, useReducer } from "react";
|
||||
import React, { type JSX, type ComponentProps, type PropsWithChildren, type Reducer, useReducer, useMemo } from "react";
|
||||
|
||||
import { AuthHeaderContext } from "./AuthHeaderContext";
|
||||
import { type AuthHeaderModifier } from "./AuthHeaderModifier";
|
||||
@@ -36,5 +36,6 @@ export function AuthHeaderProvider({ children }: PropsWithChildren): JSX.Element
|
||||
},
|
||||
[] as ComponentProps<typeof AuthHeaderModifier>[],
|
||||
);
|
||||
return <AuthHeaderContext.Provider value={{ state, dispatch }}>{children}</AuthHeaderContext.Provider>;
|
||||
const context = useMemo(() => ({ state, dispatch }), [state, dispatch]);
|
||||
return <AuthHeaderContext.Provider value={context}>{children}</AuthHeaderContext.Provider>;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ interface KeyStoragePanelState {
|
||||
* A function that can be called to enable or disable key storage.
|
||||
* @param enable True to turn key storage on or false to turn it off
|
||||
*/
|
||||
setEnabled: (enable: boolean) => void;
|
||||
setEnabled: (enable: boolean) => Promise<void>;
|
||||
|
||||
/**
|
||||
* True if the state is still loading for the first time
|
||||
|
||||
@@ -151,6 +151,7 @@ const DevtoolsDialog: React.FC<IProps> = ({ roomId, threadRootId, onFinished })
|
||||
)}
|
||||
<div className="mx_DevTools_label_bottom" />
|
||||
{cli.getRoom(roomId) && (
|
||||
// oxlint-disable-next-line react/jsx-no-constructed-context-values
|
||||
<DevtoolsContext.Provider value={{ room: cli.getRoom(roomId)!, threadRootId }}>
|
||||
{body}
|
||||
</DevtoolsContext.Provider>
|
||||
|
||||
@@ -30,7 +30,7 @@ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({
|
||||
subheading,
|
||||
children,
|
||||
rageshakeLabel,
|
||||
rageshakeData = {},
|
||||
rageshakeData,
|
||||
onFinished,
|
||||
}) => {
|
||||
const [comment, setComment] = useState("");
|
||||
|
||||
@@ -1390,7 +1390,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||
new Tab(
|
||||
TabId.UserDirectory,
|
||||
_td("invite|transfer_user_directory_tab"),
|
||||
<UserProfileSolidIcon />,
|
||||
<UserProfileSolidIcon key={TabId.UserDirectory} />,
|
||||
usersSection,
|
||||
),
|
||||
];
|
||||
|
||||
@@ -78,7 +78,7 @@ const addAllParents = (set: Set<Room>, room: Room): void => {
|
||||
});
|
||||
};
|
||||
|
||||
const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [], onFinished }) => {
|
||||
const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected, onFinished }) => {
|
||||
const cli = room.client;
|
||||
const [newSelected, setNewSelected] = useState(new Set<string>(selected));
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -92,7 +92,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||
Array.from(parents),
|
||||
SpaceStore.instance.spacePanelSpaces.filter((s) => !parents.has(s)),
|
||||
filterBoolean(
|
||||
selected.map((roomId) => {
|
||||
selected?.map((roomId) => {
|
||||
const room = cli.getRoom(roomId);
|
||||
if (!room) {
|
||||
return { roomId, name: roomId } as Room;
|
||||
@@ -100,7 +100,7 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
||||
if (room.getMyMembership() !== KnownMembership.Join || !room.isSpaceRoom()) {
|
||||
return room;
|
||||
}
|
||||
}),
|
||||
}) ?? [],
|
||||
),
|
||||
];
|
||||
}, [cli, selected, room]);
|
||||
|
||||
@@ -65,8 +65,8 @@ const SpacePreferencesDialog: React.FC<IProps> = ({ space, onFinished }) => {
|
||||
new Tab(
|
||||
SpacePreferenceTab.Appearance,
|
||||
_td("common|appearance"),
|
||||
<VisibilityOnIcon />,
|
||||
<SpacePreferencesAppearanceTab space={space} />,
|
||||
<VisibilityOnIcon key={SpacePreferenceTab.Appearance} />,
|
||||
<SpacePreferencesAppearanceTab key={SpacePreferenceTab.Appearance} space={space} />,
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
@@ -54,27 +54,36 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
|
||||
new Tab(
|
||||
SpaceSettingsTab.General,
|
||||
_td("common|general"),
|
||||
<SettingsSolidIcon />,
|
||||
<SpaceSettingsGeneralTab matrixClient={cli} space={space} />,
|
||||
<SettingsSolidIcon key={SpaceSettingsTab.General} />,
|
||||
<SpaceSettingsGeneralTab key={SpaceSettingsTab.General} matrixClient={cli} space={space} />,
|
||||
),
|
||||
new Tab(
|
||||
SpaceSettingsTab.Visibility,
|
||||
_td("room_settings|visibility|title"),
|
||||
<VisibilityOnIcon />,
|
||||
<SpaceSettingsVisibilityTab matrixClient={cli} space={space} closeSettingsFn={onFinished} />,
|
||||
<VisibilityOnIcon key={SpaceSettingsTab.Visibility} />,
|
||||
<SpaceSettingsVisibilityTab
|
||||
key={SpaceSettingsTab.Visibility}
|
||||
matrixClient={cli}
|
||||
space={space}
|
||||
closeSettingsFn={onFinished}
|
||||
/>,
|
||||
),
|
||||
new Tab(
|
||||
SpaceSettingsTab.Roles,
|
||||
_td("room_settings|permissions|title"),
|
||||
<AdminIcon />,
|
||||
<RolesRoomSettingsTab room={space} />,
|
||||
<AdminIcon key={SpaceSettingsTab.Roles} />,
|
||||
<RolesRoomSettingsTab key={SpaceSettingsTab.Roles} room={space} />,
|
||||
),
|
||||
SettingsStore.getValue(UIFeature.AdvancedSettings)
|
||||
? new Tab(
|
||||
SpaceSettingsTab.Advanced,
|
||||
_td("common|advanced"),
|
||||
<AdvancedSettingsIcon />,
|
||||
<AdvancedRoomSettingsTab room={space} closeSettingsFn={onFinished} />,
|
||||
<AdvancedSettingsIcon key={SpaceSettingsTab.Advanced} />,
|
||||
<AdvancedRoomSettingsTab
|
||||
key={SpaceSettingsTab.Advanced}
|
||||
room={space}
|
||||
closeSettingsFn={onFinished}
|
||||
/>,
|
||||
)
|
||||
: null,
|
||||
].filter(Boolean) as NonEmptyArray<Tab<SpaceSettingsTab>>;
|
||||
|
||||
@@ -36,7 +36,6 @@ export default class UploadFailureDialog extends React.Component<IProps> {
|
||||
|
||||
public render(): React.ReactNode {
|
||||
let message;
|
||||
let preview;
|
||||
let buttons;
|
||||
if (this.props.totalFiles === 1 && this.props.badFiles.length === 1) {
|
||||
message = _t(
|
||||
@@ -105,10 +104,7 @@ export default class UploadFailureDialog extends React.Component<IProps> {
|
||||
title={_t("upload_file|error_title")}
|
||||
contentId="mx_Dialog_content"
|
||||
>
|
||||
<div id="mx_Dialog_content">
|
||||
{message}
|
||||
{preview}
|
||||
</div>
|
||||
<div id="mx_Dialog_content">{message}</div>
|
||||
|
||||
{buttons}
|
||||
</BaseDialog>
|
||||
|
||||
@@ -300,7 +300,7 @@ export default class AppTile extends React.Component<IProps, IState> {
|
||||
* Set initial component state when the App wUrl (widget URL) is being updated.
|
||||
* Component props *must* be passed (rather than relying on this.props).
|
||||
* @param {Object} newProps The new properties of the component
|
||||
* @return {Object} Updated component state to be set with setState
|
||||
* @returns {Object} Updated component state to be set with setState
|
||||
*/
|
||||
private getNewState(newProps: IProps): IState {
|
||||
return {
|
||||
|
||||
@@ -43,7 +43,7 @@ const GenericEventListSummary: React.FC<IProps> = ({
|
||||
threshold = 3,
|
||||
onToggle,
|
||||
startExpanded = false,
|
||||
summaryMembers = [],
|
||||
summaryMembers,
|
||||
summaryText,
|
||||
layout = Layout.Group,
|
||||
"data-testid": testId,
|
||||
@@ -83,7 +83,7 @@ const GenericEventListSummary: React.FC<IProps> = ({
|
||||
);
|
||||
} else {
|
||||
const uniqueMembers = uniqBy(
|
||||
summaryMembers.filter((member) => {
|
||||
summaryMembers?.filter((member) => {
|
||||
if (!member?.getMxcAvatarUrl) {
|
||||
logger.error(
|
||||
"EventListSummary given null summaryMember, termites may be afoot eating event senders",
|
||||
|
||||
@@ -12,7 +12,6 @@ import { TooltipProvider } from "@vector-im/compound-web";
|
||||
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { type ActionPayload } from "../../../dispatcher/payloads";
|
||||
import { SDKContext } from "../../../contexts/SDKContext.ts";
|
||||
|
||||
@@ -170,7 +169,7 @@ export default class PersistedElement extends React.Component<IProps> {
|
||||
const content = (
|
||||
<StrictMode>
|
||||
<SDKContext.Provider value={this.context}>
|
||||
<MatrixClientContext.Provider value={MatrixClientPeg.safeGet()}>
|
||||
<MatrixClientContext.Provider value={this.context.client!}>
|
||||
<TooltipProvider>
|
||||
<div ref={this.collectChild} style={this.props.style}>
|
||||
{this.props.children}
|
||||
|
||||
@@ -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, { type ReactNode, type KeyboardEvent, type Ref, type MouseEvent } from "react";
|
||||
import React, { type ReactNode, type KeyboardEvent, type Ref, type MouseEvent, useMemo } from "react";
|
||||
import classNames from "classnames";
|
||||
import { IconButton, Text } from "@vector-im/compound-web";
|
||||
import CloseIcon from "@vector-im/compound-design-tokens/assets/web/icons/close";
|
||||
@@ -103,9 +103,10 @@ const BaseCard: React.FC<IProps> = ({
|
||||
}
|
||||
|
||||
const shouldRenderHeader = header || !hideHeaderButtons;
|
||||
const context = useMemo(() => ({ isCard: true }), []);
|
||||
|
||||
return (
|
||||
<CardContext.Provider value={{ isCard: true }}>
|
||||
<CardContext.Provider value={context}>
|
||||
<div
|
||||
id={id}
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
|
||||
@@ -96,7 +96,7 @@ describe("MessageComposerUrlPreview", () => {
|
||||
{ timeout: DEBOUNCE_REQUEST_TIMEOUT_MS },
|
||||
);
|
||||
});
|
||||
test("to reset module component override when filter function does not match ", async () => {
|
||||
test("to reset module component override when filter function does not match", async () => {
|
||||
const modApi = {
|
||||
customComponents: new CustomComponentsApi(),
|
||||
} as ModuleApi;
|
||||
|
||||
@@ -25,7 +25,7 @@ export const EMOTE_PREFIX = "/me ";
|
||||
function attachRelation(content: IContent, relation?: IEventRelation): void {
|
||||
if (relation) {
|
||||
content["m.relates_to"] = {
|
||||
...(content["m.relates_to"] || {}),
|
||||
...content["m.relates_to"],
|
||||
...relation,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
|
||||
const roomState = client.getRoom(roomId)?.currentState;
|
||||
if (!roomState) return [];
|
||||
|
||||
return BRIDGE_EVENT_TYPES.map((typeName) => roomState.getStateEvents(typeName)).flat(1);
|
||||
return BRIDGE_EVENT_TYPES.flatMap((typeName) => roomState.getStateEvents(typeName));
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
||||
@@ -80,7 +80,7 @@ export default class AudioFeed extends React.Component<IProps, IState> {
|
||||
// should serialise the ones that need to be serialised but then be able to interrupt
|
||||
// them with another load() which will cancel the pending one, but since we don't call
|
||||
// load() explicitly, it shouldn't be a problem. - Dave
|
||||
await element.load();
|
||||
element.load();
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Failed to play media element with feed for userId ` +
|
||||
|
||||
@@ -5,7 +5,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, { createContext } from "react";
|
||||
import React, { createContext, useMemo } from "react";
|
||||
|
||||
import { useCurrentPhase } from "../hooks/right-panel/useCurrentPhase";
|
||||
import { type RightPanelPhases } from "../stores/right-panel/RightPanelStorePhases";
|
||||
@@ -26,9 +26,6 @@ export const CurrentRightPanelPhaseContextProvider: React.FC<React.PropsWithChil
|
||||
children,
|
||||
}) => {
|
||||
const { currentPhase, isOpen } = useCurrentPhase(roomId);
|
||||
return (
|
||||
<CurrentRightPanelPhaseContext.Provider value={{ currentPhase, isPanelOpen: isOpen }}>
|
||||
{children}
|
||||
</CurrentRightPanelPhaseContext.Provider>
|
||||
);
|
||||
const context = useMemo(() => ({ currentPhase, isPanelOpen: isOpen }), [currentPhase, isOpen]);
|
||||
return <CurrentRightPanelPhaseContext.Provider value={context}>{children}</CurrentRightPanelPhaseContext.Provider>;
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ export function diffDeletion(oldStr: string, newStr: string): IDiff {
|
||||
* @param {String} oldValue the previous value
|
||||
* @param {String} newValue the new value
|
||||
* @param {Number} caretPosition the position of the caret after `newValue` was applied.
|
||||
* @return {object} an object with `at` as the offset where characters were removed and/or added,
|
||||
* @returns {object} an object with `at` as the offset where characters were removed and/or added,
|
||||
* `added` with the added string (if any), and
|
||||
* `removed` with the removed string (if any)
|
||||
*/
|
||||
|
||||
@@ -27,13 +27,13 @@ import { type Caret } from "./caret";
|
||||
* @param {DocumentPosition?} caretPosition the position where the caret should be position
|
||||
* @param {string?} inputType the inputType of the DOM input event
|
||||
* @param {object?} diff an object with `removed` and `added` strings
|
||||
* @return {Number?} addedLen how many characters were added/removed (-) before the caret during the transformation step.
|
||||
* @returns {Number?} addedLen how many characters were added/removed (-) before the caret during the transformation step.
|
||||
* This is used to adjust the caret position.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ManualTransformCallback
|
||||
* @return the caret position
|
||||
* @returns the caret position
|
||||
*/
|
||||
|
||||
type TransformCallback = (caretPosition: DocumentPosition, inputType: string | undefined, diff: IDiff) => number | void;
|
||||
@@ -179,7 +179,7 @@ export default class EditorModel {
|
||||
* Should be run inside a `model.transform()` callback.
|
||||
* @param {Part[]} parts the parts to replace the range with
|
||||
* @param {DocumentPosition} position the position to start inserting at
|
||||
* @return {Number} the amount of characters added
|
||||
* @returns {Number} the amount of characters added
|
||||
*/
|
||||
public insert(parts: Part[], position: IPosition): number {
|
||||
const insertIndex = this.splitAt(position);
|
||||
@@ -303,7 +303,7 @@ export default class EditorModel {
|
||||
* removes `len` amount of characters at `pos`.
|
||||
* @param {Object} pos
|
||||
* @param {Number} len
|
||||
* @return {Number} how many characters before pos were also removed,
|
||||
* @returns {Number} how many characters before pos were also removed,
|
||||
* usually because of non-editable parts that can only be removed in their entirety.
|
||||
*/
|
||||
public removeText(pos: IPosition, len: number): number {
|
||||
@@ -363,7 +363,7 @@ export default class EditorModel {
|
||||
* @param {Object} pos
|
||||
* @param {string} str
|
||||
* @param {string} inputType the source of the input, see html InputEvent.inputType
|
||||
* @return {Number} how far from position (in characters) the insertion ended.
|
||||
* @returns {Number} how far from position (in characters) the insertion ended.
|
||||
* This can be more than the length of `str` when crossing non-editable parts, which are skipped.
|
||||
*/
|
||||
private addText(pos: IPosition, str: string, inputType: string | undefined): number {
|
||||
@@ -434,7 +434,7 @@ export default class EditorModel {
|
||||
* Starts a range, which can span across multiple parts, to find and replace text.
|
||||
* @param {DocumentPosition} positionA a boundary of the range
|
||||
* @param {DocumentPosition?} positionB the other boundary of the range, optional
|
||||
* @return {Range}
|
||||
* @returns {Range}
|
||||
*/
|
||||
public startRange(positionA: DocumentPosition, positionB = positionA): Range {
|
||||
return new Range(this, positionA, positionB);
|
||||
@@ -463,7 +463,7 @@ export default class EditorModel {
|
||||
* Performs a transformation not part of an update cycle.
|
||||
* Modifying the model should only happen inside a transform call if not part of an update call.
|
||||
* @param {ManualTransformCallback} callback to run the transformations in
|
||||
* @return {Promise} a promise when auto-complete (if applicable) is done updating
|
||||
* @returns {Promise} a promise when auto-complete (if applicable) is done updating
|
||||
*/
|
||||
public transform(callback: ManualTransformCallback): Promise<void> {
|
||||
const pos = callback();
|
||||
|
||||
@@ -93,7 +93,7 @@ export default class Range {
|
||||
* Splits the model at the range boundaries and replaces with the given parts.
|
||||
* Should be run inside a `model.transform()` callback.
|
||||
* @param {Part[]} parts the parts to replace the range with
|
||||
* @return {Number} the net amount of characters added, can be negative.
|
||||
* @returns {Number} the net amount of characters added, can be negative.
|
||||
*/
|
||||
public replace(parts: Part[]): number {
|
||||
const newLength = parts.reduce((sum, part) => sum + part.text.length, 0);
|
||||
|
||||
@@ -16,7 +16,7 @@ type Fn<T> = () => Promise<T>;
|
||||
* @param fn function to memoize
|
||||
* @param deps React hooks dependencies for the function
|
||||
* @param initialValue initial value
|
||||
* @return tuple of cached value and refresh callback
|
||||
* @returns tuple of cached value and refresh callback
|
||||
*/
|
||||
export function useAsyncRefreshMemo<T>(fn: Fn<T>, deps: DependencyList, initialValue: T): [T, () => void];
|
||||
export function useAsyncRefreshMemo<T>(fn: Fn<T>, deps: DependencyList, initialValue?: T): [T | undefined, () => void];
|
||||
|
||||
@@ -177,7 +177,7 @@ export function useEventEmitterAsyncState<T, Events extends string, Arguments ex
|
||||
}
|
||||
});
|
||||
},
|
||||
[fn, ...deps], // eslint-disable-line react-compiler/react-compiler
|
||||
[fn, ...deps], // eslint-disable-line react-compiler/react-compiler, react-hooks/exhaustive-deps
|
||||
);
|
||||
|
||||
// re-run when the emitter changes
|
||||
|
||||
@@ -76,7 +76,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* optionally enable event indexing they may override this method to perform
|
||||
* the necessary runtime checks here.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve to true if event indexing
|
||||
* @returns {Promise} A promise that will resolve to true if event indexing
|
||||
* is supported, false otherwise.
|
||||
*/
|
||||
public async supportsEventIndexing(): Promise<boolean> {
|
||||
@@ -88,7 +88,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {string} userId The event that should be added to the index.
|
||||
* @param {string} deviceId The profile of the event sender at the
|
||||
*
|
||||
* @return {Promise} A promise that will resolve when the event index is
|
||||
* @returns {Promise} A promise that will resolve when the event index is
|
||||
* initialized.
|
||||
*/
|
||||
public async initEventIndex(userId: string, deviceId: string): Promise<void> {
|
||||
@@ -102,7 +102,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {IMatrixProfile} profile The profile of the event sender at the
|
||||
* time the event was received.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve when the was queued up for
|
||||
* @returns {Promise} A promise that will resolve when the was queued up for
|
||||
* addition.
|
||||
*/
|
||||
public async addEventToIndex(ev: IMatrixEvent, profile: IMatrixProfile): Promise<void> {
|
||||
@@ -123,7 +123,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {string} roomId The ID of the room which we want to check if it
|
||||
* has been already indexed.
|
||||
*
|
||||
* @return {Promise<boolean>} Returns true if the index contains events for
|
||||
* @returns {Promise<boolean>} Returns true if the index contains events for
|
||||
* the given room, false otherwise.
|
||||
*/
|
||||
public isRoomIndexed(roomId: string): Promise<boolean> {
|
||||
@@ -133,7 +133,7 @@ export default abstract class BaseEventIndexManager {
|
||||
/**
|
||||
* Get statistical information of the index.
|
||||
*
|
||||
* @return {Promise<IIndexStats>} A promise that will resolve to the index
|
||||
* @returns {Promise<IIndexStats>} A promise that will resolve to the index
|
||||
* statistics.
|
||||
*/
|
||||
public async getStats(): Promise<IIndexStats> {
|
||||
@@ -142,7 +142,7 @@ export default abstract class BaseEventIndexManager {
|
||||
|
||||
/**
|
||||
* Get the user version of the database.
|
||||
* @return {Promise<number>} A promise that will resolve to the user stored
|
||||
* @returns {Promise<number>} A promise that will resolve to the user stored
|
||||
* version number.
|
||||
*/
|
||||
public async getUserVersion(): Promise<number> {
|
||||
@@ -155,7 +155,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {number} version The new version that should be stored in the
|
||||
* database.
|
||||
*
|
||||
* @return {Promise<void>} A promise that will resolve once the new version
|
||||
* @returns {Promise<void>} A promise that will resolve once the new version
|
||||
* is stored.
|
||||
*/
|
||||
public async setUserVersion(version: number): Promise<void> {
|
||||
@@ -165,7 +165,7 @@ export default abstract class BaseEventIndexManager {
|
||||
/**
|
||||
* Commit the previously queued up events to the index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the queued up events
|
||||
* @returns {Promise} A promise that will resolve once the queued up events
|
||||
* were added to the index.
|
||||
*/
|
||||
public async commitLiveEvents(): Promise<void> {
|
||||
@@ -178,7 +178,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {ISearchArgs} searchArgs The search configuration for the search,
|
||||
* sets the search term and determines the search result contents.
|
||||
*
|
||||
* @return {Promise<IResultRoomEvents[]>} A promise that will resolve to an array
|
||||
* @returns {Promise<IResultRoomEvents[]>} A promise that will resolve to an array
|
||||
* of search results once the search is done.
|
||||
*/
|
||||
public async searchEventIndex(searchArgs: ISearchArgs): Promise<IResultRoomEvents> {
|
||||
@@ -199,7 +199,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* to fetch the current batch of events. This checkpoint will be removed
|
||||
* from the index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve to true if all the events
|
||||
* @returns {Promise} A promise that will resolve to true if all the events
|
||||
* were already added to the index, false otherwise.
|
||||
*/
|
||||
public async addHistoricEvents(
|
||||
@@ -216,7 +216,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {ICrawlerCheckpoint} checkpoint The checkpoint that should be added
|
||||
* to the index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the checkpoint has
|
||||
* @returns {Promise} A promise that will resolve once the checkpoint has
|
||||
* been stored.
|
||||
*/
|
||||
public async addCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise<void> {
|
||||
@@ -229,7 +229,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {ICrawlerCheckpoint} checkpoint The checkpoint that should be
|
||||
* removed from the index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the checkpoint has
|
||||
* @returns {Promise} A promise that will resolve once the checkpoint has
|
||||
* been removed.
|
||||
*/
|
||||
public async removeCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise<void> {
|
||||
@@ -239,7 +239,7 @@ export default abstract class BaseEventIndexManager {
|
||||
/**
|
||||
* Load the stored checkpoints from the index.
|
||||
*
|
||||
* @return {Promise<[ICrawlerCheckpoint]>} A promise that will resolve to an
|
||||
* @returns {Promise<[ICrawlerCheckpoint]>} A promise that will resolve to an
|
||||
* array of crawler checkpoints once they have been loaded from the index.
|
||||
*/
|
||||
public async loadCheckpoints(): Promise<ICrawlerCheckpoint[]> {
|
||||
@@ -258,7 +258,7 @@ export default abstract class BaseEventIndexManager {
|
||||
* @param {string} args.direction The direction to which we should continue
|
||||
* loading events from. This is used only if fromEvent is used as well.
|
||||
*
|
||||
* @return {Promise<[IEventAndProfile]>} A promise that will resolve to an
|
||||
* @returns {Promise<[IEventAndProfile]>} A promise that will resolve to an
|
||||
* array of Matrix events that contain mxc URLs accompanied with the
|
||||
* historic profile of the sender.
|
||||
*/
|
||||
@@ -269,7 +269,7 @@ export default abstract class BaseEventIndexManager {
|
||||
/**
|
||||
* close our event index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the event index has
|
||||
* @returns {Promise} A promise that will resolve once the event index has
|
||||
* been closed.
|
||||
*/
|
||||
public async closeEventIndex(): Promise<void> {
|
||||
@@ -279,7 +279,7 @@ export default abstract class BaseEventIndexManager {
|
||||
/**
|
||||
* Delete our current event index.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the event index has
|
||||
* @returns {Promise} A promise that will resolve once the event index has
|
||||
* been deleted.
|
||||
*/
|
||||
public async deleteEventIndex(): Promise<void> {
|
||||
|
||||
@@ -711,7 +711,7 @@ export default class EventIndex extends EventEmitter {
|
||||
* @param {ISearchArgs} searchArgs The search configuration for the search,
|
||||
* sets the search term and determines the search result contents.
|
||||
*
|
||||
* @return {Promise<IResultRoomEvents[]>} A promise that will resolve to an array
|
||||
* @returns {Promise<IResultRoomEvents[]>} A promise that will resolve to an array
|
||||
* of search results once the search is done.
|
||||
*/
|
||||
public async search(searchArgs: ISearchArgs): Promise<IResultRoomEvents | undefined> {
|
||||
@@ -949,7 +949,7 @@ export default class EventIndex extends EventEmitter {
|
||||
/**
|
||||
* Get statistical information of the index.
|
||||
*
|
||||
* @return {Promise<IIndexStats>} A promise that will resolve to the index
|
||||
* @returns {Promise<IIndexStats>} A promise that will resolve to the index
|
||||
* statistics.
|
||||
*/
|
||||
public async getStats(): Promise<IIndexStats | undefined> {
|
||||
@@ -963,7 +963,7 @@ export default class EventIndex extends EventEmitter {
|
||||
* @param {string} roomId The ID of the room which we want to check if it
|
||||
* has been already indexed.
|
||||
*
|
||||
* @return {Promise<boolean>} Returns true if the index contains events for
|
||||
* @returns {Promise<boolean>} Returns true if the index contains events for
|
||||
* the given room, false otherwise.
|
||||
*/
|
||||
public async isRoomIndexed(roomId: string): Promise<boolean | undefined> {
|
||||
|
||||
@@ -37,7 +37,7 @@ export class EventIndexPeg {
|
||||
* Initialize the EventIndexPeg and if event indexing is enabled initialize
|
||||
* the event index.
|
||||
*
|
||||
* @return {Promise<boolean>} A promise that will resolve to true if an
|
||||
* @returns {Promise<boolean>} A promise that will resolve to true if an
|
||||
* EventIndex was successfully initialized, false otherwise.
|
||||
*/
|
||||
public async init(): Promise<boolean> {
|
||||
@@ -111,7 +111,7 @@ export class EventIndexPeg {
|
||||
/**
|
||||
* Check if the current platform has support for event indexing.
|
||||
*
|
||||
* @return {boolean} True if it has support, false otherwise. Note that this
|
||||
* @returns {boolean} True if it has support, false otherwise. Note that this
|
||||
* does not mean that support is installed.
|
||||
*/
|
||||
public platformHasSupport(): boolean {
|
||||
@@ -125,7 +125,7 @@ export class EventIndexPeg {
|
||||
* this tells us if those are installed. Note that this should only be
|
||||
* called after the init() method was called.
|
||||
*
|
||||
* @return {boolean} True if support is installed, false otherwise.
|
||||
* @returns {boolean} True if support is installed, false otherwise.
|
||||
*/
|
||||
public supportIsInstalled(): boolean {
|
||||
return this._supportIsInstalled;
|
||||
@@ -134,7 +134,7 @@ export class EventIndexPeg {
|
||||
/**
|
||||
* Get the current event index.
|
||||
*
|
||||
* @return {EventIndex} The current event index.
|
||||
* @returns {EventIndex} The current event index.
|
||||
*/
|
||||
public get(): EventIndex | null {
|
||||
return this.index;
|
||||
@@ -155,7 +155,7 @@ export class EventIndexPeg {
|
||||
*
|
||||
* After a call to this the init() method will need to be called again.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the event index is
|
||||
* @returns {Promise} A promise that will resolve once the event index is
|
||||
* closed.
|
||||
*/
|
||||
public async unset(): Promise<void> {
|
||||
@@ -169,7 +169,7 @@ export class EventIndexPeg {
|
||||
*
|
||||
* After a call to this the init() method will need to be called again.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve once the event index is
|
||||
* @returns {Promise} A promise that will resolve once the event index is
|
||||
* deleted.
|
||||
*/
|
||||
public async deleteEventIndex(): Promise<void> {
|
||||
|
||||
@@ -37,7 +37,7 @@ export class PushRuleVectorState {
|
||||
/**
|
||||
* Convert a PushRuleVectorState to a list of actions
|
||||
*
|
||||
* @return [object] list of push-rule actions
|
||||
* @returns [object] list of push-rule actions
|
||||
*/
|
||||
public static actionsFor(pushRuleVectorState?: VectorState): PushRuleAction[] {
|
||||
if (pushRuleVectorState === VectorState.On) {
|
||||
|
||||
@@ -15,7 +15,7 @@ const PHONE_NUMBER_REGEXP = /^[0-9 -.]+$/;
|
||||
* @param {String} phoneNumber The string to validate. This could be
|
||||
* either an international format number (MSISDN or e.164) or
|
||||
* a national-format number.
|
||||
* @return True if the number could be a valid phone number, otherwise false.
|
||||
* @returns True if the number could be a valid phone number, otherwise false.
|
||||
*/
|
||||
export function looksValid(phoneNumber: string): boolean {
|
||||
return PHONE_NUMBER_REGEXP.test(phoneNumber);
|
||||
|
||||
@@ -109,7 +109,7 @@ export class ConsoleLogger {
|
||||
/**
|
||||
* Retrieve log lines to flush to disk.
|
||||
* @param {boolean} keepLogs True to not delete logs after flushing.
|
||||
* @return {string} \n delimited log lines to flush.
|
||||
* @returns {string} \n delimited log lines to flush.
|
||||
*/
|
||||
public flush(keepLogs?: boolean): string {
|
||||
// The ConsoleLogger doesn't care how these end up on disk, it just
|
||||
@@ -139,7 +139,7 @@ export class IndexedDBLogStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise} Resolves when the store is ready.
|
||||
* @returns {Promise} Resolves when the store is ready.
|
||||
*/
|
||||
public connect(): Promise<void> {
|
||||
const req = this.indexedDB.open("logs");
|
||||
@@ -195,7 +195,7 @@ export class IndexedDBLogStore {
|
||||
* This guarantees that we will always eventually do a flush when flush() is
|
||||
* called.
|
||||
*
|
||||
* @return {Promise} Resolved when the logs have been flushed.
|
||||
* @returns {Promise} Resolved when the logs have been flushed.
|
||||
*/
|
||||
public flush(): Promise<void> {
|
||||
// check if a flush() operation is ongoing
|
||||
@@ -250,7 +250,7 @@ export class IndexedDBLogStore {
|
||||
* returned are deleted at the same time, so this can be called at startup
|
||||
* to do house-keeping to keep the logs from growing too large.
|
||||
*
|
||||
* @return {Promise<Object[]>} Resolves to an array of objects. The array is
|
||||
* @returns {Promise<Object[]>} Resolves to an array of objects. The array is
|
||||
* sorted in time (oldest first) based on when the log file was created (the
|
||||
* log ID). The objects have said log ID in an "id" field and "lines" which
|
||||
* is a big string with all the new-line delimited logs.
|
||||
@@ -455,7 +455,7 @@ export class IndexedDBLogStore {
|
||||
* @param {Function} resultMapper A function which is repeatedly called with a
|
||||
* Cursor.
|
||||
* Return the data you want to keep.
|
||||
* @return {Promise<T[]>} Resolves to an array of whatever you returned from
|
||||
* @returns {Promise<T[]>} Resolves to an array of whatever you returned from
|
||||
* resultMapper.
|
||||
*/
|
||||
function selectQuery<T>(
|
||||
@@ -487,7 +487,7 @@ function selectQuery<T>(
|
||||
* Modifies globals.
|
||||
* @param {boolean} setUpPersistence When true (default), the persistence will
|
||||
* be set up immediately for the logs.
|
||||
* @return {Promise} Resolves when set up.
|
||||
* @returns {Promise} Resolves when set up.
|
||||
*/
|
||||
export function init(setUpPersistence = true): Promise<void> {
|
||||
if (global.mx_rage_initPromise) {
|
||||
@@ -512,7 +512,7 @@ export function init(setUpPersistence = true): Promise<void> {
|
||||
/**
|
||||
* Try to start up the rageshake storage for logs. If not possible (client unsupported)
|
||||
* then this no-ops.
|
||||
* @return {Promise} Resolves when complete.
|
||||
* @returns {Promise} Resolves when complete.
|
||||
*/
|
||||
export function tryInitStorage(): Promise<void> {
|
||||
if (global.mx_rage_initStoragePromise) {
|
||||
@@ -558,7 +558,7 @@ export function flush(): void {
|
||||
* @deprecated There is no need to call this explicitly: it will be done as a side-effect of {@link tryInitStorage},
|
||||
* or {@link init} with `setUpPersistence: true`.
|
||||
*
|
||||
* @return {Promise} Resolves if cleaned logs.
|
||||
* @returns {Promise} Resolves if cleaned logs.
|
||||
*/
|
||||
export async function cleanup(): Promise<void> {
|
||||
if (!global.mx_rage_store) {
|
||||
@@ -570,7 +570,7 @@ export async function cleanup(): Promise<void> {
|
||||
/**
|
||||
* Get a recent snapshot of the logs, ready for attaching to a bug report
|
||||
*
|
||||
* @return {Array<{lines: string, id, string}>} list of log data
|
||||
* @returns {Array<{lines: string, id, string}>} list of log data
|
||||
*/
|
||||
export async function getLogsForReport(): Promise<{ lines: string; id: string }[]> {
|
||||
if (!global.mx_rage_logger) {
|
||||
|
||||
@@ -340,7 +340,7 @@ async function collectLogs(
|
||||
*
|
||||
* @param {function(string)} opts.progressCallback Callback to call with progress updates
|
||||
*
|
||||
* @return {Promise<string>} URL returned by the rageshake server
|
||||
* @returns {Promise<string>} URL returned by the rageshake server
|
||||
*
|
||||
* @throws A RageshakeError when the rageshake server responds with an error. This will be `RS_UNKNOWN` if the
|
||||
* the server does not respond with an expected body format.
|
||||
@@ -361,7 +361,7 @@ export default async function sendBugReport(bugReportEndpoint?: string, opts: IO
|
||||
* Loads a bug report into a tarball.
|
||||
*
|
||||
* @param opts optional dictionary of options
|
||||
* @return Resolves with a Tarball object.
|
||||
* @returns Resolves with a Tarball object.
|
||||
*/
|
||||
export async function loadBugReport(opts: IOpts = {}): Promise<Tar> {
|
||||
const Tar = (await import("tar-js")).default;
|
||||
@@ -395,7 +395,7 @@ export async function loadBugReport(opts: IOpts = {}): Promise<Tar> {
|
||||
* but instead causes the browser to download the files locally.
|
||||
*
|
||||
* @param opts optional dictionary of options
|
||||
* @return Resolved when the bug report is downloaded (or started).
|
||||
* @returns Resolved when the bug report is downloaded (or started).
|
||||
*/
|
||||
export async function downloadBugReport(opts: IOpts = {}): Promise<void> {
|
||||
const tape = await loadBugReport(opts);
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class Resizer<C extends IConfig, I extends ResizeItem<C> = Resize
|
||||
Gives the distributor for a specific resize handle, as if you would have started
|
||||
to drag that handle. Can be used to manipulate the size of an item programmatically.
|
||||
@param {number} handleIndex the index of the resize handle in the container
|
||||
@return {FixedDistributor} a new distributor for the given handle
|
||||
@returns {FixedDistributor} a new distributor for the given handle
|
||||
*/
|
||||
public forHandleAt(handleIndex: number): FixedDistributor<C, I> | undefined {
|
||||
const handles = this.getResizeHandles();
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class Sizer {
|
||||
|
||||
/**
|
||||
@param {Element} item the dom element being resized
|
||||
@return {number} how far the edge of the item is from the edge of the container
|
||||
@returns {number} how far the edge of the item is from the edge of the container
|
||||
*/
|
||||
public getItemOffset(item: HTMLElement): number {
|
||||
const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this.getOffset();
|
||||
@@ -32,23 +32,23 @@ export default class Sizer {
|
||||
|
||||
/**
|
||||
@param {Element} item the dom element being resized
|
||||
@return {number} the width/height of an item in the container
|
||||
@returns {number} the width/height of an item in the container
|
||||
*/
|
||||
public getItemSize(item: HTMLElement): number {
|
||||
return this.vertical ? item.offsetHeight : item.offsetWidth;
|
||||
}
|
||||
|
||||
/** @return {number} the width/height of the container */
|
||||
/** @returns {number} the width/height of the container */
|
||||
public getTotalSize(): number {
|
||||
return this.vertical ? this.container.offsetHeight : this.container.offsetWidth;
|
||||
}
|
||||
|
||||
/** @return {number} container offset to offsetParent */
|
||||
/** @returns {number} container offset to offsetParent */
|
||||
private getOffset(): number {
|
||||
return this.vertical ? this.container.offsetTop : this.container.offsetLeft;
|
||||
}
|
||||
|
||||
/** @return {number} container offset to document */
|
||||
/** @returns {number} container offset to document */
|
||||
private getPageOffset(): number {
|
||||
let element = this.container;
|
||||
let offset = 0;
|
||||
@@ -90,7 +90,7 @@ export default class Sizer {
|
||||
|
||||
/**
|
||||
@param {MouseEvent} event the mouse event
|
||||
@return {number} the distance between the cursor and the edge of the container,
|
||||
@returns {number} the distance between the cursor and the edge of the container,
|
||||
along the applicable axis (vertical or horizontal)
|
||||
*/
|
||||
public offsetFromEvent(event: MouseEvent): number {
|
||||
|
||||
@@ -276,7 +276,7 @@ export default class SettingsStore {
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @param {SettingLevel} atLevel
|
||||
* The level to get the display name for; Defaults to 'default'.
|
||||
* @return {String} The display name for the setting, or null if not found.
|
||||
* @returns {String} The display name for the setting, or null if not found.
|
||||
*/
|
||||
public static getDisplayName(settingName: SettingKey, atLevel = SettingLevel.DEFAULT): string | null {
|
||||
if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null;
|
||||
@@ -299,7 +299,7 @@ export default class SettingsStore {
|
||||
/**
|
||||
* Gets the translated description for a given setting
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {String} The description for the setting, or null if not found.
|
||||
* @returns {String} The description for the setting, or null if not found.
|
||||
*/
|
||||
public static getDescription(settingName: SettingKey): string | ReactNode {
|
||||
const description = SETTINGS[settingName]?.description;
|
||||
@@ -311,7 +311,7 @@ export default class SettingsStore {
|
||||
/**
|
||||
* Determines if a setting is also a feature.
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {boolean} True if the setting is a feature.
|
||||
* @returns {boolean} True if the setting is a feature.
|
||||
*/
|
||||
public static isFeature(settingName: SettingKey): boolean {
|
||||
if (!SETTINGS[settingName]) return false;
|
||||
@@ -321,7 +321,7 @@ export default class SettingsStore {
|
||||
/**
|
||||
* Determines if a setting should have a warning sign in the microcopy
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {boolean} True if the setting should have a warning sign.
|
||||
* @returns {boolean} True if the setting should have a warning sign.
|
||||
*/
|
||||
public static shouldHaveWarning(settingName: SettingKey): boolean {
|
||||
if (!SETTINGS[settingName]) return false;
|
||||
@@ -354,7 +354,7 @@ export default class SettingsStore {
|
||||
* If a setting is not disabled, or no reason is given by the `SettingController`,
|
||||
* this will return undefined.
|
||||
* @param {string} settingName The setting to look up.
|
||||
* @return {string} The reason the setting is disabled.
|
||||
* @returns {string} The reason the setting is disabled.
|
||||
*/
|
||||
public static disabledMessage(settingName: SettingKey): string | undefined {
|
||||
const disabled = SETTINGS[settingName].controller?.settingDisabled;
|
||||
@@ -367,7 +367,7 @@ export default class SettingsStore {
|
||||
* @param {string} settingName The name of the setting to read the value of.
|
||||
* @param {String} roomId The room ID to read the setting value in, may be null.
|
||||
* @param {boolean} excludeDefault True to disable using the default value.
|
||||
* @return {*} The value, or null if not found
|
||||
* @returns {*} The value, or null if not found
|
||||
*/
|
||||
public static getValue<S extends SettingKey>(
|
||||
settingName: S,
|
||||
@@ -404,7 +404,7 @@ export default class SettingsStore {
|
||||
* @param {boolean} explicit If true, this method will not consider other levels, just the one
|
||||
* provided. Defaults to false.
|
||||
* @param {boolean} excludeDefault True to disable using the default value.
|
||||
* @return {*} The value, or null if not found.
|
||||
* @returns {*} The value, or null if not found.
|
||||
*/
|
||||
public static getValueAt<S extends SettingKey>(
|
||||
level: SettingLevel,
|
||||
@@ -460,7 +460,7 @@ export default class SettingsStore {
|
||||
/**
|
||||
* Gets the default value of a setting.
|
||||
* @param settingName The name of the setting to read the value of.
|
||||
* @return The default value
|
||||
* @returns The default value
|
||||
*/
|
||||
public static getDefaultValue<S extends SettingKey>(settingName: S): Settings[S]["default"] {
|
||||
// Verify that the setting is actually a setting
|
||||
@@ -498,7 +498,7 @@ export default class SettingsStore {
|
||||
* @param level The level
|
||||
* to change the value at.
|
||||
* @param value The new value of the setting, may be null.
|
||||
* @return Resolves when the setting has been changed.
|
||||
* @returns Resolves when the setting has been changed.
|
||||
*/
|
||||
public static async setValue<S extends SettingKey>(
|
||||
settingName: S,
|
||||
@@ -556,7 +556,7 @@ export default class SettingsStore {
|
||||
* @param {string} settingName The name of the setting to check.
|
||||
* @param {String} roomId The room ID to check in, may be null.
|
||||
* @param {SettingLevel} level The level to check at.
|
||||
* @return {boolean} True if the user may set the setting, false otherwise.
|
||||
* @returns {boolean} True if the user may set the setting, false otherwise.
|
||||
*/
|
||||
public static canSetValue(settingName: SettingKey, roomId: string | null, level: SettingLevel): boolean {
|
||||
const setting = SETTINGS[settingName];
|
||||
@@ -610,7 +610,7 @@ export default class SettingsStore {
|
||||
* Determines if the given level is supported on this device.
|
||||
* @param {SettingLevel} level The level
|
||||
* to check the feasibility of.
|
||||
* @return {boolean} True if the level is supported, false otherwise.
|
||||
* @returns {boolean} True if the level is supported, false otherwise.
|
||||
*/
|
||||
public static isLevelSupported(level: SettingLevel): boolean {
|
||||
if (!LEVEL_HANDLERS[level]) return false;
|
||||
@@ -638,7 +638,7 @@ export default class SettingsStore {
|
||||
* Determines the first supported level out of all the levels that can be used for a
|
||||
* specific setting.
|
||||
* @param {string} settingName The setting name.
|
||||
* @return {SettingLevel}
|
||||
* @returns {SettingLevel}
|
||||
*/
|
||||
public static firstSupportedLevel(settingName: SettingKey): SettingLevel | null {
|
||||
// Verify that the setting is actually a setting
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user