Compare commits

...

200 Commits

Author SHA1 Message Date
joel.poyet 4be866dd9f fix: re-enable session management 2025-08-22 15:40:44 +02:00
Joël Poyet b3f2c40c5b fix: do not open room settings when on direct chats 2025-08-22 15:09:08 +02:00
joel.poyet 273c2c83ee Revert "chore: move orginal github actions away"
This reverts commit 2db2123eed.
2025-08-22 15:09:08 +02:00
joel.poyet 6f1753629d chore: move orginal github actions away 2025-08-22 15:09:08 +02:00
joel.poyet a0a8103d6a feat: show profile pane when clicked on direct chat room title 2025-08-22 15:09:08 +02:00
Joël Poyet 661e7ad201 feat: remove unnecessary tabs 2025-08-22 15:09:08 +02:00
Joël Poyet 1b6cbad0b8 fix: disable mobile guide 2025-08-22 15:09:08 +02:00
Joël Poyet d21383ed0f Revert "fix: disable heimserver info on login page"
This reverts commit 316d335177.
2025-08-22 15:09:08 +02:00
Joël Poyet 7aa774ab5d fix: disable heimserver info on login page 2025-08-22 15:09:08 +02:00
joel.poyet 8df545b4b3 feat: improve profile view with additional fields and validation 2025-08-22 15:09:08 +02:00
Joël Poyet aaa024c986 chore: fix ci pipeline 2025-08-22 15:09:08 +02:00
Joël Poyet 5f3fe8eae7 feat: add view to see custom user profile fields 2025-08-22 15:09:08 +02:00
Joël Poyet 3561a15b47 fix: set layout 'Nachrichtenblasen' as default 2025-08-22 15:09:08 +02:00
joel.poyet 1d3dbde63c feat: add ability to edit custom user attributes 2025-08-22 15:09:00 +02:00
joel.poyet 401f70769b Revert "chore: move orginal github actions away"
This reverts commit 2db2123eed.
2025-08-22 15:04:36 +02:00
joel.poyet a93184b50a chore: move orginal github actions away 2025-08-22 15:04:36 +02:00
Joël Poyet c985a3c5de chore: pipeline 2025-08-22 15:04:36 +02:00
joel.poyet f17d1882e7 chore: initial adaption for healthchat 2025-08-22 15:04:36 +02:00
joel.poyet 5e5aed412f Merge branch 'element-hq:master' into master 2025-08-22 15:02:59 +02:00
RiotRobot 29e895095f v1.11.109 2025-08-11 11:26:35 +00:00
RiotRobot 0d3a81ee8f Upgrade dependency to matrix-js-sdk@37.13.0 2025-08-11 11:16:00 +00:00
ElementRobot e94d690587 Use userId to filter users in non-federated rooms when showing the InviteDialog (#30364) (#30537)
* Use userId to filter users in non-federated rooms.

* a line

* another line

* Add getDomain to Jest test

(cherry picked from commit 700068a558)

Co-authored-by: Will Hunt <will@half-shot.uk>
2025-08-11 10:50:40 +00:00
ElementRobot 4abdb74673 Catch error when encountering invalid m.room.pinned_events event (#30534) (#30536)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-08-11 11:22:34 +01:00
ElementRobot 93095f99db Allow /upgraderoom command without developer mode enabled (#30527) (#30529)
* Allow /upgraderoom command without developer mode enabled

This will make the instructions for upgrading rooms for hydra a lot
more straightforward, so maybe let's do this at least while hydra
upgrades happen.

* Update test to match

* Unused imports

(cherry picked from commit 4d3fde192d)

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-08-08 16:16:38 +00:00
ElementRobot adfa43dcbb Support for creator/owner power level (#30525) (#30526)
* Support for creator/owner power level

This just shows them as 'Owner' in the list.

* Add test for owner level

(cherry picked from commit 96dbddcb14)

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-08-08 14:28:52 +00:00
joel.poyet 29db63f132 Merge branch 'element-hq:master' into master 2025-08-07 19:37:39 +02:00
RiotRobot 9590e59fd2 v1.11.109-rc.0 2025-08-05 13:09:17 +00:00
RiotRobot 745c12f10d Upgrade dependency to matrix-js-sdk@37.13.0-rc.0 2025-08-05 12:53:23 +00:00
David Baker 6a8493c6eb Update for compatibility with v12 rooms (#30452)
* Update for compatibility with v12 rooms

Stop using powerLevelNorm and reading PL events manually.

To support https://github.com/matrix-org/matrix-js-sdk/pull/4937

* Add test for leave space dialog

* Don't compute stuff if we don't need it

* Use room.client

* Use getSafeUserId

* Remove client arg

* Use getJoinedMembers

and add doc

* Fix tests

* Fix more tests

* Fix other test

* Clarify comment

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-08-05 11:10:30 +00:00
ElementRobot 12927cc4a7 [create-pull-request] automated change (#30465)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-08-05 08:28:41 +00:00
Florian Duros 814f4a85df fix: tooltip on presence (#30474) 2025-08-04 13:54:38 +00:00
Florian Duros 475504d33b New room list: change icon and label of menu item for to start a DM (#30470)
* feat: change `New message` to `Start chat` and change icon

* feat: update the room list empty states

* test: update existing tests

* test(e2e): update playwright tests
2025-08-04 12:42:05 +00:00
Florian Duros 7faee3d1b7 New room list: add tooltip for presence and room status (#30472)
* feat: add tooltip to room avatar

* test: update snapshots
2025-08-04 11:32:32 +00:00
renovate[bot] 30e7567064 Update dependency linkifyjs to v4.3.2 [SECURITY] (#30430)
* Update dependency linkifyjs to v4.3.2 [SECURITY]

* Bump the other linkify deps

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-08-03 21:20:35 +00:00
David Langley 2250f5e6a2 Fix: Clicking on an item in the member list causes it to scroll to the top rather than show the profile view (#30455)
* Fix issue and add test

* Fix MemberTileView

* Add e2e test and comment
2025-08-01 13:16:13 +00:00
Will Hunt e43b696461 Kickoff an Element Web Pro build when a new Docker image is pushed (#30451)
* Kickoff an Element Web Pro build on successful docker push

* v3
2025-08-01 12:01:10 +00:00
ElementRobot bf98ede4fa [create-pull-request] automated change (#30456)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-08-01 06:22:21 +00:00
David Langley cc0ece9837 Implement the member list with virtuoso (#29869)
* implement basic scrolling and keyboard navigation

* Update focus style and improve keyboard navigation

* lint

* Use avatar tootltip for the title rather than the whole button

It's more performant and feels less glitchy than the button tooltip moving around when you scroll.

* lint

* Add tooltip for invite buttons active state

As we have for other icon based buttons in the right panel/app

* Fix location of scrollToIndex and add useCallback

* Improve voiceover experience

- As well as stylng cells, set the tabIndex(roving)
- Natively focus the div with .focus() so screen reader actually moves over the cells
- improve labels and roles

* Fix jest tests

* Add aria index/counts and remove repeating "Open" string in label

* update snapshot

* Add the rest of the keyboard navigation and handle the case when the list looses focus.

* lint and update snapshot

* lint

* Only focus first/lastFocsed cell if focus.currentTarget is the overall list.

So it isn't erroneously called during onClick of an item.

* Put back overscan and fix formatting

* Extract ListView out of MemberList

* lint and fix e2e test

* Update screenshot

It looks like it is slightly better center aligned in the new list, as if maybe it was 1 px to high with the old one.

* Fix default overscan value and add ListView tests

* Just leave the avatar as it was

* We removed the tooltip that showed power level. Removing string.

* Use key rather than index to track focus.

* Remove overscan, fix typos, fix scrollToItem logic

* Use listbox role for member list and correct position/count values to account for the separator

* Fix inadvertant scrolling of the timeline when using pageUp/pageDown

* Always set the roving tab index regardless of whether we are actually focused.

Fixes the issue of not being able to shift+t

* Add aria-hidden to items within the option to avoid the SR calling it a group.

Also

* Make sure there is a roving tab set if the last one has been removed from the list.

* Update snapshot
2025-07-31 15:49:53 +00:00
Richard van der Hoff ab6ef2fa85 Add labs option for history sharing on invite (#30313)
* Add labs option for "share history on invite"

* Set `acceptSharedHistory` when joining a room

* set `shareEncryptedHistory` when sending an invite

* Update src/i18n/strings/en_EN.json

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-31 14:20:37 +00:00
David Baker c79c8c836b Put the 'decrypting' tooltip back (#30446)
...when downloading encrypted attachments (regressed by https://github.com/element-hq/element-web/pull/30330).

Also adds tests for the tooltips and fix the tests so they don't pollute
mocks / dialogs.
2025-07-31 14:20:33 +00:00
ElementRobot 3f0dcaa64c Playwright Docker image updates (#30406)
* [create-pull-request] automated change

* [create-pull-request] automated change

* Bump playwright-common

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-31 10:23:44 +00:00
Robin 652e891663 Stop using deprecated Element Call URL parameters (#30422)
These deprecated parameters will be removed very soon (planned for Element Call version 0.15.0) and we no longer have to care about backward compatibility with old versions of Element Call (due to the embedding/bundling work), so now is the right time to migrate.
2025-07-30 22:41:30 +00:00
Richard van der Hoff 7eb5a29cf0 Hacky fix to the MatrixChat flakiness (#30429)
Add a sleep to let these tests clean up.
2025-07-30 20:50:19 +00:00
RiotRobot 1b38624fd8 Merge branch 'master' into develop 2025-07-30 14:26:24 +00:00
RiotRobot d98533025a v1.11.108 2025-07-30 14:22:51 +00:00
ElementRobot c3e5367e45 Fix downloaded attachments not being decrypted (#30433) (#30434)
* Fix downloaded attachments not being decrypted

Fixes https://github.com/element-hq/element-web/issues/30339

* Import order

(cherry picked from commit 1e15a322a5)

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-07-30 13:57:09 +00:00
David Baker 1e15a322a5 Fix downloaded attachments not being decrypted (#30433)
* Fix downloaded attachments not being decrypted

Fixes https://github.com/element-hq/element-web/issues/30339

* Import order
2025-07-30 12:30:18 +00:00
Richard van der Hoff 452996eacf Playwright: clean up after verification test, to deflake later tests (#30425) 2025-07-30 12:11:14 +00:00
Will Hunt ee120f2fa9 Use server name explicitly for via. (#30362)
* Use server name explicitly for via.

* lint
2025-07-29 17:40:56 +00:00
RiotRobot 94aa51dc57 Reset matrix-js-sdk back to develop branch 2025-07-29 13:08:36 +00:00
RiotRobot e19d3dcd44 Merge branch 'master' into develop 2025-07-29 13:08:16 +00:00
RiotRobot 5a4b5418cc v1.11.107 2025-07-29 13:04:43 +00:00
RiotRobot d1f62317ba Upgrade dependency to matrix-js-sdk@37.12.0 2025-07-29 13:01:13 +00:00
renovate[bot] 9232a220dc Update dependency filesize to v11 (#30380)
* Update dependency filesize to v11

* Update fileSize types

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-29 10:15:11 +00:00
Richard van der Hoff 45a2fd9d63 Re-enable matrixchat test (#30410)
Now that we have better logging for our tests
(https://github.com/element-hq/element-web/pull/30405), I'd like to re-enable
this test so we can try and understsnd what makes it fail.
2025-07-28 21:07:20 +00:00
Richard van der Hoff 7e40e3697f MatrixChat test robustness fixes (#30413)
* MatrixChat-test: clean up better in `afterEach`

Make the MatrixChat tests behave better by letting them finish their work in an
`act` in afterEach. Otherwise we can end up mounting new components during
cleanup, which run tasks in the background

* MatrixChat-test: clean up dispatcher test

This test was kicking off a dispatcher job which would then open a
UserDeviceSettings dialog once the test had finished. That would then throw
exceptions because some of the mock environment had been torn down.

We're just testing that it opens the right dialog, so better to intercept
`createDialog`.

Aso add an `act` to reduce warnings, and replace a `flushPromises` with a
`waitFor` to make the test more robust.
2025-07-28 16:32:53 +00:00
David Langley beaabd5b44 bump wysiwyg to 2.39.0 (#30421) 2025-07-28 15:21:24 +01:00
ElementRobot db5c69e228 Fix e2e shield being invisible in white mode for encrypted room (#30408) (#30411)
Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-28 09:58:20 +01:00
Robin a23a2c03d3 Allow Element Call to send call notifications (#30404)
* Allow Element Call to send call notifications

Currently Element Web is responsible for sending the call notification event, but this is planned to be changed soon. As of the upcoming Element Call 0.14.0 release, it will request the capability to send call notifications itself, and we should auto-approve this capability.

* Add reaction capability missing from test

Element Call does in fact request this one.
2025-07-27 13:37:10 +00:00
Richard van der Hoff c2c040dd42 Lifecycle: add a bit more logging (#30414)
... to see what exactly it thinks is wrong with the session

This may be useful in debugging
https://github.com/element-hq/element-web/issues/30337 and
https://github.com/element-hq/element-web/issues/29708. but will likely be
useful in any case.
2025-07-25 16:17:19 +01:00
Florian Duros c98358cb26 Fix e2e shield being invisible in white mode for encrypted room (#30408)
* fix: e2e icon for encrypted room

* test(e2e): add screenshot for grey shield in encrypted room
2025-07-25 10:56:21 +00:00
Richard van der Hoff d384a9b71b Work around jest bug that swallows console output (#30405)
* Work around jest bug that swallows console output

Hacky workaround for https://github.com/jestjs/jest/issues/15747

* Fix unit test

* Only write logs if there are some to write

* Another test fix
2025-07-25 10:13:52 +00:00
Richard van der Hoff fc04ad26ce Support EventShieldReason.MISMATCHED_SENDER (#30403)
The js-sdk now exposes a new event shield reason, which we should handle
correctly.
2025-07-25 09:43:40 +00:00
Florian Duros b5160c47b3 chore: move i18n.tsx into utils folder (#30400) 2025-07-25 08:14:48 +00:00
Florian Duros 3af8273d6b fix: replace hardcoded string in poll history dialog (#30402) 2025-07-24 16:41:01 +00:00
Florian Duros 81edfece6a fix: replace hardcoded string on qr code back button (#30401) 2025-07-24 15:39:26 +00:00
Florian Duros ab26004c4c Change unencrypted and public pills to blue (#30399)
* feat: change unencrypted and public pill to blue

* test: update snapshots

* test(e2e): update screenshots
2025-07-24 14:52:59 +00:00
Richard van der Hoff ffedca3954 Allow for unknown event shield reasons (#30397)
A forthcoming change to the js-sdk will add a new event shield reason. To avoid
a compile-time failure, add a `default` case to the code handling those
reasons.
2025-07-24 13:16:15 +00:00
David Baker f7ef948cf0 Update playwright-common package (#30396)
So the shared components screenshot generator works
2025-07-24 10:45:15 +00:00
ElementRobot ba828b2194 [create-pull-request] automated change (#30394)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-24 10:02:19 +00:00
Florian Duros 16ef503174 Storybook: add tooltip provider and sort stories (#30392)
* chore: add tooltip provider to storybook preview

* chore: order story alphabetically
2025-07-23 15:30:54 +00:00
Florian Duros 7bfb9818f6 Change color of public room icon (#30390)
* feat: change color of public room icon

* test: update room avatar snapshot

* test(e2E): update screenshots
2025-07-23 13:56:26 +00:00
David Baker dcbba5ea9d Script for updating storybook screenshots (#30340)
* Script for updating storybook screenshots

Requires https://github.com/element-hq/element-modules/pull/43

* Prettier
2025-07-23 12:06:33 +00:00
ElementRobot 6b40da5779 [create-pull-request] automated change (#30384)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-23 11:24:19 +00:00
ElementRobot 941835ccf2 [create-pull-request] automated change (#30326)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-23 08:23:28 +00:00
renovate[bot] 4ec10a9b4d Update typescript-eslint monorepo to v8.37.0 (#30379)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-23 08:10:40 +00:00
renovate[bot] 6a48183a35 Update dependency @sentry/webpack-plugin to v4 (#30381)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 23:13:01 +00:00
renovate[bot] 62b080a50e Update all non-major dependencies (#30374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:55:35 +00:00
renovate[bot] 0dc7fcc64a Update dependency @types/node to v18.19.120 (#30371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:39:15 +00:00
renovate[bot] 354867baa7 Update playwright to v1.54.1 (#30378)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 17:01:34 +00:00
renovate[bot] 4c1e3c82e4 Update dependency testcontainers to v11.3.0 (#30377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:33:02 +00:00
Florian Duros 1e689ac098 Move Flex & Box component into shared component folder (#30357)
* refactor: move Flex component in shared components

* refactor: update imports

* refactor: remove Flex pcss file

* fix: Flex component css override

* test: update snapshots

* fix: html export

* chore: add css module support to jest

* chore: keep old copyright

* refactor: change `mx_Flex` in `ErrorView` to `mx_ErrorView_flexContainer`

* test: update snapshots

* refactor: move Box component in shared components

* refactor: update import and css override

* test: update snapshots
2025-07-22 16:25:45 +00:00
renovate[bot] 16ab7ffbc7 Update Node.js to a803244 (#30370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:24:07 +00:00
renovate[bot] b35e2a8c45 Update dependency @stylistic/eslint-plugin to v5.2.0 (#30376)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:13:45 +00:00
renovate[bot] a07d5b82b3 Update dependency @sentry/browser to v9.40.0 (#30375)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:13:35 +00:00
renovate[bot] ca1420e604 Update nginxinc/nginx-unprivileged:alpine-slim Docker digest to 86df552 (#30369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 16:12:35 +00:00
renovate[bot] 8e59ebb754 Update storybook monorepo to v9.0.17 (#30372)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 15:28:22 +00:00
Timo cc2ee5ea78 Add toggle to hide empty state in devtools (#30352)
* Add toggle to hide empty state in devtools

* use translated string

* lint

* inverse logic(`hide`->`show`)

* move entry in i18n to correct position
2025-07-22 14:11:16 +00:00
Florian Duros 774e0e8f7b Fix color of icon button with outline (#30361)
* fix: room list header button color

* fix: room member list invite button

* test: update room list search snapshot

* test(e2e): update screenshots
2025-07-22 14:11:13 +00:00
RiotRobot acb3d31a07 v1.11.107-rc.0 2025-07-22 13:29:36 +00:00
RiotRobot 9136332f42 Upgrade dependency to matrix-js-sdk@37.12.0-rc.0 2025-07-22 13:25:38 +00:00
dependabot[bot] e0f5f48eef Bump form-data from 4.0.3 to 4.0.4 (#30360)
Bumps [form-data](https://github.com/form-data/form-data) from 4.0.3 to 4.0.4.
- [Release notes](https://github.com/form-data/form-data/releases)
- [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v4.0.3...v4.0.4)

---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-22 12:28:53 +00:00
ElementRobot e7a772472e [create-pull-request] automated change (#30341)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-22 08:51:21 +00:00
Marc 0a97cbaada MVVM userinfo: split header and verification components (#30214)
* feat: mvvm userinfo split header and verification

* test: add userinfoheader tests

* fix: userHeaderVerificationView verification method
2025-07-21 12:04:50 +00:00
R Midhun Suresh 8a879c7fca Message preview should show tooltip with the full message on hover (#30265)
* Add title attribute for message preview

So that the full message is shown in a tooltip on hover.

* Fix test

* Update src/components/views/rooms/RoomListPanel/RoomListItemView.tsx

Co-authored-by: Florian Duros <florianduros@element.io>

---------

Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-21 11:58:54 +00:00
Florian Duros 5b659fe2e5 fix: force ED titlebar color for new room list (#30332) 2025-07-18 13:24:19 +00:00
R Midhun Suresh 42c718666c Skip flaky test (#30338) 2025-07-18 11:35:51 +00:00
David Baker f3a181a792 Fix shared component diff index generation
Because OF COURSE ubuntu has a version of tree from 2023 that doesn't
support the '-' to remove the first path element.
2025-07-18 10:54:07 +01:00
David Baker 148d7fc0a9 Add deployments write priv to visual test uploader 2025-07-18 09:54:46 +01:00
David Baker e42fcb797f Add deployment env 2025-07-18 09:48:34 +01:00
ElementRobot 31fb23a170 [create-pull-request] automated change (#30335)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-18 06:19:14 +00:00
David Baker 69c2afe8e4 Upload visual diffs from storybook tests (#30298)
* Very first pass at shared component views

Turn the trivial TextualEvent into a shared component with a separate view
model for element web. Args to view model will probably change to be more
specific and VM typer needs abstracting out into an interface, but should
give the general idea.

* Remove old TextualEvent

* Pass showHiddenEvents

Because we used it anyway, we just cheated by getting it from the context

* Factor out common view model stuff

* Move ViewModel interface into the shared components

* Add tiny wrapper hook

* Move showHiddenEvents into props fully

* Fill in stories / test

* chore: setup storybook

cherry pick edc5e8705674b8708d986910b02b5d2545777fb3
from florianduros/storybook

* Add TextualEvent component to storybook

* Add mock view model & snapshot

* Remove old style stories entry

* Change import

* Change import

* Prettier

* Add paxckage patch to @types/mdx

for React 19 compat

* Pass getSnapshot as getServerSnapshot too

* Maybe make sonar regognise tests as tests

* Typo

* Use storybook reacvt-vite

There's no reason to use the react-webpack plugin just because our app
is stuck on webpack, it just means we have vite as a dependency too.

* Change here too

* Workaround for incomatible types in rollup

https://github.com/rollup/rollup/issues/5199

* Remove webpack styling addon

Not necessary now we're using vite

* Hopefully do screenshot testing...

* need newer node

* quote issues

* Make it an npm script

* colons

* use right port

* Install playwright browsers

* Try without the if

* Oh right, we need the headless shell

* Pass flag to store received screenshots

and upload diffs too

* Update snapshot from received

* Include platform in snapshot / received dir

because font rendering differs between platforms

* Suffix snapshots with platform instead

like we do for playwright

* Remove unnecessary env vars

and better name

* Add some comments

* Prettier

* Fix yarn.lock

* Memoise vm creation

Co-authored-by: Florian Duros <florianduros@element.io>

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix listener interface

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix types

* Fix more types

* Revert useMemo

as this isn't a hook

* Unused import

* Add missing playwright step

* Add return type annotation

* Change to add / remove subscription callback

* Change to 'add' rather than 'subs.subscribe'

* Add cache specifier for only shell playwright browsers

* Add copyright headers

* Upload visual diffs from storybook testing

* Replace tab

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-17 16:18:08 +00:00
Will Hunt bc1effd2a2 Support rendering notification badges on platforms that do their own icon overlays (#30315)
* Support rendering a seperate overlay icon on supported platforms.

* Add required globals.

* i18n-ize

* Add tests

* lint

* lint

* lint

* update copyrights

* Fix test

* lint

* Fixup

* lint

* remove unused string

* fix test
2025-07-17 12:59:17 +00:00
David Baker 3b0c04c2e9 Add SubscriptionViewModel base class (#30297)
* Very first pass at shared component views

Turn the trivial TextualEvent into a shared component with a separate view
model for element web. Args to view model will probably change to be more
specific and VM typer needs abstracting out into an interface, but should
give the general idea.

* Remove old TextualEvent

* Pass showHiddenEvents

Because we used it anyway, we just cheated by getting it from the context

* Factor out common view model stuff

* Move ViewModel interface into the shared components

* Add tiny wrapper hook

* Move showHiddenEvents into props fully

* Fill in stories / test

* chore: setup storybook

cherry pick edc5e8705674b8708d986910b02b5d2545777fb3
from florianduros/storybook

* Add TextualEvent component to storybook

* Add mock view model & snapshot

* Remove old style stories entry

* Change import

* Change import

* Prettier

* Add paxckage patch to @types/mdx

for React 19 compat

* Pass getSnapshot as getServerSnapshot too

* Maybe make sonar regognise tests as tests

* Typo

* Use storybook reacvt-vite

There's no reason to use the react-webpack plugin just because our app
is stuck on webpack, it just means we have vite as a dependency too.

* Change here too

* Workaround for incomatible types in rollup

https://github.com/rollup/rollup/issues/5199

* Remove webpack styling addon

Not necessary now we're using vite

* Hopefully do screenshot testing...

* need newer node

* quote issues

* Make it an npm script

* colons

* use right port

* Install playwright browsers

* Try without the if

* Oh right, we need the headless shell

* Pass flag to store received screenshots

and upload diffs too

* Update snapshot from received

* Include platform in snapshot / received dir

because font rendering differs between platforms

* Suffix snapshots with platform instead

like we do for playwright

* Remove unnecessary env vars

and better name

* Add some comments

* Prettier

* Fix yarn.lock

* Memoise vm creation

Co-authored-by: Florian Duros <florianduros@element.io>

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix listener interface

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix types

* Fix more types

* Add a superclass that simple view models can extend

to reduce boilerplate

* Revert useMemo

as this isn't a hook

* Unused import

* Actually commit the file the branch is named after

* Add missing playwright step

* Add return type annotation

* Change to add / remove subscription callback

* Change to 'add' rather than 'subs.subscribe'

* Add cache specifier for only shell playwright browsers

* Add copyright headers

* Better comment wording

* Make amit an arrow function

so it can be passed directly as a callback

* Add a test

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-17 12:32:31 +00:00
ioalexander 77cb4b3157 Enhancement: Save image on CTRL+S (#30330)
* Save image on CTRL+S

* fixed cosmetic comments

* fixed test

* refactored out downloading functionality from buttons to useDownloadMedia hook

* ImageView CTRL+S use button component

* added CTRL+S test & lint

* removed forwardRef

* fix lint

* i18n
2025-07-17 09:53:11 +00:00
AlirezaMrtz 3e11a62a3f Add quote functionality to MessageContextMenu (#29893) (#30323)
* Add quote functionality to MessageContextMenu (#29893)

* Remove unused import of getSelectedText from strings utility in EventTile component

* Add space after quoted text in ComposerInsert action

* Add space after quoted text in MessageContextMenu test

* add new line before and after the formated text
2025-07-17 09:45:08 +00:00
ElementRobot 084f447c6e [create-pull-request] automated change (#30331)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-17 06:19:13 +00:00
Florian Duros 55c8256900 fix:put a background color to the left panel when the new room list is enabled (#30328) 2025-07-16 19:13:49 +00:00
Florian Duros b64e9ed675 Add i18n to storybook (#30268)
* refactor: extract i18n from languageHandler to not import matrix-js-sdk, settings...

* fix: circular deps

* feat: add language selector to storybook

* fix: make visual test works in CI
2025-07-16 18:21:09 +00:00
R Midhun Suresh dc2060fc7b Fix flaky scrolling (#30329)
There are two potential problems here:
1. mouse.scroll returns before the scroll is completed
2. visibility check does not check if the element is actually in the
   viewport.

I've added a helper function to make it easier to scroll to the end of
an infinite list.
2025-07-16 15:10:05 +00:00
ElementRobot 0e37fea9f5 [create-pull-request] automated change (#30325)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-16 06:18:29 +00:00
RiotRobot 7bb526b83a Reset matrix-js-sdk back to develop branch 2025-07-15 15:06:00 +00:00
RiotRobot 2885fc2443 Merge branch 'master' into develop 2025-07-15 15:05:36 +00:00
RiotRobot d05806b9e9 v1.11.106 2025-07-15 15:01:54 +00:00
RiotRobot 3f2f463bc3 Upgrade dependency to matrix-js-sdk@37.11.0 2025-07-15 14:47:04 +00:00
ElementRobot 557293af31 Fix missing image download button (#30320) (#30322)
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
Fixes https://github.com/element-hq/element-web/issues/30319
2025-07-15 15:39:46 +01:00
David Baker 114ad1df0d Fix missing image download button (#30320)
Fixes https://github.com/element-hq/element-web/issues/30319
2025-07-15 15:14:14 +01:00
ElementRobot 0fe275fbd2 [create-pull-request] automated change (#30316)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-15 06:20:27 +00:00
AlirezaMrtz 93f04f7aaa Prevent default form submission in MemberListView (#30312) 2025-07-14 13:44:03 +00:00
David Baker 4bbcb8bb5d Initial structure for shared component views (#30216)
* Very first pass at shared component views

Turn the trivial TextualEvent into a shared component with a separate view
model for element web. Args to view model will probably change to be more
specific and VM typer needs abstracting out into an interface, but should
give the general idea.

* Remove old TextualEvent

* Pass showHiddenEvents

Because we used it anyway, we just cheated by getting it from the context

* Factor out common view model stuff

* Move ViewModel interface into the shared components

* Add tiny wrapper hook

* Move showHiddenEvents into props fully

* Fill in stories / test

* chore: setup storybook

cherry pick edc5e8705674b8708d986910b02b5d2545777fb3
from florianduros/storybook

* Add TextualEvent component to storybook

* Add mock view model & snapshot

* Remove old style stories entry

* Change import

* Change import

* Prettier

* Add paxckage patch to @types/mdx

for React 19 compat

* Pass getSnapshot as getServerSnapshot too

* Maybe make sonar regognise tests as tests

* Typo

* Use storybook reacvt-vite

There's no reason to use the react-webpack plugin just because our app
is stuck on webpack, it just means we have vite as a dependency too.

* Change here too

* Workaround for incomatible types in rollup

https://github.com/rollup/rollup/issues/5199

* Remove webpack styling addon

Not necessary now we're using vite

* Hopefully do screenshot testing...

* need newer node

* quote issues

* Make it an npm script

* colons

* use right port

* Install playwright browsers

* Try without the if

* Oh right, we need the headless shell

* Pass flag to store received screenshots

and upload diffs too

* Update snapshot from received

* Include platform in snapshot / received dir

because font rendering differs between platforms

* Suffix snapshots with platform instead

like we do for playwright

* Remove unnecessary env vars

and better name

* Add some comments

* Prettier

* Fix yarn.lock

* Memoise vm creation

Co-authored-by: Florian Duros <florianduros@element.io>

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix listener interface

* Add implements

Co-authored-by: Florian Duros <florianduros@element.io>

* Fix types

* Fix more types

* Revert useMemo

as this isn't a hook

* Unused import

* Add missing playwright step

* Add return type annotation

* Change to add / remove subscription callback

* Change to 'add' rather than 'subs.subscribe'

* Add cache specifier for only shell playwright browsers

* Add copyright headers

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-14 13:13:02 +00:00
ElementRobot 361d36272e [create-pull-request] automated change (#30314)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-14 08:02:29 +00:00
ElementRobot 8bb1b22d46 [create-pull-request] automated change (#30311)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-12 06:18:38 +00:00
Richard van der Hoff 1090c52410 Flaky test issue auto-closer: only close playwright test issues (#30302)
Only the playwright tests are automatically updated, and are therefore safe to
auto-close.
2025-07-11 13:03:55 +00:00
ElementRobot e528f95b2e [create-pull-request] automated change (#30307)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-11 06:19:01 +00:00
ElementRobot f3058c9597 Fix e2e icon colour (#30299) (#30304)
* fix: remove white background on e2e verification icon and put white on the checkmark

* test(e2e): add non regression tests

* chore: remove unused CSS mask

(cherry picked from commit a05ca97409)

Co-authored-by: Florian Duros <florianduros@element.io>
2025-07-10 19:47:50 +00:00
Florian Duros a05ca97409 Fix e2e icon colour (#30299)
* fix: remove white background on e2e verification icon and put white on the checkmark

* test(e2e): add non regression tests

* chore: remove unused CSS mask
2025-07-10 13:50:18 +00:00
Valere Fedronic 2d92b73e5f Widgets: Use the new ClientEvent.ReceivedToDeviceMessage instead of ToDeviceEvent (#30239) 2025-07-10 08:04:29 +00:00
ElementRobot 366eeb7d61 [create-pull-request] automated change (#30301)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-10 06:18:43 +00:00
Richard van der Hoff 26d71530f5 DeviceListener: add logging around key backup upload check (#30291)
* DeviceListener: add logging around key backup upload check

... in an attempt to diagnose what is going on with
https://github.com/element-hq/element-web/issues/30270

* fix typescript

* fix lint
2025-07-09 17:31:36 +00:00
renovate[bot] 7f97f46686 Update all non-major dependencies (#30281)
* Update all non-major dependencies

* Prettier

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-09 11:33:20 +00:00
ElementRobot 287a064127 [create-pull-request] automated change (#30219)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-09 08:58:44 +00:00
renovate[bot] cfd3a968d4 Update dependency testcontainers to v11.1.0 (#30284)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 08:38:08 +00:00
renovate[bot] 6fbc2e7078 Update dependency @vector-im/compound-design-tokens to v5 (#30286)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 08:28:35 +00:00
ElementRobot 31e6f15941 [create-pull-request] automated change (#30294)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-09 08:28:30 +00:00
renovate[bot] f6e8350522 Update babel monorepo to v7.28.0 (#30282)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 07:36:08 +00:00
renovate[bot] afb8e38fd7 Update typescript-eslint monorepo to v8.35.1 (#30280)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:45:57 +00:00
renovate[bot] 6ce5228044 Update dependency cronstrue to v3 (#30287)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 17:32:37 +00:00
renovate[bot] a1db6f5f6e Update nginxinc/nginx-unprivileged:alpine-slim Docker digest to ef0100e (#30273)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 16:47:10 +00:00
renovate[bot] 02f7c9b52d Update definitelyTyped (#30277)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 15:21:04 +00:00
renovate[bot] 8c7daae19f Update playwright to v1.53.2 (#30279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 15:19:06 +00:00
renovate[bot] c1f291347c Update dependency dotenv to v17 (#30288)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 15:14:40 +00:00
renovate[bot] a75c5e2b2b Update dependency postcss-mixins to v12 (#30289)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 14:57:40 +00:00
renovate[bot] 14d1141e8d Update dependency @stylistic/eslint-plugin to v5 (#30285)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 14:55:43 +00:00
renovate[bot] 09cea4ad3a Update dependency @sentry/browser to v9.35.0 (#30283)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 14:51:24 +00:00
renovate[bot] 39dcaaaaee Update dependency @vector-im/compound-design-tokens to v4.0.5 (#30278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 14:43:32 +00:00
renovate[bot] fd45eaaa8e Update Node.js to 125996c (#30274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 14:43:04 +00:00
RiotRobot 3a01a00d51 v1.11.106-rc.0 2025-07-08 13:27:21 +00:00
RiotRobot 33f3ee15fe Upgrade dependency to matrix-js-sdk@37.11.0-rc.0 2025-07-08 13:23:57 +00:00
ElementRobot df50a50741 [create-pull-request] automated change (#30269)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-08 13:23:10 +00:00
Banbuii aa2dc8e574 Fix transparent verification checkmark in dark mode (#30235)
* Fix transparent verification checkmark in dark mode

Fixes Issue https://github.com/element-hq/element-web/issues/28285

* Add white background to E2E Warning Icon

Also adapted the testcases to the new background.
2025-07-07 11:35:03 +00:00
ElementRobot 0f7e394487 [create-pull-request] automated change (#30218)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-07-07 10:39:39 +00:00
Will Hunt 9f313fcc14 Add support for module message hint allowDownloadingMedia (#30252)
* Add support for allowDownloadingMedia

* Add tests.

* Allow downloading when no event is associated.

* fix lint

* Update module API

* Update lock file too

* force CI
2025-07-07 09:03:46 +00:00
Florian Duros 1cb068a91e Fix e2e flakes in new room list (#30254)
* test: retry failing assertion in room list

* test: fix click on room not visible after scroll
2025-07-04 13:37:59 +00:00
Doug 5dd31685bb Rename the mobile_guide_app_variant config values to be clearer. (#30258)
* Fix the default mobile_guide links.

Whilst the script should update these if it fails these should link to Element X which is now the default app that we link out to from this page.

* Rename the mobile_guide_app_variant values to be clearer.

Also handle invalid config values by defaulting to Element X.

* Rename snapshots to match new app variant identifiers.
2025-07-04 12:27:30 +00:00
Hubert Chathi 9095ebdb1b Avoid using accessSecretStorage to create 4S (#30244)
* remove resetCrossSigning flag, which is no longer in use

* drop unnecessary check for cross-signing

The only place where verifyUser is called already checks that cross-signing is
set up.  (The function name is also incorrect, since it checks for the
cross-signing key, and not for 4S.)

* avoid calling accessSecretStorage to set up cross-signing or 4S

Send the user to the Encryption settings tab instead

* only create secret storage when specifically asked to

* deprecate using accessSecretStorage to create new 4S

* also remove the obsolete snapshot

* add tests

* Tweak comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-07-03 13:34:05 +00:00
Florian Duros 66d7c6a100 Fix release announcement test flake (#30250)
* chore: add `hideJumpToBottomButton` option to playwright screenshot

* test: hide jump to bottom button in release announcement test
2025-07-03 10:51:35 +00:00
Doug 90f4d34fbb Update the mobile_guide page to the new design and link out to Element X by default. (#30172)
* Reapply "Update the mobile_guide page to the new design. (#30006)" (#30104)

This reverts commit c51823db5e.

* Use Element X as the default mobile_guide_app_variant when omitted.

* Fix a build error on Windows.

Additionally revert "Remove unnecessary <%= require %> usages" and let webpack handle all of the assets (without a manual copy rule).

* Exclude mobile_guide from coverage gate

It has playwright tests

* Revert the re-introduction of <%= require %>

* Fix snapshot tests on mobile_guide.

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-07-03 08:28:07 +00:00
Will Hunt e1fea71c97 Filter settings exported when rageshaking (#30236)
* Submit filtered settings to rageshakes and sentry.

* Add flag to omit some settings from being exported.

* Hide user timezone

* Hide recent searches and media event ids

* Lint

* use better wording

* lint

* Prevent language from being sent

* Add tests to check keys are prevented from being uploaded.

* don't export invite rules

* Update tests
2025-07-02 08:03:31 +00:00
RiotRobot 99f7656d09 Reset matrix-js-sdk back to develop branch 2025-07-01 15:12:56 +00:00
RiotRobot 0768534885 Merge branch 'master' into develop 2025-07-01 15:12:42 +00:00
RiotRobot d83c619e65 v1.11.105 2025-07-01 15:09:02 +00:00
RiotRobot fe1cddd34b Upgrade dependency to matrix-js-sdk@37.10.0 2025-07-01 14:55:45 +00:00
Simon Knott 3f931d317b Fix link to e2e docs (#30234) 2025-07-01 09:53:00 +00:00
Hubert Chathi 37df62aa4e fix typo in comment and reinstate logging of variables (#30231) 2025-06-30 21:09:50 +00:00
Hubert Chathi 3d56aa7ff6 Fix logic in DeviceListener (#30230)
* remove incorrect check for cross-signing

SETUP_ENCRYPTION tries to set up everything (4S, cross-signing and key backup),
rather than just setting up encryption, as its name would imply.
crossSigningReady == false happens when the user's device isn't verified, so it
should trigger VERIFY_THIS_SESSION rather than SETUP_ENCRYPTION

* reorder conditions in allSystemsReady to match the order in the if statements

* explicitly handle secrets missing from 4S

rather than falling back to the SETUP_ENCRYPTION catch-all.  Also, remove
SETUP_ENCRYPTION since it is no longer used.

* convert button handlers to switch statements for consistency

(almost) all the other functions that use make decisions based on Kind use
switch statements

* update i18n (remove obsolete string)
2025-06-30 14:01:06 +00:00
Marc 58875e5cf2 Mvvm split user info, create powerlevels component (#30005)
* feat: mvvm user info powerlevels

* chore: remove unecesssary comments and add new

* chore: fix lint and rebase

* fix: lint error
2025-06-30 13:26:37 +00:00
renovate[bot] 4a8b365bf8 Update playwright to v1.53.1 (#30205)
* Update playwright to v1.53.1

* Update snapshots

Presumably chrome's font rendering has changed slightly in the new major version

* Scroll until room list item is in view

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-06-27 13:46:20 +00:00
Florian Duros 18ac6b92fa test: use forceCloseAllModals instead of closeCurrentModal (#30211) 2025-06-26 08:02:42 +00:00
Robin 6ce149a7a8 Allow Element Call to learn the room name (#30213)
The latest mobile designs for Element Call have it displaying the room name in an "app bar". So the Element Call widget will soon start requesting the capability to learn the room name, and Element Web should auto-approve this capability.
2025-06-26 07:50:23 +00:00
ElementRobot 75d7a1d644 [create-pull-request] automated change (#30215)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-06-26 06:18:40 +00:00
Florian Duros d0ddc92908 fix: use correct translation for content protection in settings (#30210) 2025-06-25 15:24:25 +00:00
renovate[bot] 4f13242de2 Update dependency @sentry/browser to v9.30.0 (#30204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 12:31:18 +00:00
renovate[bot] 900c4d60bc Update typescript-eslint monorepo to v8.34.1 (#30201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 12:21:28 +00:00
renovate[bot] 925f4f65c7 Update dependency @types/react to v19.1.8 (#30199)
* Update dependency @types/react to v19.1.8

* Remove patch that's no longer needed

(yay!)

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-06-25 10:59:52 +00:00
renovate[bot] 088d8121e7 Update vector-im (#30202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 09:57:36 +00:00
renovate[bot] d216d68e3f Update dependency caniuse-lite to v1.0.30001724 (#30200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 09:37:18 +00:00
ElementRobot f6e28cb3c7 [create-pull-request] automated change (#30208)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-06-25 06:23:44 +00:00
ElementRobot 434e58de52 [create-pull-request] automated change (#30207)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-06-25 06:17:36 +00:00
renovate[bot] 2c299fe24e Update all non-major dependencies (#30203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 17:43:32 +00:00
renovate[bot] 3965a36819 Update definitelyTyped (#30198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 17:42:14 +00:00
renovate[bot] d4dc89cd38 Update sigstore/cosign-installer digest to 398d4b0 (#30197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 16:47:00 +00:00
renovate[bot] fd199b94af Update Node.js to 9ba013a (#30196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 16:46:37 +00:00
renovate[bot] 7eefb30750 Update nginxinc/nginx-unprivileged:alpine-slim Docker digest to ec6b8b1 (#30195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 16:45:36 +00:00
renovate[bot] 5486a1f235 Update guibranco/github-status-action-v2 digest to 741ea90 (#30194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 15:55:36 +00:00
renovate[bot] 73fd91dabd Update docker (#30193)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 15:55:15 +00:00
David Baker e9922ee84f Support m.topic in topic update script (#30192) 2025-06-24 14:38:06 +00:00
David Baker 53eff065e4 Update the public room ID (#30191)
It got upgraded at some point but not changed here
2025-06-24 14:53:11 +01:00
Michael Telatynski 2b8f95a25b Disable file drag-and-drop if insufficient permissions (#30186)
* Disable file drag-and-drop if insufficient permissions

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add tests

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-06-24 13:26:03 +00:00
RiotRobot e956bb5b6d v1.11.105-rc.0 2025-06-24 12:47:31 +00:00
RiotRobot 1349726d52 Upgrade dependency to matrix-js-sdk@37.10.0-rc.0 2025-06-24 12:42:23 +00:00
Florian Duros f707bb410e New room list: add context menu to room list item (#29952)
* chore: update compound-web

* chore: remove unused export

* feat: export content of more option menu

* feat: add context menu

* feat: add `showContextMenu` to vm

* feat: use context menu in new room list

* test: add tests for room list item

* test: fix room list test

* test: add `showContextMenu` test for `useRoomListItemViewModel`

* test: add e2e test for context menu

* chore: update compound

* test: update snapshots and e2e test

* fix: avoid icon blinking when we reopen the context menu

* test: add test for menu closing

* doc: remove useless tsdoc param

* chore: update `@vector-im/compound-web`

* refactor: remove manual focus

* test(e2e): fix focus after closing notification menu

* doc: remove useless jobs
2025-06-24 09:50:27 +00:00
ElementRobot 52f836a0dd [create-pull-request] automated change (#30190)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-06-24 06:18:05 +00:00
ElementRobot c50000d124 Playwright Docker image updates (#29653)
* [create-pull-request] automated change

* Restart homeserver to clear MAS token cache

as commented

---------

Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2025-06-23 15:57:45 +00:00
Will Hunt 0edaef3f7c Support for custom message components via Module API (#30074)
* Add new custom component api.

* Remove context menu, refactor

* fix types

* Add a test for custom modules.

* tidy

* Rewrite for new API

* Update tests

* lint

* Allow passing in props to original component

* Add hinting

* Update tests to be complete

* lint a bit more

* update docstring

* update @element-hq/element-web-module-api to 1.1.0

* fix types

* updates

* hide jump to bottom button that was causing flakes

* lint

* lint

* Use module matrix event interface instead.

* update to new module sdk

* adapt custom module sample

* Issues caught by Sonar

* lint

* fix issues

* make the comment make sense

* fix import
2025-06-23 11:55:22 +00:00
ElementRobot ac9c6f11fb [create-pull-request] automated change (#30182)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-06-23 06:25:15 +00:00
joel.poyet 9400aacd07 Merge branch 'element-hq:master' into master 2025-06-22 08:37:03 +02:00
joel.poyet eb45b12a01 Merge branch 'element-hq:master' into master 2025-04-08 23:17:09 +02:00
joel.poyet d745f791ae Merge branch 'element-hq:master' into master 2025-04-05 11:20:26 +02:00
joel.poyet f7ab449efe fix: avoid flipping brand name 2024-10-22 13:24:18 +02:00
joel.poyet 93ea9917da fix: add basic branding 2024-10-22 11:48:01 +02:00
342 changed files with 12781 additions and 5166 deletions
+6 -1
View File
@@ -1,6 +1,11 @@
module.exports = {
plugins: ["matrix-org", "eslint-plugin-react-compiler"],
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react", "plugin:matrix-org/a11y"],
extends: [
"plugin:matrix-org/babel",
"plugin:matrix-org/react",
"plugin:matrix-org/a11y",
"plugin:storybook/recommended",
],
parserOptions: {
project: ["./tsconfig.json"],
},
+62
View File
@@ -0,0 +1,62 @@
name: build-healthchat-app
# run on branch release/healthchat
on:
push:
branches:
- release/healthchat
jobs:
build-healthchat-app:
runs-on: ubuntu-latest
permissions:
contents: read # This is required to read the repo content
packages: write # This is required to push the Docker image
id-token: write # Required to get the certificate for the attestation
attestations: write # Required to push the attestation
env:
DOCKER_REGISTRY: "ghcr.io"
DOCKER_IMAGE: ${{ format('{0}/healthchat-web', github.repository) }}
DOCKER_IMAGE_TAG: "latest"
DOCKER_PUSH: true
DOCKER_SIGNING: false
FORCE_COLOR: 1
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed for docker-package to be able to calculate the version
- name: Log in to the Github Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=${{ env.DOCKER_IMAGE_TAG }}
type=raw,value=${{ github.sha }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker images
id: push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: ${{ env.DOCKER_PUSH }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
#cache-from: type=gha
#cache-to: type=gha,mode=max
- name: Generate artifact attestation
if: ${{ env.DOCKER_SIGNING == 'true' }}
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: ${{ env.DOCKER_PUSH }}
+17 -4
View File
@@ -25,14 +25,14 @@ jobs:
fetch-depth: 0 # needed for docker-package to be able to calculate the version
- name: Install Cosign
uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
if: github.event_name != 'pull_request'
- name: Set up QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
with:
install: true
@@ -53,7 +53,7 @@ jobs:
- name: Build and load
id: test-build
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
context: .
load: true
@@ -110,7 +110,7 @@ jobs:
- name: Build and push
id: build-and-push
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
if: github.event_name != 'pull_request'
with:
context: .
@@ -139,3 +139,16 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: vectorim/element-web
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
if: github.event_name != 'pull_request'
with:
repository: element-hq/element-web-pro
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
event-type: image-built
# Stable way to determine the :version
client-payload: |-
{
"base-ref": "${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}"
}
@@ -0,0 +1,51 @@
# Triggers after the shared component tests have finished,
# It uploads the received images and diffs to netlify, printing the URLs to the console
name: Upload Shared Component Visual Test Diffs
on:
workflow_run:
workflows: ["Shared Component Visual Tests"]
types:
- completed
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }}
permissions: {}
jobs:
report:
if: github.event.workflow_run.conclusion == 'failure'
name: Upload Diffs
runs-on: ubuntu-24.04
environment: Netlify
permissions:
actions: read
deployments: write
steps:
- name: Install tree
run: "sudo apt-get install -y tree"
- name: Download Diffs
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: received-images
path: received-images
- name: Generate Index
run: "cd received-images && tree -L 1 --noreport -H '' -o index.html ."
- name: 📤 Deploy to Netlify
uses: matrix-org/netlify-pr-preview@9805cd123fc9a7e421e35340a05e1ebc5dee46b5 # v3
with:
path: received-images
owner: ${{ github.event.workflow_run.head_repository.owner.login }}
branch: ${{ github.event.workflow_run.head_branch }}
revision: ${{ github.event.workflow_run.head_sha }}
token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site_id: ${{ vars.NETLIFY_SITE_ID }}
desc: Shared Component Visual Diffs
deployment_env: SharedComponentDiffs
prefix: "diffs-"
@@ -0,0 +1,70 @@
name: Shared Component Visual Tests
on:
pull_request: {}
merge_group:
types: [checks_requested]
push:
branches: [develop, master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
permissions: {} # No permissions required
jobs:
testStorybook:
name: "Run Visual Tests"
runs-on: ubuntu-24.04
permissions:
actions: read
issues: read
pull-requests: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
persist-credentials: false
repository: element-hq/element-web
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
cache: "yarn"
node-version: "lts/*"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Get installed Playwright version
id: playwright
run: echo "version=$(yarn list --pattern @playwright/test --depth=0 --json --non-interactive --no-progress | jq -r '.data.trees[].name')" >> $GITHUB_OUTPUT
- name: Cache playwright binaries
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-${{ runner.arch }}-playwright-${{ steps.playwright.outputs.version }}-onlyshell
- name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: "yarn playwright install --with-deps --only-shell"
- name: Build Element Web resources
# Needed to prepare language files
run: "yarn build:res"
- name: Build storybook dependencies
# When the first test is ran, it will fail because the dependencies are not yet built.
# This step is to ensure that the dependencies are built before running the tests.
run: "yarn test:storybook:ci"
continue-on-error: true
- name: Run Visual tests
run: "yarn test:storybook:ci"
- name: Upload received images & diffs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: received-images
path: playwright/shared-component-received
+1 -1
View File
@@ -104,7 +104,7 @@ jobs:
- name: Skip SonarCloud in merge queue
if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true'
uses: guibranco/github-status-action-v2@5f2b01ce1394109f70954ae6b69ef41cf7928e63
uses: guibranco/github-status-action-v2@741ea90ba6c3ca76fe0d43ba11a90cda97d5e685
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: success
+3 -1
View File
@@ -15,12 +15,14 @@ jobs:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
with:
operations-per-run: 100
# Flaky test issue closing
only-issue-labels: "Z-Flaky-Test"
any-of-issue-labels: "Z-Flaky-Test-Chrome,Z-Flaky-Test-Firefox,Z-Flaky-Test-Webkit"
days-before-issue-stale: 14
days-before-issue-close: 0
close-issue-message: "This flaky test issue has not been updated in 14 days. It is being closed as presumed resolved."
exempt-issue-labels: "Z-Flaky-Test-Disabled"
# Stale PR closing
days-before-pr-stale: 180
days-before-pr-close: 0
+6 -1
View File
@@ -26,7 +26,7 @@ jobs:
env:
HS_URL: ${{ secrets.BETABOT_HS_URL }}
LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }}
PUBLIC_ROOM_ID: "!YTvKGNlinIzlkMTVRl:matrix.org"
PUBLIC_ROOM_ID: "!IemiTbwVankHTFiEoh:matrix.org"
ANNOUNCEMENT_ROOM_ID: "!bijaLdadorKgNGtHdA:matrix.org"
TOKEN: ${{ secrets.BETABOT_ACCESS_TOKEN }}
RELEASE_STATUS: "Release status: ${{ inputs.expected_status }} expected ${{ inputs.expected_date }}"
@@ -81,6 +81,11 @@ jobs:
d.body = d.body.replace(regex, releaseTopic);
});
}
if (data["m.topic"]) {
data["m.topic"].forEach(d => {
d.body = d.body.replace(regex, releaseTopic);
});
}
res = await fetch(apiUrl, {
method: "PUT",
+3
View File
@@ -31,3 +31,6 @@ electron/pub
/index.html
# version file and tarball created by `npm pack` / `yarn pack`
/git-revision.txt
*storybook.log
storybook-static
+28
View File
@@ -0,0 +1,28 @@
/*
Copyright 2025 New Vector 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.
*/
import { create } from "storybook/theming";
export default create({
base: "light",
// Colors
textColor: "#1b1d22",
colorSecondary: "#111111",
// UI
appBg: "#ffffff",
appContentBg: "#ffffff",
// Toolbar
barBg: "#ffffff",
brandTitle: "Element Web",
brandUrl: "https://github.com/element-hq/element-web",
brandImage: "https://element.io/images/logo-ele-secondary.svg",
brandTarget: "_self",
});
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2025 New Vector 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.
*/
import { Addon, types, useGlobals } from "storybook/manager-api";
import { WithTooltip, IconButton, TooltipLinkList } from "storybook/internal/components";
import React from "react";
import { GlobeIcon } from "@storybook/icons";
// We can't import `shared/i18n.tsx` directly here.
// The storybook addon doesn't seem to benefit the vite config of storybook and we can't resolve the alias in i18n.tsx.
import json from "../webapp/i18n/languages.json";
const languages = Object.keys(json).filter((lang) => lang !== "default");
/**
* Returns the title of a language in the user's locale.
*/
function languageTitle(language: string): string {
return new Intl.DisplayNames([language], { type: "language", style: "short" }).of(language) || language;
}
export const languageAddon: Addon = {
title: "Language Selector",
type: types.TOOL,
render: ({ active }) => {
const [globals, updateGlobals] = useGlobals();
const selectedLanguage = globals.language || "en";
return (
<WithTooltip
placement="top"
trigger="click"
closeOnOutsideClick
tooltip={({ onHide }) => {
return (
<TooltipLinkList
links={languages.map((language) => ({
id: language,
title: languageTitle(language),
active: selectedLanguage === language,
onClick: async () => {
// Update the global state with the selected language
updateGlobals({ language });
onHide();
},
}))}
/>
);
}}
>
<IconButton title="Language">
<GlobeIcon />
{languageTitle(selectedLanguage)}
</IconButton>
</WithTooltip>
);
},
};
+40
View File
@@ -0,0 +1,40 @@
/*
Copyright 2025 New Vector 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.
*/
import type { StorybookConfig } from "@storybook/react-vite";
import path from "node:path";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import { mergeConfig } from "vite";
const config: StorybookConfig = {
stories: ["../src/shared-components/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
staticDirs: ["../webapp"],
addons: ["@storybook/addon-docs", "@storybook/addon-designs"],
framework: "@storybook/react-vite",
core: {
disableTelemetry: true,
},
typescript: {
reactDocgen: "react-docgen-typescript",
},
async viteFinal(config) {
return mergeConfig(config, {
resolve: {
alias: {
// Alias used by i18n.tsx
$webapp: path.resolve("webapp"),
},
},
// Needed for counterpart to work
plugins: [nodePolyfills({ include: ["process", "util"] })],
server: {
allowedHosts: ["localhost", ".docker.internal"],
},
});
},
};
export default config;
+18
View File
@@ -0,0 +1,18 @@
/*
Copyright 2025 New Vector 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.
*/
import React from "react";
import { addons } from "storybook/manager-api";
import ElementTheme from "./ElementTheme";
import { languageAddon } from "./languageAddon";
addons.setConfig({
theme: ElementTheme,
});
addons.register("elementhq/language", () => addons.add("language", languageAddon));
+10
View File
@@ -0,0 +1,10 @@
/*
Copyright 2025 New Vector 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.
*/
.docs-story {
background: var(--cpd-color-bg-canvas-default);
}
+106
View File
@@ -0,0 +1,106 @@
import type { ArgTypes, Preview, Decorator } from "@storybook/react-vite";
import { addons } from "storybook/preview-api";
import "../res/css/shared.pcss";
import "./preview.css";
import React, { useLayoutEffect } from "react";
import { FORCE_RE_RENDER } from "storybook/internal/core-events";
import { setLanguage } from "../src/shared-components/utils/i18n";
import { TooltipProvider } from "@vector-im/compound-web";
export const globalTypes = {
theme: {
name: "Theme",
description: "Global theme for components",
toolbar: {
icon: "circlehollow",
title: "Theme",
items: [
{ title: "System", value: "system", icon: "browser" },
{ title: "Light", value: "light", icon: "sun" },
{ title: "Light (high contrast)", value: "light-hc", icon: "sun" },
{ title: "Dark", value: "dark", icon: "moon" },
{ title: "Dark (high contrast)", value: "dark-hc", icon: "moon" },
],
},
},
language: {
name: "Language",
description: "Global language for components",
},
initialGlobals: {
theme: "system",
language: "en",
},
} satisfies ArgTypes;
const allThemesClasses = globalTypes.theme.toolbar.items.map(({ value }) => `cpd-theme-${value}`);
const ThemeSwitcher: React.FC<{
theme: string;
}> = ({ theme }) => {
useLayoutEffect(() => {
document.documentElement.classList.remove(...allThemesClasses);
if (theme !== "system") {
document.documentElement.classList.add(`cpd-theme-${theme}`);
}
return () => document.documentElement.classList.remove(...allThemesClasses);
}, [theme]);
return null;
};
const withThemeProvider: Decorator = (Story, context) => {
return (
<>
<ThemeSwitcher theme={context.globals.theme} />
<Story />
</>
);
};
const LanguageSwitcher: React.FC<{
language: string;
}> = ({ language }) => {
useLayoutEffect(() => {
const changeLanguage = async (language: string) => {
await setLanguage(language);
// Force the component to re-render to apply the new language
addons.getChannel().emit(FORCE_RE_RENDER);
};
changeLanguage(language);
}, [language]);
return null;
};
export const withLanguageProvider: Decorator = (Story, context) => {
return (
<>
<LanguageSwitcher language={context.globals.language} />
<Story />
</>
);
};
const withTooltipProvider: Decorator = (Story) => {
return (
<TooltipProvider>
<Story />
</TooltipProvider>
);
};
const preview: Preview = {
tags: ["autodocs"],
decorators: [withThemeProvider, withLanguageProvider, withTooltipProvider],
parameters: {
options: {
storySort: {
method: "alphabetical",
},
},
},
};
export default preview;
+37
View File
@@ -0,0 +1,37 @@
/*
Copyright 2025 New Vector 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.
*/
import { waitForPageReady } from "@storybook/test-runner";
import { toMatchImageSnapshot } from "jest-image-snapshot";
const customSnapshotsDir = `${process.cwd()}/playwright/shared-component-snapshots/`;
const customReceivedDir = `${process.cwd()}/playwright/shared-component-received/`;
/**
* @type {import('@storybook/test-runner').TestRunnerConfig}
*/
const config = {
setup(page) {
expect.extend({ toMatchImageSnapshot });
},
async postVisit(page, context) {
await waitForPageReady(page);
// If you want to take screenshot of multiple browsers, use
// page.context().browser().browserType().name() to get the browser name to prefix the file name
const image = await page.screenshot();
expect(image).toMatchImageSnapshot({
customSnapshotsDir,
customSnapshotIdentifier: `${context.id}-${process.platform}`,
storeReceivedOnFailure: true,
customReceivedDir,
customDiffDir: customReceivedDir,
});
},
};
export default config;
+3
View File
@@ -19,3 +19,6 @@ include:
* Thom Cleary (https://github.com/thomcatdotrocks)
Small update for tarball deployment
* Alexander (https://github.com/ioalexander)
Save image on CTRL + S shortcut
+98
View File
@@ -1,3 +1,101 @@
Changes in [1.11.109](https://github.com/element-hq/element-web/releases/tag/v1.11.109) (2025-08-11)
====================================================================================================
This release supports the upcoming v12 ("hydra") Matrix room version and is necessary to view and participate in these rooms.
## ✨ Features
* [Backport staging] Allow /upgraderoom command without developer mode enabled ([#30529](https://github.com/element-hq/element-web/pull/30529)). Contributed by @RiotRobot.
* [Backport staging] Support for creator/owner power level ([#30526](https://github.com/element-hq/element-web/pull/30526)). Contributed by @RiotRobot.
* New room list: change icon and label of menu item for to start a DM ([#30470](https://github.com/element-hq/element-web/pull/30470)). Contributed by @florianduros.
* Implement the member list with virtuoso ([#29869](https://github.com/element-hq/element-web/pull/29869)). Contributed by @langleyd.
* Add labs option for history sharing on invite ([#30313](https://github.com/element-hq/element-web/pull/30313)). Contributed by @richvdh.
* Bump wysiwyg to 2.39.0 adding support for pasting rich text content in the Rich Text Edtior ([#30421](https://github.com/element-hq/element-web/pull/30421)). Contributed by @langleyd.
* Support `EventShieldReason.MISMATCHED_SENDER` ([#30403](https://github.com/element-hq/element-web/pull/30403)). Contributed by @richvdh.
* Change unencrypted and public pills to blue ([#30399](https://github.com/element-hq/element-web/pull/30399)). Contributed by @florianduros.
* Change color of public room icon ([#30390](https://github.com/element-hq/element-web/pull/30390)). Contributed by @florianduros.
* Script for updating storybook screenshots ([#30340](https://github.com/element-hq/element-web/pull/30340)). Contributed by @dbkr.
* Add toggle to hide empty state in devtools ([#30352](https://github.com/element-hq/element-web/pull/30352)). Contributed by @toger5.
## 🐛 Bug Fixes
* [Backport staging] Use userId to filter users in non-federated rooms when showing the InviteDialog ([#30537](https://github.com/element-hq/element-web/pull/30537)). Contributed by @RiotRobot.
* [Backport staging] Catch error when encountering invalid m.room.pinned\_events event ([#30536](https://github.com/element-hq/element-web/pull/30536)). Contributed by @RiotRobot.
* Update for compatibility with v12 rooms ([#30452](https://github.com/element-hq/element-web/pull/30452)). Contributed by @dbkr.
* New room list: fix tooltip on presence ([#30474](https://github.com/element-hq/element-web/pull/30474)). Contributed by @florianduros.
* New room list: add tooltip for presence and room status ([#30472](https://github.com/element-hq/element-web/pull/30472)). Contributed by @florianduros.
* Fix: Clicking on an item in the member list causes it to scroll to the top rather than show the profile view ([#30455](https://github.com/element-hq/element-web/pull/30455)). Contributed by @langleyd.
* Put the 'decrypting' tooltip back ([#30446](https://github.com/element-hq/element-web/pull/30446)). Contributed by @dbkr.
* Use server name explicitly for via. ([#30362](https://github.com/element-hq/element-web/pull/30362)). Contributed by @Half-Shot.
* fix: replace hardcoded string in poll history dialog ([#30402](https://github.com/element-hq/element-web/pull/30402)). Contributed by @florianduros.
* fix: replace hardcoded string on qr code back button ([#30401](https://github.com/element-hq/element-web/pull/30401)). Contributed by @florianduros.
* Fix color of icon button with outline ([#30361](https://github.com/element-hq/element-web/pull/30361)). Contributed by @florianduros.
Changes in [1.11.108](https://github.com/element-hq/element-web/releases/tag/v1.11.108) (2025-07-30)
====================================================================================================
## 🐛 Bug Fixes
* [Backport staging] Fix downloaded attachments not being decrypted ([#30434](https://github.com/element-hq/element-web/pull/30434)). Contributed by @RiotRobot.
Changes in [1.11.107](https://github.com/element-hq/element-web/releases/tag/v1.11.107) (2025-07-29)
====================================================================================================
## ✨ Features
* Message preview should show tooltip with the full message on hover ([#30265](https://github.com/element-hq/element-web/pull/30265)). Contributed by @MidhunSureshR.
* Support rendering notification badges on platforms that do their own icon overlays ([#30315](https://github.com/element-hq/element-web/pull/30315)). Contributed by @Half-Shot.
* Add SubscriptionViewModel base class ([#30297](https://github.com/element-hq/element-web/pull/30297)). Contributed by @dbkr.
* Enhancement: Save image on CTRL+S ([#30330](https://github.com/element-hq/element-web/pull/30330)). Contributed by @ioalexander.
* Add quote functionality to MessageContextMenu (#29893) ([#30323](https://github.com/element-hq/element-web/pull/30323)). Contributed by @AlirezaMrtz.
* Initial structure for shared component views ([#30216](https://github.com/element-hq/element-web/pull/30216)). Contributed by @dbkr.
## 🐛 Bug Fixes
* [Backport staging] Fix e2e shield being invisible in white mode for encrypted room ([#30411](https://github.com/element-hq/element-web/pull/30411)). Contributed by @RiotRobot.
* Force ED titlebar color for new room list ([#30332](https://github.com/element-hq/element-web/pull/30332)). Contributed by @florianduros.
* Add a background color to left panel for macos titlebar in element desktop ([#30328](https://github.com/element-hq/element-web/pull/30328)). Contributed by @florianduros.
* Fix: Prevent page refresh on Enter key in right panel member search ([#30312](https://github.com/element-hq/element-web/pull/30312)). Contributed by @AlirezaMrtz.
Changes in [1.11.106](https://github.com/element-hq/element-web/releases/tag/v1.11.106) (2025-07-15)
====================================================================================================
## ✨ Features
* [Backport staging] Fix e2e icon colour ([#30304](https://github.com/element-hq/element-web/pull/30304)). Contributed by @RiotRobot.
* Add support for module message hint `allowDownloadingMedia` ([#30252](https://github.com/element-hq/element-web/pull/30252)). Contributed by @Half-Shot.
* Update the mobile\_guide page to the new design and link out to Element X by default. ([#30172](https://github.com/element-hq/element-web/pull/30172)). Contributed by @pixlwave.
* Filter settings exported when rageshaking ([#30236](https://github.com/element-hq/element-web/pull/30236)). Contributed by @Half-Shot.
* Allow Element Call to learn the room name ([#30213](https://github.com/element-hq/element-web/pull/30213)). Contributed by @robintown.
## 🐛 Bug Fixes
* [Backport staging] Fix missing image download button ([#30322](https://github.com/element-hq/element-web/pull/30322)). Contributed by @RiotRobot.
* Fix transparent verification checkmark in dark mode ([#30235](https://github.com/element-hq/element-web/pull/30235)). Contributed by @Banbuii.
* Fix logic in DeviceListener ([#30230](https://github.com/element-hq/element-web/pull/30230)). Contributed by @uhoreg.
* Disable file drag-and-drop if insufficient permissions ([#30186](https://github.com/element-hq/element-web/pull/30186)). Contributed by @t3chguy.
Changes in [1.11.105](https://github.com/element-hq/element-web/releases/tag/v1.11.105) (2025-07-01)
====================================================================================================
## ✨ Features
* New room list: add context menu to room list item ([#29952](https://github.com/element-hq/element-web/pull/29952)). Contributed by @florianduros.
* Support for custom message components via Module API ([#30074](https://github.com/element-hq/element-web/pull/30074)). Contributed by @Half-Shot.
* Prompt users to set up recovery ([#30075](https://github.com/element-hq/element-web/pull/30075)). Contributed by @uhoreg.
* Update `IconButton` colors ([#30124](https://github.com/element-hq/element-web/pull/30124)). Contributed by @florianduros.
* New room list: filter list can be collapsed ([#29992](https://github.com/element-hq/element-web/pull/29992)). Contributed by @florianduros.
* Show `EmptyRoomListView` when low priority filter matches zero rooms ([#30122](https://github.com/element-hq/element-web/pull/30122)). Contributed by @MidhunSureshR.
## 🐛 Bug Fixes
* Fix untranslatable string "People" in notifications beta ([#30165](https://github.com/element-hq/element-web/pull/30165)). Contributed by @t3chguy.
* Force verification even after logging in via delegate ([#30141](https://github.com/element-hq/element-web/pull/30141)). Contributed by @andybalaam.
* Hide add integrations button based on UIComponent.AddIntegrations ([#30140](https://github.com/element-hq/element-web/pull/30140)). Contributed by @t3chguy.
* Use nav for new room list and label sections ([#30134](https://github.com/element-hq/element-web/pull/30134)). Contributed by @dbkr.
* Spacestore should emit event after rebuilding home space ([#30132](https://github.com/element-hq/element-web/pull/30132)). Contributed by @MidhunSureshR.
* Handle m.room.pinned\_events being invalid ([#30129](https://github.com/element-hq/element-web/pull/30129)). Contributed by @t3chguy.
Changes in [1.11.104](https://github.com/element-hq/element-web/releases/tag/v1.11.104) (2025-06-17)
====================================================================================================
## ✨ Features
+82
View File
@@ -0,0 +1,82 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
### Development
- `yarn start` - Run development server on http://localhost:8080
- `yarn start:https` - Run development server with HTTPS
- `yarn build` - Production build (outputs to webapp/)
- `yarn dist` - Create distribution tarball
### Testing
- `yarn test` - Run Jest unit tests
- `yarn test:playwright` - Run Playwright e2e tests
- `yarn test:playwright:open` - Open Playwright test UI
- `yarn coverage` - Run tests with coverage reporting
To run a single test file:
- `yarn test path/to/test-file.test.ts`
- `yarn test:playwright path/to/e2e-test.ts`
### Code Quality
- `yarn lint` - Run all linters (TypeScript, ESLint, Stylelint)
- `yarn lint:js-fix` - Auto-fix ESLint issues
- `yarn lint:types` - TypeScript type checking only
- `yarn lint:style` - Check CSS/PostCSS styles
### Utilities
- `yarn make-component` - Scaffold new React component
- `yarn i18n` - Manage translations
- `yarn storybook` - Run Storybook on port 6007
## Architecture
This is Element Web, a Matrix client built with React and TypeScript, customized as "HealthChat". Key architectural patterns:
### Component Structure
The application follows a hierarchical component structure:
- `MatrixChat` - Root component managing the entire application state
- `LeftPanel` - Room list, spaces, and navigation
- `MainSplit` - Central room view with messages and input
- `RightPanel` - Member list, room info, and contextual panels
Components are organized in `/src/components/`:
- `/structures/` - Major layout components
- `/views/` - Reusable UI components grouped by function (auth, dialogs, messages, rooms, settings)
### State Management
Uses Flux architecture with:
- Centralized dispatcher in `/src/dispatcher/`
- Stores in `/src/stores/` as singletons
- Actions dispatched through `dis.dispatch()`
### Styling
- PostCSS files with `.pcss` extension
- BEM-like naming: `mx_ComponentName_element`
- Component styles co-located with components (e.g., `_MessageTile.pcss`)
- Theming via CSS custom properties
### Matrix Integration
- Uses `matrix-js-sdk` for all Matrix protocol operations
- Client instance accessed via `MatrixClientPeg`
- Room and event handling through SDK abstractions
### Module System
Plugin architecture in `/src/modules/`:
- Allows runtime extension of functionality
- Module API for registering custom components and handlers
### Testing Patterns
- Unit tests in `/test/unit-tests/` using Jest
- E2E tests in `/playwright/e2e/` using Playwright
- Mock Matrix client and SDK extensively in tests
- Component tests via Storybook
### Important Conventions
- TypeScript strict mode - always use explicit types
- Functional components with hooks preferred over class components
- Translations use `_t()` function with hierarchical keys
- 4-space indentation, 120 character line limit
- Component files: UpperCamelCase, utilities: kebab-case
+3 -3
View File
@@ -1,7 +1,7 @@
# syntax=docker.io/docker/dockerfile:1.16-labs@sha256:bb5e2b225985193779991f3256d1901a0b3e6a0b284c7bffa0972064f4a6d458
# syntax=docker.io/docker/dockerfile:1.17-labs@sha256:9187104f31e3a002a8a6a3209ea1f937fb7486c093cbbde1e14b0fa0d7e4f1b5
# Builder
FROM --platform=$BUILDPLATFORM node:22-bullseye@sha256:f16d8e8af67bb6361231e932b8b3e7afa040cbfed181719a450b02c3821b26c1 AS builder
FROM --platform=$BUILDPLATFORM node:22-bullseye@sha256:a80324457a2c8d09c83ff9edf2bdf71f378d3288de920e68a358bd3c484b8c4a AS builder
# Support custom branch of the js-sdk. This also helps us build images of element-web develop.
ARG USE_CUSTOM_SDKS=false
@@ -19,7 +19,7 @@ RUN /src/scripts/docker-package.sh
RUN cp /src/config.sample.json /src/webapp/config.json
# App
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:66e34aa81c2faf290ea4e4c28a490f2b35a07478265a2d5994c8637506045eee
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:86df552d36eb24c45d3f5becf6423bd056a3fd235d7085fe3d5ea28ba89a8232
# Need root user to install packages & manipulate the usr directory
USER root
-4
View File
@@ -127,7 +127,6 @@ Unless otherwise specified, the following applies to all code:
2. "Conflicted" typically refers to a getter which wants the same name as the underlying variable.
20. Prefer readonly members over getters backed by a variable, unless an internal setter is required.
21. Prefer Interfaces for object definitions, and types for parameter-value-only declarations.
1. Note that an explicit type is optional if not expected to be used outside of the function call,
unlike in this example:
@@ -161,7 +160,6 @@ Unless otherwise specified, the following applies to all code:
28. Export only what can be reused.
29. Prefer a type like `Optional<X>` (`type Optional<T> = T | null | undefined`) instead
of truly optional parameters.
1. A notable exception is when the likelihood of a bug is minimal, such as when a function
takes an argument that is more often not required than required. An example where the
`?` operator is inappropriate is when taking a room ID: typically the caller should
@@ -260,7 +258,6 @@ Inheriting all the rules of TypeScript, the following additionally apply:
12. Interdependence between stores should be kept to a minimum. Break functions and constants out to utilities
if at all possible.
13. A component should only use CSS class names in line with the component name.
1. When knowingly using a class name from another component, document it with a [comment](#comments).
14. Curly braces within JSX should be padded with a space, however properties on those components should not.
@@ -388,7 +385,6 @@ Note: We use PostCSS + some plugins to process our styles. It looks like SCSS, b
properties should be clearly documented.
4. Inside a function, there is no need to comment every line, but consider:
- before a particular multiline section of code within the function, give an overview of what it does,
to make it easier for a reader to follow the flow through the function as a whole.
- if it is anything less than obvious, explain _why_ we are doing a particular operation, with particular emphasis
+1 -1
View File
@@ -13,7 +13,7 @@
"disable_login_language_selector": false,
"disable_3pid_login": false,
"force_verification": false,
"brand": "Element",
"brand": "HealthChat",
"integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api",
"integrations_widgets_urls": [
+8
View File
@@ -0,0 +1,8 @@
/*
* Copyright 2025 New Vector 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.
*/
declare module "*.module.css";
+1 -1
View File
@@ -109,7 +109,7 @@ yarn test
### End-to-End tests
See [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk/#end-to-end-tests) for how to run the end-to-end tests.
See [`docs/playwright.md`](./docs/playwright.md) for how to run the end-to-end tests.
## General github guidelines
+21 -16
View File
@@ -130,32 +130,37 @@ complete re-branding/private labeling, a more personalised experience can be ach
6. `mobile_builds`: Optional. Like `desktop_builds`, except for the mobile apps. Also described in more detail down below.
7. `mobile_guide_toast`: When `true` (default), users accessing the Element Web instance from a mobile device will be prompted to
download the app instead.
8. `update_base_url`: For the desktop app only, the URL where to acquire update packages. If specified, must be a path to a directory
8. `mobile_guide_app_variant`: Optional. The mobile app that the user is prompted to download from the `/mobile_guide` page. When omitted
the mobile guide will be configured for the new Element X apps. Allowed values are as follows:
1. `element`: Element X Android/iOS.
2. `element-classic`: Element Classic Android/iOS.
3. `element-pro`: Element Pro Android/iOS.
9. `update_base_url`: For the desktop app only, the URL where to acquire update packages. If specified, must be a path to a directory
containing `macos` and `win32` directories, with the update packages within. Defaults to `https://packages.element.io/desktop/update/`
in production.
9. `map_style_url`: Map tile server style URL for location sharing. e.g. `https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY_GOES_HERE`
This setting is ignored if your homeserver provides `/.well-known/matrix/client` in its well-known location, and the JSON file
at that location has a key `m.tile_server` (or the unstable version `org.matrix.msc3488.tile_server`). In this case, the
configuration found in the well-known location is used instead.
10. `welcome_user_id`: **DEPRECATED** An optional user ID to start a DM with after creating an account. Defaults to nothing (no DM created).
11. `custom_translations_url`: An optional URL to allow overriding of translatable strings. The JSON file must be in a format of
10. `map_style_url`: Map tile server style URL for location sharing. e.g. `https://api.maptiler.com/maps/streets/style.json?key=YOUR_KEY_GOES_HERE`
This setting is ignored if your homeserver provides `/.well-known/matrix/client` in its well-known location, and the JSON file
at that location has a key `m.tile_server` (or the unstable version `org.matrix.msc3488.tile_server`). In this case, the
configuration found in the well-known location is used instead.
11. `welcome_user_id`: **DEPRECATED** An optional user ID to start a DM with after creating an account. Defaults to nothing (no DM created).
12. `custom_translations_url`: An optional URL to allow overriding of translatable strings. The JSON file must be in a format of
`{"affected|translation|key": {"languageCode": "new string"}}`. See https://github.com/matrix-org/matrix-react-sdk/pull/7886 for details.
12. `branding`: Options for configuring various assets used within the app. Described in more detail down below.
13. `embedded_pages`: Further optional URLs for various assets used within the app. Described in more detail down below.
14. `disable_3pid_login`: When `false` (default), **enables** the options to log in with email address or phone number. Set to
13. `branding`: Options for configuring various assets used within the app. Described in more detail down below.
14. `embedded_pages`: Further optional URLs for various assets used within the app. Described in more detail down below.
15. `disable_3pid_login`: When `false` (default), **enables** the options to log in with email address or phone number. Set to
`true` to hide these options.
15. `disable_login_language_selector`: When `false` (default), **enables** the language selector on the login pages. Set to `true`
16. `disable_login_language_selector`: When `false` (default), **enables** the language selector on the login pages. Set to `true`
to hide this dropdown.
16. `disable_guests`: When `false` (default), **enable** guest-related functionality (peeking/previewing rooms, etc) for unregistered
17. `disable_guests`: When `false` (default), **enable** guest-related functionality (peeking/previewing rooms, etc) for unregistered
users. Set to `true` to disable this functionality.
17. `user_notice`: Optional notice to show to the user, e.g. for sunsetting a deployment and pushing users to move in their own time.
18. `user_notice`: Optional notice to show to the user, e.g. for sunsetting a deployment and pushing users to move in their own time.
Takes a configuration object as below:
1. `title`: Required. Title to show at the top of the notice.
2. `description`: Required. The description to use for the notice.
3. `show_once`: Optional. If true then the notice will only be shown once per device.
18. `help_url`: The URL to point users to for help with the app, defaults to `https://element.io/help`.
19. `help_encryption_url`: The URL to point users to for help with encryption, defaults to `https://element.io/help#encryption`.
20. `force_verification`: If true, users must verify new logins (eg. with another device / their recovery key)
19. `help_url`: The URL to point users to for help with the app, defaults to `https://element.io/help`.
20. `help_encryption_url`: The URL to point users to for help with encryption, defaults to `https://element.io/help#encryption`.
21. `force_verification`: If true, users must verify new logins (eg. with another device / their recovery key)
### `desktop_builds` and `mobile_builds`
+3 -1
View File
@@ -17,11 +17,13 @@ const config: Config = {
// This is needed to be able to load dual CJS/ESM WASM packages e.g. rust crypto & matrix-wywiwyg
customExportConditions: ["browser", "node"],
},
testMatch: ["<rootDir>/test/**/*-test.[tj]s?(x)"],
testMatch: ["<rootDir>/test/**/*-test.[tj]s?(x)", "<rootDir>/src/shared-components/**/*.test.[t]s?(x)"],
globalSetup: "<rootDir>/test/globalSetup.ts",
setupFiles: ["jest-canvas-mock", "web-streams-polyfill/polyfill"],
setupFilesAfterEnv: ["<rootDir>/test/setupTests.ts"],
moduleNameMapper: {
// Support CSS module
"\\.(module.css)$": "identity-obj-proxy",
"\\.(css|scss|pcss)$": "<rootDir>/__mocks__/cssMock.js",
"\\.(gif|png|ttf|woff2)$": "<rootDir>/__mocks__/imageMock.js",
"\\.svg$": "<rootDir>/__mocks__/svg.js",
+42 -25
View File
@@ -1,6 +1,6 @@
{
"name": "element-web",
"version": "1.11.104",
"version": "1.11.109",
"description": "Element: the future of secure communication",
"author": "New Vector Ltd.",
"repository": {
@@ -65,23 +65,28 @@
"coverage": "yarn test --coverage",
"analyse:webpack-bundles": "webpack-bundle-analyzer webpack-stats.json webapp",
"update:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js",
"postinstall": "patch-package"
"postinstall": "patch-package",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"test:storybook": "test-storybook --url http://localhost:6007/",
"test:storybook:ci": "concurrently -k -s first -n \"SB,TEST\" \"yarn storybook --no-open\" \"wait-on tcp:6007 && yarn test-storybook --url http://localhost:6007/ --ci --maxWorkers=2\"",
"test:storybook:update": "playwright-screenshots --entrypoint yarn --with-node-modules && playwright-screenshots --entrypoint /work/node_modules/.bin/test-storybook --with-node-modules --url http://host.docker.internal:6007/ --updateSnapshot"
},
"resolutions": {
"**/pretty-format/react-is": "19.1.0",
"@playwright/test": "1.52.0",
"@types/react": "19.1.6",
"@playwright/test": "1.54.1",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"oidc-client-ts": "3.2.1",
"oidc-client-ts": "3.3.0",
"jwt-decode": "4.0.0",
"caniuse-lite": "1.0.30001721",
"caniuse-lite": "1.0.30001724",
"testcontainers": "^11.0.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0",
"wrap-ansi": "npm:wrap-ansi@^7.0.0"
},
"dependencies": {
"@babel/runtime": "^7.12.5",
"@element-hq/element-web-module-api": "1.0.0",
"@element-hq/element-web-module-api": "1.3.0",
"@fontsource/inconsolata": "^5",
"@fontsource/inter": "^5",
"@formatjs/intl-segmenter": "^11.5.7",
@@ -92,9 +97,9 @@
"@sentry/browser": "^9.0.0",
"@types/png-chunks-extract": "^1.0.2",
"@types/react-virtualized": "^9.21.30",
"@vector-im/compound-design-tokens": "^4.0.0",
"@vector-im/compound-web": "^8.0.0",
"@vector-im/matrix-wysiwyg": "2.38.3",
"@vector-im/compound-design-tokens": "^5.0.0",
"@vector-im/compound-web": "^8.1.2",
"@vector-im/matrix-wysiwyg": "2.39.0",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4",
"@zxcvbn-ts/language-en": "^3.0.2",
@@ -112,7 +117,7 @@
"emojibase-regex": "15.3.2",
"escape-html": "^1.0.3",
"file-saver": "^2.0.5",
"filesize": "10.1.6",
"filesize": "11.0.2",
"github-markdown-css": "^5.5.1",
"glob-to-regexp": "^0.4.1",
"highlight.js": "^11.3.1",
@@ -123,14 +128,14 @@
"jsrsasign": "^11.0.0",
"jszip": "^3.7.0",
"katex": "^0.16.0",
"linkify-react": "4.3.1",
"linkify-string": "4.3.1",
"linkifyjs": "4.3.1",
"linkify-react": "4.3.2",
"linkify-string": "4.3.2",
"linkifyjs": "4.3.2",
"lodash": "^4.17.21",
"maplibre-gl": "^5.0.0",
"matrix-encrypt-attachment": "^1.0.3",
"matrix-events-sdk": "0.0.1",
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
"matrix-js-sdk": "37.13.0",
"matrix-widget-api": "^1.10.0",
"memoize-one": "^6.0.0",
"mime": "^4.0.4",
@@ -138,7 +143,7 @@
"opus-recorder": "^8.0.3",
"pako": "^2.0.3",
"png-chunks-extract": "^1.0.0",
"posthog-js": "1.249.4",
"posthog-js": "1.257.0",
"qrcode": "1.5.4",
"re-resizable": "6.11.2",
"react": "^19.0.0",
@@ -149,6 +154,7 @@
"react-string-replace": "^1.1.1",
"react-transition-group": "^4.4.1",
"react-virtualized": "^9.22.5",
"react-virtuoso": "^4.12.6",
"rfc4648": "^1.4.0",
"sanitize-filename": "^1.6.3",
"sanitize-html": "2.17.0",
@@ -180,14 +186,19 @@
"@babel/preset-typescript": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@casualbot/jest-sonar-reporter": "2.2.7",
"@element-hq/element-call-embedded": "0.12.2",
"@element-hq/element-web-playwright-common": "^1.4.2",
"@element-hq/element-call-embedded": "0.13.1",
"@element-hq/element-web-playwright-common": "^1.4.4",
"@peculiar/webcrypto": "^1.4.3",
"@playwright/test": "^1.50.1",
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
"@rrweb/types": "^2.0.0-alpha.18",
"@sentry/webpack-plugin": "^3.0.0",
"@stylistic/eslint-plugin": "^4.0.0",
"@sentry/webpack-plugin": "^4.0.0",
"@storybook/addon-designs": "^10.0.1",
"@storybook/addon-docs": "^9.0.12",
"@storybook/icons": "^1.4.0",
"@storybook/react-vite": "^9.0.15",
"@storybook/test-runner": "^0.23.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",
@@ -212,7 +223,7 @@
"@types/node-fetch": "^2.6.2",
"@types/pako": "^2.0.0",
"@types/qrcode": "^1.3.5",
"@types/react": "19.1.6",
"@types/react": "19.1.8",
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "19.1.6",
"@types/react-transition-group": "^4.4.0",
@@ -231,10 +242,10 @@
"concurrently": "^9.0.0",
"copy-webpack-plugin": "^13.0.0",
"core-js": "^3.38.1",
"cronstrue": "^2.41.0",
"cronstrue": "^3.0.0",
"css-loader": "^7.0.0",
"css-minimizer-webpack-plugin": "^7.0.0",
"dotenv": "^16.0.2",
"dotenv": "^17.0.0",
"eslint": "8.57.1",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^10.0.0",
@@ -246,6 +257,7 @@
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-compiler": "^19.0.0-beta-df7b47d-20241124",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-storybook": "^9.0.12",
"eslint-plugin-unicorn": "^56.0.0",
"express": "^5.0.0",
"fake-indexeddb": "^6.0.0",
@@ -254,9 +266,11 @@
"file-loader": "^6.0.0",
"html-webpack-plugin": "^5.5.3",
"husky": "^9.0.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.6.2",
"jest-canvas-mock": "^2.5.2",
"jest-environment-jsdom": "^29.7.0",
"jest-image-snapshot": "^6.5.1",
"jest-mock": "^29.6.2",
"jest-raw-loader": "^1.0.1",
"jsqr": "^1.4.0",
@@ -274,17 +288,18 @@
"postcss-hexrgba": "2.1.0",
"postcss-import": "16.1.0",
"postcss-loader": "8.1.1",
"postcss-mixins": "^11.0.0",
"postcss-mixins": "^12.0.0",
"postcss-nested": "^7.0.0",
"postcss-preset-env": "^10.0.0",
"postcss-scss": "^4.0.4",
"postcss-simple-vars": "^7.0.1",
"prettier": "3.5.3",
"prettier": "3.6.2",
"process": "^0.11.10",
"raw-loader": "^4.0.2",
"rimraf": "^6.0.0",
"semver": "^7.5.2",
"source-map-loader": "^5.0.0",
"storybook": "^9.0.12",
"stylelint": "^16.13.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-scss": "^6.0.0",
@@ -294,6 +309,8 @@
"ts-node": "^10.9.1",
"typescript": "5.8.3",
"util": "^0.12.5",
"vite": "^7.0.1",
"vite-plugin-node-polyfills": "^0.24.0",
"web-streams-polyfill": "^4.0.0",
"webpack": "^5.89.0",
"webpack-bundle-analyzer": "^4.8.0",
+46
View File
@@ -0,0 +1,46 @@
diff --git a/node_modules/@types/mdx/types.d.ts b/node_modules/@types/mdx/types.d.ts
index 498bb69..4e89216 100644
--- a/node_modules/@types/mdx/types.d.ts
+++ b/node_modules/@types/mdx/types.d.ts
@@ -5,7 +5,7 @@
*/
// @ts-ignore JSX runtimes may optionally define JSX.ElementType. The MDX types need to work regardless whether this is
// defined or not.
-type ElementType = any extends JSX.ElementType ? never : JSX.ElementType;
+type ElementType = any extends JSX.ElementType ? never : React.JSX.ElementType;
/**
* This matches any function component types that ar part of `ElementType`.
@@ -20,12 +20,12 @@ type ClassElementType = Extract<ElementType, new(props: Record<string, any>) =>
/**
* A valid JSX string component.
*/
-type StringComponent = Extract<keyof JSX.IntrinsicElements, ElementType extends never ? string : ElementType>;
+type StringComponent = Extract<keyof React.JSX.IntrinsicElements, ElementType extends never ? string : ElementType>;
/**
* A JSX element returned by MDX content.
*/
-export type Element = JSX.Element;
+export type Element = React.JSX.Element;
/**
* A valid JSX function component.
@@ -44,7 +44,7 @@ type FunctionComponent<Props> = ElementType extends never
*/
type ClassComponent<Props> = ElementType extends never
// If JSX.ElementType isn’t defined, the valid return type is a constructor that returns JSX.ElementClass
- ? new(props: Props) => JSX.ElementClass
+ ? new(props: Props) => React.JSX.ElementClass
: ClassElementType extends never
// If JSX.ElementType is defined, but doesn’t allow constructors, function components are disallowed.
? never
@@ -70,7 +70,7 @@ interface NestedMDXComponents {
export type MDXComponents =
& NestedMDXComponents
& {
- [Key in StringComponent]?: Component<JSX.IntrinsicElements[Key]>;
+ [Key in StringComponent]?: Component<React.JSX.IntrinsicElements[Key]>;
}
& {
/**
-31
View File
@@ -1,31 +0,0 @@
diff --git a/node_modules/@types/react/index.d.ts b/node_modules/@types/react/index.d.ts
index d3318dc..c2b2c77 100644
--- a/node_modules/@types/react/index.d.ts
+++ b/node_modules/@types/react/index.d.ts
@@ -134,7 +134,7 @@ declare namespace React {
props: P,
) => ReactNode | Promise<ReactNode>)
// constructor signature must match React.Component
- | (new(props: P) => Component<any, any>);
+ | (new(props: P, context?: any) => Component<any, any>);
/**
* Created by {@link createRef}, or {@link useRef} when passed `null`.
@@ -945,7 +945,7 @@ declare namespace React {
context: unknown;
// Keep in sync with constructor signature of JSXElementConstructor and ComponentClass.
- constructor(props: P);
+ constructor(props: P, context?: unknown);
// We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
// See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
@@ -1117,7 +1117,7 @@ declare namespace React {
*/
interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
// constructor signature must match React.Component
- new(props: P): Component<P, S>;
+ new(props: P, context?: any): Component<P, S>;
/**
* Ignored by React.
* @deprecated Only kept in types for backwards compatibility. Will be removed in a future major release.
+3
View File
@@ -158,6 +158,8 @@ test.describe("Cryptography", function () {
await page.getByRole("textbox", { name: "Send a message…" }).press("Enter");
await checkDMRoom(page);
const bobRoomId = await bobJoin(page, bob);
await expect(page.locator(".mx_MessageComposer_e2eIcon")).toMatchScreenshot("composer-e2e-icon-normal.png");
await testMessages(page, bob, bobRoomId);
await verify(app, bob);
@@ -168,6 +170,7 @@ test.describe("Cryptography", function () {
// Take a snapshot of RoomSummaryCard with a verified E2EE icon
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("RoomSummaryCard-with-verified-e2ee.png");
await expect(page.locator(".mx_MessageComposer_e2eIcon")).toMatchScreenshot("composer-e2e-icon.png");
},
);
@@ -48,31 +48,38 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
return promiseVerificationRequest;
}
test("Verify device with SAS during login", async ({ page, app, credentials, homeserver }) => {
await logIntoElement(page, credentials);
test(
"Verify device with SAS during login",
{ tag: "@screenshot" },
async ({ page, app, credentials, homeserver }) => {
await logIntoElement(page, credentials);
// Launch the verification request between alice and the bot
const verificationRequest = await initiateAliceVerificationRequest(page);
// Launch the verification request between alice and the bot
const verificationRequest = await initiateAliceVerificationRequest(page);
// Handle emoji SAS verification
const infoDialog = page.locator(".mx_InfoDialog");
// the bot chooses to do an emoji verification
const verifier = await verificationRequest.evaluateHandle((request) => request.startVerification("m.sas.v1"));
// Handle emoji SAS verification
const infoDialog = page.locator(".mx_InfoDialog");
// the bot chooses to do an emoji verification
const verifier = await verificationRequest.evaluateHandle((request) =>
request.startVerification("m.sas.v1"),
);
// Handle emoji request and check that emojis are matching
await doTwoWaySasVerification(page, verifier);
// Handle emoji request and check that emojis are matching
await doTwoWaySasVerification(page, verifier);
await infoDialog.getByRole("button", { name: "They match" }).click();
await infoDialog.getByRole("button", { name: "Got it" }).click();
await infoDialog.getByRole("button", { name: "They match" }).click();
await expect(page.locator(".mx_E2EIcon_verified")).toMatchScreenshot("device-verified-e2eIcon.png");
await infoDialog.getByRole("button", { name: "Got it" }).click();
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that the current device is connected to key backup
// For now we don't check that the backup key is in cache because it's a bit flaky,
// as we need to wait for the secret gossiping to happen.
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, false);
});
// Check that the current device is connected to key backup
// For now we don't check that the backup key is in cache because it's a bit flaky,
// as we need to wait for the secret gossiping to happen.
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, false);
},
);
// Regression test for https://github.com/element-hq/element-web/issues/29110
test("No toast after verification, even if the secrets take a while to arrive", async ({ page, credentials }) => {
@@ -117,6 +124,10 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
const toasts = new Toasts(page);
await toasts.rejectToast("Notifications");
await toasts.assertNoToasts();
// There may still be a `/sendToDevice/m.secret.request` in flight, which will later throw an error and cause
// a *subsequent* test to fail. Tell playwright to ignore any errors resulting from in-flight routes.
await page.unrouteAll({ behavior: "ignoreErrors" });
});
test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
@@ -30,6 +30,10 @@ test.describe("Lazy Loading", () => {
});
test.beforeEach(async ({ page, homeserver, user, bot, app }) => {
// The charlies were running off the bottom of the screen.
// We no longer overscan the member list so the result is they are not in the dom.
// Increase the viewport size to ensure they are.
await page.setViewportSize({ width: 1000, height: 1000 });
for (let i = 1; i <= 10; i++) {
const displayName = `Charly #${i}`;
const bot = new Bot(page, homeserver, { displayName, startClient: false, autoAcceptInvites: false });
@@ -229,13 +229,13 @@ test.describe("Room list filters and sort", () => {
// only one room should be visible
await expect(roomList.getByRole("gridcell", { name: "unread dm" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "unread room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(4);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(4);
await expect(primaryFilters).toMatchScreenshot("unread-primary-filters.png");
await primaryFilters.getByRole("option", { name: "People" }).click();
await expect(roomList.getByRole("gridcell", { name: "unread dm" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "invited room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(2);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(2);
await primaryFilters.getByRole("option", { name: "Rooms" }).click();
await expect(roomList.getByRole("gridcell", { name: "unread room" })).toBeVisible();
@@ -243,21 +243,21 @@ test.describe("Room list filters and sort", () => {
await expect(roomList.getByRole("gridcell", { name: "empty room" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "room with mention" })).toBeVisible();
await expect(roomList.getByRole("gridcell", { name: "Low prio room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(5);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(5);
await getFilterExpandButton(page).click();
await primaryFilters.getByRole("option", { name: "Favourite" }).click();
await expect(roomList.getByRole("gridcell", { name: "favourite room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(1);
await primaryFilters.getByRole("option", { name: "Mentions" }).click();
await expect(roomList.getByRole("gridcell", { name: "room with mention" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(1);
await primaryFilters.getByRole("option", { name: "Invites" }).click();
await expect(roomList.getByRole("gridcell", { name: "invited room" })).toBeVisible();
expect(await roomList.locator("role=gridcell").count()).toBe(1);
await expect.poll(() => roomList.locator("role=gridcell").count()).toBe(1);
await getFilterCollapseButton(page).click();
await expect(primaryFilters.locator("role=option").first()).toHaveText("Invites");
@@ -35,8 +35,8 @@ test.describe("Header section of the room list", () => {
await expect(page.getByRole("menu")).toMatchScreenshot("room-list-header-compose-menu.png");
// New message should open the direct messages dialog
await page.getByRole("menuitem", { name: "New message" }).click();
// Start chat should open the direct messages dialog
await page.getByRole("menuitem", { name: "Start chat" }).click();
await expect(page.getByRole("heading", { name: "Direct Messages" })).toBeVisible();
await app.closeDialog();
@@ -49,8 +49,7 @@ test.describe("Room list", () => {
// Put focus on the room list
await roomListView.getByRole("gridcell", { name: "Open room room29" }).click();
// Scroll to the end of the room list
await page.mouse.wheel(0, 1000);
await expect(roomListView.getByRole("gridcell", { name: "Open room room0" })).toBeVisible();
await app.scrollListToBottom(page.locator(".mx_RoomList_List"));
await expect(roomListView).toMatchScreenshot("room-list-scrolled.png");
});
@@ -60,6 +59,12 @@ test.describe("Room list", () => {
await expect(page.getByRole("heading", { name: "room29", level: 1 })).toBeVisible();
});
test("should open the context menu", { tag: "@screenshot" }, async ({ page, app, user }) => {
const roomListView = getRoomList(page);
await roomListView.getByRole("gridcell", { name: "Open room room29" }).click({ button: "right" });
await expect(page.getByRole("menu", { name: "More Options" })).toBeVisible();
});
test("should open the more options menu", { tag: "@screenshot" }, async ({ page, app, user }) => {
const roomListView = getRoomList(page);
const roomItem = roomListView.getByRole("gridcell", { name: "Open room room29" });
@@ -109,10 +114,13 @@ test.describe("Room list", () => {
// It should make the room muted
await page.getByRole("menuitem", { name: "Mute room" }).click();
await expect(roomItem.getByTestId("notification-decoration")).not.toBeVisible();
// Put focus on the room list
await roomListView.getByRole("gridcell", { name: "Open room room28" }).click();
// Scroll to the end of the room list
await page.mouse.wheel(0, 1000);
await app.scrollListToBottom(page.locator(".mx_RoomList_List"));
// The room decoration should have the muted icon
await expect(roomItem.getByTestId("notification-decoration")).toBeVisible();
@@ -133,8 +141,9 @@ test.describe("Room list", () => {
// Put focus on the room list
await roomListView.getByRole("gridcell", { name: "Open room room29" }).click();
// Scroll to the end of the room list
await page.mouse.wheel(0, 1000);
await app.scrollListToBottom(page.locator(".mx_RoomList_List"));
await expect(roomListView.getByRole("gridcell", { name: "Open room room0" })).toBeVisible();
await roomListView.getByRole("gridcell", { name: "Open room room0" }).click();
const filters = page.getByRole("listbox", { name: "Room list filters" });
@@ -223,17 +232,17 @@ test.describe("Room list", () => {
await expect(notificationButton).toBeFocused();
// Open the menu
await notificationButton.click();
await page.keyboard.press("Enter");
// Wait for the menu to be open
await expect(page.getByRole("menuitem", { name: "Match default settings" })).toHaveAttribute(
"aria-selected",
"true",
);
// Close the menu
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Escape");
// Focus should be back on the room list item
await expect(room29).toBeFocused();
// Focus should be back on the notification button
await expect(notificationButton).toBeFocused();
});
});
});
@@ -0,0 +1,36 @@
/*
Copyright 2025 New Vector 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.
*/
import { test, expect } from "../../element-web-test";
import { MobileAppVariant } from "../../../src/vector/mobile_guide/mobile-apps";
const variants = [MobileAppVariant.Classic, MobileAppVariant.X, MobileAppVariant.Pro];
test.describe("Mobile Guide Screenshots", { tag: "@screenshot" }, () => {
for (const variant of variants) {
test.describe(`for variant ${variant}`, () => {
test.use({
config: {
default_server_config: {
"m.homeserver": {
base_url: "https://matrix.server.invalid",
server_name: "server.invalid",
},
},
mobile_guide_app_variant: variant,
},
viewport: { width: 390, height: 844 }, // iPhone 16e
});
test("should match the mobile_guide screenshot", async ({ page, axe }) => {
await page.goto("/mobile_guide/");
await expect(page).toMatchScreenshot(`mobile-guide-${variant}.png`);
await expect(axe).toHaveNoViolations();
});
});
}
});
@@ -0,0 +1,160 @@
/*
Copyright 2025 New Vector 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.
*/
import { type Page } from "@playwright/test";
import fs from "node:fs";
import { test, expect } from "../../element-web-test";
const screenshotOptions = (page: Page) => ({
mask: [page.locator(".mx_MessageTimestamp")],
// Hide the jump to bottom button in the timeline to avoid flakiness
// Exclude timestamp and read marker from snapshot
css: `
.mx_JumpToBottomButton {
display: none !important;
}
.mx_TopUnreadMessagesBar, .mx_MessagePanel_myReadMarker {
display: none !important;
}
`,
});
const IMAGE_FILE = fs.readFileSync("playwright/sample-files/element.png");
test.describe("Custom Component API", () => {
test.use({
displayName: "Manny",
config: {
modules: ["/modules/custom-component-module.js"],
},
page: async ({ page }, use) => {
await page.route("/modules/custom-component-module.js", async (route) => {
await route.fulfill({ path: "playwright/sample-files/custom-component-module.js" });
});
await use(page);
},
room: async ({ page, app, user, bot }, use) => {
const roomId = await app.client.createRoom({ name: "TestRoom" });
await use({ roomId });
},
});
test.describe("basic functionality", () => {
test(
"should replace the render method of a textual event",
{ tag: "@screenshot" },
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(
"custom-component-tile.png",
screenshotOptions(page),
);
},
);
test(
"should fall through if one module does not render a component",
{ tag: "@screenshot" },
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(
"custom-component-tile-fall-through.png",
screenshotOptions(page),
);
},
);
test(
"should render the original content of a textual event conditionally",
{ tag: "@screenshot" },
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(
"custom-component-tile-original.png",
screenshotOptions(page),
);
},
);
test("should disallow editing when the allowEditingEvent hint is set to false", async ({ page, room, app }) => {
await app.viewRoomById(room.roomId);
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" }),
).not.toBeVisible();
});
test("should disallow downloading media when the allowDownloading hint is set to false", async ({
page,
room,
app,
}) => {
await app.viewRoomById(room.roomId);
await app.viewRoomById(room.roomId);
const upload = await app.client.uploadContent(IMAGE_FILE, { name: "bad.png", type: "image/png" });
await app.client.sendEvent(room.roomId, null, "m.room.message", {
msgtype: "m.image",
body: "bad.png",
url: upload.content_uri,
});
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
await expect(imgTile).toBeVisible();
await imgTile.hover();
await expect(page.getByRole("button", { name: "Download" })).not.toBeVisible();
await imgTile.click();
await expect(page.getByLabel("Image view").getByLabel("Download")).not.toBeVisible();
});
test("should allow downloading media when the allowDownloading hint is set to true", async ({
page,
room,
app,
}) => {
await app.viewRoomById(room.roomId);
await app.viewRoomById(room.roomId);
const upload = await app.client.uploadContent(IMAGE_FILE, { name: "good.png", type: "image/png" });
await app.client.sendEvent(room.roomId, null, "m.room.message", {
msgtype: "m.image",
body: "good.png",
url: upload.content_uri,
});
await app.timeline.scrollToBottom();
const imgTile = page.locator(".mx_MImageBody").first();
await expect(imgTile).toBeVisible();
await imgTile.hover();
await expect(page.getByRole("button", { name: "Download" })).toBeVisible();
await imgTile.click();
await expect(page.getByLabel("Image view").getByLabel("Download")).toBeVisible();
});
test(
"should render the next registered component if the filter function throws",
{ tag: "@screenshot" },
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(
"custom-component-crash-handle-filter.png",
screenshotOptions(page),
);
},
);
test(
"should render original component if the render function throws",
{ tag: "@screenshot" },
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(
"custom-component-crash-handle-renderer.png",
screenshotOptions(page),
);
},
);
});
});
+6 -2
View File
@@ -81,7 +81,7 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
test(
"it should log out the user & wipe data when logging out via MAS",
{ tag: "@screenshot" },
async ({ mas, page, mailpitClient }, testInfo) => {
async ({ mas, page, mailpitClient, homeserver }, testInfo) => {
// We use this over the `user` fixture to ensure we get an OIDC session rather than a compatibility one
await page.goto("/#/login");
await page.getByRole("button", { name: "Continue" }).click();
@@ -95,11 +95,15 @@ test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => {
const result = await mas.manage("kill-sessions", userId);
expect(result.output).toContain("Ended 1 active OAuth 2.0 session");
// Workaround for Synapse's 2 minute cache on MAS token validity
// (https://github.com/element-hq/synapse/pull/18231)
await homeserver.restart();
await page.goto("http://localhost:8080");
await expect(
page.getByText("For security, this session has been signed out. Please sign in again."),
).toBeVisible();
await expect(page).toMatchScreenshot("token-expired.png", { includeDialogBackground: true });
//await expect(page).toMatchScreenshot("token-expired.png", { includeDialogBackground: true });
const localStorageKeys = await page.evaluate(() => Object.keys(localStorage));
expect(localStorageKeys).toHaveLength(0);
+4 -1
View File
@@ -42,7 +42,10 @@ export class Helpers {
*/
async assertReleaseAnnouncementIsVisible(name: string) {
await expect(this.getReleaseAnnouncement(name)).toBeVisible();
await expect(this.page).toMatchScreenshot(`release-announcement-${name}.png`, { showTooltips: true });
await expect(this.page).toMatchScreenshot(`release-announcement-${name}.png`, {
showTooltips: true,
hideJumpToBottomButton: true,
});
}
/**
+60 -10
View File
@@ -11,6 +11,32 @@ import { Bot } from "../../pages/bot";
const ROOM_NAME = "Test room";
const NAME = "Alice";
async function setupRoomWithMembers(
app: any,
page: any,
homeserver: any,
roomName: string,
memberNames: string[],
): Promise<string> {
const visibility = await page.evaluate(() => (window as any).matrixcs.Visibility.Public);
const id = await app.client.createRoom({ name: roomName, visibility });
const bots: Bot[] = [];
for (let i = 0; i < memberNames.length; i++) {
const displayName = memberNames[i];
const bot = new Bot(page, homeserver, { displayName, startClient: false, autoAcceptInvites: false });
if (displayName === "Susan") {
await bot.prepareClient();
await app.client.inviteUser(id, bot.credentials?.userId);
} else {
await bot.joinRoom(id);
}
bots.push(bot);
}
return id;
}
test.use({
synapseConfig: {
presence: {
@@ -25,17 +51,8 @@ test.use({
test.describe("Memberlist", () => {
test.beforeEach(async ({ app, user, page, homeserver }, testInfo) => {
testInfo.setTimeout(testInfo.timeout + 30_000);
const id = await app.client.createRoom({ name: ROOM_NAME });
const newBots: Bot[] = [];
const names = ["Bob", "Bob", "Susan"];
for (let i = 0; i < 3; i++) {
const displayName = names[i];
const autoAcceptInvites = displayName !== "Susan";
const bot = new Bot(page, homeserver, { displayName, startClient: true, autoAcceptInvites });
await bot.prepareClient();
await app.client.inviteUser(id, bot.credentials?.userId);
newBots.push(bot);
}
await setupRoomWithMembers(app, page, homeserver, ROOM_NAME, names);
});
test("Renders correctly", { tag: "@screenshot" }, async ({ page, app }) => {
@@ -45,4 +62,37 @@ test.describe("Memberlist", () => {
await expect(memberlist.getByText("Invited")).toHaveCount(1);
await expect(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png");
});
test("should handle scroll and click to view member profile", async ({ page, app, homeserver }) => {
// Create a room with many members to enable scrolling
const memberNames = Array.from({ length: 15 }, (_, i) => `Member${i.toString()}`);
await setupRoomWithMembers(app, page, homeserver, "Large Room", memberNames);
// Navigate to the room and open member list
await app.viewRoomByName("Large Room");
const memberlist = await app.toggleMemberlistPanel();
// Get the scrollable container
const memberListContainer = memberlist.locator(".mx_AutoHideScrollbar");
// Scroll down to the bottom of the member list
await app.scrollListToBottom(memberListContainer);
// Wait for the target member to be visible after scrolling
const targetName = "Member14";
const targetMember = memberlist.locator(".mx_MemberTileView_name").filter({ hasText: targetName });
await targetMember.waitFor({ state: "visible" });
// Verify Alice is not visible at this point
await expect(memberlist.locator(".mx_MemberTileView_name").filter({ hasText: "Alice" })).toHaveCount(0);
// Click on a member near the bottom of the list
await expect(targetMember).toBeVisible();
await targetMember.click();
// Verify that the user info screen is shown and hasn't scrolled back to top
await expect(page.locator(".mx_UserInfo")).toBeVisible();
await expect(page.locator(".mx_UserInfo_profile").getByText(targetName)).toBeVisible();
});
});
@@ -35,7 +35,7 @@ test.describe("Share dialog", () => {
const rightPanel = await app.toggleRoomInfoPanel();
await rightPanel.getByRole("menuitem", { name: "People" }).click();
await rightPanel.getByRole("button", { name: `${user.userId} (power 100)` }).click();
await rightPanel.getByRole("option", { name: user.displayName }).click();
await rightPanel.getByRole("button", { name: "Share profile" }).click();
const dialog = page.getByRole("dialog", { name: "Share User" });
+18 -11
View File
@@ -23,7 +23,7 @@ async function openSpaceContextMenu(page: Page, app: ElementAppPage, spaceName:
return page.locator(".mx_SpacePanel_contextMenu");
}
function spaceCreateOptions(spaceName: string, roomIds: string[] = []): ICreateRoomOpts {
function spaceCreateOptions(serverName: string, spaceName: string, roomIds: string[] = []): ICreateRoomOpts {
return {
creation_content: {
type: "m.space",
@@ -35,17 +35,21 @@ function spaceCreateOptions(spaceName: string, roomIds: string[] = []): ICreateR
name: spaceName,
},
},
...roomIds.map((r) => spaceChildInitialState(r)),
...roomIds.map((r) => spaceChildInitialState(serverName, r)),
],
};
}
function spaceChildInitialState(roomId: string, order?: string): ICreateRoomOpts["initial_state"]["0"] {
function spaceChildInitialState(
serverName: string,
roomId: string,
order?: string,
): ICreateRoomOpts["initial_state"]["0"] {
return {
type: "m.space.child",
state_key: roomId,
content: {
via: [roomId.split(":")[1]],
via: [serverName],
order,
},
};
@@ -240,7 +244,7 @@ test.describe("Spaces", () => {
});
await expect(await app.getSpacePanelButton("My Space")).toBeVisible();
const roomId = await bot.createRoom(spaceCreateOptions("Space Space"));
const roomId = await bot.createRoom(spaceCreateOptions(user.homeServer, "Space Space"));
await bot.inviteUser(roomId, user.userId);
// Assert that `Space Space` is above `My Space` due to it being an invite
@@ -260,7 +264,10 @@ test.describe("Spaces", () => {
const spaceName = "Spacey Mc. Space Space";
await app.client.createSpace({
name: spaceName,
initial_state: [spaceChildInitialState(roomId1), spaceChildInitialState(roomId2)],
initial_state: [
spaceChildInitialState(user.homeServer, roomId1),
spaceChildInitialState(user.homeServer, roomId2),
],
});
await app.viewSpaceHomeByName(spaceName);
@@ -287,7 +294,7 @@ test.describe("Spaces", () => {
});
await app.client.createSpace({
name: "Root Space",
initial_state: [spaceChildInitialState(childSpaceId)],
initial_state: [spaceChildInitialState(user.homeServer, childSpaceId)],
});
// Find collapsed Space panel
@@ -323,7 +330,7 @@ test.describe("Spaces", () => {
name: "Test Room",
topic: "This is a topic https://github.com/matrix-org/matrix-react-sdk/pull/10060 with a link",
});
const spaceId = await bot.createRoom(spaceCreateOptions("Test Space", [roomId]));
const spaceId = await bot.createRoom(spaceCreateOptions(user.homeServer, "Test Space", [roomId]));
await bot.inviteUser(spaceId, user.userId);
await expect(await app.getSpacePanelButton("Test Space")).toBeVisible();
@@ -361,9 +368,9 @@ test.describe("Spaces", () => {
await app.client.createSpace({
name: "Root Space",
initial_state: [
spaceChildInitialState(childSpaceId1, "a"),
spaceChildInitialState(childSpaceId2, "b"),
spaceChildInitialState(childSpaceId3, "c"),
spaceChildInitialState(user.homeServer, childSpaceId1, "a"),
spaceChildInitialState(user.homeServer, childSpaceId2, "b"),
spaceChildInitialState(user.homeServer, childSpaceId3, "c"),
],
});
await app.viewSpaceByName("Root Space");
+9
View File
@@ -107,6 +107,7 @@ interface ExtendedToMatchScreenshotOptions extends ToMatchScreenshotOptions {
includeDialogBackground?: boolean;
showTooltips?: boolean;
timeout?: number;
hideJumpToBottomButton?: boolean;
}
type Expectations = {
@@ -165,6 +166,14 @@ export const expect = baseExpect.extend<Expectations>({
`;
}
if (options?.hideJumpToBottomButton) {
css += `
.mx_JumpToBottomButton {
display: none !important;
}
`;
}
if (options?.css) {
css += options.css;
}
+22
View File
@@ -213,4 +213,26 @@ export class ElementAppPage {
.getByRole("button", { name: "Dismiss" })
.click();
}
/**
* Scroll an infinite list to the bottom.
* @param list The element to scroll
*/
public async scrollListToBottom(list: Locator): Promise<void> {
// First hover the mouse over the element that we want to scroll
await list.hover();
const needsScroll = async () => {
// From https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled
const fullyScrolled = await list.evaluate(
(e) => Math.abs(e.scrollHeight - e.clientHeight - e.scrollTop) <= 1,
);
return !fullyScrolled;
};
// Scroll the element until we detect that it is fully scrolled
do {
await this.page.mouse.wheel(0, 1000);
} while (await needsScroll());
}
}
@@ -0,0 +1,74 @@
/*
Copyright 2025 New Vector 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.
*/
// Note: eslint-plugin-jsdoc doesn't like import types as parameters, so we
// get around it with @typedef
/**
* @typedef {import("@element-hq/element-web-module-api").Api} Api
*/
export default class CustomComponentModule {
static moduleApiVersion = "^1.2.0";
/**
* Basic module for testing.
* @param {Api} api API object
*/
constructor(api) {
this.api = api;
this.api.customComponents.registerMessageRenderer(
(evt) => evt.content.body === "Do not show edits",
(_props, originalComponent) => {
return originalComponent();
},
{ allowEditingEvent: false },
);
this.api.customComponents.registerMessageRenderer(
(evt) => evt.content.body === "Fall through here",
(props) => {
const body = props.mxEvent.content.body;
return `Fallthrough text for ${body}`;
},
);
this.api.customComponents.registerMessageRenderer(
(evt) => {
if (evt.content.body === "Crash the filter!") {
throw new Error("Fail test!");
}
return false;
},
() => {
return `Should not render!`;
},
);
this.api.customComponents.registerMessageRenderer(
(evt) => evt.content.body === "Crash the renderer!",
() => {
throw new Error("Fail test!");
},
);
this.api.customComponents.registerMessageRenderer(
(mxEvent) => mxEvent.type === "m.room.message" && mxEvent.content.msgtype === "m.image",
(_props, originalComponent) => {
return originalComponent();
},
{ allowDownloadingMedia: async (mxEvent) => mxEvent.content.body !== "bad.png" },
);
// Order is specific here to avoid this overriding the other renderers
this.api.customComponents.registerMessageRenderer("m.room.message", (props, originalComponent) => {
const body = props.mxEvent.content.body;
if (body === "Do not replace me") {
return originalComponent();
} else if (body === "Fall through here") {
return null;
}
return `Custom text for ${body}`;
});
}
async load() {}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

+1 -1
View File
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
import { SynapseContainer as BaseSynapseContainer } from "@element-hq/element-web-playwright-common/lib/testcontainers";
const TAG = "develop@sha256:66955f34a593cfc3b6e77b8d5510c60c6094f5bade8a17d2feaefbb8662ccf09";
const TAG = "develop@sha256:2f6fff14ff23f356705abdbf2ed62c3dd6ca2103cef4ae813714ddc199bbd76a";
/**
* SynapseContainer which freezes the docker digest to stabilise tests,
+1 -3
View File
@@ -53,8 +53,6 @@
@import "./components/views/settings/shared/_SettingsSubsectionHeading.pcss";
@import "./components/views/spaces/_QuickThemeSwitcher.pcss";
@import "./components/views/typography/_Caption.pcss";
@import "./components/views/utils/_Box.pcss";
@import "./components/views/utils/_Flex.pcss";
@import "./compound/_Icon.pcss";
@import "./compound/_SuccessDialog.pcss";
@import "./structures/_AutoHideScrollbar.pcss";
@@ -177,7 +175,6 @@
@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.pcss";
@import "./views/dialogs/security/_AccessSecretStorageDialog.pcss";
@import "./views/dialogs/security/_CreateCrossSigningDialog.pcss";
@import "./views/dialogs/security/_CreateKeyBackupDialog.pcss";
@import "./views/dialogs/security/_CreateSecretStorageDialog.pcss";
@import "./views/dialogs/security/_KeyBackupFailedDialog.pcss";
@import "./views/dialogs/security/_RestoreKeyBackupDialog.pcss";
@@ -364,6 +361,7 @@
@import "./views/settings/_ThemeChoicePanel.pcss";
@import "./views/settings/_UpdateCheckButton.pcss";
@import "./views/settings/_UserProfileSettings.pcss";
@import "./views/settings/_ExtendedProfileSettings.pcss";
@import "./views/settings/encryption/_AdvancedPanel.pcss";
@import "./views/settings/encryption/_ChangeRecoveryKey.pcss";
@import "./views/settings/encryption/_EncryptionCard.pcss";
+9
View File
@@ -0,0 +1,9 @@
/*
* Copyright 2025 New Vector 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.
*/
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
@import url("@vector-im/compound-web/dist/style.css");
+1 -1
View File
@@ -50,7 +50,7 @@ Please see LICENSE files in the repository root for full details.
color: var(--cpd-color-text-secondary);
}
.mx_Flex {
.mx_ErrorView_flexContainer {
margin: 0 auto;
max-width: max-content;
flex-wrap: wrap;
+8 -6
View File
@@ -28,12 +28,6 @@ Please see LICENSE files in the repository root for full details.
--collapsedWidth: 68px;
}
.mx_LeftPanel_newRoomList {
/* Thew new rooms list is not designed to be collapsed to just icons. */
/* 224 + 68(spaces bar) was deemed by design to be a good minimum for the left panel. */
--collapsedWidth: 224px;
}
.mx_LeftPanel_wrapper {
display: flex;
flex-direction: row;
@@ -246,3 +240,11 @@ Please see LICENSE files in the repository root for full details.
}
}
}
.mx_LeftPanel_newRoomList {
/* Thew new rooms list is not designed to be collapsed to just icons. */
/* 224 + 68(spaces bar) was deemed by design to be a good minimum for the left panel. */
--collapsedWidth: 224px;
/* Important to force the color on ED titlebar until we remove the old room list */
background-color: var(--cpd-color-bg-canvas-default) !important;
}
@@ -1,73 +0,0 @@
/*
Copyright 2018-2024 New Vector 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.
*/
.mx_CreateKeyBackupDialog .mx_Dialog_title {
/* TODO: Consider setting this for all dialog titles. */
margin-bottom: 1em;
}
.mx_CreateKeyBackupDialog_primaryContainer {
/* FIXME: plinth colour in new theme(s). background-color: $accent; */
padding: 20px;
}
.mx_CreateKeyBackupDialog_primaryContainer::after {
content: "";
clear: both;
display: block;
}
.mx_CreateKeyBackupDialog_passPhraseContainer {
display: flex;
align-items: flex-start;
}
.mx_CreateKeyBackupDialog_passPhraseInput {
flex: none;
width: 250px;
border: 1px solid $accent;
border-radius: 5px;
padding: 10px;
margin-bottom: 1em;
}
.mx_CreateKeyBackupDialog_passPhraseMatch {
margin-left: 20px;
}
.mx_CreateKeyBackupDialog_recoveryKeyHeader {
margin-bottom: 1em;
}
.mx_CreateKeyBackupDialog_recoveryKeyContainer {
display: flex;
}
.mx_CreateKeyBackupDialog_recoveryKey {
width: 262px;
padding: 20px;
color: $info-plinth-fg-color;
background-color: $info-plinth-bg-color;
margin-right: 12px;
}
.mx_CreateKeyBackupDialog_recoveryKeyButtons {
flex: 1;
display: flex;
align-items: center;
}
.mx_CreateKeyBackupDialog_recoveryKeyButtons button {
flex: 1;
white-space: nowrap;
}
.mx_CreateKeyBackupDialog {
details .mx_AccessibleButton {
margin: 1em 0; /* emulate paragraph spacing because we can't put this button in a paragraph due to HTML rules */
}
}
@@ -0,0 +1,79 @@
/*
Copyright 2025 New Vector 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.
*/
.mx_ExtendedProfileView {
/* Anpassung an das bestehende UserInfo Panel */
font-size: var(--cpd-font-size-body-sm);
padding: 0;
/* Styling für das Accordion */
.mx_ExtendedProfileView_accordion {
width: 100%;
}
/* Abstand zwischen den Feldern */
.mx_ExtendedProfileView_content {
padding: var(--cpd-space-2x) 0;
display: flex;
flex-direction: column;
gap: var(--cpd-space-4x);
}
/* Styling für die Felder */
.mx_ExtendedProfileView_field {
margin-bottom: var(--cpd-space-2x);
.mx_ExtendedProfileView_icon {
width: 20px;
height: 20px;
color: var(--cpd-color-icon-secondary);
flex-shrink: 0;
}
}
/* Labels und Werte */
.mx_ExtendedProfileView_label {
color: var(--cpd-color-text-secondary);
font-size: var(--cpd-font-size-body-xs);
margin-bottom: var(--cpd-space-1x);
}
.mx_ExtendedProfileView_value {
color: var(--cpd-color-text-primary);
word-break: break-word;
&.mx_ExtendedProfileView_multiline {
white-space: pre-line;
margin-top: var(--cpd-space-1x);
}
}
/* Spezielle Styles für Website-Links */
.mx_ExtendedProfileView_link {
color: var(--cpd-color-text-action-accent);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
/* Für Bereich "Weitere Informationen" */
.mx_ExtendedProfileView_further_info {
padding: var(--cpd-space-1x) 0;
}
/* Loading State */
.mx_ExtendedProfileView_loading {
padding: var(--cpd-space-4x) 0;
}
/* Error State */
.mx_ExtendedProfileView_error {
margin: var(--cpd-space-2x) 0;
}
}
@@ -32,7 +32,7 @@ Please see LICENSE files in the repository root for full details.
padding: 0 12px;
color: var(--cpd-color-text-secondary);
.mx_Box {
.mx_RoomSummaryCard_topic_box {
width: 100%;
}
@@ -0,0 +1,59 @@
/*
Copyright 2025 New Vector Ltd
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
*/
.mx_UserExtendedProfileInfo {
padding: 16px;
background-color: $system;
}
.mx_UserExtendedProfileInfo_loading {
display: flex;
justify-content: center;
padding: 20px 0;
}
.mx_UserExtendedProfileInfo_heading {
margin-bottom: 12px;
}
.mx_UserExtendedProfileInfo_content {
display: flex;
flex-direction: column;
gap: 12px;
}
.mx_UserExtendedProfileInfo_row {
display: flex;
gap: 16px;
}
.mx_UserExtendedProfileInfo_row .mx_UserExtendedProfileInfo_field {
flex: 1;
}
.mx_UserExtendedProfileInfo_field {
margin-bottom: 4px;
}
.mx_UserExtendedProfileInfo_label {
margin-bottom: 3px;
color: $tertiary-content;
}
.mx_UserExtendedProfileInfo_value {
word-break: break-word;
overflow-wrap: break-word;
}
/* Dark theme specific styles */
.mx_UserExtendedProfileInfo_value a {
color: $accent;
text-decoration: none;
}
.mx_UserExtendedProfileInfo_value a:hover {
text-decoration: underline;
}
-5
View File
@@ -108,11 +108,6 @@ Please see LICENSE files in the repository root for full details.
margin: 0;
font-size: $font-20px;
line-height: $font-25px;
/* E2E icon wrapper */
.mx_Flex > span {
display: inline-block;
}
}
.mx_UserInfo_profile_name {
@@ -12,10 +12,6 @@
border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-bg-subtle-primary);
padding: 0 var(--cpd-space-3x);
svg {
fill: var(--cpd-color-icon-secondary);
}
.mx_RoomListSearch_search {
/* The search button should take all the remaining space */
flex: 1;
@@ -23,6 +19,10 @@
color: var(--cpd-color-text-secondary);
min-width: 0;
svg {
fill: var(--cpd-color-icon-secondary);
}
span {
flex: 1;
@@ -42,10 +42,4 @@
}
}
}
.mx_RoomListSearch_button:hover {
svg {
fill: var(--cpd-color-icon-primary);
}
}
}
+6
View File
@@ -55,6 +55,12 @@ Please see LICENSE files in the repository root for full details.
background-color: var(--cpd-color-icon-tertiary);
}
.mx_E2EIcon_verified {
.mx_E2EIcon_normal::after {
background-color: white;
}
}
.mx_E2EIcon_verified::after {
mask-image: url("$(res)/img/e2e/verified.svg");
background-color: $e2e-verified-color;
@@ -0,0 +1,76 @@
.mx_ExtendedProfileSettings {
margin-top: 24px;
margin-bottom: 16px;
}
.mx_ExtendedProfileSettings h3 {
font-size: 16px;
font-weight: 600;
margin-top: 0;
margin-bottom: 16px;
}
.mx_ExtendedProfileSettings_fields {
display: flex;
flex-direction: column;
gap: 16px;
}
.mx_ExtendedProfileSettings_field {
width: 100%;
margin-bottom: 20px;
}
.mx_ExtendedProfileSettings_fieldsRow {
display: flex;
gap: 16px;
margin-bottom: 20px;
.mx_ExtendedProfileSettings_field {
flex: 1;
margin-bottom: 0;
}
}
/* Business contact field specific layouts */
.mx_ExtendedProfileSettings_address_row {
.mx_ExtendedProfileSettings_field_business_street {
flex: 1;
}
.mx_ExtendedProfileSettings_field_business_street_nr {
flex: 1;
}
}
.mx_ExtendedProfileSettings_postal_row {
.mx_ExtendedProfileSettings_field_business_plz {
flex: 1;
}
.mx_ExtendedProfileSettings_field_business_city {
flex: 1;
}
}
.mx_ExtendedProfileSettings_contact_row {
.mx_ExtendedProfileSettings_field_business_email {
flex: 1;
}
.mx_ExtendedProfileSettings_field_business_tel {
flex: 1;
}
}
.mx_ExtendedProfileSettings_buttons {
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 8px;
}
.mx_ExtendedProfileSettings_multiline textarea {
min-height: 200px;
resize: vertical;
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "Element",
"short_name": "Element",
"name": "HealthChat",
"short_name": "HealthChat",
"display": "standalone",
"theme_color": "#76CFA6",
"start_url": "index.html",

Some files were not shown because too many files have changed in this diff Show More