Compare commits

...

182 Commits

Author SHA1 Message Date
RiotRobot 2ef02fa39e v1.12.9
Docker / Docker Buildx (push) Failing after 54s
2026-01-27 12:50:07 +00:00
RiotRobot 68cc500705 Upgrade dependency to matrix-js-sdk@40.1.0 2026-01-27 12:41:33 +00:00
RiotRobot 1ec05298cf v1.12.9-rc.1
Docker / Docker Buildx (push) Failing after 54s
2026-01-20 14:18:57 +00:00
ElementRobot eaa34e6dfa Update secret paths for OCI credentials in Docker workflow (#31802) (#31803)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-20 14:16:04 +00:00
RiotRobot fefe093ce0 v1.12.9-rc.0
Docker / Docker Buildx (push) Failing after 52s
2026-01-20 14:02:47 +00:00
RiotRobot ee4277fd95 Upgrade dependency to matrix-js-sdk@40.1.0-rc.0 2026-01-20 13:59:36 +00:00
Will Hunt a15efcc6d0 Allow local log downloads when a rageshake URL is not configured. (#31716)
* Add support for storing debug logs locally and allowing local downloads.

* static

* Comprehensive testing for bug report flow.

* Driveby cleanup of typography

* fix i18n

* Improvements to UX

* More testing

* update snaps

* linting

* lint

* Fix feedback

* Fix boldnewss

* fix bold

* fix heading

* Increase test coverage

* remove focus

* Don't show the FAQ depending on whether you can submit feedback.

* move reset

* fix err

* Remove unused

* update snap

* Remove text

* Bumping up that coverage

* tidy

* lint

* update snap

* Use a const

* fix imports

* Remove import in e2e test

* whoops
2026-01-20 12:29:18 +00:00
ElementRobot b7a2e8c64e [create-pull-request] automated change (#31795)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-20 08:59:40 +00:00
Aditya Cherukuru 93a8b67ed0 Fix flaky Jest test: RoomView search results (#31785)
Signed-off-by: aditya-cherukuru <cherukuru.aditya01@gmail.com>
2026-01-19 13:31:48 +00:00
Michael Telatynski 3b08b5c582 Improve icon rendering accessibility (#31776)
* Switch to rendered svg for Field select decoration instead of SVG mask

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

* Replace warning.svg with Compound icon

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

* Replace device kind icons with Compound

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

* Draw notification badge decoration using SVG rather than CSS masks

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

* Replace {collapse,expand}-message icons with Compound

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

* Remove stale icon prefetch

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

* Render icons in AddExistingToSpaceDialog using SVGs rather than CSS masks

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

* Render icons in Jitsi landing page using SVGs rather than CSS masks

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

* Delint

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

* Update snapshots

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

* Update screenshot

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

* Fix field label

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

* Update snapshots

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

* Add tests

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

* Revert icon colour

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-19 13:27:09 +00:00
Michael Telatynski f236c26356 Fix avatar decorations in thread activity centre not being atop avatar (#31789)
* Fix avatar decorations in thread activity centre not being atop avatar

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

* Delint

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

* Update snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-19 12:10:24 +00:00
Michael Telatynski b8ad0b93db Fix room settings roles tab getting confused if power level change fails (#31768)
* Fix room settings roles tab getting confused if power level change fails

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-19 12:08:42 +00:00
Florian Duros 3f021472c2 doc: fix typo in deprecated-modules.md file (#31788) 2026-01-19 10:28:59 +00:00
ElementRobot 1c42173e5b [create-pull-request] automated change (#31786)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-19 09:23:52 +00:00
Michael Telatynski 0b91be5a78 Update CODEOWNERS for i18n strings
Added CODEOWNERS entries for shared components translations.
2026-01-19 09:23:32 +00:00
ElementRobot c91a24f17b [create-pull-request] automated change (#31782)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-18 06:22:29 +00:00
ElementRobot 20de09e80f [create-pull-request] automated change (#31781)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-17 06:21:44 +00:00
Richard van der Hoff 52748d6d35 Minor corrections on shared-components/README.md (#31741)
* Minor corrections shared-components-README.md

a few minor edits and clarifications

* Wrap lines at 80 characters

Mostly, this means that diff comments on PRs work better.

* Update packages/shared-components/README.md

* Apply suggestion from @richvdh
2026-01-16 18:13:57 +00:00
Richard van der Hoff 92a6db5912 Show "Bob shared this message" on messages shared via MSC4268 (#31684)
* Factor out E2ePadlock to its own file

* Show "Bob shared this message" on messages shared via MSC4268

If we received the keys for a given message from another user, indicate that in
the timeline, rather than just saying "authenticity not guaranteed"

* Apply suggestions from code review

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

* Address review comments

* Move E2ePadlock to shared-components

* update snapshots

* Revert "update snapshots"

This reverts commit 751e31f9db901fda085143c98e5dffa3d2b4c099.

* Revert "Move E2ePadlock to shared-components"

This reverts commit 172ef9f70ab26fd36b0ac854379cfd3371d22c18.

---------

Co-authored-by: Florian Duros <florianduros@element.io>
2026-01-16 17:22:42 +00:00
Florian Duros d9a4858b1d doc: update module doc (#31775) 2026-01-16 16:06:24 +00:00
Florian Duros fbac316991 doc: add shared component mention in CONTRIBUTING.md (#31772) 2026-01-16 15:13:26 +00:00
Florian Duros b9638695b7 Update compound to 8.3.5 (#31736)
* chore: update compound to `8.3.5`

* refactor: remove incorrect color in shared components

* test: update shared components snapshots

* test: update shared component screenshots

* test: update EW snapshots

* test: update EW screenshots

* test: update snapshot
2026-01-16 14:30:08 +00:00
ElementRobot e2dad68169 [create-pull-request] automated change (#31753)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-16 11:45:30 +00:00
Michael Telatynski 466f60ead5 Update the way we render icons for accessibility (#31731)
* Switch to Compound icons to replace old icons

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

* Apply same treatment to missed icons

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

* Iterate

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

* Update snapshots

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

* Remove duplicated icon

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

* Update icon

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

* Update snapshots

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

* Switch from css masks to rendering svg in ImageView

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

* Switch from css masks to rendering svg in ExtensionsCard

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

* Switch from css masks to rendering svg in LegacyRoomListHeader

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

* Switch from css masks to rendering svg in ImageSizePanel

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

* Switch from css masks to rendering svg in LegacyRoomList

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

* Remove icon from CreateSecretStorageDialog title

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

* Switch from css masks to rendering svg in LiveContentSummary

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

* Switch from css masks to rendering svg in RoomCallBanner

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

* Switch from css masks to rendering svg in NonUrgentEchoFailureToast

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

* Switch from css masks to rendering svg in LegacyCallViewHeader

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

* Switch from css masks to rendering svg in CallEvent

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

* Delint

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

* Iterate

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

* Update screenshots

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

* Replace dark-light-mode.svg with Compound

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

* Draw stop icon using svg rather than square mask

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

* Replace masks in RoomSublist with SVG icons

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

* Replace masks with SVG icons in LegacyCall views

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

* Replace masks with SVG icons in EventTile

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

* Replace masks with SVG icons in ForwardDialog

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

* Remove redundant css style

The `::before` has no content so is never rendered

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

* delint

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

* Update tests

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

* Update playwright tests & screenshots

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

* Iterate

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

* Update snapshot

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

* Remove snapshot as it causes issues

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

* Delint

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

* More tests

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-16 11:21:57 +00:00
Michael Telatynski 28464b4d12 Call shared-components i18n scripts from web's i18n scripts (#31760)
So that localazy_download.yaml sorts & lints both

This will be cleaner in a proper monorepo where the root package.json isn't its own project

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-16 10:19:15 +00:00
Florian Duros 420576f4ae doc: add missing entries to doc/SUMMARY.md (#31750) 2026-01-16 10:09:14 +00:00
Philip Örnfeldt e811cf0f84 Custom themes now import highlights in css (#31758)
Added import for codeblock highlights in css for custom themes

Signed-off-by: Örnfeldt Philip (66140321) <philip.ornfeldt@forsakringskassan.se>
2026-01-16 10:00:18 +00:00
Michael Telatynski 7e5a3a530d Switch from css masks to rendering svg (#31681)
* Switch to Compound icons to replace old icons

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

* Apply same treatment to missed icons

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

* Iterate

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

* Update snapshots

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

* Remove duplicated icon

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

* Update icon

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

* Update snapshots

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

* Switch from css masks to rendering svg in ImageView

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

* Switch from css masks to rendering svg in ExtensionsCard

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

* Switch from css masks to rendering svg in LegacyRoomListHeader

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

* Switch from css masks to rendering svg in ImageSizePanel

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

* Switch from css masks to rendering svg in LegacyRoomList

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

* Remove icon from CreateSecretStorageDialog title

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

* Switch from css masks to rendering svg in LiveContentSummary

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

* Switch from css masks to rendering svg in RoomCallBanner

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

* Switch from css masks to rendering svg in NonUrgentEchoFailureToast

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

* Switch from css masks to rendering svg in LegacyCallViewHeader

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

* Switch from css masks to rendering svg in CallEvent

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

* Delint

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

* Iterate

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

* Update screenshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-16 09:52:31 +00:00
ElementRobot f9778fcbd3 [create-pull-request] automated change (#31752)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-16 06:23:14 +00:00
ElementRobot 575b3b5400 Localazy Download (#31595)
* [create-pull-request] automated change

* chore: format i18n files

---------

Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
2026-01-15 10:52:53 +00:00
Florian Duros cac682247c Use correct translation for url preview settings (#31740)
* fix: use correct translation for url preview settings

* test: update snapshot
2026-01-15 10:36:57 +00:00
David Baker 82b270616f Fix error shown if accepting a 3pid invite (#31735)
* Fix error shown if accepting a 3pid invite

If no matrix ID was bound to the email address, the code would
just throw an exception and display a very generic error.

* Unused import

* I hate you too, yarn.

* i18n

* Add test
2026-01-15 09:43:19 +00:00
Michael Telatynski 6f0cd7621b Update fetch-mock-jest to @fetch-mock/jest (#31720)
* Remove tests which assert feature_oidc_native_flow=false behaviour, that setting is long gone

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

* Upgrade fetch-mock-jest to @fetch-mock/jest

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

* Update yarn.lock

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

* Make knip happy

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

* Disable broken tests

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

* Fix shared-components tests

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

* Snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-15 09:21:25 +00:00
ElementRobot f5c6477ef7 [create-pull-request] automated change (#31739)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-15 06:23:05 +00:00
Michael Telatynski 1eb07ba750 Push docker images to oci.element.io (#31734)
For https://github.com/element-hq/serverproduct-internal/issues/1153
2026-01-14 15:59:48 +00:00
Michael Telatynski 45ed3c500b Update reference desktop icon (#31730)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-14 15:59:32 +00:00
Hugh Nimmo-Smith 7f408bd6cf Support for stable MSC4191 account management action parameter (#31701)
* Support for stable MSC4191 account management action parameter

* Pass accountManagementActionsSupported around and refactor name

* Iterate

* Iterate

* Attempt to improve clarity of action fallback

* Use name "actions supported" consistently

* Update test cases for revised default behaviour
2026-01-14 14:53:44 +00:00
Florian Duros 9cc80c5f36 doc: add shared-components readme (#31725) 2026-01-14 14:13:09 +00:00
Florian Duros bdee36ca7c doc: add recommendation to use compound typography component (#31715)
* doc: add recommendation to use compound typograpghy component

* Update code_style.md

Co-authored-by: R Midhun Suresh <hi@midhun.dev>

---------

Co-authored-by: R Midhun Suresh <hi@midhun.dev>
2026-01-14 11:07:37 +00:00
Andy Balaam 9640c330e5 Remove the count indicator from toasts (#31718) 2026-01-14 09:57:00 +00:00
ElementRobot 33764d39ba [create-pull-request] automated change (#31722)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-14 06:23:34 +00:00
RiotRobot 775332b179 Reset matrix-js-sdk back to develop branch 2026-01-13 14:52:40 +00:00
RiotRobot b2a5f4d58b Merge branch 'master' into develop 2026-01-13 14:52:11 +00:00
RiotRobot 71d9312452 v1.12.8
Docker / Docker Buildx (push) Failing after 58s
2026-01-13 14:48:05 +00:00
RiotRobot fe1e0df5ad Upgrade dependency to matrix-js-sdk@40.0.0 2026-01-13 14:30:42 +00:00
Aditya Cherukuru 04800c15af Fix flaky MemberListView tests (#31707)
Replace unreliable setTimeout(1000) with proper waitFor() patterns for async assertions.

Fixes element-hq/element-web#31251

Fixes element-hq/element-web#31582

Signed-off-by: aditya-cherukuru <cherukuru.aditya01@gmail.com>
2026-01-13 12:43:20 +00:00
Hugh Nimmo-Smith fb060721dc Support for stable m.oauth UIA stage from MSC4312 (#31704)
* Support for stable m.oauth UIA stage from MSC4312

* Unit tests

* readonly props
2026-01-13 12:18:03 +00:00
Michael Telatynski f079224dd6 Remove old pro pipeline trigger (#31677)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-13 11:41:03 +00:00
ElementRobot 5e8024009c [create-pull-request] automated change (#31706)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-13 06:23:01 +00:00
Will Hunt 2e6cf8734b Refactor RoomStatusBar into MVVM (#31523)
* Refactor RoomStatusBar into MVVM

* cleanup

* updated snaps

* More cleanup

* fix loop

* fixup

* drop comment

* lint

* cleanup console statements

* Starting to move to a MVVM v2 component.

* extra

* Refactor as a shared-componend / MVVM v2

* some cleanup

* i18n for banner

* remove removed css

* Update playwright tests to have a two stage on the consent bar.

* Update snaps

* Update snapshots

* cleanup

* update snaps

* refactor to use enum

* fix slight differences in pw snaps

* Add unit tests

* fix snaps

* snaps updated

* more test cleanups

* fix snaps

* fixed now?

* Disable animationsq

* lint lint lint

* remove console

* lint

* fix snap

* Refactor based on review comments.

* update view model test

* oops!

* fix snap

* Update snaps

* snap snap snap

* switch to a const map of strings

* Use this.disposables

* Update translations to be inside shared-components

* fix the tac

* Also retry

* Cleanup

* update snaps

* update other snaps

* snap updates
2026-01-12 21:13:15 +00:00
ElementRobot deb3355811 Fix space settings visibility tab crashing (#31703) (#31705)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-12 17:47:27 +00:00
Michael Telatynski d9be851965 Fix space settings visibility tab crashing (#31703)
* Fix space settings visibility tab crashing

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

* Add test

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

* Remove spurious semi-colon

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-12 17:08:20 +00:00
Hugh Nimmo-Smith 2db10037f2 Fix links to contributing and review guidelines in PR template (#31702)
* Fix links to contributing and review guidelines in PR

* Make links absolute
2026-01-12 14:08:04 +00:00
ElementRobot 133951b663 [create-pull-request] automated change (#31695)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-10 06:22:26 +00:00
Will Hunt 06f70d1d7c Ensure we react to RTC transport changes in useRoomCall (#31691) 2026-01-09 13:33:47 +00:00
Will Hunt 7ad6b4b411 Ensure correct focus configuration for Element Call before allowing users to call. (#31490)
* fixup type

* Validate Element Call foci config

* revert changes

* Split out logic to CallStore so we don't repeat checks.

* Refactor to use CallStore so we only fetch once.

* Add test for useRoomCall

* lint

* Ensure we enable MatrixRTC when configuring element call.

* fix test

* Update @element-hq/element-web-playwright-common to 2.2.2 and enable matrix rtc

* lint

* Ensure call is configured for header test

* type

* Improve coverage

* Update based on feedback

* fix type
2026-01-09 12:04:31 +00:00
ElementRobot 239527996a [create-pull-request] automated change (#31688)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-09 10:41:14 +00:00
renovate[bot] 795780da66 Update dependency typescript to v5.9.3 (#30492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 19:23:40 +00:00
Michael Telatynski ce741f055c Switch to Compound icons to replace old icons (#31667)
* Switch to Compound icons to replace old icons

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

* Apply same treatment to missed icons

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

* Iterate

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

* Update snapshots

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

* Remove duplicated icon

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

* Update icon

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

* Update snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 15:50:02 +00:00
R Midhun Suresh 7d72775af9 Add more MVVM documentation (#31680)
* Move benefits section to the top

* Improve existing doc

* Add more documentation
2026-01-08 12:59:40 +00:00
Michael Telatynski 540d71f49c Fix emoji font in emoji picker header buttons (#31679)
* Fix emoji font in emoji picker header buttons

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

* Update screnshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 12:58:02 +00:00
Michael Telatynski 220e93596a Switch from svg masks to svg rendering in more places (#31652)
* Replace icons with Compound alternatives

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

* Remove unused icon

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

* Replace more icons with Compound alternatives

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

* Swap for outline icons in spotlight & update screenshots

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

* Switch emoji picker to use emoji for header icons

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

* Update screenshot

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

* Update football emoji

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

* Switch from svg masks to svg rendering in ExtensionsCard

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

* Switch from svg masks to svg rendering in BaseCard

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

* Switch from svg masks to svg rendering in EmojiPicker

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

* Switch from svg masks to svg rendering in Spotlight

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

* Update snapshot

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

* Update screenshots

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

* Tweak emoji and fix disabled state

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

* Switch from svg masks to svg rendering in HomePage

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

* Switch from svg masks to svg rendering in DecoratedRoomAvatar

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

* Switch from svg masks to svg rendering in SpaceRoomView

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

* Switch from svg masks to svg rendering in DialPadBackspaceButton

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

* Switch from svg masks to svg rendering in NewRoomIntro

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

* Switch from svg masks to svg rendering in SpaceCreateMenu

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

* Switch from svg masks to svg rendering in InlineTermsAgreement

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

* Switch from svg masks to svg rendering in PollCreateDialog

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

* Switch from svg masks to svg rendering in ServerPicker

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

* Revert size change

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

* Delint

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

* Update snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 11:20:55 +00:00
Aditya Cherukuru 2c90eee2dd chore: use matrix-sort-i18n instead of jq for i18n:sort (#31669)
* chore: use matrix-sort-i18n instead of jq for i18n:sort

Signed-off-by: aditya-cherukuru <cherukuru.aditya01@gmail.com>

* chore: fix prettier formatting in package.json

Signed-off-by: aditya-cherukuru <cherukuru.aditya01@gmail.com>

---------

Signed-off-by: aditya-cherukuru <cherukuru.aditya01@gmail.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 11:12:00 +00:00
Michael Telatynski edd4eab195 Switch from svg masks to svg rendering in more places (#31650)
* Replace icons with Compound alternatives

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

* Remove unused icon

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

* Replace more icons with Compound alternatives

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

* Swap for outline icons in spotlight & update screenshots

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

* Switch emoji picker to use emoji for header icons

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

* Update screenshot

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

* Update football emoji

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

* Switch from svg masks to svg rendering in ExtensionsCard

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

* Switch from svg masks to svg rendering in BaseCard

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

* Switch from svg masks to svg rendering in EmojiPicker

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

* Switch from svg masks to svg rendering in Spotlight

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

* Update snapshot

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

* Update screenshots

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

* Tweak emoji and fix disabled state

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

* Revert size change

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

* Delint

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

* Add test

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-08 10:44:54 +00:00
ElementRobot 15c409491d [create-pull-request] automated change (#31676)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-08 06:22:45 +00:00
Michael Telatynski d060b77e8f Update notification icons using Compound icons (#31671)
* Update notification icons using Compound icons

For https://element-io.atlassian.net/browse/PSB-968

This removes icons in places where we only have on/off variants rather than the previous 4

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

* Update tests

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

* Update screenshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-07 15:58:28 +00:00
Michael Telatynski 6e9d168dd2 Exclude Upload* workflows from blocking develop CD (#31674) 2026-01-07 15:28:03 +00:00
Michael Telatynski cb7e8f4910 Memoise ListView context (#31668)
* Update npm non-major dependencies

* Make types happier

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

* Memoise ListView context

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

* Discard changes to yarn.lock

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-07 15:05:14 +00:00
renovate[bot] a5af6cf23f Update dependency @element-hq/element-web-playwright-common to v2.2.0 (#31659)
* Update dependency @element-hq/element-web-playwright-common to v2.2.0

* Update playwright-common

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

* Update playwright-common s'more

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>
2026-01-07 14:45:03 +00:00
renovate[bot] 9db08a4574 Update dependency matrix-web-i18n to v3.5.0 (#31660)
* Update dependency matrix-web-i18n to v3.5.0

* Update matrix-web-i18n

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

* Update matrix-web-i18n in shared-components too

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

* matrix-web-i18n is now ESM

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>
2026-01-07 14:15:03 +00:00
David Baker 2f817f32ce Fix shared components i18n check (#31672)
* Remove extra encryption strings

Found their way in during the i18n changes

* Remove log level silent

to try & work out why it only fails on CI

* Try giving it its own prettierrc

so the import is correct

* Comment why it needs its own prettierrc & put log level silent back

* Comment the right .prettierrc
2026-01-07 12:42:30 +00:00
David Baker 13696af194 Split translations between EW and shared components (#31441)
* Split translations between EW and shared components

Uses update module API with global TranslationKey type that can be
overridden.

WIP.

* Removed the wrong script (for now)

* Add the type files

* Add shared components i18n file

* More i18n strings

* Add i18n check for shared conmponents

* Needs a different name

* rerun i18n for merge from develop, fix test

* Move translated strings to shared components file

NB. there are lots of removed strings for a few languages where we
seem to have hit a localazy bug or something where the key/value
for plurals got switched, making the translations invalid. They've
been missing for a while so I'm removing them rather than trying to
restore them,

* Add shared components files to localazy

* Merge element web & shared component translations

for the built app

* Use right translations for shared component tests

and fix missign en_EN strings

* Pull shared components translations too

* Fix/disable warnings

* We can now remove the build:res call

...right? (right?)

* Remove webpack import for languages index

..and just load it using a relative path which we do for the individual
language files and also did anyway for the index because even in non-test
it was an object, not a string, so we always usesd the 'test' code path.

* Make the storybook language selector work

...without referring to the parent app's files

* Revert unnecessary yarn lock change

* Typo

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

* Add comment on why we use merge

* Fix localazy download config

to actually put the translations in the right place

* Better typescript syntax

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

* Watch both translations files

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-07 11:49:01 +00:00
renovate[bot] 4ee04d0661 Update npm non-major dependencies (#31662)
* Update npm non-major dependencies

* Make types happier

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>
2026-01-07 10:52:05 +00:00
Michael Telatynski 7f057faaad Switch emoji picker to use emoji for header icons (#31645)
* Replace icons with Compound alternatives

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

* Remove unused icon

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

* Replace more icons with Compound alternatives

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

* Swap for outline icons in spotlight & update screenshots

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

* Switch emoji picker to use emoji for header icons

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

* Update screenshot

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

* Update football emoji

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

* Tweak emoji and fix disabled state

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-07 10:22:26 +00:00
ElementRobot d7a58216ae [create-pull-request] automated change (#31670)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-07 07:27:41 +00:00
ElementRobot 4dd128fd18 [create-pull-request] automated change (#31580)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2026-01-06 16:11:27 +00:00
Valere Fedronic 126b216d44 fix flaky test by waiting for chat panel before counting messages (#31633)
* fix flaky test by waiting for chat panel before counting messages

* improve test stability by waiting for visibility before elements count()
2026-01-06 15:49:48 +00:00
renovate[bot] b8ecc0e07e Update GitHub Artifact Actions (#31665)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:41:37 +00:00
renovate[bot] 4668c15ea1 Update dependency @formatjs/intl-segmenter to v12 (#31664)
* Update dependency @formatjs/intl-segmenter to v12

* Update imports

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>
2026-01-06 15:22:01 +00:00
renovate[bot] 867a6850e4 Update octokit/graphql-action action to v3.0.2 (#31657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:19:25 +00:00
renovate[bot] adc5ee22cc Update peter-evans/create-pull-request action to v8 (#31666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:09:55 +00:00
renovate[bot] aa6509e01c Update storybook (#31658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:08:29 +00:00
renovate[bot] 770ff42496 Update eslint-plugins (#31661)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:07:03 +00:00
renovate[bot] db352ef876 Update actions/cache action to v5 (#31663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:04:37 +00:00
renovate[bot] acca876697 Update dependency caniuse-lite to v1.0.30001762 (#31656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 15:02:57 +00:00
renovate[bot] d9e7948920 Update docker/setup-buildx-action digest to 8d2750c (#31653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 14:57:30 +00:00
renovate[bot] d7feaa0b2a Update nginxinc/nginx-unprivileged:alpine-slim Docker digest to 2c49851 (#31654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 14:55:34 +00:00
renovate[bot] ebd7cdb09d Update Node.js to 32bde4f (#31655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-06 14:55:33 +00:00
Valere Fedronic df091a7d3e rtc: use new API in tests (instead of deprecated calls) (#31649) 2026-01-06 14:13:48 +00:00
RiotRobot 1407d0f046 v1.12.8-rc.0
Docker / Docker Buildx (push) Failing after 46s
2026-01-06 14:12:21 +00:00
RiotRobot 40fb7f0ca7 Upgrade dependency to matrix-js-sdk@40.0.0-rc.0 2026-01-06 14:03:47 +00:00
Michael Telatynski fea10b3c19 Replace icons with Compound alternatives (#31642)
* Replace icons with Compound alternatives

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

* Remove unused icon

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

* Replace more icons with Compound alternatives

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

* Swap for outline icons in spotlight & update screenshots

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

* Update screenshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-06 13:55:04 +00:00
Michael Telatynski ddad82075a Fix expand/collapse reply preview not showing in some cases (#31639)
* Fix expand/collapse reply preview not showing in some cases

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

* Move tests to appropriate place

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

* Iterate

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

* Add comments

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-06 11:57:23 +00:00
Florian Duros c078a596f9 Update playwright doc (#31594)
* doc: update playwright doc

* doc: review changes

* doc: update projects declaration

* doc: run prettier
2026-01-06 10:45:28 +00:00
Michael Telatynski d62206b7e8 Remove superfluous rageshake label for Rust Crypto (#31646)
* Remove superfluous rageshake label for Rust Crypto

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

* Remove old test

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

* Delint

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-06 10:21:03 +00:00
Michael Telatynski 914c959e31 Switch to rendering svg icons rather than masking them (#31557)
* Switch to rendering svg icons rather than masking them in SpacePanel

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

* Fix badly rendered icon in JoinRuleDropdown

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

* Fix badly rendered icon in RoomPreviewCard

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

* Fix badly rendered icon in Space menus

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

* Fix badly rendered icon in ThreadPanel

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

* Update snapshots

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

* Update screenshot

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

* Remove unused icon underfill

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

* Update screenshot

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

* Add test

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

* Add missing snapshot

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

* Remove unused AccessibleButton kinds

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

* Switch to rendering svg icons rather than masking them in EventTileBubble

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

* Switch to rendering svg icons rather than masking them in ReactionsRow

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

* Switch to rendering svg icons rather than masking them in MFileBody

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

* Switch to rendering svg icons rather than masking them in BaseCard

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

* Switch to rendering svg icons rather than masking them in RedactedBody

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

* Switch to rendering svg icons rather than masking them in E2ePadlock

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

* Tidy up E2EIcon

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

* Switch to rendering svg icons rather than masking them in DialPad

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

* Switch to rendering svg icons rather than masking them in AccessSecretStorageDialog

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

* Switch to rendering svg icons rather than masking them in HiddenBody

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

* Update tests

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

* Iterate

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

* Update tests

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

* Fix overflow in base card size

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

* Add missing screenshots

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>
2026-01-05 17:14:51 +00:00
Florian Duros be7be39d0f Fix bundled font or custom font not applied after theme switch (#31591)
* refactor: transform `FontWater.onAction` to switch

* fix: reload font after switching theme

Fix #26248 #31588

When a theme is swiched, `clearCustomTheme` remove all css variables.
After the styles are re-applied but the custom fonts or emoji are not
re-applied.

* test: add test for `Action.ReloadFont`

* test: add missing tests for existing actions

* test(e2e): add tests to ensure that font and emoji stay unchanged

* Revert "fix: reload font after switching theme"

This reverts commit 2b0071af21c38bf2c86780356aa39d290e9d9148.

* Revert "refactor: transform `FontWater.onAction` to switch"

This reverts commit 411915860923230cabce3ad5498fb46696a9a65e.

* Revert "test: add test for `Action.ReloadFont`"

This reverts commit 31b3b224cd2c443663a2b9bba312a4140907a8ed.

* fix: don't remove custom emoji and cpd font when clearing custom theme

Fix #26248 #31588

When a theme is swiched, `clearCustomTheme` remove all css variables.
After the styles are re-applied but the custom fonts or emoji are not
re-applied.
This fix avoid the custom font and emoji to be removed.

* test: add tests
2026-01-05 16:14:08 +00:00
dependabot[bot] 4bd1d4144f Bump qs from 6.14.0 to 6.14.1 in /packages/shared-components (#31636)
Bumps [qs](https://github.com/ljharb/qs) from 6.14.0 to 6.14.1.
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 15:00:41 +00:00
Valere Fedronic 0c47ca2a45 cleaning: Stop using deprecated callMembershipsForRoom (#31616)
* cleaning: Stop using deprecated callMembershipsForRoom

* fix test

* review: Added quick doc
2026-01-05 13:47:10 +00:00
Brendon Walsh 5e6ee49509 Add ol override CSS for markdown-body (#31618) 2026-01-05 13:07:51 +00:00
David Langley 05e7203f1b Update history visibility UX (#31635)
* Update history visibility UX

* don't change voip strings
2026-01-05 12:24:42 +00:00
Michael Telatynski 5d1cb24a6c Fix reaction left margin in timeline card (#31625)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-05 11:55:43 +00:00
R Midhun Suresh f509dc031f Document how to remove existing strings from localazy (#31640)
* Fix punctuation

* Use backticks instead of single quote for html tag

* Explain how to remove existing strings
2026-01-05 11:36:07 +00:00
Will Hunt 13ded7db84 Remove element_call.participant_limit config and associated code. (#31638)
* Remove `element_call.participant_limit`

* fix disabledTooltip

* reducer ftw

* Remove unused bits

* prettier
2026-01-05 11:19:14 +00:00
Florian Duros 56dcb668d1 doc: improve modules doc in config.json (#31597) 2026-01-05 10:22:14 +00:00
Michael Telatynski 885305aa46 Open right panel timeline when jumping to event with maximised widget (#31626)
* Open right panel timeline when jumping to event with maximised widget

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

* Add test

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

* Fix types & update snapshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2026-01-05 09:36:55 +00:00
Will Hunt cf7bf71d01 Fix Compound Link elements not having an underline. (#31583)
* Do not alter text-decoration if an <a> tag is a Link.

* Update screenshots

* update compound web to 8.3.4

* Update snaps

* Update alllllll the snaps

* update screenshots
2026-01-05 09:27:00 +00:00
Will Hunt 7398a83ae4 Show correct call icon for joining a call. (#31489)
* Show correct call icon in header.

* fix import

* Simply useRoomCall output

* Add tests and a label

* update snap

* update test
2026-01-02 17:51:15 +00:00
Tol Wassman cbe3eb1709 Recalculate mentions metadata of forwarded messages based on message body (#31193)
* recalculate mentions of forwarded messages

In transformEvent(), parse event body back into an EditorModel, and pass this into attachMentions(), so that it actually recalculates mentions.

* refactor ForwardDialog-test.tsx

Refactor test for stripping mentions on forwards to allow for more tests of mention recalculation

* add test to recalculate mention pills

Fails due to not mocking room membership

* fix lint

* fix test: add ability to provide source room stub
2026-01-02 15:45:46 +00:00
Germain 8e6045a687 Fix Room Preview Card Layout (#31611) 2026-01-02 11:09:08 +00:00
Will Hunt 494bc1a468 Reduce complexity of ElementWidgetDriver.readRoomTimeline (#31465)
* Reduce complexity of ElementWidgetDriver.readRoomTimeline

* Remove reverse to pass tests

* Slightly more exotic loop

* remove type

* fix lint
2025-12-29 17:17:03 +00:00
Will Hunt 004dbcd062 Update StopGapWidgetDriver to support sticky events (#31205)
* Update StopGapWidgetDriver to support sticky events

* Update to-device

* Update tests

* Clean up duplication

* lint

* yarn lock
2025-12-29 13:34:01 +00:00
Valere Fedronic 3f472c8812 Fix: WidgetMessaging not properly closed causing side effects and bugs (#31598)
* test: Add a failing test reproducing the multi messaging leak bug

* fix: Missing widgetApi stop causing leaks
2025-12-24 09:23:04 +00:00
ElementRobot fe73a0358c [create-pull-request] automated change (#31589)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-22 07:04:37 +00:00
Hubert Chathi ebd5df633e Handle cross-signing keys missing locally and/or from secret storage (#31367)
* show correct toast when cross-signing keys missing

If cross-signing keys are missing both locally and in 4S, show a new toast
saying that identity needs resetting, rather than saying that the device
needs to be verified.

* refactor: make DeviceListener in charge of device state

- move enum from SetupEncryptionToast to DeviceListener
- DeviceListener has public method to get device state
- DeviceListener emits events to update device state

* reset key backup when needed in RecoveryPanelOutOfSync

brings RecoveryPanelOutOfSync in line with SetupEncryptionToast behaviour

* update strings to agree with designs from Figma

* use DeviceListener to determine EncryptionUserSettingsTab display

rather than using its own logic

* prompt to reset identity in Encryption Settings when needed

* fix type

* calculate device state even if we aren't going to show a toast

* update snapshot

* make logs more accurate

* add tests

* make the bot use a different access token/device

* only log in a new session when requested

* Mark properties as read-only

Co-authored-by: Skye Elliot <actuallyori@gmail.com>

* remove some duplicate strings

* make accessToken optional instead of using empty string

* switch from enum to string union as per review

* apply other changes from review

* handle errors in accessSecretStorage

* remove incorrect testid

---------

Co-authored-by: Skye Elliot <actuallyori@gmail.com>
2025-12-19 17:00:50 +00:00
Skye Elliot ce9c66ba4c Update algorithm for history visible banner. (#31577)
* feat: Update algorithm for history visible banner.

- The banner now only shows for rooms with `shared` or `worldReadable`
  history visibility.
- The banner does not show in rooms in which the current user cannot
  send messages.

* tests: Add `getHistoryVisibility` to stub room.

* docs: Add description to `visible` condition check.

* docs: Fix spelling.

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>

* chore: Remove `jest-sonar.xml`.

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
2025-12-19 15:41:09 +00:00
Skye Elliot aa84b2e07c fix: Allow wrapping in Banner component. (#31532)
* fix: Allow wrapping in `Banner` component.

* chore: Remove translations from stories, update snapshot.
2025-12-19 15:40:45 +00:00
ElementRobot d1762ed29d Localazy Download (#31563)
* [create-pull-request] automated change

* Update screenshots

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

* Update screenshot

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-12-19 14:41:00 +00:00
Michael Telatynski c37fef459d Remove release announcements for new sounds & room list (#31544)
* Remove release announcements for new sounds & room list

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

* Update tests

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

* Update tests

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

* Update tests

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-19 14:40:44 +00:00
mxandreas 71c5b71f5c Add button to restore from backup into /devtools (#31581)
* Add button to restore from backup.

* Fix formatting.
2025-12-19 14:32:54 +00:00
Florian Duros dad8072ff8 test: add mask to create room spec to fix flakyness (#31575) 2025-12-19 12:39:04 +00:00
Will Hunt 87d529701c Playwright tests for RoomStatusBar (#31579)
* Add a timeout for toast checks

* Add tests for room status bar

* Fix MAU toast never appearing.

* Also cover local room create fails.

* fix await

* docstring

* Enwiden

* Add a test for the changes
2025-12-19 12:16:01 +00:00
Michael Telatynski 63bf04384a Switch to non-solid compound icons for room settings & composer (#31561)
* Switch to non-solid compound icons for room settings & composer

Also manually fixes sticker.svg to be tintable until it is redrawn

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

* Replace sticker.svg

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

* Update snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-19 10:19:02 +00:00
Florian Duros e15f80c371 Fix styling issue when using EW modules (#31533)
* style: move compound loading order

* fix: spotlight fiting

* fix: don't use internal compound css var in settings subsection

* fix: don't use internaal compound css var in read receipt group

* fix: add important to font settings on body element

* fix: remove play pause button color and fix padding

This color wasn't apply because this PR. Removing to avoid visual
regression

* fix: add important to form help message override in preference settings

* fix: override compound in space panel buttons

* fix: layout of forgot password

* fix: height of encryption tab

* fix: widget avatar border radius
2025-12-19 10:08:23 +00:00
renovate[bot] 2a669d492d Update dependency storybook to v10.1.10 [SECURITY] (#31578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-19 09:40:12 +00:00
Andy Balaam ff3f069122 Provide a labs flag for encrypted state events (MSC3414) (#31513)
Signed-off-by: Skye Elliot <actuallyori@gmail.com>
Co-authored-by: Skye Elliot <actuallyori@gmail.com>
2025-12-18 14:45:52 +00:00
Florian Duros 6f0369e623 Fix shared component screenshot update (#31568)
* build: fix shared component screenshot update

The yarn command `test:storybook:update` was running twice
`playwright-sceenshots`. However this script is using ryuk to delete
remaining containers/etc and ryuk does the cleanup after 50sec of idle.
So on the script second call, ryuk container was still running and the
script failed.

This PR introduces a shell script to install the dependencies and to run
the tests in the same playrwright-screenshots call.

* Update packages/shared-components/scripts/storybook-screenshot-update.sh

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

* Update packages/shared-components/scripts/storybook-screenshot-update.sh

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

* doc: fix duplicated documentation after github commit

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-12-18 10:44:17 +00:00
Florian Duros 7a69ab8be4 Fix act warning in member list test (#31570)
* test: fix act warning in member list

Wrapping rerender in act

* refactor: remove extra inline function
2025-12-17 17:08:00 +00:00
Skye Elliot 4da149e56f Update prop type & documentation for HistoryVisibleBanner and VM. (#31545)
* docs: Update documentation for HistoryVisibleBanner and VM.

* docs: Improve documentation for `HistoryVisibleBanner`, second pass.

* docs: Move documentation to prop types over FC.

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

* fix: Simplify type for `HistoryVisibleBannerViewModel` `threadId`.

* docs: Apply suggestions from code review

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-12-17 16:04:53 +00:00
Michael Telatynski e696f92bd3 Switch to Compound icons in more places (#31560)
* Switch to Compound icons in ServerPicker

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

* Switch to Compound ask-to-join icon

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

* Switch to Compound invite icon

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

* Switch to Compound pin icon

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

* Switch to Compound Spinner

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

* Update snapshots

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

* Fix ServerPicker icon rendering

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

* Update screenshots

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

* Update screenshot

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

* Replace search-inset.svg with Compound Message icon

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-17 11:17:11 +00:00
ElementRobot 48c360f688 [create-pull-request] automated change (#31554)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-17 10:57:57 +00:00
RiotRobot 3ee50c59f8 Reset matrix-js-sdk back to develop branch 2025-12-16 14:54:45 +00:00
RiotRobot ba2386ae41 Merge branch 'master' into develop 2025-12-16 14:53:41 +00:00
Michael Telatynski 7e3a6d9c42 Switch to rendering svg icons rather than masking them (#31550)
* Switch to rendering svg icons rather than masking them in SpacePanel

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

* Fix badly rendered icon in JoinRuleDropdown

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

* Fix badly rendered icon in RoomPreviewCard

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

* Fix badly rendered icon in Space menus

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

* Fix badly rendered icon in ThreadPanel

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

* Update snapshots

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

* Update screenshot

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

* Remove unused icon underfill

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

* Update screenshot

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

* Add test

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

* Add missing snapshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-16 13:56:36 +00:00
Michael Telatynski 773662e018 Amend e2e normal icon from lock-solid to info (#31555)
* Amend e2e normal icon from lock-solid to info

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

* Update screenshot

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-16 12:28:01 +00:00
Michael Telatynski 040c348700 Make AccessibleButton contrast control compatible (#31308)
* Make AccessibleButton contrast control compatible

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>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-16 09:51:15 +00:00
Michael Telatynski 9d9782f62b Switch to compound-design-tokens for platform icons (#31543)
* Switch to compound-design-tokens for platform icons

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

* Revert app-store badge usage

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

* Update snapshots

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-15 16:37:24 +00:00
Michael Telatynski 0cfaeaa3a7 Fix CSS specificity causing icon issues in e2e verification (#31542)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-15 15:46:03 +00:00
Michael Telatynski 4a3cf3e69d Switch to rendering svg icons rather than masking them (#31531)
* Switch to rendering svg icons rather than masking them in left panel

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

* Remove unused stylesheet

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

* Switch to rendering svg icons rather than masking them for ExternalLink

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

* Switch to rendering svg icons rather than masking them for TabbedView

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

* Switch to rendering svg icons rather than masking them for JoinRuleDropdown

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

* Switch to rendering svg icons rather than masking them in ManageRestrictedJoinRuleDialog

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

* Switch to rendering svg icons rather than masking them in LeaveSpaceDialog

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

* Switch to rendering svg icons rather than masking them in ReplyPreview

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

* Switch to rendering svg icons rather than masking them in SearchBox

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

* Switch to rendering svg icons rather than masking them in RoomStatusBar

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

* Fix advanced.svg

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

* Update snapshots

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

* Update screenshots

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

* Iterate

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

* Fix bad merge conflict resolution

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

* Switch to rendering svg icons rather than masking them in Toasts

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

* Switch to rendering svg icons rather than masking them in RoomInfoLine

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

* Switch to rendering svg icons rather than masking them in UploadBar

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

* Remove unused class

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

* Switch to rendering svg icons rather than masking them in ConfirmSpaceUserActionDialog

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

* Switch to rendering svg icons rather than masking them in FeedbackDialog

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

* Switch to rendering svg icons rather than masking them in KeyBackupFailedDialog

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

* Switch to rendering svg icons rather than masking them in CopyableText

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

* Switch to rendering svg icons rather than masking them in EventTile

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

* Switch to rendering svg icons rather than masking them in InviteReason

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

* Delint

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

* Update tests

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

* Add test

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

* Add test

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-15 12:00:35 +00:00
Skye Elliot c7134e8532 Prevent history visible banner from displaying in threads. (#31535)
* fix: Prevent history visible banner from displaying in threads.

* tests: Verify banner is not visible in threads.
2025-12-15 11:43:00 +00:00
Michael Telatynski 1d3421417f Switch to rendering svg icons rather than css masking (#31517)
* Switch to rendering svg icons rather than masking them in left panel

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

* Remove unused stylesheet

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

* Switch to rendering svg icons rather than masking them for ExternalLink

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

* Switch to rendering svg icons rather than masking them for TabbedView

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

* Switch to rendering svg icons rather than masking them for JoinRuleDropdown

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

* Switch to rendering svg icons rather than masking them in ManageRestrictedJoinRuleDialog

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

* Switch to rendering svg icons rather than masking them in LeaveSpaceDialog

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

* Switch to rendering svg icons rather than masking them in ReplyPreview

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

* Switch to rendering svg icons rather than masking them in SearchBox

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

* Switch to rendering svg icons rather than masking them in RoomStatusBar

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

* Fix advanced.svg

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

* Update snapshots

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

* Update screenshots

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

* Iterate

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

* Fix bad merge conflict resolution

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-15 09:52:50 +00:00
ElementRobot ef63661cb0 [create-pull-request] automated change (#31541)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-15 06:32:58 +00:00
ElementRobot e29da89826 [create-pull-request] automated change (#31537)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-13 06:22:12 +00:00
David Baker d2727754e3 Tidy up token refresh code (#31519)
* Tidy up token refresh code

This was a bit odd where the function to create a refresher sometimes
created a refresher and sometimes just returned null, including if the
init failed, in which case you would just end up with no token refresher.

Pairs with https://github.com/matrix-org/matrix-js-sdk/pull/5106 but
doesn't depend on either way.

* Remove deviceId property in favour of superclass one

* Fix tests

* Fix argument order in super call

redirect URI & device ID were swapped. It appears that gthe OIDS client
only actually sends the redirect URI when refreshing a token, so we will
have been sending a device ID for that when refreshing. I think this is safe
to fix since this is only when refreshing so it already would not have
matched what was passed at login time.

* Pass client ID into createOidcTokenRefresher
2025-12-12 18:23:50 +00:00
Robin 179cf0f8e1 Make the feedback icon be the right color in dark theme (#31527)
Our feedback.svg is not tintable. Rather than mess with it I think it makes sense to use the equivalent Compound icon.
2025-12-12 09:40:38 +00:00
ElementRobot de74816dd8 [create-pull-request] automated change (#31528)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-12 06:31:41 +00:00
Michael Telatynski 7b024f956d Fix e2e icons in CompleteSecurity & SetupEncryptionBody (#31521)
* Fix e2e icons in CompleteSecurity & SetupEncryptionBody

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

* Tests

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

* Prevent screenshot clash between tests

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-11 16:37:49 +00:00
Michael Telatynski 362e34513d Stabilise flaky tests relying on bots (#31520)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-11 16:16:05 +00:00
Florian Duros 5b900ab6e2 Move room list search to shared components (#31502)
* refactor: move room list search to shared components

* refactor: add view model

* refactor: use view and vm in room list search component

* refactor: use room list id instead of class for landmark navigation

* refactor: remove old room list search css

* test: add screenshots test for room list search view

* test: fix e2e test using class as selector...
2025-12-11 15:43:20 +00:00
Florian Duros 23fbe9cef6 UseCreateAutoDisposedViewModel for audio player (#31503)
* refactor: useCreateAutoDisposedViewModel for audio player

* Update src/viewmodels/audio/AudioPlayerViewModel.ts

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

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-11 15:41:27 +00:00
renovate[bot] cd71c109d3 Update npm non-major dependencies (#31516)
* Update npm non-major dependencies

* Run 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-12-11 15:37:25 +00:00
Timo a28eabf73b Auto approve matrix rtc member event (sticky events) (#31452) 2025-12-11 12:20:42 +00:00
renovate[bot] dbe8ad0529 Update dependency @vector-im/compound-design-tokens to v6.4.2 (#31478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 11:16:53 +00:00
David Langley b446506aee Size Autocomplete relative to the RoomView height rather than the viewport height (#31425)
* Size Autocomplete relative to the RoomView height rather than the viewport height

* Add screenshot for the autocomplete in a regression changes the height

* Add cjk fonts to support rendering text emoticons displayed in slash command picker

* Maybe when actually running the tests?

* Try after system dependencies and clear font cache

* Add cjk fonts to support rendering text emoticons displayed in slash command picker

Try after system dependencies and clear font cache

Maybe when actually running the tests?

Revert "Add cjk fonts to support rendering text emoticons displayed in slash command picker"

This reverts commit 46fa014308b6010626174f8cd0d3a978488963ee.

* Render emoji autocoplete instead

* Remove font install that didn't work
2025-12-11 10:55:20 +00:00
renovate[bot] 9254c4247e Update dependency @casualbot/jest-sonar-reporter to v2.5.0 (#31482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 10:00:22 +00:00
Andy Balaam 3d80e607ce Remove an extra paragraph in advanced room settings (#31500)
This was introduced (presumably accidentally) in
[#30169](https://github.com/element-hq/element-web/pull/30169/files#diff-89268874351e08a327e47b0a7e1d4e916e1ad8dc4be8b4a3f1ef67f3f83a5bc9R459)
2025-12-11 09:55:28 +00:00
renovate[bot] 0a1ac23681 Update react monorepo (#31479)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-11 09:53:12 +00:00
ElementRobot 976d1bc9ec [create-pull-request] automated change (#31509)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-11 09:47:41 +00:00
Hubert Chathi 4bd8eeb17a Don't show the key storage out of sync toast when backup disabled (#31506) 2025-12-10 16:03:47 +00:00
Skye Elliot cff9119324 Implement UI for history visibility acknowledgement. (#31156)
* feat: Implement UI for history visibility acknowledgement.

Shows a banner above the message composer whenever a user opens a room
with non-join history visibility, which they can dismiss.

- Whenever a user opens an encrypted room with non-join history
  visibility, show them a banner, unless we have already marked it as
  dismissed.
- Whenever a user opens an encrypted room with joined history
  visibility, we unmark it as dismissed.

Issue: https://github.com/element-hq/element-meta/issues/2875

* tests: Add test suite for `RoomStatusBarHistoryVisible`.

* docs: Document `RoomStatusBarHistoryVisible` and props interface.

* feat: Use newer `@vector-im/compound` components.

* test: Update snapshots for `RoomStatusBarHistoryVisible` tests.

* chore: Update playwright screenshots.

* feat: Move `RoomStatusBarHistoryVisible` to `shared-components`.

* fix: Address review comments on `RoomStatusBarHistoryVisible`.

* fix: Address review comments on `RoomStatusBar` and tests.

* chore: Move `RoomStatusBarHistoryVisible` to `room/RoomStatusBarHistoryVisible`

* chore: Fix linting issues.

* feat: Gate behind history visibility labs flag.

* feat: Add link to history sharing docs.

* fix: Resolve build issue with shared-components.

* tests: Enable history sharing lab for unit tests.

* tests: Set labs flag in SettingsStore mock.

* fix: Remove non-existent arg - documentation should be updated!

* chore: Remove old CSS rule filter.

* fix: Use package name for import over relative path.

* fix: Mark styles as important due to improper CSS load order.

* docs: Add doc comments to `!important` directives.

This change should restore my status as a good person.

* docs: Correct license header.

* tests: Update `RoomStatusBarHistoryVisible` snapshot.

* tests: Update shared history invite screenshot.

* tests: Revert spurious screenshot changes.

* feat: Update to use `Banner` component.

* chore: Remove broken import.

* chore: Remove unused translation string.

* tests: Add `getHistoryVisibility` to `currentState` of stub room.

* tests: Update screenshot.

* chore: Remove old snapshots.

* tests: Update playwright screenshot.

* feat: Separate `HistoryVisibleBanner` hooks into MVVM architecture.

* chore: Remove unused imports.

* feat: Use info link over action button for `HistoryVisibleBanner`

* tests: Update snapshot for `HistoryVisibleBanner`.

* chore: Remove unused imports.

* feat: Switch to MVVM architecture per style guide.

* tests: Update snapshot for `HistoryVisibleBanner`.

* tests: Update shared components snapshots.

* tests: Add unit tests for `HistoryVisibleBannerView` stories.

* fix: Linting errors from SonarCloud.

* feat: Finalise conversion to MVVM.

* fix: Silent `this` binding issue.

* tests: Update playwright snapshot.

* feat: Introduce wrapper component for `HistoryVisibleBanner`.

* tests: Update playwright screenshots for `HistoryVisibleBanner`.

* docs: Add doc comments to fields in `HistoryVisibleBannerViewModel`.

* tests: Update playwright snapshot.
2025-12-10 10:37:04 +00:00
R Midhun Suresh a13e9c1285 Export disposing hook from package (#31498)
* Export disposing hook from package

* Increment package version

* Fix lint: Add back new-line
2025-12-10 09:59:54 +00:00
ElementRobot 9272f0180c [create-pull-request] automated change (#31497)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-10 06:32:36 +00:00
ElementRobot 9d233c49f4 [create-pull-request] automated change (#31496)
Co-authored-by: t3chguy <2403652+t3chguy@users.noreply.github.com>
2025-12-10 06:23:42 +00:00
renovate[bot] 98af06b949 Update storybook (#31487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 22:00:33 +00:00
renovate[bot] e066f3836d Update dependency testcontainers to v11.9.0 (#31486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 21:53:42 +00:00
renovate[bot] ea5117944c Update dependency @sentry/browser to v10.29.0 (#31484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 21:36:38 +00:00
renovate[bot] 3f1831577e Update nginxinc/nginx-unprivileged:alpine-slim Docker digest to a6bec37 (#31473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-09 17:10:20 +00:00
renovate[bot] 4fcbaaf6e1 Update dependency eslint-plugin-storybook to v10.1.4 (#31485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:49:00 +00:00
renovate[bot] bdeae0711a Update dependency @element-hq/element-web-playwright-common to v2.1.0 (#31483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:46:13 +00:00
renovate[bot] 1b25e62698 Update actions/setup-node digest to 395ad32 (#31470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:42:16 +00:00
renovate[bot] 9adcea3079 Update browserslist (#31476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:37:45 +00:00
renovate[bot] 014a9edf0f Update dependency is-ip to v5. (#31467)
* Update dependency is-ip to v5

* Fix import

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

* Make jest happier

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-12-09 16:36:22 +00:00
renovate[bot] 67b0311852 Update actions/stale digest to 9971854 (#31471)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:34:10 +00:00
renovate[bot] df084ebe11 Update dependency chokidar to v5 (#31488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:33:28 +00:00
renovate[bot] 6ed3dc32c5 Update typescript-eslint monorepo to v8.48.1 (#31480)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:26:06 +00:00
renovate[bot] dbdf2f6353 Update docker/metadata-action digest to c299e40 (#31472)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:25:57 +00:00
renovate[bot] 7b8082a818 Update peter-evans/create-pull-request digest to 22a9089 (#31475)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:25:46 +00:00
renovate[bot] a155948231 Update dependency @element-hq/element-call-embedded to v0.16.3 (#31477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:23:11 +00:00
renovate[bot] b8f4e87185 Update Node.js to 5583cbe (#31474)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:21:16 +00:00
th0mcat 3e928cf6a6 Change header-panel-bg-hover to use var(--cpd-color-bg-action-secondary-hovered) for better custom theming (#31457)
* Update header-panel-bg-hover in dark theme

* Update header-panel-bg-hover in light custom theme

* Update header-panel-bg-hover in light theme

* Fix syntax error

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-09 16:16:59 +00:00
renovate[bot] a2ca6f858f Update actions/checkout digest to 8e8c483 (#31469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-09 16:11:04 +00:00
Michael Telatynski efe59ff35f Improve icon rendering in iconized context menu (#31458)
* Fix composer button visibility in contrast colour mode

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

* Iterate

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

* Update snapshot

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>

* Update test

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

* Simplify

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

* Update snapshots

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

* Update screenshots

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

* Update screenshots

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

* Update screenshot

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

* Improve icon rendering in iconized context menu

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

* Iterate

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

* Add test

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

* Delint

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-12-09 15:10:42 +00:00
936 changed files with 32693 additions and 11938 deletions
+4 -1
View File
@@ -25,7 +25,10 @@
# Ignore translations as those will be updated by GHA for Localazy download
/src/i18n/strings
/src/i18n/strings/en_EN.json @element-hq/element-web-reviewers
/packages/shared-components/src/i18n/strings
/src/i18n/strings/en_EN.json @element-hq/element-web-reviewers
/packages/shared-components/src/i18n/strings/en_EN.json @element-hq/element-web-reviewers
# Ignore the synapse & mas plugins as this is updated by GHA for docker image updating
/playwright/testcontainers/synapse.ts
/playwright/testcontainers/mas.ts
+1 -1
View File
@@ -2,7 +2,7 @@
## Checklist
- [ ] I have read through [review guidelines](../docs/review.md) and [CONTRIBUTING.md](../CONTRIBUTING.md).
- [ ] I have read through [review guidelines](https://github.com/element-hq/element-web/blob/develop/docs/review.md) and [CONTRIBUTING.md](https://github.com/element-hq/element-web/blob/develop/CONTRIBUTING.md).
- [ ] Tests written for new code (and old code if feasible).
- [ ] New or updated `public`/`exported` symbols have accurate [TSDoc](https://tsdoc.org/) documentation.
- [ ] Linter and other CI checks pass.
+3 -3
View File
@@ -42,9 +42,9 @@ jobs:
run:
shell: bash
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
# Disable cache on Windows as it is slower than not caching
# https://github.com/actions/setup-node/issues/975
@@ -66,7 +66,7 @@ jobs:
run: VERSION=$(scripts/get-version-from-git.sh) yarn build
- name: Upload Artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: webapp-${{ matrix.image }}
path: webapp
+2 -2
View File
@@ -14,7 +14,7 @@ jobs:
R2_URL: ${{ vars.CF_R2_S3_API }}
VERSION: ${{ github.ref_name }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Download package
run: |
@@ -62,7 +62,7 @@ jobs:
dpkg-gencontrol -v"$VERSION" -ldebian/tmp/DEBIAN/changelog
dpkg-deb -Zxz --root-owner-group --build debian/tmp element-web.deb
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: element-web.deb
path: element-web.deb
+4 -4
View File
@@ -26,9 +26,9 @@ jobs:
R2_URL: ${{ vars.CF_R2_S3_API }}
R2_PUBLIC_URL: "https://element-web-develop.element.io"
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -53,7 +53,7 @@ jobs:
- run: mv dist/element-*.tar.gz dist/develop.tar.gz
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: webapp
path: dist/develop.tar.gz
@@ -104,7 +104,7 @@ jobs:
running-workflow-name: "Build & Deploy develop.element.io"
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label|Release|prepare|GitHub Pages).)*$
check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label|Release|prepare|GitHub Pages|Upload).)*$
# We keep the latest develop.tar.gz on R2 instead of relying on the github artifact uploaded earlier
# as the expires after 24h and requires auth to download.
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
env:
SITE: ${{ inputs.site || 'staging.element.io' }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Load GPG key
run: |
+55 -31
View File
@@ -20,7 +20,7 @@ jobs:
env:
TEST_TAG: vectorim/element-web:test
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
fetch-depth: 0 # needed for docker-package to be able to calculate the version
@@ -32,25 +32,10 @@ jobs:
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
with:
install: true
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and load
id: test-build
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
@@ -96,18 +81,70 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
if: github.event_name != 'pull_request'
with:
images: |
vectorim/element-web
ghcr.io/element-hq/element-web
oci-push.vpn.infra.element.io/element-web
tags: |
type=ref,event=branch
type=ref,event=tag
flavor: |
latest=${{ contains(github.ref_name, '-rc.') && 'false' || 'auto' }}
- name: Login to Docker Hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Connect to Tailscale
uses: tailscale/github-action@53acf823325fe9ca47f4cdaa951f90b4b0de5bb9 # v4
if: github.event_name != 'pull_request'
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
audience: ${{ secrets.TS_AUDIENCE }}
tags: tag:github-actions
- name: Compute vault jwt role name
id: vault-jwt-role
if: github.event_name != 'pull_request'
run: |
echo "role_name=github_service_management_$( echo "${{ github.repository }}" | sed -r 's|[/-]|_|g')" | tee -a "$GITHUB_OUTPUT"
- name: Get team registry token
id: import-secrets
uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3
if: github.event_name != 'pull_request'
with:
url: https://vault.infra.ci.i.element.dev
role: ${{ steps.vault-jwt-role.outputs.role_name }}
path: service-management/github-actions
jwtGithubAudience: https://vault.infra.ci.i.element.dev
method: jwt
secrets: |
services/web-repositories/secret/data/oci.element.io username | OCI_USERNAME ;
services/web-repositories/secret/data/oci.element.io password | OCI_PASSWORD ;
- name: Login to oci.element.io Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
if: github.event_name != 'pull_request'
with:
registry: oci-push.vpn.infra.element.io
username: ${{ steps.import-secrets.outputs.OCI_USERNAME }}
password: ${{ steps.import-secrets.outputs.OCI_PASSWORD }}
- name: Build and push
id: build-and-push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
@@ -139,16 +176,3 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: vectorim/element-web
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4
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'] }}"
}
+4 -4
View File
@@ -17,23 +17,23 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Fetch element-desktop
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
repository: element-hq/element-desktop
path: element-desktop
- name: Fetch element-web
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
path: element-web
- name: Fetch matrix-js-sdk
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
repository: matrix-org/matrix-js-sdk
path: matrix-js-sdk
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
cache-dependency-path: element-web/yarn.lock
@@ -25,7 +25,7 @@ jobs:
actions: read
steps:
- name: Download HTML report
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
+12 -12
View File
@@ -50,11 +50,11 @@ jobs:
runners-matrix: ${{ steps.runner-vars.outputs.matrix }}
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
repository: element-hq/element-web
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -74,7 +74,7 @@ jobs:
run: VERSION=$(scripts/get-version-from-git.sh) yarn build
- name: Upload Artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: webapp
path: webapp
@@ -122,18 +122,18 @@ jobs:
- runAllTests: false
project: Pinecone
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
persist-credentials: false
repository: element-hq/element-web
- name: 📥 Download artifact
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
name: webapp
path: webapp
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
cache-dependency-path: yarn.lock
@@ -147,7 +147,7 @@ jobs:
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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
@@ -172,7 +172,7 @@ jobs:
- name: Upload blob report to GitHub Actions Artifacts
if: always()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: all-blob-reports-${{ matrix.project }}-${{ matrix.runner }}
path: blob-report
@@ -194,13 +194,13 @@ jobs:
if: always()
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
if: inputs.skip != true
with:
persist-credentials: false
repository: element-hq/element-web
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
if: inputs.skip != true
with:
cache: "yarn"
@@ -212,7 +212,7 @@ jobs:
- name: Download blob reports from GitHub Actions Artifacts
if: inputs.skip != true
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
pattern: all-blob-reports-*
path: all-blob-reports
@@ -228,7 +228,7 @@ jobs:
# Upload the HTML report even if one of our reporters fails, this can happen when stale screenshots are detected
- name: Upload HTML report
if: always() && inputs.skip != true
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: html-report
path: playwright-report
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
Exercise caution. Use test accounts.
- name: 📥 Download artifact
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
@@ -10,7 +10,7 @@ jobs:
permissions:
pull-requests: write
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: Update synapse image
run: |
@@ -32,7 +32,7 @@ jobs:
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
branch: actions/playwright-image-updates
+3 -3
View File
@@ -41,7 +41,7 @@ jobs:
REPOS: matrix-js-sdk element-web element-desktop
steps:
- name: Checkout Element Desktop
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
if: inputs.element-desktop
with:
repository: element-hq/element-desktop
@@ -51,7 +51,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
- name: Checkout Element Web
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
if: inputs.element-web
with:
repository: element-hq/element-web
@@ -61,7 +61,7 @@ jobs:
fetch-tags: true
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
- name: Checkout Matrix JS SDK
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
if: inputs.matrix-js-sdk
with:
repository: matrix-org/matrix-js-sdk
@@ -13,10 +13,10 @@ jobs:
steps:
- name: 🧮 Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- name: 🔧 Set up node environment
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version-file: ".node-version"
@@ -27,7 +27,7 @@ jobs:
run: "sudo apt-get install -y tree"
- name: Download Diffs
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
@@ -21,12 +21,12 @@ jobs:
issues: read
pull-requests: read
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
persist-credentials: false
repository: element-hq/element-web
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -44,7 +44,7 @@ jobs:
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@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5
id: playwright-cache
with:
path: ~/.cache/ms-playwright
@@ -60,7 +60,7 @@ jobs:
- name: Upload received images & diffs
if: always()
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: received-images
path: packages/shared-components/playwright/shared-component-received
+22 -13
View File
@@ -22,9 +22,9 @@ jobs:
name: "Typescript Syntax Check"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -41,8 +41,8 @@ jobs:
- name: Typecheck Shared Components
run: "yarn --cwd packages/shared-components run lint:types"
i18n_lint:
name: "i18n Check"
i18n_lint_ew:
name: "i18n Check (Element Web)"
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
permissions:
pull-requests: read
@@ -59,11 +59,20 @@ jobs:
devtools|settings|elementCallUrl
labs|sliding_sync_description
i18n_lint_shared_components:
name: "i18n Check (Shared Components)"
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
permissions:
pull-requests: read
with:
path: "packages/shared-components"
hardcoded-words: "Element"
rethemendex_lint:
name: "Rethemendex Check"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- run: ./res/css/rethemendex.sh
@@ -73,9 +82,9 @@ jobs:
name: "ESLint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -97,9 +106,9 @@ jobs:
name: "Style Lint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -115,9 +124,9 @@ jobs:
name: "Workflow Lint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -133,9 +142,9 @@ jobs:
name: "Analyse Dead Code"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
+8 -8
View File
@@ -39,12 +39,12 @@ jobs:
runner: [1, 2]
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/element-web' || github.repository }}
- name: Yarn cache
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: "lts/*"
cache: "yarn"
@@ -55,7 +55,7 @@ jobs:
JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }}
- name: Jest Cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5
with:
path: /tmp/jest_cache
key: ${{ hashFiles('**/yarn.lock') }}
@@ -84,7 +84,7 @@ jobs:
- name: Upload Artifact
if: env.ENABLE_COVERAGE == 'true'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: coverage-${{ matrix.runner }}
path: |
@@ -118,12 +118,12 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
with:
repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/element-web' || github.repository }}
- name: Yarn cache
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
node-version: "lts/*"
cache: "yarn"
@@ -136,7 +136,7 @@ jobs:
run: "yarn install"
- name: Jest Cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5
with:
path: /tmp/jest_cache
key: ${{ hashFiles('**/yarn.lock') }}
@@ -159,7 +159,7 @@ jobs:
- name: Upload Artifact
if: env.ENABLE_COVERAGE == 'true'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: coverage-sharedcomponents
path: |
@@ -9,7 +9,7 @@ jobs:
name: Move PRs asking for design review to the design board
runs-on: ubuntu-24.04
steps:
- uses: octokit/graphql-action@abaeca7ba4f0325d63b8de7ef943c2418d161b93 # v3.0.0
- uses: octokit/graphql-action@ddde8ebb2493e79f390e6449c725c21663a67505 # v3.0.2
id: find_team_members
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
@@ -52,7 +52,7 @@ jobs:
fi
env:
TEAM: "design"
- uses: octokit/graphql-action@abaeca7ba4f0325d63b8de7ef943c2418d161b93 # v3.0.0
- uses: octokit/graphql-action@ddde8ebb2493e79f390e6449c725c21663a67505 # v3.0.2
id: add_to_project
if: steps.any_matching_reviewers.outputs.match == 'true'
with:
@@ -76,7 +76,7 @@ jobs:
name: Move PRs asking for design review to the design board
runs-on: ubuntu-24.04
steps:
- uses: octokit/graphql-action@abaeca7ba4f0325d63b8de7ef943c2418d161b93 # v3.0.0
- uses: octokit/graphql-action@ddde8ebb2493e79f390e6449c725c21663a67505 # v3.0.2
id: find_team_members
with:
headers: '{"GraphQL-Features": "projects_next_graphql"}'
@@ -119,7 +119,7 @@ jobs:
fi
env:
TEAM: "product"
- uses: octokit/graphql-action@abaeca7ba4f0325d63b8de7ef943c2418d161b93 # v3.0.0
- uses: octokit/graphql-action@ddde8ebb2493e79f390e6449c725c21663a67505 # v3.0.2
id: add_to_project
if: steps.any_matching_reviewers.outputs.match == 'true'
with:
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10
with:
operations-per-run: 100
+3 -3
View File
@@ -9,9 +9,9 @@ jobs:
update:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
with:
cache: "yarn"
node-version: "lts/*"
@@ -23,7 +23,7 @@ jobs:
run: "yarn update:jitsi"
- name: Create Pull Request
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
branch: actions/jitsi-update
+81
View File
@@ -1,3 +1,84 @@
Changes in [1.12.9](https://github.com/element-hq/element-web/releases/tag/v1.12.9) (2026-01-27)
================================================================================================
## ✨ Features
* Allow local log downloads when a rageshake URL is not configured. ([#31716](https://github.com/element-hq/element-web/pull/31716)). Contributed by @Half-Shot.
* Improve icon rendering accessibility ([#31776](https://github.com/element-hq/element-web/pull/31776)). Contributed by @t3chguy.
* Show "Bob shared this message" on messages shared via MSC4268 ([#31684](https://github.com/element-hq/element-web/pull/31684)). Contributed by @richvdh.
* Update the way we render icons for accessibility ([#31731](https://github.com/element-hq/element-web/pull/31731)). Contributed by @t3chguy.
* Switch from css masks to rendering svg ([#31681](https://github.com/element-hq/element-web/pull/31681)). Contributed by @t3chguy.
* Support for stable MSC4191 account management action parameter ([#31701](https://github.com/element-hq/element-web/pull/31701)). Contributed by @hughns.
* Support for stable m.oauth UIA stage from MSC4312 ([#31704](https://github.com/element-hq/element-web/pull/31704)). Contributed by @hughns.
* Switch to Compound icons to replace old icons ([#31667](https://github.com/element-hq/element-web/pull/31667)). Contributed by @t3chguy.
* Switch from svg masks to svg rendering in more places ([#31652](https://github.com/element-hq/element-web/pull/31652)). Contributed by @t3chguy.
* Switch from svg masks to svg rendering in more places ([#31650](https://github.com/element-hq/element-web/pull/31650)). Contributed by @t3chguy.
* Update notification icons using Compound icons ([#31671](https://github.com/element-hq/element-web/pull/31671)). Contributed by @t3chguy.
* Memoise ListView context ([#31668](https://github.com/element-hq/element-web/pull/31668)). Contributed by @t3chguy.
* Switch emoji picker to use emoji for header icons ([#31645](https://github.com/element-hq/element-web/pull/31645)). Contributed by @t3chguy.
* Replace icons with Compound alternatives ([#31642](https://github.com/element-hq/element-web/pull/31642)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Fix avatar decorations in thread activity centre not being atop avatar ([#31789](https://github.com/element-hq/element-web/pull/31789)). Contributed by @t3chguy.
* Fix room settings roles tab getting confused if power level change fails ([#31768](https://github.com/element-hq/element-web/pull/31768)). Contributed by @t3chguy.
* Custom themes now import highlights in css ([#31758](https://github.com/element-hq/element-web/pull/31758)). Contributed by @Philldomd.
* Use correct translation for url preview settings ([#31740](https://github.com/element-hq/element-web/pull/31740)). Contributed by @florianduros.
* Fix error shown if accepting a 3pid invite ([#31735](https://github.com/element-hq/element-web/pull/31735)). Contributed by @dbkr.
* Ensure correct focus configuration for Element Call before allowing users to call. ([#31490](https://github.com/element-hq/element-web/pull/31490)). Contributed by @Half-Shot.
* Fix emoji font in emoji picker header buttons ([#31679](https://github.com/element-hq/element-web/pull/31679)). Contributed by @t3chguy.
* fix flaky test by waiting for chat panel before counting messages ([#31633](https://github.com/element-hq/element-web/pull/31633)). Contributed by @BillCarsonFr.
Changes in [1.12.8](https://github.com/element-hq/element-web/releases/tag/v1.12.8) (2026-01-13)
================================================================================================
## 🦖 Deprecations
* Remove `element_call.participant_limit` config and associated code. ([#31638](https://github.com/element-hq/element-web/pull/31638)). Contributed by @Half-Shot.
## ✨ Features
* Switch to rendering svg icons rather than masking them ([#31557](https://github.com/element-hq/element-web/pull/31557)). Contributed by @t3chguy.
* Update history visibility UX ([#31635](https://github.com/element-hq/element-web/pull/31635)). Contributed by @langleyd.
* Show correct call icon for joining a call. ([#31489](https://github.com/element-hq/element-web/pull/31489)). Contributed by @Half-Shot.
* Update StopGapWidgetDriver to support sticky events ([#31205](https://github.com/element-hq/element-web/pull/31205)). Contributed by @Half-Shot.
* Remove release announcements for new sounds \& room list ([#31544](https://github.com/element-hq/element-web/pull/31544)). Contributed by @t3chguy.
* Add button to restore from backup into /devtools ([#31581](https://github.com/element-hq/element-web/pull/31581)). Contributed by @mxandreas.
* Switch to non-solid compound icons for room settings \& composer ([#31561](https://github.com/element-hq/element-web/pull/31561)). Contributed by @t3chguy.
* Support encrypted state events MSC4362 ([#31513](https://github.com/element-hq/element-web/pull/31513)). Contributed by @andybalaam.
* Update prop type \& documentation for HistoryVisibleBanner and VM. ([#31545](https://github.com/element-hq/element-web/pull/31545)). Contributed by @kaylendog.
* Switch to Compound icons in more places ([#31560](https://github.com/element-hq/element-web/pull/31560)). Contributed by @t3chguy.
* Switch to rendering svg icons rather than masking them ([#31550](https://github.com/element-hq/element-web/pull/31550)). Contributed by @t3chguy.
* Make AccessibleButton contrast control compatible ([#31308](https://github.com/element-hq/element-web/pull/31308)). Contributed by @t3chguy.
* Switch to compound-design-tokens for platform icons ([#31543](https://github.com/element-hq/element-web/pull/31543)). Contributed by @t3chguy.
* Switch to rendering svg icons rather than masking them ([#31531](https://github.com/element-hq/element-web/pull/31531)). Contributed by @t3chguy.
* Switch to rendering svg icons rather than css masking ([#31517](https://github.com/element-hq/element-web/pull/31517)). Contributed by @t3chguy.
* Auto approve matrix rtc member event (`m.rtc.member`) (sticky events) ([#31452](https://github.com/element-hq/element-web/pull/31452)). Contributed by @toger5.
* Size Autocomplete relative to the RoomView height rather than the viewport height ([#31425](https://github.com/element-hq/element-web/pull/31425)). Contributed by @langleyd.
* Implement UI for history visibility acknowledgement. ([#31156](https://github.com/element-hq/element-web/pull/31156)). Contributed by @kaylendog.
* Export disposing hook from package ([#31498](https://github.com/element-hq/element-web/pull/31498)). Contributed by @MidhunSureshR.
* Change `header-panel-bg-hover` to use `var(--cpd-color-bg-action-secondary-hovered)` for better custom theming ([#31457](https://github.com/element-hq/element-web/pull/31457)). Contributed by @th0mcat.
* Improve icon rendering in iconized context menu ([#31458](https://github.com/element-hq/element-web/pull/31458)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* [Backport staging] Fix space settings visibility tab crashing ([#31705](https://github.com/element-hq/element-web/pull/31705)). Contributed by @RiotRobot.
* Fix expand/collapse reply preview not showing in some cases ([#31639](https://github.com/element-hq/element-web/pull/31639)). Contributed by @t3chguy.
* Fix bundled font or custom font not applied after theme switch ([#31591](https://github.com/element-hq/element-web/pull/31591)). Contributed by @florianduros.
* Add ol override CSS for markdown-body ([#31618](https://github.com/element-hq/element-web/pull/31618)). Contributed by @niamu.
* Fix reaction left margin in timeline card ([#31625](https://github.com/element-hq/element-web/pull/31625)). Contributed by @t3chguy.
* Open right panel timeline when jumping to event with maximised widget ([#31626](https://github.com/element-hq/element-web/pull/31626)). Contributed by @t3chguy.
* Fix Compound Link elements not having an underline. ([#31583](https://github.com/element-hq/element-web/pull/31583)). Contributed by @Half-Shot.
* Recalculate mentions metadata of forwarded messages based on message body ([#31193](https://github.com/element-hq/element-web/pull/31193)). Contributed by @twassman.
* Fix Room Preview Card Layout ([#31611](https://github.com/element-hq/element-web/pull/31611)). Contributed by @germain-gg.
* Fix: WidgetMessaging not properly closed causing side effects and bugs ([#31598](https://github.com/element-hq/element-web/pull/31598)). Contributed by @BillCarsonFr.
* Handle cross-signing keys missing locally and/or from secret storage ([#31367](https://github.com/element-hq/element-web/pull/31367)). Contributed by @uhoreg.
* fix: Allow wrapping in `Banner` component. ([#31532](https://github.com/element-hq/element-web/pull/31532)). Contributed by @kaylendog.
* Update algorithm for history visible banner. ([#31577](https://github.com/element-hq/element-web/pull/31577)). Contributed by @kaylendog.
* Fix styling issue when using EW modules ([#31533](https://github.com/element-hq/element-web/pull/31533)). Contributed by @florianduros.
* Prevent history visible banner from displaying in threads. ([#31535](https://github.com/element-hq/element-web/pull/31535)). Contributed by @kaylendog.
* Make the feedback icon be the right color in dark theme ([#31527](https://github.com/element-hq/element-web/pull/31527)). Contributed by @robintown.
Changes in [1.12.7](https://github.com/element-hq/element-web/releases/tag/v1.12.7) (2025-12-16)
================================================================================================
## ✨ Features
+10
View File
@@ -184,6 +184,16 @@ Please ensure your changes match the cosmetic style of the existing project,
and **_never_** mix cosmetic and functional changes in the same commit, as it
makes it horribly hard to review otherwise.
## Shared Components
When creating new UI components, consider whether they should be added to the shared components package (`packages/shared-components`) rather than directly in the main `src/` directory. Components should be placed in shared components if they:
- Are reusable across different parts of the application
- Could potentially be used by other Element projects (Element Desktop, Aurora, Element modules...)
- Follow established patterns and don't have tight coupling to specific application logic
For more details, see the [shared components README](./packages/shared-components/README.md).
## Attribution
Everyone who contributes anything to Matrix is welcome to be listed in the
+2 -2
View File
@@ -1,7 +1,7 @@
# syntax=docker.io/docker/dockerfile:1.20-labs@sha256:dbcde2ebc4abc8bb5c3c499b9c9a6876842bf5da243951cd2697f921a7aeb6a9
# Builder
FROM --platform=$BUILDPLATFORM node:24-bullseye@sha256:b36a1eab6bdeb43cf4808370d18b6706452e810e3563b1ce669d2965af3c0464 AS builder
FROM --platform=$BUILDPLATFORM node:24-bullseye@sha256:32bde4fc7635942cafb9681e5479a0ba4b2d53b279e44a67ba9303a71fecd706 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:8e23ab31c214ee1d7f832d63b2ee768d5cbc270a94a2cba0752fed93ad83e345
FROM nginxinc/nginx-unprivileged:alpine-slim@sha256:2c49851f9b34ef35567dc3cbbb56d06d1f56dbb764e75eeb4a599223ee64819c
# Need root user to install packages & manipulate the usr directory
USER root
+11
View File
@@ -194,6 +194,17 @@ To add a new translation, head to the [translating doc](docs/translating.md).
For a developer guide, see the [translating dev doc](docs/translating-dev.md).
# Extending Element Web with Modules
Element Web supports a module system that allows you to extend or modify functionality at runtime. Modules are loaded dynamically and provide a safe, predictable API for customization.
## What are modules?
Modules are extensions that can add or modify Element Web's functionality. They are:
- Built using the [`@element-hq/element-web-module-api`](https://github.com/element-hq/element-modules/tree/main/packages/element-web-module-api)
- Loaded in EW via [config.json](docs/config.md#modules)
# Triaging issues
Issues are triaged by community members and the Web App Team, following the [triage process](https://github.com/element-hq/element-meta/wiki/Triage-process).
+2
View File
@@ -272,6 +272,8 @@ Inheriting all the rules of TypeScript, the following additionally apply:
18. Components should serve a single, or near-single, purpose.
19. Prefer to derive information from component properties rather than establish state.
20. Do not use `React.Component::forceUpdate`.
21. Prefer to use [compound typography components](https://compound.element.io/?path=/docs/compound-web_typography--docs) instead of raw HTML elements for text. This ensures consistent font usage and letter spacing across the app.
22. If you can't use 21, don't forget to apply the correct CSS classes for font and letter spacing.
## Stylesheets (\*.pcss = PostCSS + Plugins)
-1
View File
@@ -43,7 +43,6 @@
},
"element_call": {
"url": "https://call.element.io",
"participant_limit": 8,
"brand": "Element Call"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
+139 -10
View File
@@ -8,7 +8,13 @@ General description of the pattern can be found [here](https://en.wikipedia.org/
If you do MVVM right, your view should be dumb i.e it gets data from the view model and merely displays it.
### Practical guidelines for MVVM in element-web
## Why are we using MVVM?
1. MVVM forces a separation of concern i.e we will no longer have large react components that have a lot of state and rendering code mixed together. This improves code readability and makes it easier to introduce changes.
2. Introduces the possibility of code reuse. You can reuse an old view model with a new view or vice versa.
3. Adding to the point above, in future you could import element-web view models to your project and supply your own views thus creating something similar to the [hydrogen sdk](https://github.com/element-hq/hydrogen-web/blob/master/doc/SDK.md).
## Practical guidelines for MVVM in element-web
A first documentation and implementation of MVVM was done in [MVVM-v1.md](MVVM-v1.md). This v1 version is now deprecated and this document describes the current implementation.
@@ -19,12 +25,12 @@ This is anywhere your data or business logic comes from. If your view model is a
#### View
1. Located in [`shared-components`](https://github.com/element-hq/element-web/tree/develop/packages/shared-components). Develop it in storybook!
2. Views are simple react components (eg: `FooView`).
3. Views use [useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore) internally where the view model is the external store.
2. Views are simple react components (eg: `FooView`) with very little state and logic.
3. Views must call `useViewModel` hook with the corresponding view model passed in as argument. This allows the view to re-render when something has changed in the view model. This entire mechanism is powered by [useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore).
4. Views should define the interface of the view model they expect:
```tsx
// Snapshot is the return type of your view model
// Snapshot is the data that your view-model provides which is rendered by the view.
interface FooViewSnapshot {
value: string;
}
@@ -34,16 +40,16 @@ This is anywhere your data or business logic comes from. If your view model is a
doSomething: () => void;
}
// ViewModel is a type defining the methods needed for `useSyncExternalStore`
// ViewModel is an object (usually a class) that implements both the interfaces listed above.
// https://github.com/element-hq/element-web/blob/develop/packages/shared-components/src/ViewModel.ts
type FooViewModel = ViewModel<FooViewSnapshot> & FooViewActions;
interface FooViewProps {
// Ideally the view only depends on the view model i.e you don't expect any other props here.
vm: FooViewModel;
}
function FooView({ vm }: FooViewProps) {
// useViewModel is a helper function that uses useSyncExternalStore under the hood
const { value } = useViewModel(vm);
return (
<button type="button" onClick={() => vm.doSomething()}>
@@ -82,8 +88,131 @@ This is anywhere your data or business logic comes from. If your view model is a
4. A full example is available [here](https://github.com/element-hq/element-web/blob/develop/src/viewmodels/audio/AudioPlayerViewModel.ts)
### Benefits
### `useViewModel` hook
1. MVVM forces a separation of concern i.e we will no longer have large react components that have a lot of state and rendering code mixed together. This improves code readability and makes it easier to introduce changes.
2. Introduces the possibility of code reuse. You can reuse an old view model with a new view or vice versa.
3. Adding to the point above, in future you could import element-web view models to your project and supply your own views thus creating something similar to the [hydrogen sdk](https://github.com/element-hq/hydrogen-web/blob/master/doc/SDK.md).
Your view must call this hook with the view-model as argument. Think of this as your view subscribing to the view model.<br>
This hook returns the snapshot from your view-model.
## Disposables and helper hooks
Disposables provide a mechanism for tracking and releases resources. This is necessary for avoiding memory leaks.
### Lifecycle of a view model
The lifecycle of a given view model is from its creation (usually through the constructor i.e `new FooViewModel(prop1, prop2)`) to the time the `dispose` method on it is called (eg: `fooViewModel.dispose()`). It is the responsibility of whoever creates the view model to call the dispose method when the view model is no longer necessary.
Disposable work by tracking anything that needs to be disposed of and then sequentially disposing them when `viewModel.dispose()` is called.
### How to use disposables
Consider the following scenarios:
#### Scenario 1: Your view model listens to some event on an event emitter <br>
In the example given below, how do you ensure that the listener on `props.emitter` is removed when the view model is disposed?
```ts
class FooViewModel ... {
constructor(props: Props) {
...
props.emitter.on("my-event", this.doSomething());
}
}
```
You can use disposables to remove the listener when the view-model is disposed:
```ts
class FooViewModel ... {
constructor(props: Props) {
...
this.disposables.trackListener(props.emitter, "my-event", this.doSomething());
}
}
```
#### Scenario 2: Your view model creates sub view models <br>
```ts
class FooViewModel ... {
constructor(props: Props) {
...
this.barViewModel = new BarViewModel(...);
}
}
```
Here, we want to ensure that when `FooViewModel.dispose()` is called, it also disposes any sub view models (in this case `BarViewModel`):
```ts
class FooViewModel ... {
constructor(props: Props) {
...
this.barViewModel = this.disposables.track(new BarViewModel(...));
}
}
```
#### Scenario 3: Tracking and disposing arbitrary resources <br>
A disposable is:
- a function
- an object with `dispose` method (like a view model)
You can therefore use disposables to track any resource that must be eventually relinquished, eg:
```ts
class Call {
....
public endCall();
public stopConnections();
}
class CallViewModel {
...
constructor(props: Props) {
const call = new Call();
// When the view model is disposed, the following call methods will be called
this.disposables.track(() => {
call.endCall();
call.stopConnections();
});
}
}
```
### Disposing view models from non-MVVMed react components
While we eventually want all our UI code to use MVVM, the current reality is that most of the existing code is just normal react components. We follow a bottoms up approach when it comes to moving code over to MVVM i.e we deal with child components before dealing with parent components.
This means that you need to dispose child view models from the non-MVVMed parent component.
#### Class component:
Create the view model in `componentDidMount()` and dispose the view model in `componentWillUnmount()`:
```ts
class FooComponent extends Component {
componentDidMount() {
this.barViewModel = new BarViewModel(...);
}
componentWillUnmount() {
this.barViewModel.dispose();
}
}
```
#### Functional Component:
Use the `useCreateAutoDisposedViewModel` hook:
```ts
export function FooComponent(props) {
const vm = useCreateAutoDisposedViewModel(() => new BarViewModel(...));
return <BarView vm={vm}>;
}
```
This hook will call the `dispose` method on the view model when `FooComponent` is unmounted.
+3 -1
View File
@@ -19,7 +19,7 @@
# Build
- [Customisations](customisations.md)
- [Modules](modules.md)
- [Deprecated Modules](deprecated-modules.md)
- [Native Node modules](native-node-modules.md)
# Contribution
@@ -40,6 +40,8 @@
- [Feature flags](feature-flags.md)
- [OIDC and delegated authentication](oidc.md)
- [Release Process](release.md)
- [MVVM](MVVM.md)
- [Settings](settings.md)
# Deep dive
+17 -3
View File
@@ -391,8 +391,6 @@ The VoIP and Jitsi options are:
6. `element_call`: Optional configuration for native group calls using Element Call, with the following subkeys:
- `use_exclusively`: A boolean specifying whether Element Call should be used exclusively as the only VoIP stack in
the app, removing the ability to start legacy 1:1 calls or Jitsi calls. Defaults to `false`.
- `participant_limit`: The maximum number of users who can join a call; if
this number is exceeded, the user will not be able to join a given call.
- `brand`: Optional name for the app. Defaults to `Element Call`. This is
used throughout the application in various strings/locations.
- `guest_spa_url`: Optional URL for an Element Call single-page app (SPA),
@@ -409,6 +407,7 @@ If you run your own rageshake server to collect bug reports, the following optio
1. `bug_report_endpoint_url`: URL for where to submit rageshake logs to. Rageshakes include feedback submissions and bug reports. When
not present in the config, the app will disable all rageshake functionality. Set to `https://rageshakes.element.io/api/submit` to submit
rageshakes to us, or use your own rageshake server.
You may also set the value to `"local"` if you wish to only store logs locally, in order to download them for debugging.
2. `uisi_autorageshake_app`: If a user has enabled the "automatically send debug logs on decryption errors" flag, this option will be sent
alongside the rageshake so the rageshake server can filter them by app name. By default, this will be `element-auto-uisi`
(in contrast to other rageshakes submitted by the app, which use `element-web`).
@@ -588,6 +587,22 @@ Currently, the following UI feature flags are supported:
- `UIFeature.allowCreatingPublicRooms` - Whether or not public rooms can be created.
- `UIFeature.allowCreatingPublicSpaces` - Whether or not public spaces can be created.
## Modules
`modules`: An optional array of module paths to load at runtime. Each entry is a URL or path to a JavaScript module entry point that will be dynamically imported when Element Web starts.
**Note:** This is separate from the build-time module system configured via `build_config.yaml`. Runtime modules are loaded dynamically from the paths specified in `config.json`, while build-time modules are bundled during compilation.
**Example:**
```json
{
"modules": ["https://example.com/my-module.js", "/path/to/local-module.js"]
}
```
Each module URL is loaded using dynamic import (`import()`). The modules are loaded in order after Element Web initializes but before the application fully starts. Modules must be accessible from the browser and should export a compatible module format that works with the [Module API](https://github.com/element-hq/element-modules/tree/main/packages/element-web-module-api).
## Undocumented / developer options
The following are undocumented or intended for developer use only.
@@ -596,4 +611,3 @@ The following are undocumented or intended for developer use only.
2. `sync_timeline_limit`
3. `dangerously_allow_unsafe_and_insecure_passwords`
4. `latex_maths_delims`: An optional setting to override the default delimiters used for maths parsing. See https://github.com/matrix-org/matrix-react-sdk/pull/5939 for details. Only used when `feature_latex_maths` is enabled.
5. `modules`: An optional list of modules to load. This is used for testing and development purposes only.
@@ -1,4 +1,7 @@
# Module system
# Deprecated Module system
> [!CAUTION]
> DEPRECATED. Use [Element web module api](https://github.com/element-hq/element-modules/tree/main/packages/element-web-module-api) instead.
The module system in Element Web is a way to add or modify functionality of Element Web itself, bundled at compile time
for the app. This means that modules are loaded as part of the `yarn build` process but have an effect on user experience
+22
View File
@@ -112,3 +112,25 @@ Enables knock feature for rooms. This allows users to ask to join a room.
## New room list (`feature_new_room_list`) [In Development]
Enable the new room list that is currently in development.
## Exclude insecure devices when sending/receiving messages (`feature_exclude_insecure_devices`)
Do not send or receive messages to/from devices that are not properly verified. Users with unverified devices will not
receive your messages at all on those devices, and if they send messages, you will not be able to read them, but you
will be aware that a message exists.
## Share encrypted history with new members (`feature_share_history_on_invite`) [In Development]
When inviting users to an encrypted room with shared history (i.e. a room with the "Who can read history?" setting set
to "Members only (since the point in time of selecting this option)"), send the keys for previous messages to the
invitee so they can read them.
Both the inviter and the invitee must set this labs flag, before the invitation is sent.
## Encrypted state events (MSC4362) (`feature_msc4362_encrypted_state_events`)
Encrypt most of the state events in the room, including the room name and topic.
WARNING: this means that users joining a room who do not have access to its history will not be able to see the name or
topic of the room, or any other room state information. It also means the room name and topic are not available before
joining a room.
+403 -134
View File
@@ -2,216 +2,485 @@
## Contents
- How to run the tests
- How the tests work
- How to write great Playwright tests
- Visual testing
- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Running the Tests](#running-the-tests)
- [Element Web E2E Tests](#element-web-e2e-tests)
- [Shared Components Tests](#shared-components-tests)
- [Projects](#projects)
- [How the Tests Work](#how-the-tests-work)
- [Test Structure](#test-structure)
- [Homeserver Setup](#homeserver-setup)
- [Fixtures](#fixtures)
- [Writing Tests](#writing-tests)
- [Getting a Homeserver](#getting-a-homeserver)
- [Logging In](#logging-in)
- [Joining a Room](#joining-a-room)
- [Using matrix-js-sdk](#using-matrix-js-sdk)
- [Best Practices](#best-practices)
- [Visual Testing](#visual-testing)
- [Test Tags](#test-tags)
- [Supported Container Runtimes](#supported-container-runtimes)
## Overview
Element Web contains two sets of Playwright tests:
1. **Element Web E2E Tests** (`playwright/e2e/`) - Full end-to-end tests of the Element Web application with real homeserver instances
2. **Shared Components Tests** (`packages/shared-components/`) - Visual regression tests for the shared component library using Storybook
Both test suites run automatically in CI on every pull request and on every merge to develop & master.
## Prerequisites
Before running Playwright tests, ensure you have the following set up:
### 1. Install Playwright Browsers and System Dependencies
Follow the Playwright installation instructions:
- **Browsers:** <https://playwright.dev/docs/browsers#install-browsers>
- **System dependencies:** <https://playwright.dev/docs/browsers#install-system-dependencies>
```sh
yarn playwright install --with-deps
```
### 2. Container Runtime
See [Supported Container Runtimes](#supported-container-runtimes) for details on supported container runtimes (Docker, Podman, Colima).
### 3. Element Web Server (for E2E tests)
Element Web E2E tests require an instance running on `http://localhost:8080` (configured in `playwright.config.ts`).
You can either:
- **Run manually:** `yarn start` in a separate terminal (not working for screenshot tests running in a docker environment).
- **Auto-start:** Playwright will start the webserver automatically if it's not already running
## Running the Tests
Our Playwright tests run automatically as part of our CI along with our other tests,
on every pull request and on every merge to develop & master.
### Element Web E2E Tests
You may need to follow instructions to set up your development environment for running
Playwright by following <https://playwright.dev/docs/browsers#install-browsers> and
<https://playwright.dev/docs/browsers#install-system-dependencies>.
Our main Playwright tests run against a full Element Web instance with Synapse/Dendrite homeservers.
However the Playwright tests are run, an element-web instance must be running on
http://localhost:8080 (this is configured in `playwright.config.ts`) - this is what will
be tested. When running Playwright tests yourself, the standard `yarn start` from the
element-web project is fine: leave it running it a different terminal as you would
when developing. Alternatively if you followed the development set up from element-web then
Playwright will be capable of running the webserver on its own if it isn't already running.
**Run all E2E tests:**
The tests use [testcontainers](https://node.testcontainers.org/) to launch Homeserver (Synapse or Dendrite)
instances to test against, so you'll also need to one of the
[supported container runtimes](#supporter-container-runtimes)
installed and working in order to run the Playwright tests.
There are a few different ways to run the tests yourself. The simplest is to run:
```shell
```sh
yarn run test:playwright
```
This will run the Playwright tests once, non-interactively.
**Run a specific test file:**
You can also run individual tests this way too, as you'd expect:
```shell
yarn run test:playwright --spec playwright/e2e/register/register.spec.ts
```sh
yarn run test:playwright playwright/e2e/register/register.spec.ts
```
Playwright also has its own UI that you can use to run and debug the tests.
To launch it:
**Run tests interactively with Playwright UI:**
```shell
yarn run test:playwright:open --headed --debug
```sh
yarn run test:playwright:open
```
See more command line options at <https://playwright.dev/docs/test-cli>.
**Run screenshot tests only:**
## Projects
> [!WARNING]
> This command run the playwright tests in a docker environment.
By default, Playwright will run all "Projects", this means tests will run against Chrome, Firefox and "Safari" (Webkit).
We only run tests against Chrome in pull request CI, but all projects in the merge queue.
Some tests are excluded from running on certain browsers due to incompatibilities in the test harness.
```sh
yarn run test:playwright:screenshots
```
For more information about visual testing, see [Visual Testing](playwright#visual-testing).
**Additional command line options:** <https://playwright.dev/docs/test-cli>
### Shared Components Tests
The shared-components package uses Playwright (via Storybook test runner) to validate component rendering across different states and configurations.
**Run Storybook tests:**
```sh
cd packages/shared-components
yarn test:storybook
```
**Run Storybook tests in CI mode:**
```sh
cd packages/shared-components
yarn test:storybook:ci
```
**Update Storybook screenshots:**
```sh
cd packages/shared-components
yarn test:storybook:update
```
This uses the same Docker-based screenshot rendering as Element Web to ensure consistency across platforms.
### Projects
By default, Playwright runs tests against all "Projects": Chrome, Firefox, "Safari" (Webkit), Dendrite and Picone.
- Chrome, Firefox, Safari run against Synapse
- Dendrite and Picone run against Chrome
Misc:
- **Pull Request CI:** Tests run only against Chrome
- **Merge Queue:** Tests run against all projects
- Some tests are excluded from certain browsers due to incompatibilities (see [Test Tags](#test-tags))
## How the Tests Work
Everything Playwright-related lives in the `playwright/` subdirectory
as is typical for Playwright tests. Likewise, tests live in `playwright/e2e`.
### Test Structure
`playwright/testcontainers` contains the testcontainers which start instances
of Synapse/Dendrite. These servers are what Element-web runs against in the tests.
**Element Web tests** are located in the `playwright/` subdirectory:
Synapse can be launched with different configurations in order to test element
in different configurations. You can specify `synapseConfig` as such:
- `playwright/e2e/` - E2E test files
- `playwright/testcontainers/` - Testcontainers for Synapse/Dendrite instances
- `playwright/snapshots/` - Visual regression test screenshots
- `playwright/pages/` - Page object models
- `playwright/plugins/` - Custom Playwright plugins
**Shared components tests** are located in `packages/shared-components/`:
- `packages/shared-components/playwright/snapshots/` - Storybook screenshot baselines
- `packages/shared-components/.storybook/` - Storybook configuration
The shared components use Storybook's test runner (powered by Playwright) to validate component rendering across different states and configurations.
### Homeserver Setup
Homeservers (Synapse or Dendrite) are launched by Playwright workers and reused for all tests matching the worker configuration.
**Configure Synapse options:**
```typescript
test.use({
synapseConfig: {
// The config options to pass to the Synapse instance
// Configuration options for the Synapse instance
},
});
```
The appropriate homeserver will be launched by the Playwright worker and reused for all tests which match the worker configuration.
Due to homeservers being reused between tests, please use unique names for any rooms put into the room directory as
they may be visible from other tests, the suggested approach is to use `testInfo.testId` within the name or lodash's uniqueId.
We remove public rooms from the room directory between tests but deleting users doesn't have a homeserver agnostic solution.
The logs from testcontainers will be attached to any reports output from Playwright.
**Important notes:**
- Homeservers are reused between tests for efficiency
- Please use unique names for any rooms put into the room directory as they may be visible from other tests, the suggested approach is to use `testInfo.testId` within the name or lodash's uniqueId.
- We remove public rooms from the room directory between tests but deleting users doesn't have a homeserver agnostic solution.
- Homeserver logs are attached to Playwright test reports
### Fixtures
We heavily leverage [Playwright fixtures](https://playwright.dev/docs/test-fixtures) to provide:
- Homeserver instances (`homeserver`)
- Logged-in users (`user`)
- Bot users (`bot`)
- Application state (`app`)
See [Writing Tests](#writing-tests) for usage examples.
## Writing Tests
Mostly this is the same advice as for writing any other Playwright test: the Playwright
docs are well worth a read if you're not already familiar with Playwright testing, eg.
https://playwright.dev/docs/best-practices. To avoid your tests being flaky it is also
recommended to use [auto-retrying assertions](https://playwright.dev/docs/test-assertions#auto-retrying-assertions).
For general Playwright best practices, see:
### Getting a Synapse
- <https://playwright.dev/docs/best-practices>
- <https://playwright.dev/docs/test-assertions#auto-retrying-assertions> (recommended for avoiding flaky tests)
We heavily leverage the magic of [Playwright fixtures](https://playwright.dev/docs/test-fixtures).
To acquire a homeserver within a test just add the `homeserver` fixture to the test:
### Getting a Homeserver
Use the `homeserver` fixture to acquire a Homeserver instance:
```typescript
test("should do something", async ({ homeserver }) => {
// homeserver is a Synapse/Dendrite instance
// homeserver is a ready-to-use Synapse/Dendrite instance
});
```
This returns an object with information about the Homeserver instance, including what port
it was started on and the ID that needs to be passed to shut it down again. It also
returns the registration shared secret (`registrationSecret`) that can be used to
register users via the REST API. The Homeserver has been ensured ready to go by awaiting
its internal health-check.
**The fixture provides:**
Homeserver instances should be reasonably cheap to start (you may see the first one take a
while as it pulls the Docker image).
You do not need to explicitly clean up the instance as it will be cleaned up by the fixture.
- Server port information
- Instance ID for shutdown
- Registration shared secret (`registrationSecret`) for registering users via REST API
Homeserver instances are:
- Reasonably cheap to start (first run may be slow while pulling Docker image)
- Automatically cleaned up by the fixture
### Logging In
We again heavily leverage the magic of [Playwright fixtures](https://playwright.dev/docs/test-fixtures).
To acquire a logged-in user within a test just add the `user` fixture to the test:
Use the `user` fixture to get a logged-in user:
```typescript
test("should do something", async ({ user }) => {
// user is a logged in user
// user is logged in and ready to use
});
```
You can specify a display name for the user via `test.use` `displayName`,
otherwise a random one will be generated.
This will register a random userId using the registrationSecret with a random password
and the given display name. The user fixture will contain details about the credentials for if
they are needed for User-Interactive Auth or similar but localStorage will already be seeded with them
and the app loaded (path `/`).
**Customize the user:**
```typescript
test.use({
displayName: "Alice",
});
test("should do something", async ({ user }) => {
// user is logged in as "Alice"
});
```
**What the fixture does:**
- Registers a random userId with the `registrationSecret`
- Generates a random password (or uses specified display name)
- Seeds localStorage with credentials
- Loads the app at path `/`
- Provides user details for User-Interactive Auth if needed
### Joining a Room
Many tests will also want to start with the client in a room, ready to send & receive messages. Best
way to do this may be to get an access token for the user and use this to create a room with the REST
API before logging the user in.
You can make use of the bot fixture and the `client` field on the app fixture to do this.
To start with a user in a room:
### Try to write tests from the users' perspective
```typescript
test("should send a message", async ({ user, app, bot }) => {
// Use the bot client to create a room
const roomId = await bot.createRoom({
name: "Test Room",
invite: [user.userId],
});
Like for instance a user will not look for a button by querying a CSS selector.
Instead, you should work with roles / labels etc, see https://playwright.dev/docs/locators.
// Accept the invite using the app client
await app.client.joinRoom(roomId);
// Now ready to test messaging
});
```
**Best practice:** Use the REST API (via `bot` or `app.client`) to set up room state rather than driving the UI.
### Using matrix-js-sdk
Due to the way we run the Playwright tests in CI, at this time you can only use the matrix-js-sdk module
exposed on `window.matrixcs`. This has the limitation that it is only accessible with the app loaded.
This may be revisited in the future.
Due to CI constraints, use the matrix-js-sdk module exposed on `window.matrixcs`:
## Good Test Hygiene
```typescript
const matrixcs = window.matrixcs;
```
This section mostly summarises general good Playwright testing practice, and should not be news to anyone
already familiar with Playwright.
**Limitation:** Only accessible when the app is loaded. This may be revisited in the future.
1. Test a well-isolated unit of functionality. The more specific, the easier it will be to tell what's
wrong when they fail.
1. Don't depend on state from other tests: any given test should be able to run in isolation.
1. Try to avoid driving the UI for anything other than the UI you're trying to test. e.g. if you're
testing that the user can send a reaction to a message, it's best to send a message using a REST
API, then react to it using the UI, rather than using the element-web UI to send the message.
1. Avoid explicit waits. Playwright locators & assertions will implicitly wait for the specified
element to appear and all assertions are retried until they either pass or time out, so you should
never need to manually wait for an element.
- For example, for asserting about editing an already-edited message, you can't wait for the
'edited' element to appear as there was already one there, but you can assert that the body
of the message is what is should be after the second edit and this assertion will pass once
it becomes true. You can then assert that the 'edited' element is still in the DOM.
- You can also wait for other things like network requests in the
browser to complete (https://playwright.dev/docs/api/class-page#page-wait-for-response).
Needing to wait for things can also be because of race conditions in the app itself, which ideally
shouldn't be there!
### Best Practices
This is a small selection - the Playwright best practices guide, linked above, has more good advice, and we
should generally try to adhere to them.
For more guidance, see the [Playwright best practices guide](https://playwright.dev/docs/best-practices).
## Screenshot testing
#### 1. Test from the User's Perspective
When we previously used Cypress we also dabbled with Percy, and whilst powerful it did not
lend itself well to being executed on all PRs without needing to budget it substantially.
Work with roles, labels, and accessible elements rather than CSS selectors:
```typescript
// Good
await page.getByRole("button", { name: "Send" }).click();
// Avoid
await page.locator(".mx_MessageComposer_sendButton").click();
```
See <https://playwright.dev/docs/locators> for more guidance.
#### 2. Test Well-Isolated Functionality
- Focus on specific, well-defined units of functionality
- Easier to debug when tests fail
- More maintainable over time
#### 3. Maintain Test Independence
- Each test should run successfully in isolation
- Don't depend on state from other tests
- Clean up after your test if needed
#### 4. Minimize UI Driving for Setup
- Use REST APIs to set up test state when possible
- Only drive the UI for the functionality you're actually testing
**Example:**
```typescript
// Testing reactions - good approach
test("should react to a message", async ({ page, app, bot }) => {
// Send message via API
const eventId = await bot.sendMessage(roomId, "Hello");
// Test the reaction UI
await page.getByText("Hello").hover();
await page.getByRole("button", { name: "React" }).click();
await page.getByLabel("😀").click();
// Verify reaction was sent
await expect(page.getByLabel("😀 1")).toBeVisible();
});
```
#### 5. Avoid Explicit Waits
Playwright locators and assertions automatically wait and retry:
```typescript
// Good - implicit waiting
await expect(page.getByText("Message sent")).toBeVisible();
// Avoid - explicit waits
await page.waitForTimeout(1000);
```
**For dynamic content:**
```typescript
// Assert on the final state - Playwright will wait for it
await expect(page.getByRole("textbox")).toHaveValue("Edited message");
await expect(page.getByText("edited")).toBeVisible();
```
**When you do need to wait:**
```typescript
// Wait for network requests
await page.waitForResponse("**/messages");
// Wait for specific conditions
await page.waitForFunction(() => window.matrixcs !== undefined);
```
## Visual Testing
Playwright has built-in support for [visual comparison testing](https://playwright.dev/docs/test-snapshots).
Screenshots are saved in `playwright/snapshots` and are rendered in a Linux Docker environment for stability.
One must be careful to exclude any dynamic content from the screenshot, such as timestamps, avatars, etc,
via the `mask` option. See the [Playwright docs](https://playwright.dev/docs/test-snapshots#masking).
**Screenshot location:** `playwright/snapshots/`
Some UI elements render differently between test runs, such as BaseAvatar when
there is no avatar set, choosing a colour from the theme palette based on the
hash of the user/room's Matrix ID. To avoid this creating flaky tests we inject
some custom CSS, for this to happen we use the custom assertion `toMatchScreenshot`
instead of the native `toHaveScreenshot`.
**Rendering environment:** Linux Docker (for consistency across environments)
If you are running Linux and are unfortunate that the screenshots are not rendering identically,
you may wish to specify `--ignore-snapshots` and rely on Docker to render them for you.
### Test Tag for Screenshots
All screenshot tests must use the `@screenshot` tag:
```typescript
test("should render message list", { tag: "@screenshot" }, async ({ page }) => {
await expect(page).toMatchScreenshot("message-list.png");
});
```
**Purpose of `@screenshot` tag:**
- Allows running only screenshot tests via `test:playwright:screenshots`
- Speeds up screenshot test runs and updates
### Taking Screenshots
Use the custom `toMatchScreenshot` assertion (not the native `toHaveScreenshot`):
```typescript
await expect(page).toMatchScreenshot("my-screenshot.png");
```
**Why a custom assertion?** We inject custom CSS to stabilize dynamic UI elements (e.g., BaseAvatar color selection based on Matrix ID hash).
### Masking Dynamic Content
Always mask dynamic content that changes between runs:
```typescript
await expect(page).toMatchScreenshot("chat.png", {
mask: [page.locator(".mx_MessageTimestamp"), page.locator(".mx_BaseAvatar")],
});
```
Common elements to mask:
- Timestamps
- Avatars (when dynamic)
- Animated elements
- User-generated IDs
See [Playwright masking docs](https://playwright.dev/docs/test-snapshots#masking) for more details.
### Updating Screenshots
This command runs only tests tagged with `@screenshot` in the Docker environment.
When you need to update screenshot baselines (e.g., after intentional UI changes):
```sh
yarn run test:playwright:screenshots
```
**Important:** Always use this command to update screenshots rather than running tests locally with `--update-snapshots`.
**Why?** Screenshots must be rendered in a consistent Linux Docker environment because:
- Font rendering differs between operating systems (macOS, Windows, Linux)
- Subpixel rendering varies across systems
- Browser rendering engines have platform-specific differences
Using `test:playwright:screenshots` ensures screenshots are generated in the same Docker environment used in CI, preventing false failures due to rendering differences.
## Test Tags
We use test tags to categorise tests for running subsets more efficiently.
Test tags categorize tests for efficient subset execution.
- `@mergequeue`: Tests that are slow or flaky and cover areas of the app we update seldom, should not be run on every PR commit but will be run in the Merge Queue.
- `@screenshot`: Tests that use `toMatchScreenshot` to speed up a run of `test:playwright:screenshots`. A test with this tag must not also have the `@mergequeue` tag as this would cause false positives in the stale screenshot detection.
- `@no-$project`: Tests which are unsupported in $Project. These tests will be skipped when running in $Project.
### Available Tags
Anything testing Matrix media will need to have `@no-firefox` and `@no-webkit` as those rely on the service worker which
has to be disabled in Playwright on Firefox & Webkit to retain routing functionality.
Anything testing VoIP/microphone will need to have `@no-webkit` as fake microphone functionality is not available
there at this time.
- **`@mergequeue`**: Slow or flaky tests covering rarely-updated app areas
- Not run on every PR commit
- Run in the Merge Queue
If you wish to run all tests in a PR, you can give it the label `X-Run-All-Tests`.
- **`@screenshot`**: Tests using `toMatchScreenshot` for visual regression testing
- See the [Visual Testing](#visual-testing) section for detailed usage
## Supporter container runtimes
- **`@no-firefox`**: Tests unsupported in Firefox
- Automatically skipped in Firefox project
- Common reason: Service worker required (disabled in Playwright Firefox for routing)
We use testcontainers to spin up various instances of Synapse, Matrix Authentication Service, and more.
It supports Docker out of the box but also has support for Podman, Colima, Rancher, you just need to follow some instructions to achieve it:
https://node.testcontainers.org/supported-container-runtimes/
- **`@no-webkit`**: Tests unsupported in Webkit
- Automatically skipped in Webkit project
- Common reasons: Service worker required, microphone functionality unavailable
If you are running under Colima, you may need to set the environment variable `TMPDIR` to `/tmp/colima` or a path
within `$HOME` to allow bind mounting temporary directories into the Docker containers.
### Running All Tests in a PR
Add the `X-Run-All-Tests` label to your pull request to run all tests, including `@mergequeue` tests.
## Supported Container Runtimes
We use [testcontainers](https://node.testcontainers.org/) to manage Synapse, Matrix Authentication Service, and other service instances.
**Supported runtimes:**
- Docker (default, recommended)
- Podman
- Colima
See setup instructions: <https://node.testcontainers.org/supported-container-runtimes/>
### Platform-Specific Configuration
**Colima users:**
If using Colima, you may need to set the `TMPDIR` environment variable to allow bind mounting temporary directories:
```sh
export TMPDIR=/tmp/colima
# or
export TMPDIR=$HOME/tmp
```
**macOS users:**
Docker Desktop and Colima are both well-supported on macOS.
> [!CAUTION]
> Do not set `DOCKER_HOST` when running tests. Element Web uses [element-web-playwright-common](https://github.com/element-hq/element-modules/tree/main/packages/element-web-playwright-common), and setting `DOCKER_HOST` causes issues with testcontainers when running in the container VM.
+8 -2
View File
@@ -58,6 +58,12 @@ We are aiming for a set of common strings to be shared then some more localised
Edits to existing strings should be performed only via Localazy.
There you can also require all translations to be redone if the meaning of the string has changed significantly.
## Removing existing strings
You can remove an existing string by removing the key from `en_EN.json`. Do not modify other language json files for this purpose.
Localazy will mark the keys you removed as deprecated. See https://localazy.com/docs/general/editing-source-language#source-key-states for more information about the difference between deprecated keys and deleted keys.
## Adding variables inside a string.
1. Extend your `_t()` call. Instead of `_t(TKEY)` use `_t(TKEY, {})`
@@ -66,7 +72,7 @@ There you can also require all translations to be redone if the meaning of the s
1. Add the variable inside the string. The syntax for variables is `%(variable)s`. Please note the _s_ at the end. The name of the variable has to match the previous used name.
- You can use the special `count` variable to choose between multiple versions of the same string, in order to get the correct pluralization. E.g. `_t('You have %(count)s new messages', { count: 2 })` would show 'You have 2 new messages', while `_t('You have %(count)s new messages', { count: 1 })` would show 'You have one new message' (assuming a singular version of the string has been added to the translation file. See above). Passing in `count` is much preferred over having an if-statement choose the correct string to use, because some languages have much more complicated plural rules than english (e.g. they might need a completely different form if there are three things rather than two).
- If you want to translate text that includes e.g. hyperlinks or other HTML you have to also use tag substitution, e.g. `_t('<a>Click here!</a>', {}, { 'a': (sub) => <a>{sub}</a> })`. If you don't do the tag substitution you will end up showing literally '<a>' rather than making a hyperlink.
- If you want to translate text that includes e.g. hyperlinks or other HTML you have to also use tag substitution, e.g. `_t('<a>Click here!</a>', {}, { 'a': (sub) => <a>{sub}</a> })`. If you don't do the tag substitution you will end up showing literally `<a>` rather than making a hyperlink.
- You can also use React components with normal variable substitution if you want to insert HTML markup, e.g. `_t('Your email address is %(emailAddress)s', { emailAddress: <i>{userEmailAddress}</i> })`.
## Things to know/Style Guides
@@ -78,4 +84,4 @@ There you can also require all translations to be redone if the meaning of the s
- Concatenating strings often also introduces an implicit assumption about word order (e.g. that the subject of the sentence comes first), which is incorrect for many languages.
- Translation 'smell test': If you have a string that does not begin with a capital letter (is not the start of a sentence) or it ends with e.g. ':' or a preposition (e.g. 'to') you should recheck that you are not trying to translate a partial sentence.
- If you have multiple strings, that are almost identical, except some part (e.g. a word or two) it is still better to translate the full sentence multiple times. It may seem like inefficient repetition, but unlike programming where you try to minimize repetition, translation is much faster if you have many, full, clear, sentences to work with, rather than fewer, but incomplete sentence fragments.
- Don't forget curly braces when you assign an expression to JSX attributes in the render method)
- Don't forget curly braces when you assign an expression to JSX attributes in the render method.
+2 -3
View File
@@ -11,7 +11,7 @@ import { env } from "process";
import type { Config } from "jest";
const config: Config = {
testEnvironment: "jsdom",
testEnvironment: "jest-fixed-jsdom",
testEnvironmentOptions: {
url: "http://localhost/",
// This is needed to be able to load dual CJS/ESM WASM packages e.g. rust crypto & matrix-wywiwyg
@@ -39,11 +39,10 @@ const config: Config = {
"workers/(.+)Factory": "<rootDir>/__mocks__/workerFactoryMock.js",
"^!!raw-loader!.*": "jest-raw-loader",
"recorderWorkletFactory": "<rootDir>/__mocks__/empty.js",
"^fetch-mock$": "<rootDir>/node_modules/fetch-mock",
"counterpart": "<rootDir>/node_modules/counterpart",
},
transformIgnorePatterns: [
"/node_modules/(?!(mime|matrix-js-sdk|uuid|p-retry|is-network-error|react-merge-refs)).+$",
"/node_modules/(?!(mime|matrix-js-sdk|uuid|p-retry|is-network-error|react-merge-refs|is-ip|ip-regex|super-regex|function-timeout|time-span|convert-hrtime|clone-regexp|is-regexp|matrix-web-i18n)).+$",
],
collectCoverageFrom: [
"<rootDir>/src/**/*.{js,ts,tsx}",
+2 -1
View File
@@ -43,7 +43,8 @@ export default {
// Embedded into webapp
"@element-hq/element-call-embedded",
// Transitive dep of jest
"jsdom",
"@jest/globals",
"vitest-environment-jest-fixed-jsdom",
// Used by matrix-js-sdk, which means we have to include them as a
// dependency so that // we can run `tsc` (since we import the typescript
+16
View File
@@ -18,6 +18,18 @@
"file": "element-web.json",
"excludes": ["src/i18n/strings/en_EN.json"],
"lang": "${autodetectLang}"
},
{
"pattern": "packages/shared-components/src/i18n/strings/en_EN.json",
"file": "shared-components.json",
"lang": "inherited"
},
{
"group": "existing",
"pattern": "packages/shared-components/src/i18n/strings/*.json",
"file": "shared-components.json",
"excludes": ["packages/shared-components/src/i18n/strings/en_EN.json"],
"lang": "${autodetectLang}"
}
]
},
@@ -27,6 +39,10 @@
{
"conditions": "equals: ${file}, element-web.json",
"output": "src/i18n/strings/${langLsrUnderscore}.json"
},
{
"conditions": "equals: ${file}, shared-components.json",
"output": "packages/shared-components/src/i18n/strings/${langLsrUnderscore}.json"
}
],
"includeSourceLang": "${includeSourceLang|false}",
+25 -28
View File
@@ -1,6 +1,6 @@
{
"name": "element-web",
"version": "1.12.7",
"version": "1.12.9",
"description": "Element: the future of secure communication",
"author": "New Vector Ltd.",
"repository": {
@@ -29,9 +29,9 @@
"UserFriendlyError"
],
"scripts": {
"i18n": "matrix-gen-i18n src res packages/shared-components/src && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
"i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"i18n": "matrix-gen-i18n src res && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "matrix-sort-i18n src/i18n/strings/en_EN.json && yarn --cwd packages/shared-components i18n:sort",
"i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null && yarn --cwd packages/shared-components i18n:lint",
"i18n:diff": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && yarn i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
"make-component": "node scripts/make-react-component.js",
"rethemendex": "./res/css/rethemendex.sh",
@@ -69,12 +69,12 @@
"postinstall": "patch-package"
},
"resolutions": {
"**/pretty-format/react-is": "19.2.0",
"@types/react": "19.2.6",
"**/pretty-format/react-is": "19.2.3",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",
"oidc-client-ts": "3.4.1",
"jwt-decode": "4.0.0",
"caniuse-lite": "1.0.30001756",
"caniuse-lite": "1.0.30001762",
"testcontainers": "^11.0.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0",
"wrap-ansi": "npm:wrap-ansi@^7.0.0"
@@ -85,15 +85,15 @@
"@element-hq/web-shared-components": "link:packages/shared-components",
"@fontsource/fira-code": "^5",
"@fontsource/inter": "^5",
"@formatjs/intl-segmenter": "^11.5.7",
"@formatjs/intl-segmenter": "^12.0.0",
"@matrix-org/analytics-events": "^0.30.0",
"@matrix-org/emojibase-bindings": "^1.5.0",
"@matrix-org/react-sdk-module-api": "^2.4.0",
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^10.0.0",
"@types/png-chunks-extract": "^1.0.2",
"@vector-im/compound-design-tokens": "6.4.1",
"@vector-im/compound-web": "^8.3.1",
"@vector-im/compound-design-tokens": "6.8.0",
"@vector-im/compound-web": "^8.3.5",
"@vector-im/matrix-wysiwyg": "2.40.0",
"@zxcvbn-ts/core": "^3.0.4",
"@zxcvbn-ts/language-common": "^3.0.4",
@@ -117,7 +117,7 @@
"highlight.js": "^11.3.1",
"html-entities": "^2.0.0",
"html-react-parser": "^5.2.2",
"is-ip": "^3.1.0",
"is-ip": "^5.0.0",
"js-xxhash": "^5.0.0",
"jsrsasign": "^11.0.0",
"jszip": "^3.7.0",
@@ -129,15 +129,15 @@
"lodash": "^4.17.21",
"maplibre-gl": "^5.0.0",
"matrix-encrypt-attachment": "^1.0.3",
"matrix-js-sdk": "39.4.0",
"matrix-widget-api": "^1.14.0",
"matrix-js-sdk": "40.1.0",
"matrix-widget-api": "^1.15.0",
"memoize-one": "^6.0.0",
"mime": "^4.0.4",
"oidc-client-ts": "^3.0.1",
"opus-recorder": "^8.0.3",
"pako": "^2.0.3",
"png-chunks-extract": "^1.0.0",
"posthog-js": "1.297.2",
"posthog-js": "1.313.0",
"qrcode": "1.5.4",
"re-resizable": "6.11.2",
"react": "^19.0.0",
@@ -179,9 +179,10 @@
"@babel/preset-react": "^7.12.10",
"@babel/preset-typescript": "^7.12.7",
"@babel/runtime": "^7.12.5",
"@casualbot/jest-sonar-reporter": "2.4.0",
"@element-hq/element-call-embedded": "0.16.1",
"@element-hq/element-web-playwright-common": "^2.0.0",
"@casualbot/jest-sonar-reporter": "2.5.0",
"@element-hq/element-call-embedded": "0.16.3",
"@element-hq/element-web-playwright-common": "2.2.3",
"@fetch-mock/jest": "^0.2.20",
"@peculiar/webcrypto": "^1.4.3",
"@playwright/test": "1.57.0",
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
@@ -210,10 +211,9 @@
"@types/minimist": "^1.2.5",
"@types/modernizr": "^3.5.3",
"@types/node": "18",
"@types/node-fetch": "^2.6.2",
"@types/pako": "^2.0.0",
"@types/qrcode": "^1.3.5",
"@types/react": "19.2.6",
"@types/react": "19.2.7",
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-dom": "19.2.3",
"@types/react-transition-group": "^4.4.0",
@@ -228,10 +228,9 @@
"babel-loader": "^10.0.0",
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
"blob-polyfill": "^9.0.0",
"chokidar": "^4.0.0",
"chokidar": "^5.0.0",
"concurrently": "^9.0.0",
"copy-webpack-plugin": "^13.0.0",
"core-js": "^3.38.1",
"cronstrue": "^3.0.0",
"css-loader": "^7.0.0",
"css-minimizer-webpack-plugin": "^7.0.0",
@@ -250,25 +249,23 @@
"eslint-plugin-unicorn": "^56.0.0",
"express": "^5.0.0",
"fake-indexeddb": "^6.0.0",
"fetch-mock": "9.11.0",
"fetch-mock-jest": "^1.5.1",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^5.5.3",
"husky": "^9.0.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^30.0.0",
"jest-canvas-mock": "^2.5.2",
"jest-environment-jsdom": "^30.0.0",
"jest-environment-jsdom": "^30.2.0",
"jest-fixed-jsdom": "^0.0.11",
"jest-mock": "^30.0.0",
"jest-raw-loader": "^1.0.1",
"jsqr": "^1.4.0",
"knip": "^5.36.2",
"lint-staged": "^16.0.0",
"matrix-web-i18n": "^3.2.1",
"matrix-web-i18n": "3.5.2",
"mini-css-extract-plugin": "2.9.2",
"minimist": "^1.2.6",
"modernizr": "^3.12.0",
"node-fetch": "^2.6.7",
"patch-package": "^8.0.0",
"playwright-core": "^1.51.0",
"postcss": "8.4.46",
@@ -281,7 +278,7 @@
"postcss-preset-env": "^10.0.0",
"postcss-scss": "^4.0.4",
"postcss-simple-vars": "^7.0.1",
"prettier": "3.6.2",
"prettier": "3.7.4",
"process": "^0.11.10",
"raw-loader": "^4.0.2",
"rimraf": "^6.0.0",
@@ -294,7 +291,7 @@
"stylelint-value-no-unknown-custom-properties": "^6.0.1",
"terser-webpack-plugin": "^5.3.9",
"testcontainers": "^11.0.0",
"typescript": "5.8.3",
"typescript": "5.9.3",
"util": "^0.12.5",
"web-streams-polyfill": "^4.0.0",
"webpack": "^5.89.0",
@@ -0,0 +1,5 @@
// Even though this (at time of writing) is identical Element Web's
// .prettierrc.js, shared components needs its own because otherwise
// this refers to element web's copy of eslint-plugin-matrix-org which
// would require element-web's modules to be installed.
module.exports = require("eslint-plugin-matrix-org/.prettierrc.js");
@@ -10,16 +10,14 @@ import { WithTooltip, IconButton, TooltipLinkList } from "storybook/internal/com
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");
const languages = JSON.parse(process.env.STORYBOOK_LANGUAGES);
/**
* 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;
const normalisedLang = language.toLowerCase().replace("_", "-");
return new Intl.DisplayNames([normalisedLang], { type: "language", style: "short" }).of(normalisedLang) || language;
}
export const languageAddon: Addon = {
+44 -3
View File
@@ -7,12 +7,15 @@ Please see LICENSE files in the repository root for full details.
import type { StorybookConfig } from "@storybook/react-vite";
import path from "node:path";
import fs from "node:fs";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import { mergeConfig } from "vite";
// Get a list of available languages so the language selector can display them at runtime
const languages = fs.readdirSync("src/i18n/strings").map((f) => f.slice(0, -5));
const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
staticDirs: ["../../../webapp"],
addons: ["@storybook/addon-docs", "@storybook/addon-designs", "@storybook/addon-a11y"],
framework: "@storybook/react-vite",
core: {
@@ -29,8 +32,42 @@ const config: StorybookConfig = {
$webapp: path.resolve("../../webapp"),
},
},
// Needed for counterpart to work
plugins: [nodePolyfills({ include: ["process", "util"] })],
plugins: [
// Needed for counterpart to work
nodePolyfills({ include: ["process", "util"] }),
{
name: "language-middleware",
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (req.url === "/i18n/languages.json") {
// Dynamically generate a languages.json file based on what files are available
const langJson: Record<string, string> = {};
for (const lang of languages) {
const normalizedLanguage = lang.toLowerCase().replace("_", "-");
const languageParts = normalizedLanguage.split("-");
if (languageParts.length === 2 && languageParts[0] === languageParts[1]) {
langJson[languageParts[0]] = `${lang}.json`;
} else {
langJson[normalizedLanguage] = `${lang}.json`;
}
}
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(langJson));
} else if (req.url?.startsWith("/i18n/")) {
// Serve the individual language files, which annoyingly can't be a simple
// static dir because the directory structure in src doesn't match what
// the app requests.
const langFile = req.url.split("/").pop();
res.setHeader("Content-Type", "application/json");
fs.createReadStream(`src/i18n/strings/${langFile}`).pipe(res);
} else {
next();
}
});
},
},
],
server: {
allowedHosts: ["localhost", ".docker.internal"],
},
@@ -42,5 +79,9 @@ const config: StorybookConfig = {
url: "https://element-hq.github.io/compound-web/",
},
},
env: (config) => ({
...config,
STORYBOOK_LANGUAGES: JSON.stringify(languages),
}),
};
export default config;
@@ -20,7 +20,7 @@ const config: TestRunnerConfig = {
// 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();
const image = await page.screenshot({ animations: "disabled" });
expect(image).toMatchImageSnapshot({
customSnapshotsDir,
customSnapshotIdentifier: `${context.id}-${process.platform}`,
+165
View File
@@ -0,0 +1,165 @@
# @element-hq/web-shared-components
Shared React components library for Element Web, Aurora, Element
modules... This package provides opinionated UI components built on top of the
[Compound Design System](https://compound.element.io) and [Compound
Web](https://github.com/element-hq/compound-web). This is not a design system
by itself, but rather a set of larger components.
## Installation in a new project
When adding this library to a new project, as well as installing
`@element-hq/web-shared-components` as normal, you will also need to add
[compound-web](https://github.com/element-hq/compound-web) as a peer
dependency:
```bash
yarn add @element-hq/web-shared-components
yarn add @vector-im/compound-web
```
(This avoids problems where we end up with different versions of compound-web in the
top-level project and web-shared-components).
## Usage
### Basic Import
Both JavaScript and CSS can be imported as follows:
```javascript
import { RoomListHeaderView, useViewModel } from "@element-hq/web-shared-components";
import "@element-hq/web-shared-components/dist/element-web-shared-components.css";
```
or in CSS file:
```css
@import url("@element-hq/web-shared-components");
```
### Using Components
There are two kinds of components in this library:
- _regular_ react component which doesn't follow specific pattern.
- _view_ component(MVVM pattern).
> [!TIP]
> These components are available in the project storybook.
#### Regular Components
These components can be used directly by passing props. Example:
```tsx
import { Flex } from "@element-hq/web-shared-components";
function MyApp() {
return <Flex align="center" />;
}
```
#### View (MVVM) Components
These components follow the [MVVM pattern](../../docs/MVVM.md). A ViewModel
instance should be provided as a prop.
Here's a basic example:
```jsx
import { ViewExample } from "@element-hq/web-shared-components";
function MyApp() {
const viewModel = new ViewModelExample();
return <ViewExample vm={viewModel} />;
}
```
### Utilities
#### Internationalization
- `useI18n()` - Hook for translations
- `I18nApi` - Internationalization API utilities
#### Date & Time
- `DateUtils` - Date formatting and manipulation
- `humanize` - Human-readable time formatting
#### Formatting
- `FormattingUtils` - Text and data formatting utilities
- `numbers` - Number formatting utilities
## Development
### Prerequisites
- Node.js >= 20.0.0
- Yarn 1.22.22+
### Setup
```bash
# Install dependencies
yarn install
# Build the library
yarn prepare
```
### Running Storybook
```bash
yarn storybook
```
### Write components
Most components should be written as [MVVM pattern](../../docs/MVVM.md) view
components. See existing components for examples. The exceptions are low level
components that don't need a view model.
### Tests
Two types of tests are available: unit tests and visual regression tests.
### Unit Tests
These tests cover the logic of the components and utilities. Built with Jest
and React Testing Library.
```bash
yarn test
```
### Visual Regression Tests
These tests ensure the UI components render correctly. They need Storybook to
be running and they will run in docker using [Playwright](../../playwright.md).
First run storybook:
```bash
yarn storybook
```
Then, in another terminal, run:
```bash
yarn test:storybook:update
```
Each story will be rendered and a screenshot will be taken and compared to the
existing baseline. If there are visual changes or AXE violation, the test will
fail.
### Translations
First see our [translation guide](../../docs/translation.md) and [translation dev guide](../../docs/translation-dev.md).
To generate translation strings for this package, run:
```bash
yarn i18n
```
+2 -2
View File
@@ -10,7 +10,7 @@ import { env } from "process";
import type { Config } from "jest";
const config: Config = {
testEnvironment: "jsdom",
testEnvironment: "jest-fixed-jsdom",
testEnvironmentOptions: {
url: "http://localhost/",
},
@@ -30,7 +30,7 @@ const config: Config = {
"workers/(.+)Factory": "<rootDir>/__mocks__/workerFactoryMock.js",
},
transformIgnorePatterns: [
"/node_modules/(?!(mime|matrix-js-sdk|uuid|p-retry|is-network-error|react-merge-refs|@storybook|storybook)).+$",
"/node_modules/(?!(mime|matrix-js-sdk|uuid|p-retry|is-network-error|react-merge-refs|@storybook|storybook|matrix-web-i18n)).+$",
],
collectCoverageFrom: [
"<rootDir>/src/**/*.{js,ts,tsx}",
+10 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@element-hq/web-shared-components",
"version": "0.0.0-test.11",
"version": "0.0.0-test.12",
"description": "Shared components for Element",
"author": "New Vector Ltd.",
"repository": {
@@ -34,8 +34,11 @@
"package.json"
],
"scripts": {
"i18n": "matrix-gen-i18n src && yarn i18n:sort && yarn i18n:lint",
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
"i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null",
"test": "jest",
"prepare": "patch-package && yarn --cwd ../.. build:res && node scripts/gatherTranslationKeys.ts && vite build",
"prepare": "patch-package && vite build",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"lint": "yarn lint:types && yarn lint:js",
@@ -43,24 +46,24 @@
"lint:types": "tsc --noEmit --jsx react",
"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"
"test:storybook:update": "playwright-screenshots --entrypoint /work/scripts/storybook-screenshot-update.sh --with-node-modules"
},
"resolutions": {
"playwright": "1.57.0"
},
"dependencies": {
"@element-hq/element-web-module-api": "^1.8.0",
"@vector-im/compound-design-tokens": "^6.3.0",
"@vector-im/compound-design-tokens": "^6.4.3",
"classnames": "^2.5.1",
"counterpart": "^0.18.6",
"lodash": "^4.17.21",
"matrix-web-i18n": "^3.4.0",
"matrix-web-i18n": "3.5.2",
"patch-package": "^8.0.1",
"react-merge-refs": "^3.0.2",
"temporal-polyfill": "^0.3.0"
},
"devDependencies": {
"@element-hq/element-web-playwright-common": "^2.0.0",
"@element-hq/element-web-playwright-common": "2.2.3",
"@playwright/test": "1.57.0",
"@storybook/addon-a11y": "^10.0.7",
"@storybook/addon-designs": "^11.0.1",
@@ -93,6 +96,6 @@
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"peerDependencies": {
"@vector-im/compound-web": "^8.2.5"
"@vector-im/compound-web": "^8.3.5"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -1,67 +0,0 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
// Gathers all the translation keys from element-web's en_EN.json into a TypeScript type definition file
// that exports a type `TranslationKey` which is a union of all supported translation keys.
// This prevents having to import the json file and make typescript do the work as this results in vite-dts
// generating an import to the json file in the .d.ts which doesn't work at runtime: this way, the type
// gets put into the bundle.
// XXX: It should *not* be in the 'src' directory, being a generated file, but if it isn't then the type
// bundler won't bundle the types and will leave the file as a relative import, which will break.
import * as fs from "fs";
import * as path from "path";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const i18nStringsPath = path.resolve(__dirname, "../../../src/i18n/strings/en_EN.json");
const outPath = path.resolve(__dirname, "../src/i18nKeys.d.ts");
function gatherKeys(obj: any, prefix: string[] = []): string[] {
if (typeof obj !== "object" || obj === null) return [];
let keys: string[] = [];
for (const key of Object.keys(obj)) {
const value = obj[key];
// add the path (for both leaves and intermediates as then we include plurals)
keys.push([...prefix, key].join("|"));
if (typeof value === "object" && value !== null) {
// If the value is an object, recurse
keys = keys.concat(gatherKeys(value, [...prefix, key]));
}
}
return keys;
}
function main() {
const json = JSON.parse(fs.readFileSync(i18nStringsPath, "utf8"));
const keys = gatherKeys(json);
const typeDef =
"/*\n" +
" * Copyright 2025 Element Creations Ltd.\n" +
" *\n" +
" * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial\n" +
" * Please see LICENSE files in the repository root for full details.\n" +
" */\n" +
"\n" +
"// This file is auto-generated by gatherTranslationKeys.ts\n" +
"// Do not edit manually.\n\n" +
"export type TranslationKey =\n" +
keys.map((k) => ` | \"${k}\"`).join("\n") +
";\n";
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, typeDef, "utf8");
console.log(`Wrote ${keys.length} keys to ${outPath}`);
}
if (import.meta.url.startsWith("file:")) {
const modulePath = fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
main();
}
}
@@ -0,0 +1,32 @@
#!/bin/bash
#
# Update storybook screenshots
#
# This script should be used as the entrypoint parameter of the `playwright-screenshots` script. It
# installs the yarn dependencies, and then runs `test-storybook` to update the storybook screenshots.
#
# It expects to find a storybook instance running at :6007 on the host machine. It also requires that
# `playwright-screenshots` is given the `--with-node-modules` parameter.
#
# Example:
#
# test-storybook --url http://localhost:6007/
# playwright-screenshots --entrypoint /work/scripts/storybook-screenshot-update.sh --with-node-modules
#
#
# Note: even though this script is small, it is important because the alternative is running
# `playwright-screenshots` twice in quick succession (once to do `yarn install`, a second to do the
# actual updates): and that fails, because running `playwright-screenshots` without actually starting
# Testcontainers leaves a ryuk container hanging around for up to 60s, which will block the second
# invocation.
set -e
# First install dependencies. We have to do this within the playwright container rather than the host,
# because we have which must be built for the right architecture (and some environments use a VM
# to run docker containers, meaning that things inside a container use a different architecture than
# those on the host).
yarn
# Now run the screenshot update
/work/node_modules/.bin/test-storybook --url http://host.docker.internal:6007/ --updateSnapshot
+14
View File
@@ -0,0 +1,14 @@
/*
Copyright 2025 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type TranslationKey as _TranslationKey } from "matrix-web-i18n";
import type Translations from "../i18n/strings/en_EN.json";
declare global {
type TranslationKey = _TranslationKey<typeof Translations>;
}
@@ -16,7 +16,7 @@ exports[`AudioPlayerView renders the audio player in default state 1`] = `
aria-disabled="false"
aria-label="Play"
aria-labelledby="_r_0_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -107,7 +107,7 @@ exports[`AudioPlayerView renders the audio player in error state 1`] = `
aria-disabled="false"
aria-label="Play"
aria-labelledby="_r_i_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -203,7 +203,7 @@ exports[`AudioPlayerView renders the audio player without media name 1`] = `
aria-disabled="false"
aria-label="Play"
aria-labelledby="_r_6_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -294,7 +294,7 @@ exports[`AudioPlayerView renders the audio player without size 1`] = `
aria-disabled="false"
aria-label="Play"
aria-labelledby="_r_c_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -6,7 +6,7 @@ exports[`PlayPauseButton renders the button in default state 1`] = `
aria-disabled="false"
aria-label="Play"
aria-labelledby="_r_0_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -38,7 +38,7 @@ exports[`PlayPauseButton renders the button in playing state 1`] = `
aria-disabled="false"
aria-label="Pause"
aria-labelledby="_r_6_"
class="_icon-button_1pz9o_8 button"
class="_icon-button_1215g_8 button"
data-kind="primary"
role="button"
style="--cpd-icon-button-size: 32px;"
@@ -27,8 +27,6 @@
padding: var(--cpd-space-4x);
border-top: 1px solid var(--cpd-color-gray-400);
white-space: nowrap;
}
.banner[data-type="success"] {
@@ -90,4 +88,6 @@
flex-direction: row;
gap: var(--cpd-space-1x);
align-self: center;
white-space: nowrap;
}
@@ -11,7 +11,6 @@ import { type Meta, type StoryObj } from "@storybook/react-vite";
import { Button } from "@vector-im/compound-web";
import { Banner } from "./Banner";
import { _t } from "../../utils/i18n";
const meta = {
title: "room/Banner",
@@ -46,17 +45,14 @@ export const WithAction: Story = {
args: {
children: (
<p>
{_t(
"encryption|pinned_identity_changed",
{ displayName: "Alice", userId: "@alice:example.org" },
{
a: (sub) => <a href="https://example.org">{sub}</a>,
b: (sub) => <b>{sub}</b>,
},
)}
Alice's (<b>@alice:example.com</b>) identity was reset. <a href="https://example.org">Learn more</a>
</p>
),
actions: <Button kind="primary">{_t("encryption|withdraw_verification_action")}</Button>,
actions: (
<Button kind="primary" size="sm">
Withdraw verification
</Button>
),
},
};
@@ -71,3 +67,19 @@ export const WithoutClose: Story = {
onClose: undefined,
},
};
export const WithLoadsOfContent: Story = {
args: {
type: "info",
children: (
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quis massa facilisis, venenatis risus
consectetur, sagittis libero. Aenean et scelerisque justo. Nunc luctus, mi sed facilisis suscipit, magna
ante pharetra sem, eu rutrum purus quam quis arcu. Sed eleifend arcu vitae magna sodales, sit amet
fermentum urna dictum. Mauris vel velit pulvinar enim mollis tincidunt. Vivamus egestas rhoncus
sagittis. Curabitur auctor vehicula massa, et cursus lacus laoreet a. Maecenas et sollicitudin lectus,
in ligula.
</p>
),
},
};
@@ -12,6 +12,7 @@ import React, {
type ReactNode,
type PropsWithChildren,
useMemo,
type HTMLAttributes,
} from "react";
import { Button } from "@vector-im/compound-web";
import CheckCircleIcon from "@vector-im/compound-design-tokens/assets/web/icons/check-circle";
@@ -32,8 +33,6 @@ interface BannerProps {
*/
avatar?: React.ReactNode;
className?: string;
/**
* Actions presented to the user in the right-hand side of the banner alongside the dismiss button.
*/
@@ -60,26 +59,26 @@ export function Banner({
actions,
onClose,
...props
}: PropsWithChildren<BannerProps>): ReactElement {
}: PropsWithChildren<BannerProps & HTMLAttributes<HTMLDivElement>>): ReactElement {
const classes = classNames(styles.banner, className);
const icon = useMemo(() => {
const icon = useMemo((): ReactElement => {
switch (type) {
case "critical":
return <ErrorIcon fontSize={24} {...props} />;
return <ErrorIcon fontSize={24} />;
case "info":
return <InfoIcon fontSize={24} {...props} />;
return <InfoIcon fontSize={24} />;
case "success":
return <CheckCircleIcon fontSize={24} {...props} />;
return <CheckCircleIcon fontSize={24} />;
default:
return <InfoIcon fontSize={24} {...props} />;
return <InfoIcon fontSize={24} />;
}
}, [type, props]);
}, [type]);
return (
<div {...props} className={classes} data-type={type}>
<div className={styles.icon}>{avatar ?? icon}</div>
<span className={styles.content}>{children}</span>
<div className={styles.content}>{children}</div>
<div className={styles.actions}>
{actions}
{onClose && (
@@ -26,27 +26,36 @@ exports[`AvatarWithDetails renders a banner with an action 1`] = `
/>
</svg>
</div>
<span
<div
class="content"
>
<p>
encryption|pinned_identity_changed
Alice's (
<b>
@alice:example.com
</b>
) identity was reset.
<a
href="https://example.org"
>
Learn more
</a>
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="primary"
data-size="lg"
data-size="sm"
role="button"
tabindex="0"
>
encryption|withdraw_verification_action
Withdraw verification
</button>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -72,18 +81,18 @@ exports[`AvatarWithDetails renders a banner with an avatar iamge 1`] = `
src="https://picsum.photos/32/32"
/>
</div>
<span
<div
class="content"
>
<p>
Hello! This is a status banner.
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -118,18 +127,18 @@ exports[`AvatarWithDetails renders a critical banner 1`] = `
/>
</svg>
</div>
<span
<div
class="content"
>
<p>
Hello! This is a status banner.
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -168,18 +177,18 @@ exports[`AvatarWithDetails renders a default banner 1`] = `
/>
</svg>
</div>
<span
<div
class="content"
>
<p>
Hello! This is a status banner.
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -219,18 +228,18 @@ exports[`AvatarWithDetails renders a info banner 1`] = `
/>
</svg>
</div>
<span
<div
class="content"
>
<p>
Hello! This is a status banner.
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -265,18 +274,18 @@ exports[`AvatarWithDetails renders a success banner 1`] = `
/>
</svg>
</div>
<span
<div
class="content"
>
<p>
Hello! This is a status banner.
</p>
</span>
</div>
<div
class="actions"
>
<button
class="_button_187yx_8"
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { type Meta, type StoryFn } from "@storybook/react-vite";
import React, { type JSX } from "react";
import { fn } from "storybook/test";
import { useMockedViewModel } from "../../useMockedViewModel";
import {
HistoryVisibleBannerView,
type HistoryVisibleBannerViewActions,
type HistoryVisibleBannerViewSnapshot,
} from "./HistoryVisibleBannerView";
type HistoryVisibleBannerProps = HistoryVisibleBannerViewSnapshot & HistoryVisibleBannerViewActions;
const HistoryVisibleBannerViewWrapper = ({ onClose, ...rest }: HistoryVisibleBannerProps): JSX.Element => {
const vm = useMockedViewModel(rest, {
onClose,
});
return <HistoryVisibleBannerView vm={vm} />;
};
export default {
title: "composer/HistoryVisibleBannerView",
component: HistoryVisibleBannerViewWrapper,
tags: ["autodocs"],
argTypes: {},
args: {
visible: true,
onClose: fn(),
},
} as Meta<typeof HistoryVisibleBannerViewWrapper>;
const Template: StoryFn<typeof HistoryVisibleBannerViewWrapper> = (args) => (
<HistoryVisibleBannerViewWrapper {...args} />
);
export const Default = Template.bind({});
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import React from "react";
import { render } from "jest-matrix-react";
import { composeStories } from "@storybook/react-vite";
import * as stories from "./HistoryVisibleBannerView.stories.tsx";
const { Default } = composeStories(stories);
describe("HistoryVisibleBannerView", () => {
it("renders a history visible banner", () => {
const dismissFn = jest.fn();
const { container } = render(<Default onClose={dismissFn} />);
expect(container).toMatchSnapshot();
const button = container.querySelector("button");
expect(button).not.toBeNull();
button?.click();
expect(dismissFn).toHaveBeenCalled();
});
});
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { Link } from "@vector-im/compound-web";
import React, { type JSX } from "react";
import { useViewModel } from "../../useViewModel";
import { _t } from "../../utils/i18n";
import { type ViewModel } from "../../viewmodel";
import { Banner } from "../Banner";
export interface HistoryVisibleBannerViewActions {
/**
* Called when the user dismisses the banner.
*/
onClose: () => void;
}
export interface HistoryVisibleBannerViewSnapshot {
/**
* Whether the banner is currently visible.
*/
visible: boolean;
}
/**
* The view model for the banner.
*/
export type HistoryVisibleBannerViewModel = ViewModel<HistoryVisibleBannerViewSnapshot> &
HistoryVisibleBannerViewActions;
interface HistoryVisibleBannerViewProps {
/**
* The view model for the banner.
*/
vm: HistoryVisibleBannerViewModel;
}
/**
* A component to alert that history is shared to new members of the room.
*
* @example
* ```tsx
* <HistoryVisibleBannerView vm={historyVisibleBannerViewModel} />
* ```
*/
export function HistoryVisibleBannerView({ vm }: Readonly<HistoryVisibleBannerViewProps>): JSX.Element {
const { visible } = useViewModel(vm);
const contents = _t(
"room|status_bar|history_visible",
{},
{
a: substituteATag,
},
);
return (
<>
{visible && (
<Banner type="info" onClose={() => vm.onClose()}>
{contents}
</Banner>
)}
</>
);
}
function substituteATag(sub: string): JSX.Element {
return (
<Link href="https://element.io/en/help#e2ee-history-sharing" target="_blank">
{sub}
</Link>
);
}
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`HistoryVisibleBannerView renders a history visible banner 1`] = `
<div>
<div
class="banner"
data-type="info"
>
<div
class="icon"
>
<svg
fill="currentColor"
font-size="24"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.288 7.288A.97.97 0 0 1 12 7q.424 0 .713.287Q13 7.576 13 8t-.287.713A.97.97 0 0 1 12 9a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 8q0-.424.287-.713m.001 4.001A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713v4q0 .424-.287.712A.97.97 0 0 1 12 17a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 16v-4q0-.424.287-.713"
/>
<path
clip-rule="evenodd"
d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 1-16 0 8 8 0 0 1 16 0"
fill-rule="evenodd"
/>
</svg>
</div>
<div
class="content"
>
<span>
This room has been configured so that new members can read history.
<a
class="_link_1v5rz_8"
data-kind="primary"
data-size="medium"
href="https://element.io/en/help#e2ee-history-sharing"
rel="noreferrer noopener"
target="_blank"
>
Learn More
</a>
</span>
</div>
<div
class="actions"
>
<button
class="_button_13vu4_8"
data-kind="secondary"
data-size="sm"
role="button"
tabindex="0"
>
Dismiss
</button>
</div>
</div>
</div>
`;
@@ -0,0 +1,8 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
export * from "./HistoryVisibleBannerView";
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Panel posunu zvuku"
},
"action": {
"delete": "Smazat",
"dismiss": "Zavřít",
"explore_rooms": "Procházet místnosti",
"pause": "Pozastavit",
"play": "Přehrát",
"search": "Hledání"
},
"left_panel": {
"open_dial_pad": "Otevřít číselník"
},
"time": {
"about_day_ago": "před jedním dnem",
"about_hour_ago": "asi před hodinou",
"about_minute_ago": "před minutou",
"few_seconds_ago": "před pár vteřinami",
"in_about_day": "asi za den",
"in_about_hour": "asi za hodinu",
"in_about_minute": "asi za minutu",
"in_few_seconds": "za pár vteřin",
"in_n_days": "za %(num)s dní",
"in_n_hours": "za %(num)s hodin",
"in_n_minutes": "za %(num)s minut",
"n_days_ago": "před %(num)s dny",
"n_hours_ago": "před %(num)s hodinami",
"n_minutes_ago": "před %(num)s minutami"
},
"timeline": {
"m.audio": {
"audio_player": "Audio přehrávač",
"error_downloading_audio": "Chyba při stahování audia",
"unnamed_audio": "Nepojmenovaný audio soubor"
}
}
}
@@ -0,0 +1,60 @@
{
"a11y": {
"seek_bar_label": "Bar chwilio sain"
},
"action": {
"delete": "Dileu",
"dismiss": "Gwrthod",
"explore_rooms": "Archwilio Ystafelloedd",
"pause": "Oedi",
"play": "Chwarae",
"retry": "Ceisio eto",
"search": "Chwilio"
},
"left_panel": {
"open_dial_pad": "Agor y pad deialu"
},
"room": {
"status_bar": {
"delete_all": "Dileu'r cyfan",
"exceeded_resource_limit_description": "Cysylltwch â gweinyddwr eich gwasanaeth i barhau i ddefnyddio'r gwasanaeth.",
"exceeded_resource_limit_title": "Dyw eich neges heb ei anfon oherwydd bod y gweinydd cartref hwn wedi mynd y tu hwnt i derfyn ei adnoddau.",
"failed_to_create_room_title": "Methwyd dechrau sgwrs gyda'r defnyddiwr hwn",
"history_visible": "Mae'r ystafell hon wedi'i ffurfweddu fel y gall aelodau newydd ddarllen hanes. <a>Dysgu Mwy</a>",
"homeserver_blocked_title": "Dyw eich neges heb ei anfon oherwydd bod y gweinydd cartref hwn wedi'i rwystro gan ei weinyddwr.",
"monthly_user_limit_reached_title": "Dyw eich neges heb ei anfon oherwydd bod y gweinydd cartref hwn wedi cyrraedd ei Derfyn Defnyddiwr Gweithredol Misol.",
"requires_consent_agreement_title": "Does dim modd i chi anfon unrhyw negeseuon nes i chi adolygu a chytuno â'n telerau ac amodau.",
"retry_all": "Ail-geisio popeth",
"select_messages_to_retry": "Gallwch ddewis pob neges neu negeseuon unigol i geisio eto neu eu dileu",
"server_connectivity_lost_description": "Bydd negeseuon sy'n cael eu hanfon yn cael eu cadw nes bod eich cysylltiad wedi dychwelyd.",
"server_connectivity_lost_title": "Mae'r cysylltiad â'r gweinydd wedi'i golli.",
"some_messages_not_sent": "Dyw rhai o'ch negeseuon heb eu hanfon"
}
},
"terms": {
"tac_button": "Adolygwch y telerau a'r amodau"
},
"time": {
"about_day_ago": "tua diwrnod yn ôl",
"about_hour_ago": "tua awr yn ol",
"about_minute_ago": "tua munud yn ôl",
"few_seconds_ago": "ychydig eiliadau yn ôl",
"in_about_day": "tua diwrnod o nawr",
"in_about_hour": "tuag awr o hyn",
"in_about_minute": "tua munud o nawr",
"in_few_seconds": "ychydig eiliadau o nawr",
"in_n_days": "%(num)s diwrnod o nawr",
"in_n_hours": "%(num)s awr o nawr",
"in_n_minutes": "%(num)s munud o nawr",
"n_days_ago": "%(num)s diwrnod yn ôl",
"n_hours_ago": "%(num)s awr yn ôl",
"n_minutes_ago": "%(num)s munud yn ôl"
},
"timeline": {
"m.audio": {
"audio_player": "Chwaraewr sain",
"error_downloading_audio": "Gwall wrth llwytho i lawrsain",
"unnamed_audio": "Sain dienw"
}
}
}
@@ -0,0 +1,35 @@
{
"a11y": {
"seek_bar_label": "Progressionsmarkør for lydafspiller"
},
"action": {
"delete": "Slet",
"dismiss": "Afvis",
"explore_rooms": "Udforsk rum",
"pause": "Pausér",
"play": "Afspil",
"search": "Søg"
},
"time": {
"about_day_ago": "omkring en dag siden",
"about_hour_ago": "for omkring en time siden",
"about_minute_ago": "for omkring et minut siden",
"few_seconds_ago": "for et par sekunder siden",
"in_about_day": "om cirka en dag fra nu",
"in_about_hour": "omkring en time fra nu",
"in_about_minute": "omkring et minut fra nu",
"in_few_seconds": "et par sekunder fra nu",
"in_n_days": "%(num)s dage fra nu",
"in_n_hours": "%(num)s timer fra nu",
"in_n_minutes": "%(num)s minutter fra nu",
"n_days_ago": "%(num)s dage siden",
"n_hours_ago": "%(num)s timer siden",
"n_minutes_ago": "%(num)s minutter siden"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Fejl ved download af lyd",
"unnamed_audio": "Unavngiven lyd"
}
}
}
@@ -0,0 +1,58 @@
{
"a11y": {
"seek_bar_label": "Audio-Suchleiste"
},
"action": {
"delete": "Löschen",
"dismiss": "Ausblenden",
"explore_rooms": "Chats erkunden",
"pause": "Pausieren",
"play": "Abspielen",
"retry": "Erneut versuchen",
"search": "Suchen"
},
"left_panel": {
"open_dial_pad": "Wähltastatur öffnen"
},
"room": {
"status_bar": {
"delete_all": "Alle löschen",
"exceeded_resource_limit_title": "Deine Nachricht konnte nicht versendet werden, da dein Homeserver ein Ressourcenlimit überschritten hat.",
"failed_to_create_room_title": "Es konnte kein Chat mit diesem Nutzer gestartet werden",
"history_visible": "Diese Gruppe wurde konfiguriert, neuen Mitgliedern Zugriff auf den vergangenen Nachrichtenverlauf zu gestatten. <a>Mehr erfahren</a>",
"homeserver_blocked_title": "Deine Nachricht konnte nicht versendet werden, da der Admin deinen Homeserver gesperrt hat.",
"monthly_user_limit_reached_title": "Deine Nachricht konnte nicht versendet werden, da dein Homeserver das monatliche Nutzerlimit erreicht hat.",
"requires_consent_agreement_title": "Du kannst erst dann Nachrichten verschicken, wenn du unsere Geschäftsbedingungen gelesen und akzeptiert hast.",
"select_messages_to_retry": "Du kannst einzelne oder alle Nachrichten erneut senden oder löschen",
"server_connectivity_lost_description": "Nachrichten werden gespeichert und gesendet, wenn die Internetverbindung wiederhergestellt ist.",
"server_connectivity_lost_title": "Verbindung zum Server wurde unterbrochen.",
"some_messages_not_sent": "Einige Nachrichten konnten nicht gesendet werden"
}
},
"terms": {
"tac_button": "Geschäftsbedingungen anzeigen"
},
"time": {
"about_day_ago": "vor etwa einem Tag",
"about_hour_ago": "vor etwa einer Stunde",
"about_minute_ago": "vor etwa einer Minute",
"few_seconds_ago": "vor ein paar Sekunden",
"in_about_day": "in etwa einem Tag",
"in_about_hour": "in etwa einer Stunde",
"in_about_minute": "in etwa einer Minute",
"in_few_seconds": "in ein paar Sekunden",
"in_n_days": "in %(num)s Tagen",
"in_n_hours": "in %(num)s Stunden",
"in_n_minutes": "In etwa %(num)s Minuten",
"n_days_ago": "vor %(num)s Tagen",
"n_hours_ago": "vor %(num)s Stunden",
"n_minutes_ago": "vor %(num)s Minuten"
},
"timeline": {
"m.audio": {
"audio_player": "Audio-Player",
"error_downloading_audio": "Fehler beim Herunterladen der Audiodatei",
"unnamed_audio": "Unbenannte Audiodatei"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Διαγραφή",
"dismiss": "Απόρριψη",
"explore_rooms": "Εξερευνήστε αίθουσες",
"pause": "Παύση",
"play": "Αναπαραγωγή",
"search": "Αναζήτηση"
},
"left_panel": {
"open_dial_pad": "Άνοιγμα πληκτρολογίου κλήσης"
},
"time": {
"about_day_ago": "σχεδόν μία μέρα πριν",
"about_hour_ago": "σχεδόν μία ώρα πριν",
"about_minute_ago": "σχεδόν ένα λεπτό πριν",
"few_seconds_ago": "λίγα δευτερόλεπτα πριν",
"in_about_day": "περίπου μια μέρα από τώρα",
"in_about_hour": "περίπου μία ώρα από τώρα",
"in_about_minute": "περίπου ένα λεπτό από τώρα",
"in_few_seconds": "λίγα δευτερόλεπτα από τώρα",
"in_n_days": "%(num)s μέρες από τώρα",
"in_n_hours": "%(num)s ώρες από τώρα",
"in_n_minutes": "%(num)s λεπτά από τώρα",
"n_days_ago": "%(num)s μέρες πριν",
"n_hours_ago": "%(num)s ώρες πριν",
"n_minutes_ago": "%(num)s λεπτά πριν"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Σφάλμα λήψης ήχου",
"unnamed_audio": "Ήχος χωρίς όνομα"
}
}
}
@@ -0,0 +1,60 @@
{
"a11y": {
"seek_bar_label": "Audio seek bar"
},
"action": {
"delete": "Delete",
"dismiss": "Dismiss",
"explore_rooms": "Explore rooms",
"pause": "Pause",
"play": "Play",
"retry": "Retry",
"search": "Search"
},
"left_panel": {
"open_dial_pad": "Open dial pad"
},
"room": {
"status_bar": {
"delete_all": "Delete all",
"exceeded_resource_limit_description": "Please contact your service administrator to continue using the service.",
"exceeded_resource_limit_title": "Your message wasn't sent because this homeserver has exceeded a resource limit.",
"failed_to_create_room_title": "Could not start a chat with this user",
"history_visible": "This room has been configured so that new members can read history. <a>Learn More</a>",
"homeserver_blocked_title": "Your message wasn't sent because this homeserver has been blocked by its administrator.",
"monthly_user_limit_reached_title": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit.",
"requires_consent_agreement_title": "You can't send any messages until you review and agree to our terms and conditions.",
"retry_all": "Retry all",
"select_messages_to_retry": "You can select all or individual messages to retry or delete",
"server_connectivity_lost_description": "Sent messages will be stored until your connection has returned.",
"server_connectivity_lost_title": "Connectivity to the server has been lost.",
"some_messages_not_sent": "Some of your messages have not been sent"
}
},
"terms": {
"tac_button": "Review terms and conditions"
},
"time": {
"about_day_ago": "about a day ago",
"about_hour_ago": "about an hour ago",
"about_minute_ago": "about a minute ago",
"few_seconds_ago": "a few seconds ago",
"in_about_day": "about a day from now",
"in_about_hour": "about an hour from now",
"in_about_minute": "about a minute from now",
"in_few_seconds": "a few seconds from now",
"in_n_days": "%(num)s days from now",
"in_n_hours": "%(num)s hours from now",
"in_n_minutes": "%(num)s minutes from now",
"n_days_ago": "%(num)s days ago",
"n_hours_ago": "%(num)s hours ago",
"n_minutes_ago": "%(num)s minutes ago"
},
"timeline": {
"m.audio": {
"audio_player": "Audio player",
"error_downloading_audio": "Error downloading audio",
"unnamed_audio": "Unnamed audio"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Forigi",
"dismiss": "Rezigni",
"explore_rooms": "Esplori ĉambrojn",
"pause": "Paŭzigi",
"play": "Ludi",
"search": "Serĉi"
},
"left_panel": {
"open_dial_pad": "Malfermi ciferplaton"
},
"time": {
"about_day_ago": "antaŭ ĉirkaŭ tago",
"about_hour_ago": "antaŭ ĉirkaŭ horo",
"about_minute_ago": "antaŭ ĉirkaŭ minuto",
"few_seconds_ago": "antaŭ kelkaj sekundoj",
"in_about_day": "ĉirkaŭ tagon de nun",
"in_about_hour": "ĉirkaŭ horon de nun",
"in_about_minute": "ĉirkaŭ minuton de nun",
"in_few_seconds": "kelkajn sekundojn de nun",
"in_n_days": "%(num)s tagojn de nun",
"in_n_hours": "%(num)s horojn de nun",
"in_n_minutes": "%(num)s minutojn de nun",
"n_days_ago": "antaŭ %(num)s tagoj",
"n_hours_ago": "antaŭ %(num)s horoj",
"n_minutes_ago": "antaŭ %(num)s minutoj"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Eraris elŝuto de sondosiero",
"unnamed_audio": "Sennoma sondosiero"
}
}
}
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Barra de búsqueda de audio"
},
"action": {
"delete": "Borrar",
"dismiss": "Omitir",
"explore_rooms": "Explorar salas",
"pause": "Pausar",
"play": "Reproducir",
"search": "Buscar"
},
"left_panel": {
"open_dial_pad": "Abrir teclado numérico"
},
"time": {
"about_day_ago": "hace aprox. un día",
"about_hour_ago": "hace aprox. una hora",
"about_minute_ago": "hace aproximadamente un minuto",
"few_seconds_ago": "hace unos segundos",
"in_about_day": "dentro de un día",
"in_about_hour": "dentro de una hora",
"in_about_minute": "dentro de un minuto",
"in_few_seconds": "dentro de unos segundos",
"in_n_days": "dentro de %(num)s días",
"in_n_hours": "dentro de %(num)s horas",
"in_n_minutes": "dentro de %(num)s minutos",
"n_days_ago": "hace %(num)s días",
"n_hours_ago": "hace %(num)s horas",
"n_minutes_ago": "hace %(num)s minutos"
},
"timeline": {
"m.audio": {
"audio_player": "Reproductor de audio",
"error_downloading_audio": "Error al descargar el audio",
"unnamed_audio": "Audio sin título"
}
}
}
@@ -0,0 +1,44 @@
{
"a11y": {
"seek_bar_label": "Heli kerimisriba"
},
"action": {
"delete": "Kustuta",
"dismiss": "Loobu",
"explore_rooms": "Tutvu jututubadega",
"pause": "Peata",
"play": "Esita",
"search": "Otsing"
},
"left_panel": {
"open_dial_pad": "Ava numbriklahvistik"
},
"room": {
"status_bar": {
"history_visible": "See jututuba on seadistatud sel viisil, et uued liikmed saavad lugeda varasemat ajalugu.<a> Lisateave</a>"
}
},
"time": {
"about_day_ago": "umbes päev tagasi",
"about_hour_ago": "umbes tund aega tagasi",
"about_minute_ago": "umbes minut tagasi",
"few_seconds_ago": "mõni sekund tagasi",
"in_about_day": "umbes päeva pärast",
"in_about_hour": "umbes tunni pärast",
"in_about_minute": "umbes minuti pärast",
"in_few_seconds": "mõne sekundi pärast",
"in_n_days": "%(num)s päeva pärast",
"in_n_hours": "%(num)s tunni pärast",
"in_n_minutes": "%(num)s minuti pärast",
"n_days_ago": "%(num)s päeva tagasi",
"n_hours_ago": "%(num)s tundi tagasi",
"n_minutes_ago": "%(num)s minutit tagasi"
},
"timeline": {
"m.audio": {
"audio_player": "Meediaesitaja",
"error_downloading_audio": "Helifaili allalaadimine ei õnnestunud",
"unnamed_audio": "Nimetu helifail"
}
}
}
@@ -0,0 +1,29 @@
{
"action": {
"delete": "پاک‌کردن",
"dismiss": "نادیده بگیر",
"explore_rooms": "جستجو در اتاق ها",
"pause": "متوقف‌کردن",
"play": "اجرا کردن",
"search": "جستجو"
},
"left_panel": {
"open_dial_pad": "باز کردن صفحه شماره‌گیری"
},
"time": {
"about_day_ago": "حدود یک روز قبل",
"about_hour_ago": "حدود یک ساعت قبل",
"about_minute_ago": "حدود یک دقیقه قبل",
"few_seconds_ago": "چند ثانیه قبل",
"in_about_day": "حدود یک روز دیگر",
"in_about_hour": "حدود یک ساعت دیگر",
"in_about_minute": "حدود یک دقیقه دیگر",
"in_few_seconds": "چند ثانیه دیگر",
"in_n_days": "%(num)s روز دیگر",
"in_n_hours": "%(num)s ساعت دیگر",
"in_n_minutes": "%(num)s دقیقه دیگر",
"n_days_ago": "%(num)s روز قبل",
"n_hours_ago": "%(num)s ساعت قبل",
"n_minutes_ago": "%(num)s دقیقه قبل"
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Äänen siirtymispalkki"
},
"action": {
"delete": "Poista",
"dismiss": "Hylkää",
"explore_rooms": "Selaa huoneita",
"pause": "Keskeytä",
"play": "Toista",
"search": "Haku"
},
"left_panel": {
"open_dial_pad": "Avaa näppäimistö"
},
"time": {
"about_day_ago": "noin päivä sitten",
"about_hour_ago": "noin tunti sitten",
"about_minute_ago": "noin minuutti sitten",
"few_seconds_ago": "muutama sekunti sitten",
"in_about_day": "noin päivä sitten",
"in_about_hour": "noin tunti sitten",
"in_about_minute": "noin minuutti sitten",
"in_few_seconds": "muutama sekunti sitten",
"in_n_days": "%(num)s päivää sitten",
"in_n_hours": "%(num)s tuntia sitten",
"in_n_minutes": "%(num)s minuuttia sitten",
"n_days_ago": "%(num)s päivää sitten",
"n_hours_ago": "%(num)s tuntia sitten",
"n_minutes_ago": "%(num)s minuuttia sitten"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Virhe ääntä ladattaessa",
"unnamed_audio": "Nimetön ääni"
}
}
}
@@ -0,0 +1,60 @@
{
"a11y": {
"seek_bar_label": "Barre de recherche audio"
},
"action": {
"delete": "Supprimer",
"dismiss": "Ignorer",
"explore_rooms": "Parcourir les salons",
"pause": "Pause",
"play": "Lecture",
"retry": "Réessayer",
"search": "Rechercher"
},
"left_panel": {
"open_dial_pad": "Ouvrir le pavé de numérotation"
},
"room": {
"status_bar": {
"delete_all": "Tout supprimer",
"exceeded_resource_limit_description": "Veuillez contacter votre administrateur pour continuer à utiliser le service.",
"exceeded_resource_limit_title": "Votre message n'a pas pu être envoyé car ce serveur d'accueil a dépassé sa limite de ressources.",
"failed_to_create_room_title": "Impossible de démarrer une discussion avec cet utilisateur",
"history_visible": "Ce salon a été configuré afin que les nouveaux membres puissent lire l'historique.<a> En savori plus</a>",
"homeserver_blocked_title": "Votre message n'a pas pu être envoyé car ce serveur d'accueil a été bloqué par son administrateur.",
"monthly_user_limit_reached_title": "Votre message n'a pas pu être envoyé car ce serveur d'accueil a atteint sa limite mensuelle d'utilisateurs actifs.",
"requires_consent_agreement_title": "Vous ne pouvez envoyer aucun message tant que vous n'aurez pas consulté et accepté nos conditions générales.",
"retry_all": "Tout réessayer",
"select_messages_to_retry": "Vous pouvez choisir de renvoyer ou supprimer tous les messages ou seulement certains",
"server_connectivity_lost_description": "Les messages envoyés seront stockés jusqu’à ce que votre connexion revienne.",
"server_connectivity_lost_title": "La connexion avec le serveur a été perdue.",
"some_messages_not_sent": "Certains de vos messages nont pas été envoyés"
}
},
"terms": {
"tac_button": "Voir les conditions générales"
},
"time": {
"about_day_ago": "il y a environ un jour",
"about_hour_ago": "il y a environ une heure",
"about_minute_ago": "il y a environ une minute",
"few_seconds_ago": "il y a quelques secondes",
"in_about_day": "dans un jour environ",
"in_about_hour": "dans une heure environ",
"in_about_minute": "dans une minute environ",
"in_few_seconds": "dans quelques secondes",
"in_n_days": "dans %(num)s jours",
"in_n_hours": "dans %(num)s heures",
"in_n_minutes": "dans %(num)s minutes",
"n_days_ago": "il y a %(num)s jours",
"n_hours_ago": "il y a %(num)s heures",
"n_minutes_ago": "il y a %(num)s minutes"
},
"timeline": {
"m.audio": {
"audio_player": "Lecteur audio",
"error_downloading_audio": "Erreur lors du téléchargement de laudio",
"unnamed_audio": "Audio sans nom"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Eliminar",
"dismiss": "Rexeitar",
"explore_rooms": "Explorar salas",
"pause": "Deter",
"play": "Reproducir",
"search": "Busca"
},
"left_panel": {
"open_dial_pad": "Abrir marcador"
},
"time": {
"about_day_ago": "onte",
"about_hour_ago": "fai unha hora",
"about_minute_ago": "fai un minuto",
"few_seconds_ago": "fai uns segundos",
"in_about_day": "foi onte",
"in_about_hour": "fará unha hora",
"in_about_minute": "haberá un minuto",
"in_few_seconds": "hai só uns segundos",
"in_n_days": "fará %(num)s días",
"in_n_hours": "fará %(num)s horas",
"in_n_minutes": "fará %(num)s minutos",
"n_days_ago": "fai %(num)s días",
"n_hours_ago": "fai %(num)s horas",
"n_minutes_ago": "fai %(num)s minutos"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Erro ao descargar o audio",
"unnamed_audio": "Audio sen nome"
}
}
}
@@ -0,0 +1,27 @@
{
"action": {
"delete": "מחק",
"dismiss": "התעלם",
"explore_rooms": "גלה חדרים",
"search": "חפש"
},
"left_panel": {
"open_dial_pad": "פתח לוח חיוג"
},
"time": {
"about_day_ago": "בערך לפני יום",
"about_hour_ago": "בערך לפני כשעה",
"about_minute_ago": "לפני בערך דקה",
"few_seconds_ago": "לפני מספר שניות",
"in_about_day": "בערך בעוד יום מעכשיו",
"in_about_hour": "בערך בעוד כשעה",
"in_about_minute": "בערך עוד דקה אחת",
"in_few_seconds": "בעוד מספר שניות מעכשיו",
"in_n_days": "בעוד %(num)s ימים מעכשיו",
"in_n_hours": "בעוד %(num)s שעות",
"in_n_minutes": "בעוד %(num)s דקות",
"n_days_ago": "לפני %(num)s ימים",
"n_hours_ago": "לפני %(num)s שעות",
"n_minutes_ago": "לפני %(num)s דקות"
}
}
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Hang keresősávja"
},
"action": {
"delete": "Törlés",
"dismiss": "Eltüntetés",
"explore_rooms": "Szobák felderítése",
"pause": "Szünet",
"play": "Lejátszás",
"search": "Keresés"
},
"left_panel": {
"open_dial_pad": "Számlap megnyitása"
},
"time": {
"about_day_ago": "egy napja",
"about_hour_ago": "egy órája",
"about_minute_ago": "egy perce",
"few_seconds_ago": "néhány másodperce",
"in_about_day": "egy nap múlva",
"in_about_hour": "egy óra múlva",
"in_about_minute": "egy perc múlva",
"in_few_seconds": "másodpercek múlva",
"in_n_days": "%(num)s nap múlva",
"in_n_hours": "%(num)s óra múlva",
"in_n_minutes": "%(num)s perc múlva",
"n_days_ago": "%(num)s nappal ezelőtt",
"n_hours_ago": "%(num)s órával ezelőtt",
"n_minutes_ago": "%(num)s perccel ezelőtt"
},
"timeline": {
"m.audio": {
"audio_player": "Hanglejátszó",
"error_downloading_audio": "Hiba a hang letöltésekor",
"unnamed_audio": "Névtelen hang"
}
}
}
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Աուդիո որոնման գոտի"
},
"action": {
"delete": "Ջնջել",
"dismiss": "Հեռացնել",
"explore_rooms": "Փնտրել սենյակներ",
"pause": "Դադար",
"play": "Միացնել",
"search": "Որոնել"
},
"left_panel": {
"open_dial_pad": "Բացեք թվերի հավաքման վահանակը"
},
"time": {
"about_day_ago": "մոտ մեկ օր առաջ",
"about_hour_ago": "մոտ մեկ ժամ առաջ",
"about_minute_ago": "մոտ մեկ րոպե առաջ",
"few_seconds_ago": "մի քանի վայրկյան առաջ",
"in_about_day": "մոտ մեկ օր անց",
"in_about_hour": "մոտ մեկ ժամ անց",
"in_about_minute": "մոտ մեկ րոպե անց",
"in_few_seconds": "մի քանի վայրկյան անց",
"in_n_days": "%(num)s օր անց",
"in_n_hours": "%(num)s ժամ անց",
"in_n_minutes": "%(num)s րոպեներ անց",
"n_days_ago": "%(num)s օր առաջ",
"n_hours_ago": "%(num)s ժամ առաջ",
"n_minutes_ago": "%(num)s րոպե առաջ"
},
"timeline": {
"m.audio": {
"audio_player": "Աուդիո նվագարկիչ",
"error_downloading_audio": "Աուդիո ներբեռնման սխալ",
"unnamed_audio": "Անանուն աուդիո"
}
}
}
@@ -0,0 +1,39 @@
{
"a11y": {
"seek_bar_label": "Bilah pencarian audio"
},
"action": {
"delete": "Hapus",
"dismiss": "Abaikan",
"explore_rooms": "Jelajahi ruangan",
"pause": "Jeda",
"play": "Mainkan",
"search": "Cari"
},
"left_panel": {
"open_dial_pad": "Buka tombol penyetel"
},
"time": {
"about_day_ago": "1 hari yang lalu",
"about_hour_ago": "1 jam yang lalu",
"about_minute_ago": "1 menit yang lalu",
"few_seconds_ago": "beberapa detik yang lalu",
"in_about_day": "1 hari dari sekarang",
"in_about_hour": "1 jam dari sekarang",
"in_about_minute": "1 menit dari sekarang",
"in_few_seconds": "beberapa detik dari sekarang",
"in_n_days": "%(num)s hari dari sekarang",
"in_n_hours": "%(num)s jam dari sekarang",
"in_n_minutes": "%(num)s dari sekarang",
"n_days_ago": "%(num)s hari yang lalu",
"n_hours_ago": "%(num)s jam yang lalu",
"n_minutes_ago": "%(num)s menit yang lalu"
},
"timeline": {
"m.audio": {
"audio_player": "Pemutar audio",
"error_downloading_audio": "Terjadi kesalahan mengunduh audio",
"unnamed_audio": "Audio tidak dinamai"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "Eyða",
"dismiss": "Hunsa",
"explore_rooms": "Kanna spjallrásir",
"pause": "Bið",
"play": "Spila",
"search": "Leita"
},
"left_panel": {
"open_dial_pad": "Opna talnaborð"
},
"time": {
"about_day_ago": "fyrir um degi síðan",
"about_hour_ago": "fyrir um klukkustund síðan",
"about_minute_ago": "fyrir um það bil mínútu síðan",
"few_seconds_ago": "fyrir örfáum sekúndum síðan",
"in_about_day": "eftir um það bil einn dag",
"in_about_hour": "eftir um það bil klukkustund",
"in_about_minute": "eftir um það bil mínútu",
"in_few_seconds": "eftir nokkrar sekúndur",
"in_n_days": "eftir %(num)s daga",
"in_n_hours": "eftir %(num)s klukkustundir",
"in_n_minutes": "eftir %(num)s mínútur",
"n_days_ago": "fyrir %(num)s dögum síðan",
"n_hours_ago": "fyrir %(num)s klukkustundum síðan",
"n_minutes_ago": "fyrir %(num)s mínútum síðan"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Villa við að sækja hljóð",
"unnamed_audio": "Nafnlaust hljóð"
}
}
}
@@ -0,0 +1,38 @@
{
"a11y": {
"seek_bar_label": "Barra di ricerca audio"
},
"action": {
"delete": "Elimina",
"dismiss": "Chiudi",
"explore_rooms": "Esplora stanze",
"pause": "Pausa",
"play": "Riproduci",
"search": "Cerca"
},
"left_panel": {
"open_dial_pad": "Apri tastierino"
},
"time": {
"about_day_ago": "circa un giorno fa",
"about_hour_ago": "circa un'ora fa",
"about_minute_ago": "circa un minuto fa",
"few_seconds_ago": "pochi secondi fa",
"in_about_day": "circa un giorno da adesso",
"in_about_hour": "circa un'ora da adesso",
"in_about_minute": "circa un minuto da adesso",
"in_few_seconds": "pochi secondi da adesso",
"in_n_days": "%(num)s giorni da adesso",
"in_n_hours": "%(num)s ore da adesso",
"in_n_minutes": "%(num)s minuti da adesso",
"n_days_ago": "%(num)s giorni fa",
"n_hours_ago": "%(num)s ore fa",
"n_minutes_ago": "%(num)s minuti fa"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "Errore di scaricamento dell'audio",
"unnamed_audio": "Audio senza nome"
}
}
}
@@ -0,0 +1,35 @@
{
"action": {
"delete": "削除",
"dismiss": "閉じる",
"explore_rooms": "ルームを探す",
"pause": "一時停止",
"play": "再生",
"search": "検索"
},
"left_panel": {
"open_dial_pad": "ダイヤルパッドを開く"
},
"time": {
"about_day_ago": "約1日前",
"about_hour_ago": "約1時間前",
"about_minute_ago": "約1分前",
"few_seconds_ago": "数秒前",
"in_about_day": "今から約1日前",
"in_about_hour": "今から約1時間前",
"in_about_minute": "今から約1分前",
"in_few_seconds": "今から数秒前",
"in_n_days": "今から%(num)s日前",
"in_n_hours": "今から%(num)s時間前",
"in_n_minutes": "今から%(num)s分前",
"n_days_ago": "%(num)s日前",
"n_hours_ago": "%(num)s時間前",
"n_minutes_ago": "%(num)s分前"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "音声をダウンロードする際にエラーが発生しました",
"unnamed_audio": "名前のない音声"
}
}
}
@@ -0,0 +1,32 @@
{
"action": {
"delete": "წაშლა",
"dismiss": "დახურვა",
"explore_rooms": "ოთახების დათავლიერება",
"pause": "პაუზა",
"play": "დაკვრა",
"search": "ძიება"
},
"time": {
"about_day_ago": "დაახლოებით ერთი დღის წინ",
"about_hour_ago": "დაახლოებით ერთი საათის წინ",
"about_minute_ago": "დაახლოებით ერთი წუთის წინ",
"few_seconds_ago": "რამდენიმე წამის წინ",
"in_about_day": "დაახლოებით ერთი დღის შემდეგ",
"in_about_hour": "დაახლოებით ერთი საათის შემდეგ",
"in_about_minute": "დაახლოებით ერთი წუთის შემდეგ",
"in_few_seconds": "რამდენიმე წამის შემდეგ",
"in_n_days": "%(num)sდღეებიდან",
"in_n_hours": "%(num)sსაათის შემდეგ",
"in_n_minutes": "%(num)sწუთის შემდეგ",
"n_days_ago": "%(num)sდღის წინ",
"n_hours_ago": "%(num)sსაათის წინ",
"n_minutes_ago": "%(num)sწუთის წინ"
},
"timeline": {
"m.audio": {
"error_downloading_audio": "შეცდომა აუდიოს ჩამოტვირთვისას",
"unnamed_audio": "უსახელო აუდიო"
}
}
}

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