Skip to content

Commit 5e36209

Browse files
committed
Merge Element Call v0.22.0-rc.2
# Conflicts: # .github/workflows/test.yaml # .github/workflows/zizmor.yml # pnpm-lock.yaml # src/button/Button.tsx # src/components/MediaMuteAndSwitchButton.tsx # src/room/__snapshots__/InCallView.test.tsx.snap # src/tile/MediaView.tsx
2 parents 2b86075 + 73758f7 commit 5e36209

72 files changed

Lines changed: 1198 additions & 682 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/zizmor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ jobs:
2020
persist-credentials: false
2121

2222
- name: Run zizmor 🌈
23-
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
23+
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7

.oxlintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"/*\nCopyright %%CURRENT_YEAR%% Element Creations Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE in the repository root for full details.\n*/\n\n"
3535
],
3636
"element-call/no-observablescope-leak": "error",
37+
"element-call/no-top-level-logger-get-child": "error",
3738
"jsdoc/empty-tags": "error",
3839
"jsdoc/check-property-names": "error",
3940
"jsdoc/require-param-description": "warn",

config/config.sample.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"feature_use_device_session_member_events": true
1313
},
1414
"ssla": "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf",
15-
"matrix_rtc_mode": "legacy",
15+
"matrix_rtc_mode": "compatibility",
1616
"matrix_rtc_session": {
1717
"wait_for_key_rotation_ms": 3000,
1818
"membership_event_expiry_ms": 180000000,

docs/url_params.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ These parameters are relevant to both [widget](./embedded_standalone.md) and [st
6767
| `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. |
6868
| `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) |
6969
| `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. |
70+
| `background` | One of: `solid`, `gradient` | No, defaults to `gradient` | No, defaults to `gradient` | Visual style of the page background. |
7071
| `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. |
7172
| `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. |
7273
| `autoLeave` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. |

eslint/NoObservableScopeLeak.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,21 @@ import { ESLintUtils } from "@typescript-eslint/utils";
99

1010
// These ObservableScope methods will not generally cause resource leaks even if
1111
// called from a callback
12-
const safeScopeMethods = ["bind", "end"];
12+
const safeScopeMethods = new Set(["bind", "end"]);
13+
14+
/**
15+
* Determines whether the variable with the given name is local to
16+
* the enclosing function or class scope.
17+
*/
18+
function isLocal(name, scope) {
19+
// If it is nowhere to be found in the "through" scope, it is local.
20+
if (!scope.through.some(({ identifier }) => identifier.name === name))
21+
return true;
22+
if (scope.type === "function" || scope.type === "class") return false;
23+
// If this is something other than a function or class scope, check its outer
24+
// scope.
25+
return !scope.upper || isLocal(name, scope.upper);
26+
}
1327

1428
const rule = ESLintUtils.RuleCreator(
1529
() => "https://github.com/element-hq/element-call",
@@ -32,15 +46,13 @@ const rule = ESLintUtils.RuleCreator(
3246
Identifier(node) {
3347
const scope = context.sourceCode.getScope(node);
3448
if (
35-
// Is this a reference to a variable defined in an outer ("through") scope?
36-
scope.through.some(
37-
({ identifier }) => identifier.name === node.name,
38-
) &&
49+
// Is this a reference to a variable defined in an outer scope?
50+
!isLocal(node.name, scope) &&
3951
// Exclude calls to "safe" ObservableScope methods
4052
node.parent?.type === "MemberExpression" &&
4153
node.parent.object === node &&
4254
node.parent.property.type === "Identifier" &&
43-
!safeScopeMethods.includes(node.parent.property.name) &&
55+
!safeScopeMethods.has(node.parent.property.name) &&
4456
/(^s|S)cope$/.test(node.name)
4557
) {
4658
// TODO: Once oxlint supports lint rules that rely on TypeScript type-awareness,

eslint/NoTopLevelLoggerGetChild.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
Copyright 2026 Element Creations Ltd.
3+
4+
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
Please see LICENSE in the repository root for full details.
6+
*/
7+
8+
import { ESLintUtils } from "@typescript-eslint/utils";
9+
10+
/**
11+
* Node types that introduce a new non-module scope. A getChild() call nested
12+
* inside any of these is considered "not at the top level".
13+
*/
14+
const FUNCTION_OR_CLASS_TYPES = new Set([
15+
"FunctionDeclaration",
16+
"FunctionExpression",
17+
"ArrowFunctionExpression",
18+
"ClassBody",
19+
]);
20+
21+
const rule = ESLintUtils.RuleCreator(
22+
() => "https://github.com/element-hq/element-call",
23+
)({
24+
name: "no-top-level-logger-get-child",
25+
meta: {
26+
type: "problem",
27+
docs: {
28+
description:
29+
"Disallow calling logger.getChild() at the top level of a module." +
30+
"`getChild` has to be called after the rageshake logger `init()`." +
31+
"If it is called at the top level the child logger will never be setup for rageshakes.",
32+
},
33+
messages: {
34+
noTopLevelGetChild:
35+
"Do not call logger.getChild() at the top level of a module; move it inside a function or class instead that gets called after rageshake logger `init()` is called.",
36+
},
37+
schema: [],
38+
},
39+
create(context) {
40+
// Tracks the local binding names that refer to the logger imported from
41+
// 'matrix-js-sdk/lib/logger', e.g. both `logger` and `rootLogger` in:
42+
// import { logger } from "matrix-js-sdk/lib/logger";
43+
// import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
44+
const loggerNames = new Set();
45+
46+
return {
47+
ImportDeclaration(node) {
48+
if (node.source.value !== "matrix-js-sdk/lib/logger") return;
49+
for (const specifier of node.specifiers) {
50+
if (
51+
specifier.type === "ImportSpecifier" &&
52+
specifier.imported.name === "logger"
53+
) {
54+
loggerNames.add(specifier.local.name);
55+
}
56+
}
57+
},
58+
59+
CallExpression(node) {
60+
// Must be a non-computed member expression call: something.getChild(...)
61+
if (
62+
node.callee.type !== "MemberExpression" ||
63+
node.callee.computed ||
64+
node.callee.property.type !== "Identifier" ||
65+
node.callee.property.name !== "getChild"
66+
)
67+
return;
68+
69+
// The receiver must be one of the tracked logger names.
70+
const object = node.callee.object;
71+
if (object.type !== "Identifier" || !loggerNames.has(object.name))
72+
return;
73+
74+
// Flag the call only when it is at module top level — i.e. there is no
75+
// enclosing function or class body anywhere in the ancestor chain.
76+
const ancestors = context.sourceCode.getAncestors(node);
77+
const isTopLevel = !ancestors.some((a) =>
78+
FUNCTION_OR_CLASS_TYPES.has(a.type),
79+
);
80+
81+
if (isTopLevel) {
82+
context.report({
83+
messageId: "noTopLevelGetChild",
84+
node,
85+
});
86+
}
87+
},
88+
};
89+
},
90+
});
91+
92+
export default rule;

eslint/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ module.exports = {
22
rules: {
33
"copyright-header": require("./CopyrightHeader").default,
44
"no-observablescope-leak": require("./NoObservableScopeLeak").default,
5+
"no-top-level-logger-get-child": require("./NoTopLevelLoggerGetChild")
6+
.default,
57
},
68
};

locales/en/app.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@
228228
"codec_label": "Codec",
229229
"developer_tab_title": "Developer",
230230
"devices": {
231+
"activating": "Activating…",
231232
"camera": "Camera",
232233
"camera_numbered": "Camera {{n}}",
233234
"change_device_button": "Change audio device",

package.json

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
"@formatjs/intl-segmenter": "^11.7.3",
4848
"@livekit/components-core": "^0.12.0",
4949
"@livekit/components-react": "^2.0.0",
50-
"@livekit/protocol": "^1.42.2",
5150
"@livekit/track-processors": "^0.7.1",
5251
"@mediapipe/tasks-vision": "^0.10.18",
5352
"@playwright/test": "^1.60.0",
@@ -81,13 +80,12 @@
8180
"@vitejs/plugin-react": "^6.0.2",
8281
"@vitest/browser-playwright": "^4.1.5",
8382
"@vitest/coverage-v8": "^4.0.18",
84-
"@vitest/ui": "4.1.7",
83+
"@vitest/ui": "4.1.9",
8584
"classnames": "^2.3.1",
8685
"copy-to-clipboard": "^3.3.3",
8786
"eslint-plugin-element-call": "link:eslint",
8887
"eslint-plugin-storybook": "^10.3.6",
8988
"fetch-mock": "11.1.5",
90-
"global-jsdom": "^26.0.0",
9189
"i18next": "^25.0.0",
9290
"i18next-browser-languagedetector": "^8.0.0",
9391
"i18next-cli": "^1.61.0",
@@ -101,7 +99,7 @@
10199
"node-stdlib-browser": "^1.3.1",
102100
"normalize.css": "^8.0.1",
103101
"observable-hooks": "^4.2.3",
104-
"oxfmt": "^0.55.0",
102+
"oxfmt": "^0.56.0",
105103
"oxlint": "^1.70.0",
106104
"oxlint-tsgolint": "^0.23.0",
107105
"pako": "^2.0.4",
@@ -131,18 +129,6 @@
131129
"vitest": "^4.1.5",
132130
"vitest-axe": "^1.0.0-pre.3"
133131
},
134-
"pnpm": {
135-
"overrides": {
136-
"@livekit/components-core>rxjs": "^7.8.1",
137-
"@livekit/track-processors>@mediapipe/tasks-vision": "^0.10.18",
138-
"minimatch": "^10.2.3",
139-
"tar": "^7.5.11",
140-
"glob": "^10.5.0",
141-
"qs": "^6.14.1",
142-
"js-yaml": "^4.1.1",
143-
"esbuild": "^0.28.0"
144-
}
145-
},
146132
"packageManager": "pnpm@11.6.0+sha512.9a36518224080c6fe5165afdcfe79bfa118c29be703f3f462b1e32efe1e98e47e8750b148e08286250aad4113cc7993ca413c4e2cd447752708c2ee5751bc95f",
147133
"dependencies": {
148134
"@jitsi/rnnoise-wasm": "0.2.1",

playwright/fixtures/widget-user.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ export const widgetTest = test.extend<MyFixtures>({
120120
.getByRole("heading", { name: "Welcome Room" }),
121121
).toBeVisible();
122122
} else if (callType === "dm") {
123+
await TestHelpers.closeReleaseAnnouncement(
124+
ewPage1,
125+
"Introducing Sections",
126+
);
127+
123128
await ewPage1
124129
.getByRole("navigation", { name: "Room list" })
125130
.getByRole("button", { name: "New conversation" })

0 commit comments

Comments
 (0)