mirror of
https://github.com/element-hq/element-web
synced 2024-11-22 01:05:42 +03:00
Merge branch 'develop' of https://github.com/vector-im/element-web into staging
# Conflicts: # yarn.lock
This commit is contained in:
commit
88b3b922f9
13 changed files with 3337 additions and 1679 deletions
6
.github/workflows/dockerhub.yaml
vendored
6
.github/workflows/dockerhub.yaml
vendored
|
@ -37,10 +37,10 @@ jobs:
|
||||||
run: ${{ matrix.prepare }}
|
run: ${{ matrix.prepare }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3
|
uses: docker/setup-qemu-action@5927c834f5b4fdf503fca6f4c7eccda82949e1ee # v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3
|
uses: docker/setup-buildx-action@4fd812986e6c8c2a69e18311145f9371337f27d4 # v3
|
||||||
with:
|
with:
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
id: build-and-push
|
id: build-and-push
|
||||||
uses: docker/build-push-action@31159d49c0d4756269a0940a750801a1ea5d7003 # v6
|
uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
|
|
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
|
@ -46,6 +46,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
cache: "yarn"
|
cache: "yarn"
|
||||||
cache-dependency-path: element-web/yarn.lock
|
cache-dependency-path: element-web/yarn.lock
|
||||||
|
node-version: "lts/*"
|
||||||
|
|
||||||
- name: Generate automations docs
|
- name: Generate automations docs
|
||||||
working-directory: element-web
|
working-directory: element-web
|
||||||
|
|
45
.github/workflows/triage-labelled.yml
vendored
45
.github/workflows/triage-labelled.yml
vendored
|
@ -56,13 +56,48 @@ jobs:
|
||||||
move_needs_info_issues:
|
move_needs_info_issues:
|
||||||
name: X-Needs-Info issues to Need info column on triage board
|
name: X-Needs-Info issues to Need info column on triage board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'X-Needs-Info')
|
||||||
steps:
|
steps:
|
||||||
- uses: konradpabjan/move-labeled-or-milestoned-issue@190352295fe309fcb113b49193bc81d9aaa9cb01
|
- id: add_to_project
|
||||||
|
uses: actions/add-to-project@v1.0.1
|
||||||
with:
|
with:
|
||||||
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
|
project-url: ${{ env.PROJECT_URL }}
|
||||||
project-url: "https://github.com/orgs/element-hq/projects/120"
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
column-name: "Needs info"
|
|
||||||
label-name: "X-Needs-Info"
|
- id: set_fields
|
||||||
|
uses: titoportas/update-project-fields@421a54430b3cdc9eefd8f14f9ce0142ab7678751 # v0.1.0
|
||||||
|
with:
|
||||||
|
project-url: ${{ env.PROJECT_URL }}
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
item-id: ${{ steps.add_to_project.outputs.itemId }} # Use the item-id output of the previous step
|
||||||
|
field-keys: Status
|
||||||
|
field-values: "Needs info"
|
||||||
|
env:
|
||||||
|
PROJECT_URL: https://github.com/orgs/element-hq/projects/120
|
||||||
|
|
||||||
|
move_flakey_test_issues:
|
||||||
|
name: Z-Flaky-Test issues to Sized for maintainer column on triage board
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'Z-Flaky-Test')
|
||||||
|
steps:
|
||||||
|
- id: add_to_project
|
||||||
|
uses: actions/add-to-project@v1.0.1
|
||||||
|
with:
|
||||||
|
project-url: ${{ env.PROJECT_URL }}
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
- id: set_fields
|
||||||
|
uses: titoportas/update-project-fields@421a54430b3cdc9eefd8f14f9ce0142ab7678751 # v0.1.0
|
||||||
|
with:
|
||||||
|
project-url: ${{ env.PROJECT_URL }}
|
||||||
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
item-id: ${{ steps.add_to_project.outputs.itemId }} # Use the item-id output of the previous step
|
||||||
|
field-keys: Status
|
||||||
|
field-values: "Sized for maintainer"
|
||||||
|
env:
|
||||||
|
PROJECT_URL: https://github.com/orgs/element-hq/projects/120
|
||||||
|
|
||||||
add_priority_design_issues_to_project:
|
add_priority_design_issues_to_project:
|
||||||
name: P1 X-Needs-Design to Design project board
|
name: P1 X-Needs-Design to Design project board
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"minify": true,
|
"minify": false,
|
||||||
"enableClasses": false,
|
"enableClasses": false,
|
||||||
"feature-detects": [
|
"feature-detects": [
|
||||||
"test/css/animations",
|
"test/css/animations",
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
"test/json",
|
"test/json",
|
||||||
"test/network/fetch",
|
"test/network/fetch",
|
||||||
"test/storage/localstorage",
|
"test/storage/localstorage",
|
||||||
"test/window/resizeobserver"
|
"test/window/resizeobserver",
|
||||||
|
"test/audio/webaudio"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,8 +374,8 @@ The VoIP and Jitsi options are:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
The `widget` is the `content` of a normal widget state event. The `layout` is the layout specifier for the widget being created,
|
The `widget` is the `content` of a normal widget state event. The `layout` is the layout specifier for the widget being created,
|
||||||
as defined by the `io.element.widgets.layout` state event. By default this applies to all rooms, but the behaviour can be skipped for DMs
|
as defined by the `io.element.widgets.layout` state event. By default this applies to all rooms, but the behaviour can be skipped for
|
||||||
by setting the option `widget_build_url_ignore_dm` to `true`.
|
2-person rooms, causing Element to fall back to 1:1 VoIP, by setting the option `widget_build_url_ignore_dm` to `true`.
|
||||||
5. `audio_stream_url`: Optional URL to pass to Jitsi to enable live streaming. This option is considered experimental and may be removed
|
5. `audio_stream_url`: Optional URL to pass to Jitsi to enable live streaming. This option is considered experimental and may be removed
|
||||||
at any time without notice.
|
at any time without notice.
|
||||||
6. `element_call`: Optional configuration for native group calls using Element Call, with the following subkeys:
|
6. `element_call`: Optional configuration for native group calls using Element Call, with the following subkeys:
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"@types/react": "17.0.80"
|
"@types/react": "17.0.80"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@formatjs/intl-segmenter": "^11.5.7",
|
||||||
"@matrix-org/react-sdk-module-api": "^2.3.0",
|
"@matrix-org/react-sdk-module-api": "^2.3.0",
|
||||||
"jsrsasign": "^11.0.0",
|
"jsrsasign": "^11.0.0",
|
||||||
"katex": "^0.16.0",
|
"katex": "^0.16.0",
|
||||||
|
@ -187,7 +188,7 @@
|
||||||
"prettier": "3.3.2",
|
"prettier": "3.3.2",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"rimraf": "^5.0.0",
|
"rimraf": "^6.0.0",
|
||||||
"semver": "^7.5.2",
|
"semver": "^7.5.2",
|
||||||
"string-replace-loader": "3",
|
"string-replace-loader": "3",
|
||||||
"style-loader": "4",
|
"style-loader": "4",
|
||||||
|
@ -197,7 +198,7 @@
|
||||||
"terser-webpack-plugin": "^5.3.9",
|
"terser-webpack-plugin": "^5.3.9",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"ts-prune": "^0.10.3",
|
"ts-prune": "^0.10.3",
|
||||||
"typescript": "5.5.2",
|
"typescript": "5.5.3",
|
||||||
"util": "^0.12.5",
|
"util": "^0.12.5",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-bundle-analyzer": "^4.8.0",
|
"webpack-bundle-analyzer": "^4.8.0",
|
||||||
|
|
|
@ -10,5 +10,5 @@ sonar.exclusions=__mocks__,docs,element.io,nginx
|
||||||
|
|
||||||
sonar.typescript.tsconfigPath=./tsconfig.json
|
sonar.typescript.tsconfigPath=./tsconfig.json
|
||||||
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
||||||
sonar.coverage.exclusions=test/**/*,res/**/*
|
sonar.coverage.exclusions=test/**/*,res/**/*,src/vector/modernizr.js
|
||||||
sonar.testExecutionReportPaths=coverage/jest-sonar-report.xml
|
sonar.testExecutionReportPaths=coverage/jest-sonar-report.xml
|
||||||
|
|
4
src/@types/global.d.ts
vendored
4
src/@types/global.d.ts
vendored
|
@ -33,7 +33,9 @@ type ElectronChannel =
|
||||||
| "update-downloaded"
|
| "update-downloaded"
|
||||||
| "userDownloadCompleted"
|
| "userDownloadCompleted"
|
||||||
| "userDownloadAction"
|
| "userDownloadAction"
|
||||||
| "openDesktopCapturerSourcePicker";
|
| "openDesktopCapturerSourcePicker"
|
||||||
|
| "userAccessToken"
|
||||||
|
| "serverSupportedVersions";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
|
@ -102,11 +102,15 @@ async function tryUpdateServerSupportMap(clientApiUrl: string, accessToken?: str
|
||||||
|
|
||||||
const config = fetchConfigForToken(accessToken);
|
const config = fetchConfigForToken(accessToken);
|
||||||
const versions = await (await fetch(`${clientApiUrl}/_matrix/client/versions`, config)).json();
|
const versions = await (await fetch(`${clientApiUrl}/_matrix/client/versions`, config)).json();
|
||||||
|
console.log(`[ServiceWorker] /versions response for '${clientApiUrl}': ${JSON.stringify(versions)}`);
|
||||||
|
|
||||||
serverSupportMap[clientApiUrl] = {
|
serverSupportMap[clientApiUrl] = {
|
||||||
supportsAuthedMedia: Boolean(versions?.versions?.includes("v1.11")),
|
supportsAuthedMedia: Boolean(versions?.versions?.includes("v1.11")),
|
||||||
cacheExpiryTimeMs: new Date().getTime() + 2 * 60 * 60 * 1000, // 2 hours from now
|
cacheExpiryTimeMs: new Date().getTime() + 2 * 60 * 60 * 1000, // 2 hours from now
|
||||||
};
|
};
|
||||||
|
console.log(
|
||||||
|
`[ServiceWorker] serverSupportMap update for '${clientApiUrl}': ${JSON.stringify(serverSupportMap[clientApiUrl])}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideally we'd use the `Client` interface for `client`, but since it's not available (see 'fetch' listener), we use
|
// Ideally we'd use the `Client` interface for `client`, but since it's not available (see 'fetch' listener), we use
|
||||||
|
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { shouldPolyfill as shouldPolyFillIntlSegmenter } from "@formatjs/intl-segmenter/should-polyfill";
|
||||||
|
|
||||||
// These are things that can run before the skin loads - be careful not to reference the react-sdk though.
|
// These are things that can run before the skin loads - be careful not to reference the react-sdk though.
|
||||||
import { parseQsFromFragment } from "./url_utils";
|
import { parseQsFromFragment } from "./url_utils";
|
||||||
|
@ -75,8 +76,16 @@ function checkBrowserFeatures(): boolean {
|
||||||
() => window.RegExp?.prototype && "unicodeSets" in window.RegExp.prototype,
|
() => window.RegExp?.prototype && "unicodeSets" in window.RegExp.prototype,
|
||||||
);
|
);
|
||||||
// ES2024: https://402.ecma-international.org/9.0/#sec-intl.segmenter
|
// ES2024: https://402.ecma-international.org/9.0/#sec-intl.segmenter
|
||||||
|
// The built-in modernizer 'intl' check only checks for the presence of the Intl object, not the Segmenter,
|
||||||
|
// and older Firefox has the former but not the latter, so we add our own.
|
||||||
|
// This is polyfilled now, but we still want to show the warning because we want to remove the polyfill
|
||||||
|
// at some point.
|
||||||
window.Modernizr.addTest("intlsegmenter", () => typeof window.Intl?.Segmenter === "function");
|
window.Modernizr.addTest("intlsegmenter", () => typeof window.Intl?.Segmenter === "function");
|
||||||
|
|
||||||
|
// Basic test for WebAssembly support. We could also try instantiating a simple module,
|
||||||
|
// although this would start to make (more) assumptions about how rust-crypto loads its wasm.
|
||||||
|
window.Modernizr.addTest("wasm", () => typeof WebAssembly === "object" && typeof WebAssembly.Module === "function");
|
||||||
|
|
||||||
const featureList = Object.keys(window.Modernizr) as Array<keyof ModernizrStatic>;
|
const featureList = Object.keys(window.Modernizr) as Array<keyof ModernizrStatic>;
|
||||||
|
|
||||||
let featureComplete = true;
|
let featureComplete = true;
|
||||||
|
@ -106,6 +115,10 @@ const supportedBrowser = checkBrowserFeatures();
|
||||||
// the browser to use as much parallelism as it can.
|
// the browser to use as much parallelism as it can.
|
||||||
// Load parallelism is based on research in https://github.com/element-hq/element-web/issues/12253
|
// Load parallelism is based on research in https://github.com/element-hq/element-web/issues/12253
|
||||||
async function start(): Promise<void> {
|
async function start(): Promise<void> {
|
||||||
|
if (shouldPolyFillIntlSegmenter()) {
|
||||||
|
await import(/* webpackChunkName: "intl-segmenter-polyfill" */ "@formatjs/intl-segmenter/polyfill-force");
|
||||||
|
}
|
||||||
|
|
||||||
// load init.ts async so that its code is not executed immediately and we can catch any exceptions
|
// load init.ts async so that its code is not executed immediately and we can catch any exceptions
|
||||||
const {
|
const {
|
||||||
rageshakePromise,
|
rageshakePromise,
|
||||||
|
@ -126,6 +139,8 @@ async function start(): Promise<void> {
|
||||||
"./init"
|
"./init"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Now perform the next stage of initialisation. This has its own try/catch in which we render
|
||||||
|
// a react error page on failure.
|
||||||
try {
|
try {
|
||||||
// give rageshake a chance to load/fail, we don't actually assert rageshake loads, we allow it to fail if no IDB
|
// give rageshake a chance to load/fail, we don't actually assert rageshake loads, we allow it to fail if no IDB
|
||||||
await settled(rageshakePromise);
|
await settled(rageshakePromise);
|
||||||
|
@ -238,6 +253,10 @@ async function start(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
start().catch((err) => {
|
start().catch((err) => {
|
||||||
|
// If we get here, things have gone terribly wrong and we cannot load the app javascript at all.
|
||||||
|
// Show a different, very simple iframed-static error page. Or actually, one of two different ones
|
||||||
|
// depending on whether the browser is supported (ie. we think we should be able to load but
|
||||||
|
// failed) or unsupported (where we tried anyway and, lo and behold, we failed).
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
// show the static error in an iframe to not lose any context / console data
|
// show the static error in an iframe to not lose any context / console data
|
||||||
// with some basic styling to make the iframe full page
|
// with some basic styling to make the iframe full page
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -44,6 +44,7 @@ import { UPDATE_EVENT } from "matrix-react-sdk/src/stores/AsyncStore";
|
||||||
import { avatarUrlForRoom, getInitialLetter } from "matrix-react-sdk/src/Avatar";
|
import { avatarUrlForRoom, getInitialLetter } from "matrix-react-sdk/src/Avatar";
|
||||||
import DesktopCapturerSourcePicker from "matrix-react-sdk/src/components/views/elements/DesktopCapturerSourcePicker";
|
import DesktopCapturerSourcePicker from "matrix-react-sdk/src/components/views/elements/DesktopCapturerSourcePicker";
|
||||||
import { OidcRegistrationClientMetadata } from "matrix-js-sdk/src/matrix";
|
import { OidcRegistrationClientMetadata } from "matrix-js-sdk/src/matrix";
|
||||||
|
import { MatrixClientPeg } from "matrix-react-sdk/src/MatrixClientPeg";
|
||||||
|
|
||||||
import VectorBasePlatform from "./VectorBasePlatform";
|
import VectorBasePlatform from "./VectorBasePlatform";
|
||||||
import { SeshatIndexManager } from "./SeshatIndexManager";
|
import { SeshatIndexManager } from "./SeshatIndexManager";
|
||||||
|
@ -127,6 +128,19 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// `userAccessToken` (IPC) is requested by the main process when appending authentication
|
||||||
|
// to media downloads. A reply is sent over the same channel.
|
||||||
|
window.electron.on("userAccessToken", () => {
|
||||||
|
window.electron!.send("userAccessToken", MatrixClientPeg.get()?.getAccessToken());
|
||||||
|
});
|
||||||
|
|
||||||
|
// `serverSupportedVersions` is requested by the main process when it needs to know if the
|
||||||
|
// server supports a particular version. This is primarily used to detect authenticated media
|
||||||
|
// support. A reply is sent over the same channel.
|
||||||
|
window.electron.on("serverSupportedVersions", async () => {
|
||||||
|
window.electron!.send("serverSupportedVersions", await MatrixClientPeg.get()?.getVersions());
|
||||||
|
});
|
||||||
|
|
||||||
// try to flush the rageshake logs to indexeddb before quit.
|
// try to flush the rageshake logs to indexeddb before quit.
|
||||||
window.electron.on("before-quit", function () {
|
window.electron.on("before-quit", function () {
|
||||||
logger.log("element-desktop closing");
|
logger.log("element-desktop closing");
|
||||||
|
|
Loading…
Reference in a new issue