Skip to content

Commit 6155fac

Browse files
authored
Merge branch 'develop' into langleyd/improve-poll-ended-ux
2 parents 7ffcffb + 39fb67c commit 6155fac

File tree

252 files changed

+8069
-6286
lines changed

Some content is hidden

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

252 files changed

+8069
-6286
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"],
1111
parserOptions: {
1212
project: ["./tsconfig.json"],
13+
tsconfigRootDir: __dirname,
1314
},
1415
env: {
1516
browser: true,

.github/labels.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,6 @@
279279
- name: "Z-Flaky-Test-Disabled"
280280
description: "The flaking test has been disabled"
281281
color: "ededed"
282+
- name: "Z-Skip-Coverage"
283+
description: "Skip SonarQube coverage for this PR"
284+
color: "ededed"

.github/workflows/update-topics.yaml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ jobs:
2626
env:
2727
HS_URL: ${{ secrets.BETABOT_HS_URL }}
2828
LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }}
29-
PUBLIC_ROOM_ID: "!IemiTbwVankHTFiEoh:matrix.org"
30-
ANNOUNCEMENT_ROOM_ID: "!bijaLdadorKgNGtHdA:matrix.org"
29+
PUBLIC_DISCUSSION_ROOM_ID: "!xUW4PpAe1CmThA3r2wI8IrgwwsK006-zqWdJCljpd10"
30+
ANNOUNCEMENT_ROOM_ID: "!ars5ndgI6IIYZXECiJ-u8YljHNzShJn3nHdB-3rYI2M"
3131
TOKEN: ${{ secrets.BETABOT_ACCESS_TOKEN }}
3232
RELEASE_STATUS: "Release status: ${{ inputs.expected_status }} expected ${{ inputs.expected_date }}"
3333
with:
3434
script: |
35-
const { HS_URL, TOKEN, RELEASE_STATUS, LOBBY_ROOM_ID, PUBLIC_ROOM_ID, ANNOUNCEMENT_ROOM_ID } = process.env;
35+
const { HS_URL, TOKEN, RELEASE_STATUS, LOBBY_ROOM_ID, PUBLIC_DISCUSSION_ROOM_ID, ANNOUNCEMENT_ROOM_ID } = process.env;
3636
3737
const repo = context.repo;
3838
const { data } = await github.rest.repos.getLatestRelease({
@@ -71,18 +71,23 @@ jobs:
7171
const data = await res.json();
7272
console.log(roomId, "got event", data);
7373
74+
if (!regex.test(data.topic)) {
75+
core.setFailed("Topic format is incorrect for room " + roomId);
76+
return;
77+
}
78+
7479
const topic = data.topic.replace(regex, releaseTopic);
7580
if (topic === data.topic) {
7681
console.log(roomId, "nothing to do");
7782
return;
7883
}
7984
if (data["org.matrix.msc3765.topic"]) {
80-
data["org.matrix.msc3765.topic"].forEach(d => {
85+
data["org.matrix.msc3765.topic"]?.["m.text"].forEach(d => {
8186
d.body = d.body.replace(regex, releaseTopic);
8287
});
8388
}
8489
if (data["m.topic"]) {
85-
data["m.topic"].forEach(d => {
90+
data["m.topic"]?.["m.text"].forEach(d => {
8691
d.body = d.body.replace(regex, releaseTopic);
8792
});
8893
}
@@ -97,12 +102,18 @@ jobs:
97102
});
98103
99104
if (res.ok) {
100-
console.log(roomId, "topic updated:", topic);
105+
const resJson = res.json();
106+
if (resJson.errcode) {
107+
core.setFailed(`Error updating ${roomId}: ${resJson.error}`);
108+
} else {
109+
console.log(roomId, "topic updated:", topic);
110+
}
101111
} else {
102-
console.log(roomId, await res.text());
112+
const errText = await res.text();
113+
core.setFailed(`Error updating ${roomId}: ${errText}`);
103114
}
104115
}
105116
106117
await updateReleaseInTopic(LOBBY_ROOM_ID);
107-
await updateReleaseInTopic(PUBLIC_ROOM_ID);
118+
await updateReleaseInTopic(PUBLIC_DISCUSSION_ROOM_ID);
108119
await updateReleaseInTopic(ANNOUNCEMENT_ROOM_ID);

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
Changes in [1.12.6](https://github.com/element-hq/element-web/releases/tag/v1.12.6) (2025-12-03)
2+
================================================================================================
3+
This release fixes a bug where 1:1 calling was incorrectly not available if no Element Call focus was set.
4+
5+
## 🐛 Bug Fixes
6+
7+
* Add option to pick call options for voice calls. ([#31413](https://github.com/element-hq/element-web/pull/31413)).
8+
19
Changes in [1.12.5](https://github.com/element-hq/element-web/releases/tag/v1.12.5) (2025-12-02)
210
================================================================================================
311
## ✨ Features

code_style.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Unless otherwise specified, the following applies to all code:
7979
11. If a variable is not receiving a value on declaration, its type must be defined.
8080

8181
```typescript
82-
let errorMessage: Optional<string>;
82+
let errorMessage: string;
8383
```
8484

8585
12. Objects can use shorthand declarations, including mixing of types.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "element-web",
3-
"version": "1.12.5",
3+
"version": "1.12.6",
44
"description": "Element: the future of secure communication",
55
"author": "New Vector Ltd.",
66
"repository": {
@@ -129,7 +129,6 @@
129129
"lodash": "^4.17.21",
130130
"maplibre-gl": "^5.0.0",
131131
"matrix-encrypt-attachment": "^1.0.3",
132-
"matrix-events-sdk": "0.0.1",
133132
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
134133
"matrix-widget-api": "^1.14.0",
135134
"memoize-one": "^6.0.0",

packages/shared-components/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
],
1717
parserOptions: {
1818
project: ["./tsconfig.json"],
19+
tsconfigRootDir: __dirname,
1920
},
2021
env: {
2122
browser: true,
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2025 Element Creations Ltd.
3+
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
4+
Please see LICENSE files in the repository root for full details.
5+
*/
6+
7+
import { renderHook } from "jest-matrix-react";
8+
9+
import { BaseViewModel } from "../BaseViewModel";
10+
import { useCreateAutoDisposedViewModel } from "../useCreateAutoDisposedViewModel";
11+
12+
class TestViewModel extends BaseViewModel<{ count: number }, { initial: number }> {
13+
public constructor(props: { initial: number }) {
14+
super(props, { count: props.initial });
15+
}
16+
17+
public increment(): void {
18+
const newCount = this.getSnapshot().count + 1;
19+
this.snapshot.set({ count: newCount });
20+
}
21+
}
22+
23+
describe("useAutoDisposedViewModel", () => {
24+
it("should return view-model", () => {
25+
const vmCreator = (): TestViewModel => new TestViewModel({ initial: 0 });
26+
const { result } = renderHook(() => useCreateAutoDisposedViewModel(vmCreator));
27+
const vm = result.current;
28+
expect(vm).toBeInstanceOf(TestViewModel);
29+
expect(vm.isDisposed).toStrictEqual(false);
30+
});
31+
32+
it("should dispose view-model on unmount", () => {
33+
const vmCreator = (): TestViewModel => new TestViewModel({ initial: 0 });
34+
const { result, unmount } = renderHook(() => useCreateAutoDisposedViewModel(vmCreator));
35+
const vm = result.current;
36+
vm.increment();
37+
unmount();
38+
expect(vm.isDisposed).toStrictEqual(true);
39+
});
40+
41+
it("should recreate view-model on react strict mode", async () => {
42+
const vmCreator = (): TestViewModel => new TestViewModel({ initial: 0 });
43+
const output = renderHook(() => useCreateAutoDisposedViewModel(vmCreator), { reactStrictMode: true });
44+
const vm = output.result.current;
45+
expect(vm.isDisposed).toStrictEqual(false);
46+
});
47+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2025 Element Creations Ltd.
3+
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
4+
Please see LICENSE files in the repository root for full details.
5+
*/
6+
7+
import { useEffect, useState } from "react";
8+
9+
import type { BaseViewModel } from "./BaseViewModel";
10+
11+
type VmCreator<B extends BaseViewModel<unknown, unknown>> = () => B;
12+
13+
/**
14+
* Instantiate a view-model that gets disposed when the calling react component unmounts.
15+
* In other words, this hook ties the lifecycle of a view-model to the lifecycle of a
16+
* react component.
17+
*
18+
* @param vmCreator A function that returns a view-model instance
19+
* @returns view-model instance from vmCreator
20+
* @example
21+
* const vm = useCreateAutoDisposedViewModel(() => new FooViewModel({prop1, prop2, ...});
22+
*/
23+
export function useCreateAutoDisposedViewModel<B extends BaseViewModel<unknown, unknown>>(vmCreator: VmCreator<B>): B {
24+
/**
25+
* The view-model instance may be replaced by a different instance in some scenarios.
26+
* We want to be sure that whichever react component called this hook gets re-rendered
27+
* when this happens, hence the state.
28+
*/
29+
const [viewModel, setViewModel] = useState<B>(vmCreator);
30+
31+
/**
32+
* Our intention here is to ensure that the dispose method of the view-model gets called
33+
* when the component that uses this hook unmounts.
34+
* We can do that by combining a useEffect cleanup with an empty dependency array.
35+
*/
36+
useEffect(() => {
37+
let toDispose = viewModel;
38+
39+
/**
40+
* Because we use react strict mode, react will run our effects twice in dev mode to make
41+
* sure that they are pure.
42+
* This presents a complication - the vm instance that we created in our state initializer
43+
* will get disposed on the first cleanup.
44+
* So we'll recreate the view-model if it's already disposed.
45+
*/
46+
if (viewModel.isDisposed) {
47+
const newViewModel = vmCreator();
48+
// Change toDispose so that we don't end up disposing the already disposed vm.
49+
toDispose = newViewModel;
50+
setViewModel(newViewModel);
51+
}
52+
return () => {
53+
// Dispose the view-model when this component unmounts
54+
toDispose.dispose();
55+
};
56+
57+
/**
58+
* We explicitly provide an empty dependency array as we don't expect the viewModel/viewCreator to
59+
* change.
60+
* Or to put it in another way, the only reason to use this hook is to create/dispose the view-model
61+
* and that is something that should only happen at the start/end of the lifecycle of this component.
62+
*/
63+
// eslint-disable-next-line react-compiler/react-compiler
64+
// eslint-disable-next-line react-hooks/exhaustive-deps
65+
}, []);
66+
67+
return viewModel;
68+
}

playwright/e2e/left-panel/room-list-panel/room-list.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,9 @@ test.describe("Room list", () => {
428428
await app.settings.closeDialog();
429429

430430
await app.settings.openUserSettings("Notifications");
431-
await page.getByText("Show all activity in the room list (dots or number of unread messages)").click();
431+
await page
432+
.getByRole("switch", { name: "Show all activity in the room list (dots or number of unread messages)" })
433+
.check();
432434
await app.settings.closeDialog();
433435

434436
// Switch to the other room to avoid the notification to be cleared

0 commit comments

Comments
 (0)