Compare commits
91 Commits
t3chguy/st
...
element-ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
656e4aed1b | ||
|
|
9cde9af706 | ||
|
|
54765b4473 | ||
|
|
db30bc51a1 | ||
|
|
c8c107405f | ||
|
|
17de66140d | ||
|
|
f3d0fc4d68 | ||
|
|
0b636aec4b | ||
|
|
d0cddc5b66 | ||
|
|
cb0d72fc2f | ||
|
|
9a6be72c10 | ||
|
|
536d6ad360 | ||
|
|
b604a6ea8c | ||
|
|
da4672d715 | ||
|
|
74a919cb65 | ||
|
|
b92101a3da | ||
|
|
5057668705 | ||
|
|
931edd7419 | ||
|
|
044eaf7eb5 | ||
|
|
88c72a1514 | ||
|
|
d06cf09bf0 | ||
|
|
2f8e98242c | ||
|
|
3ff5a511e5 | ||
|
|
6042625198 | ||
|
|
9d79a934bf | ||
|
|
a355292a7f | ||
|
|
24fabfff89 | ||
|
|
0b6ed44390 | ||
|
|
a6ce6dc7ab | ||
|
|
15984455af | ||
|
|
6e4bd564d5 | ||
|
|
aeabf3b188 | ||
|
|
c9d9c421bc | ||
|
|
d7d96b6b8b | ||
|
|
2631b908b6 | ||
|
|
502cc91dfe | ||
|
|
38e5eeea00 | ||
|
|
1ccbdb21e9 | ||
|
|
b1ef099cd6 | ||
|
|
00d46f1c8f | ||
|
|
8e304713a2 | ||
|
|
0899165d9e | ||
|
|
2d9982f9f0 | ||
|
|
b8fd98ab3c | ||
|
|
a27dfa1825 | ||
|
|
a3ece9d902 | ||
|
|
23613ac37e | ||
|
|
195337d865 | ||
|
|
4bb9f2ed7b | ||
|
|
e0ffddf3eb | ||
|
|
386b782f2a | ||
|
|
c23c9dfacb | ||
|
|
5c45ca5e3c | ||
|
|
fbc96f458c | ||
|
|
a7b3337c39 | ||
|
|
7daa8b232b | ||
|
|
7408a83618 | ||
|
|
8a743a9f89 | ||
|
|
3e8f55f883 | ||
|
|
e606b5f5d4 | ||
|
|
a4e4ac45c4 | ||
|
|
2ff51c218f | ||
|
|
76b9c27250 | ||
|
|
13bfb51d8c | ||
|
|
99542c9eda | ||
|
|
849f2c9818 | ||
|
|
8ebfaadeed | ||
|
|
95c3027657 | ||
|
|
1d49a46dd2 | ||
|
|
e5b55db1db | ||
|
|
dabe6722aa | ||
|
|
10a63b3c23 | ||
|
|
9ce515a646 | ||
|
|
79c956388f | ||
|
|
f4dc9048db | ||
|
|
a2c7870810 | ||
|
|
de9a2cc382 | ||
|
|
86bb0ec00d | ||
|
|
954ff0adc0 | ||
|
|
ef605260b5 | ||
|
|
7de5c84b3d | ||
|
|
da5c97f9fa | ||
|
|
bdf0f1dcc3 | ||
|
|
1cf1a0c4ee | ||
|
|
5b5348ec1e | ||
|
|
1df72ce2d0 | ||
|
|
6a960204b3 | ||
|
|
26cd13ae3c | ||
|
|
3793c6daca | ||
|
|
65f0d7930a | ||
|
|
8b914c02d0 |
@@ -266,6 +266,9 @@ module.exports = {
|
||||
parserOptions: {
|
||||
project: ["./playwright/tsconfig.json"],
|
||||
},
|
||||
rules: {
|
||||
"react-hooks/rules-of-hooks": ["off"],
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
|
||||
2
.github/workflows/release.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
ref: master
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
wait-interval: 10
|
||||
check-name: "Docker Buildx (vanilla)"
|
||||
check-name: "Docker Buildx"
|
||||
allowed-conclusions: success
|
||||
|
||||
- name: Wait for debian package
|
||||
|
||||
3
.github/workflows/release_prepare.yml
vendored
@@ -20,6 +20,9 @@ on:
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
# The order is specified bottom-up to avoid any races for allchange
|
||||
REPOS: matrix-js-sdk element-web element-desktop
|
||||
steps:
|
||||
- name: Checkout Element Desktop
|
||||
uses: actions/checkout@v4
|
||||
|
||||
21
.github/workflows/static_analysis.yaml
vendored
@@ -34,27 +34,6 @@ jobs:
|
||||
- name: Typecheck
|
||||
run: "yarn run lint:types"
|
||||
|
||||
- name: Switch js-sdk to release mode
|
||||
working-directory: node_modules/matrix-js-sdk
|
||||
run: |
|
||||
scripts/switch_package_to_release.cjs
|
||||
yarn install
|
||||
yarn run build:compile
|
||||
yarn run build:types
|
||||
|
||||
- name: Typecheck (release mode)
|
||||
run: "yarn run lint:types"
|
||||
|
||||
# Temporary while we directly import matrix-js-sdk/src/* which means we need
|
||||
# certain @types/* packages to make sense of matrix-js-sdk types.
|
||||
#- name: Typecheck (release mode; no yarn link)
|
||||
# if: github.event_name != 'pull_request' && github.ref_name != 'master'
|
||||
# run: |
|
||||
# yarn unlink matrix-js-sdk
|
||||
# yarn add github:matrix-org/matrix-js-sdk#develop
|
||||
# yarn install --force
|
||||
# yarn run lint:types
|
||||
|
||||
i18n_lint:
|
||||
name: "i18n Check"
|
||||
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
|
||||
|
||||
@@ -1 +1 @@
|
||||
20
|
||||
22
|
||||
|
||||
65
CHANGELOG.md
@@ -1,3 +1,68 @@
|
||||
Changes in [1.11.84](https://github.com/element-hq/element-web/releases/tag/v1.11.84) (2024-11-05)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
* Remove abandoned MSC3886, MSC3903, MSC3906 implementations ([#28274](https://github.com/element-hq/element-web/pull/28274)). Contributed by @t3chguy.
|
||||
* Update to React 18 ([#24763](https://github.com/element-hq/element-web/pull/24763)). Contributed by @t3chguy.
|
||||
* Deduplicate icons using Compound ([#28239](https://github.com/element-hq/element-web/pull/28239)). Contributed by @t3chguy.
|
||||
* Replace legacy Tooltips with Compound tooltips ([#28231](https://github.com/element-hq/element-web/pull/28231)). Contributed by @t3chguy.
|
||||
* Deduplicate icons using Compound Design Tokens ([#28219](https://github.com/element-hq/element-web/pull/28219)). Contributed by @t3chguy.
|
||||
* Add reactions to html export ([#28210](https://github.com/element-hq/element-web/pull/28210)). Contributed by @langleyd.
|
||||
* Remove feature\_dehydration ([#28173](https://github.com/element-hq/element-web/pull/28173)). Contributed by @florianduros.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
* Remove upgrade encryption in `DeviceListener` and `SetupEncryptionToast` ([#28299](https://github.com/element-hq/element-web/pull/28299)). Contributed by @florianduros.
|
||||
* Fix 'remove alias' button in room settings ([#28269](https://github.com/element-hq/element-web/pull/28269)). Contributed by @Dev-Gurjar.
|
||||
* Add back unencrypted path in `StopGapWidgetDriver.sendToDevice` ([#28295](https://github.com/element-hq/element-web/pull/28295)). Contributed by @florianduros.
|
||||
* Fix other devices not being decorated as such ([#28279](https://github.com/element-hq/element-web/pull/28279)). Contributed by @t3chguy.
|
||||
* Fix pill contrast in invitation dialog ([#28250](https://github.com/element-hq/element-web/pull/28250)). Contributed by @florianduros.
|
||||
* Close right panel chat when minimising maximised voip widget ([#28241](https://github.com/element-hq/element-web/pull/28241)). Contributed by @t3chguy.
|
||||
* Fix develop changelog parsing ([#28232](https://github.com/element-hq/element-web/pull/28232)). Contributed by @t3chguy.
|
||||
* Fix Ctrl+F shortcut not working with minimised room summary card ([#28223](https://github.com/element-hq/element-web/pull/28223)). Contributed by @t3chguy.
|
||||
* Fix network dropdown missing checkbox \& aria-checked ([#28220](https://github.com/element-hq/element-web/pull/28220)). Contributed by @t3chguy.
|
||||
|
||||
|
||||
Changes in [1.11.83](https://github.com/element-hq/element-web/releases/tag/v1.11.83) (2024-10-29)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
* Enable Element Call by default on release instances ([#28314](https://github.com/element-hq/element-web/pull/28314)). Contributed by @t3chguy.
|
||||
|
||||
|
||||
|
||||
Changes in [1.11.82](https://github.com/element-hq/element-web/releases/tag/v1.11.82) (2024-10-22)
|
||||
==================================================================================================
|
||||
## ✨ Features
|
||||
|
||||
* Deduplicate more icons using Compound Design Tokens ([#132](https://github.com/element-hq/matrix-react-sdk/pull/132)). Contributed by @t3chguy.
|
||||
* Always show link new device flow even if unsupported ([#147](https://github.com/element-hq/matrix-react-sdk/pull/147)). Contributed by @t3chguy.
|
||||
* Update design of files list in right panel ([#144](https://github.com/element-hq/matrix-react-sdk/pull/144)). Contributed by @t3chguy.
|
||||
* Remove feature\_dehydration ([#138](https://github.com/element-hq/matrix-react-sdk/pull/138)). Contributed by @florianduros.
|
||||
* Upgrade emojibase-bindings and remove local handling of emoticon variations ([#127](https://github.com/element-hq/matrix-react-sdk/pull/127)). Contributed by @langleyd.
|
||||
* Add support for rendering media captions ([#43](https://github.com/element-hq/matrix-react-sdk/pull/43)). Contributed by @tulir.
|
||||
* Replace composer icons with Compound variants ([#123](https://github.com/element-hq/matrix-react-sdk/pull/123)). Contributed by @t3chguy.
|
||||
* Tweak default right panel size to be 320px except for maximised widgets at 420px ([#110](https://github.com/element-hq/matrix-react-sdk/pull/110)). Contributed by @t3chguy.
|
||||
* Add a pinned message badge under a pinned message ([#118](https://github.com/element-hq/matrix-react-sdk/pull/118)). Contributed by @florianduros.
|
||||
* Ditch right panel tabs and re-add close button ([#99](https://github.com/element-hq/matrix-react-sdk/pull/99)). Contributed by @t3chguy.
|
||||
* Force verification even for refreshed clients ([#44](https://github.com/element-hq/matrix-react-sdk/pull/44)). Contributed by @dbkr.
|
||||
* Update emoji text, border and background colour in timeline ([#119](https://github.com/element-hq/matrix-react-sdk/pull/119)). Contributed by @florianduros.
|
||||
* Disable ICE fallback based on well-known configuration ([#111](https://github.com/element-hq/matrix-react-sdk/pull/111)). Contributed by @t3chguy.
|
||||
* Remove legacy room header and promote beta room header ([#105](https://github.com/element-hq/matrix-react-sdk/pull/105)). Contributed by @t3chguy.
|
||||
* Respect `io.element.jitsi` `useFor1To1Calls` in well-known ([#112](https://github.com/element-hq/matrix-react-sdk/pull/112)). Contributed by @t3chguy.
|
||||
* Use Compound close icon in favour of mishmash of x/close icons ([#108](https://github.com/element-hq/matrix-react-sdk/pull/108)). Contributed by @t3chguy.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
* Correct typo in option documentation ([#28148](https://github.com/element-hq/element-web/pull/28148)). Contributed by @AndrewKvalheim.
|
||||
* Revert #124 and #135 ([#139](https://github.com/element-hq/matrix-react-sdk/pull/139)). Contributed by @dbkr.
|
||||
* Add aria-label to e2e icon ([#136](https://github.com/element-hq/matrix-react-sdk/pull/136)). Contributed by @florianduros.
|
||||
* Fix bell icons on room list hover being black squares ([#135](https://github.com/element-hq/matrix-react-sdk/pull/135)). Contributed by @dbkr.
|
||||
* Fix vertical overflow on the mobile register screen ([#137](https://github.com/element-hq/matrix-react-sdk/pull/137)). Contributed by @langleyd.
|
||||
* Allow to unpin redacted event ([#98](https://github.com/element-hq/matrix-react-sdk/pull/98)). Contributed by @florianduros.
|
||||
|
||||
|
||||
|
||||
Changes in [1.11.81](https://github.com/element-hq/element-web/releases/tag/v1.11.81) (2024-10-15)
|
||||
==================================================================================================
|
||||
This release fixes High severity vulnerability CVE-2024-47771 / GHSA-963w-49j9-gxj6
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Builder
|
||||
FROM --platform=$BUILDPLATFORM node:20-bullseye as builder
|
||||
FROM --platform=$BUILDPLATFORM node:22-bullseye as builder
|
||||
|
||||
# Support custom branch of the js-sdk. This also helps us build images of element-web develop.
|
||||
ARG USE_CUSTOM_SDKS=false
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
{
|
||||
"src/components/views/auth/AuthFooter.tsx": "src/components/views/auth/VectorAuthFooter.tsx",
|
||||
"src/components/views/auth/AuthHeaderLogo.tsx": "src/components/views/auth/VectorAuthHeaderLogo.tsx",
|
||||
"src/components/views/auth/AuthPage.tsx": "src/components/views/auth/VectorAuthPage.tsx"
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -11,8 +11,8 @@ Customisations will be removed from the codebase in a future release.
|
||||
Element Web and the React SDK support "customisation points" that can be used to
|
||||
easily add custom logic specific to a particular deployment of Element Web.
|
||||
|
||||
An example of this is the [security customisations
|
||||
module](https://github.com/element-hq/element-web/blob/develop/src/customisations/Security.ts).
|
||||
An example of this is the [media customisations
|
||||
module](https://github.com/element-hq/element-web/blob/develop/src/customisations/Media.ts).
|
||||
This module in the React SDK only defines some empty functions and their types:
|
||||
it does not do anything by default.
|
||||
|
||||
@@ -21,14 +21,14 @@ Web so that you can add your own code. Even though the default module is part of
|
||||
the React SDK, you can still override it from the Element Web layer:
|
||||
|
||||
1. Copy the default customisation module to
|
||||
`element-web/src/customisations/YourNameSecurity.ts`
|
||||
`element-web/src/customisations/YourNameMedia.ts`
|
||||
2. Edit customisations points and make sure export the ones you actually want to
|
||||
activate
|
||||
3. Create/add an entry to `customisations.json` next to the webpack config:
|
||||
|
||||
```json
|
||||
{
|
||||
"src/customisations/Security.ts": "src/customisations/YourNameSecurity.ts"
|
||||
"src/customisations/Media.ts": "src/customisations/YourNameMedia.ts"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -41,7 +41,15 @@ The Docker image can be used to serve element-web as a web server. The easiest w
|
||||
it is to use the prebuilt image:
|
||||
|
||||
```bash
|
||||
docker run -p 80:80 vectorim/element-web
|
||||
docker run --rm -p 127.0.0.1:80:80 vectorim/element-web
|
||||
```
|
||||
|
||||
A server can also be made available to clients outside the local host by omitting the
|
||||
explicit local address as described in
|
||||
[docker run documentation](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose):
|
||||
|
||||
```bash
|
||||
docker run --rm -p 80:80 vectorim/element-web
|
||||
```
|
||||
|
||||
To supply your own custom `config.json`, map a volume to `/app/config.json`. For example,
|
||||
@@ -49,7 +57,7 @@ if your custom config was located at `/etc/element-web/config.json` then your Do
|
||||
would be:
|
||||
|
||||
```bash
|
||||
docker run -p 80:80 -v /etc/element-web/config.json:/app/config.json vectorim/element-web
|
||||
docker run --rm -p 127.0.0.1:80:80 -v /etc/element-web/config.json:/app/config.json vectorim/element-web
|
||||
```
|
||||
|
||||
To build the image yourself:
|
||||
|
||||
@@ -29,7 +29,7 @@ default theme, you would use `default_theme: "custom-Electric Blue"`.
|
||||
|
||||
e.g. in config.json:
|
||||
|
||||
```
|
||||
```json5
|
||||
"setting_defaults": {
|
||||
"custom_themes": [
|
||||
{
|
||||
@@ -59,6 +59,10 @@ e.g. in config.json:
|
||||
"timeline-text-color": "#2e2f32",
|
||||
"timeline-text-secondary-color": "#61708b",
|
||||
"timeline-highlights-color": "#f3f8fd",
|
||||
|
||||
// These should both be 8 values long
|
||||
"username-colors": ["#ff0000", /*...*/],
|
||||
"avatar-background-colors": ["#cc0000", /*...*/]
|
||||
},
|
||||
"compound": {
|
||||
"--cpd-color-icon-accent-tertiary": "var(--cpd-color-blue-800)",
|
||||
|
||||
@@ -46,5 +46,13 @@
|
||||
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx",
|
||||
"setting_defaults": {
|
||||
"RustCrypto.staged_rollout_percent": 60
|
||||
},
|
||||
"features": {
|
||||
"feature_video_rooms": true,
|
||||
"feature_group_calls": true,
|
||||
"feature_element_call_video_rooms": true
|
||||
},
|
||||
"element_call": {
|
||||
"url": "https://call.element.io"
|
||||
}
|
||||
}
|
||||
|
||||
20
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-web",
|
||||
"version": "1.11.81",
|
||||
"version": "1.11.84",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "New Vector Ltd.",
|
||||
"repository": {
|
||||
@@ -84,14 +84,14 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@formatjs/intl-segmenter": "^11.5.7",
|
||||
"@matrix-org/analytics-events": "^0.26.0",
|
||||
"@matrix-org/analytics-events": "^0.29.0",
|
||||
"@matrix-org/emojibase-bindings": "^1.3.3",
|
||||
"@vector-im/matrix-wysiwyg": "2.37.13",
|
||||
"@matrix-org/react-sdk-module-api": "^2.4.0",
|
||||
"@matrix-org/spec": "^1.7.0",
|
||||
"@sentry/browser": "^8.0.0",
|
||||
"@vector-im/compound-design-tokens": "^1.8.0",
|
||||
"@vector-im/compound-web": "^7.1.0",
|
||||
"@vector-im/matrix-wysiwyg": "2.37.13",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"@zxcvbn-ts/language-common": "^3.0.4",
|
||||
"@zxcvbn-ts/language-en": "^3.0.2",
|
||||
@@ -114,8 +114,8 @@
|
||||
"highlight.js": "^11.3.1",
|
||||
"html-entities": "^2.0.0",
|
||||
"is-ip": "^3.1.0",
|
||||
"jsrsasign": "^11.0.0",
|
||||
"js-xxhash": "^4.0.0",
|
||||
"jsrsasign": "^11.0.0",
|
||||
"jszip": "^3.7.0",
|
||||
"katex": "^0.16.0",
|
||||
"linkify-element": "4.1.3",
|
||||
@@ -126,8 +126,8 @@
|
||||
"maplibre-gl": "^2.0.0",
|
||||
"matrix-encrypt-attachment": "^1.0.3",
|
||||
"matrix-events-sdk": "0.0.1",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||
"matrix-widget-api": "^1.9.0",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8e65c13d5019eb215fa99c86ddef463d9c383115",
|
||||
"matrix-widget-api": "^1.10.0",
|
||||
"memoize-one": "^6.0.0",
|
||||
"oidc-client-ts": "^3.0.1",
|
||||
"opus-recorder": "^8.0.3",
|
||||
@@ -148,7 +148,7 @@
|
||||
"tar-js": "^0.3.0",
|
||||
"temporal-polyfill": "^0.2.5",
|
||||
"ua-parser-js": "^1.0.2",
|
||||
"uuid": "^10.0.0",
|
||||
"uuid": "^11.0.0",
|
||||
"what-input": "^5.2.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -208,7 +208,7 @@
|
||||
"@types/qrcode": "^1.3.5",
|
||||
"@types/react": "18.3.3",
|
||||
"@types/react-beautiful-dnd": "^13.0.0",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@types/react-transition-group": "^4.4.0",
|
||||
"@types/sanitize-html": "2.13.0",
|
||||
"@types/sdp-transform": "^2.4.6",
|
||||
@@ -219,7 +219,7 @@
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"axe-core": "4.10.0",
|
||||
"axe-core": "4.10.2",
|
||||
"babel-jest": "^29.0.0",
|
||||
"babel-loader": "^9.0.0",
|
||||
"babel-plugin-jsx-remove-data-test-id": "^3.0.0",
|
||||
@@ -242,7 +242,7 @@
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-matrix-org": "^2.0.2",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"express": "^4.18.2",
|
||||
"fake-indexeddb": "^6.0.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/playwright:v1.48.0-jammy
|
||||
FROM mcr.microsoft.com/playwright:v1.48.2-jammy
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
|
||||
@@ -51,6 +51,6 @@ test.describe("Invisible cryptography", () => {
|
||||
/* should show an error for a message from a previously verified device */
|
||||
await bobSecondDevice.sendMessage(testRoomId, "test encrypted from user that was previously verified");
|
||||
const lastTile = page.locator(".mx_EventTile_last");
|
||||
await expect(lastTile).toContainText("Verified identity has changed");
|
||||
await expect(lastTile).toContainText("Sender's verified identity has changed");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,6 +60,11 @@ test.describe("User verification", () => {
|
||||
// Accept
|
||||
await toast.getByRole("button", { name: "Verify User" }).click();
|
||||
|
||||
// Wait for the QR code to be rendered. If we don't do this, then the QR code can be rendered just as
|
||||
// Playwright tries to click the "Verify by emoji" button, which seems to make it miss the button.
|
||||
// (richvdh: I thought Playwright was supposed to be resilient to such things, but empirically not.)
|
||||
await expect(page.getByAltText("QR Code")).toBeVisible();
|
||||
|
||||
// request verification by emoji
|
||||
await page.locator("#mx_RightPanel").getByRole("button", { name: "Verify by emoji" }).click();
|
||||
|
||||
@@ -101,13 +106,20 @@ test.describe("User verification", () => {
|
||||
const toast = await toasts.getToast("Verification requested");
|
||||
await toast.getByRole("button", { name: "Verify User" }).click();
|
||||
|
||||
// Wait for the QR code to be rendered. If we don't do this, then the QR code can be rendered just as
|
||||
// Playwright tries to click the "Verify by emoji" button, which seems to make it miss the button.
|
||||
// (richvdh: I thought Playwright was supposed to be resilient to such things, but empirically not.)
|
||||
await expect(page.getByAltText("QR Code")).toBeVisible();
|
||||
|
||||
// request verification by emoji
|
||||
await page.locator("#mx_RightPanel").getByRole("button", { name: "Verify by emoji" }).click();
|
||||
|
||||
/* on the bot side, wait for the verifier to exist ... */
|
||||
const botVerifier = await awaitVerifier(bobVerificationRequest);
|
||||
// ... confirm ...
|
||||
botVerifier.evaluate((verifier) => verifier.verify()).catch(() => {});
|
||||
// ... and confirm. We expect the verification to fail; we catch the error on the DOM side
|
||||
// to stop playwright marking the evaluate as failing in the UI.
|
||||
const botVerification = botVerifier.evaluate((verifier) => verifier.verify().catch(() => {}));
|
||||
|
||||
// ... and abort the verification
|
||||
await page.getByRole("button", { name: "They don't match" }).click();
|
||||
|
||||
@@ -115,6 +127,8 @@ test.describe("User verification", () => {
|
||||
await expect(dialog.getByText("Your messages are not secure")).toBeVisible();
|
||||
await dialog.getByRole("button", { name: "OK" }).click();
|
||||
await expect(dialog).not.toBeVisible();
|
||||
|
||||
await botVerification;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import { randB64Bytes } from "../../utils/rand";
|
||||
// Docker tag to use for synapse docker image.
|
||||
// We target a specific digest as every now and then a Synapse update will break our CI.
|
||||
// This digest is updated by the playwright-image-updates.yaml workflow periodically.
|
||||
const DOCKER_TAG = "develop@sha256:85dc2cf25f45ee91fd87efa0ddf2220a5933d212ed656886d5f3832ae3a9ddaf";
|
||||
const DOCKER_TAG = "develop@sha256:b90c4e10abfc6bb4fb9301d5b148ab7e1ab752298624a705e84e7e1ad6037d08";
|
||||
|
||||
async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise<Omit<HomeserverConfig, "dockerUrl">> {
|
||||
const templateDir = path.join(__dirname, "templates", opts.template);
|
||||
|
||||
@@ -102,3 +102,5 @@ experimental_features:
|
||||
# messages > non-joined historical messages.
|
||||
# Can be removed after Synapse enables it by default
|
||||
msc4115_membership_on_events: true
|
||||
|
||||
enable_authenticated_media: true
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -186,7 +186,7 @@ input[type="search"].mx_textinput_icon {
|
||||
/* FIXME THEME - Tint by CSS rather than referencing a duplicate asset */
|
||||
input[type="text"].mx_textinput_icon.mx_textinput_search,
|
||||
input[type="search"].mx_textinput_icon.mx_textinput_search {
|
||||
background-image: url("$(res)/img/feather-customised/search-input.svg");
|
||||
background-image: url("@vector-im/compound-design-tokens/icons/search.svg");
|
||||
}
|
||||
|
||||
/* dont search UI as not all browsers support it, */
|
||||
|
||||
@@ -282,11 +282,11 @@
|
||||
@import "./views/rooms/_EmojiButton.pcss";
|
||||
@import "./views/rooms/_EntityTile.pcss";
|
||||
@import "./views/rooms/_EventBubbleTile.pcss";
|
||||
@import "./views/rooms/_EventPreview.pcss";
|
||||
@import "./views/rooms/_EventTile.pcss";
|
||||
@import "./views/rooms/_HistoryTile.pcss";
|
||||
@import "./views/rooms/_IRCLayout.pcss";
|
||||
@import "./views/rooms/_JumpToBottomButton.pcss";
|
||||
@import "./views/rooms/_LegacyRoomHeader.pcss";
|
||||
@import "./views/rooms/_LinkPreviewGroup.pcss";
|
||||
@import "./views/rooms/_LinkPreviewWidget.pcss";
|
||||
@import "./views/rooms/_LiveContentSummary.pcss";
|
||||
|
||||
@@ -32,8 +32,8 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_DeviceExpandDetailsButton_icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
|
||||
transition: all 0.3s;
|
||||
transform: var(--icon-transform);
|
||||
|
||||
@@ -25,7 +25,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: currentColor;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
mask-size: 100%;
|
||||
mask-repeat: no-repeat;
|
||||
float: right;
|
||||
|
||||
@@ -125,7 +125,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
padding-left: 34px; /* 28px from above, but +6px to account for the wider icon */
|
||||
|
||||
&::before {
|
||||
mask-image: url("$(res)/img/element-icons/retry.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/restart.svg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
&::before {
|
||||
background-color: $info-plinth-fg-color;
|
||||
mask: url("$(res)/img/feather-customised/search-input.svg");
|
||||
mask: url("@vector-im/compound-design-tokens/icons/search.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: 50px;
|
||||
@@ -181,11 +181,6 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
}
|
||||
|
||||
/* Rooms with immersive content */
|
||||
.mx_RoomView_immersive .mx_LegacyRoomHeader_wrapper {
|
||||
border: unset;
|
||||
}
|
||||
|
||||
.mx_RoomView_inCall {
|
||||
.mx_RoomView_statusAreaBox_line {
|
||||
margin-top: 2px;
|
||||
|
||||
@@ -77,7 +77,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 0;
|
||||
background-image: url("$(res)/img/element-icons/warning-badge.svg");
|
||||
background-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
background-color: $tertiary-content;
|
||||
mask-size: 16px;
|
||||
transform: rotate(270deg);
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
|
||||
&.mx_SpaceHierarchy_subspace_toggle_shown::before {
|
||||
|
||||
@@ -48,7 +48,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $background;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-size: 20px;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $tertiary-content;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
|
||||
.mx_SpaceButton_icon {
|
||||
|
||||
@@ -29,7 +29,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_MessageContextMenu_iconReport::before {
|
||||
mask-image: url("$(res)/img/element-icons/warning-badge.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||
}
|
||||
|
||||
.mx_MessageContextMenu_iconLink::before {
|
||||
@@ -61,7 +61,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_MessageContextMenu_iconResend::before {
|
||||
mask-image: url("$(res)/img/element-icons/retry.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/restart.svg");
|
||||
}
|
||||
|
||||
.mx_MessageContextMenu_iconSource::before {
|
||||
|
||||
@@ -125,7 +125,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-image: url("$(res)/img/element-icons/retry.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/restart.svg");
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
left: 0;
|
||||
|
||||
@@ -36,9 +36,24 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_AnalyticsLearnMore_bullets li {
|
||||
background: url("$(res)/img/tick-circle.svg") no-repeat;
|
||||
list-style-type: none;
|
||||
padding: 2px 0px 20px 32px;
|
||||
padding: 2px 0 0 32px;
|
||||
margin-bottom: 20px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: #0dbd8b;
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/check-circle.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
&.mx_AccessSecretStorageDialog_resetBadge::before {
|
||||
/* The image isn't capable of masking, so we use a background instead. */
|
||||
background-image: url("$(res)/img/element-icons/warning-badge.svg");
|
||||
background-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||
background-size: 24px;
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
width: 16px;
|
||||
left: 0;
|
||||
top: 2px; /* alignment */
|
||||
background-image: url("$(res)/img/element-icons/warning-badge.svg");
|
||||
background-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,13 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_Dropdown_arrow {
|
||||
width: 10px;
|
||||
height: 6px;
|
||||
padding-right: 9px;
|
||||
mask: url("$(res)/img/feather-customised/dropdown-arrow.svg");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
mask: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: 18px;
|
||||
background: $primary-content;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,9 @@ Please see LICENSE files in the repository root for full details.
|
||||
.mx_EditableItem_delete {
|
||||
@mixin customisedCancelButton;
|
||||
order: 3;
|
||||
margin-right: 5px;
|
||||
vertical-align: middle;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background-color: $alert;
|
||||
mask-size: 100%;
|
||||
}
|
||||
@@ -42,7 +41,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
.mx_EditableItem_item {
|
||||
flex: auto 1 0;
|
||||
order: 1;
|
||||
width: calc(100% - 14px); /* leave space for the remove button */
|
||||
width: calc(100% - 28px); /* leave space for the remove button */
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@@ -51,12 +51,15 @@ Please see LICENSE files in the repository root for full details.
|
||||
.mx_Field_select::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 10px;
|
||||
width: 10px;
|
||||
height: 6px;
|
||||
mask: url("$(res)/img/feather-customised/dropdown-arrow.svg");
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 4px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
mask: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
background-color: $primary-content;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -29,5 +29,5 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
|
||||
.mx_InfoTooltip_icon_warning::before {
|
||||
mask-image: url("$(res)/img/element-icons/warning.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/error.svg");
|
||||
}
|
||||
|
||||
@@ -30,6 +30,6 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
background-color: var(--cpd-color-icon-secondary);
|
||||
}
|
||||
|
||||
@@ -11,22 +11,11 @@ Please see LICENSE files in the repository root for full details.
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Formatting for the "Verified identity has changed" error */
|
||||
.mx_DecryptionFailureVerifiedIdentityChanged > span {
|
||||
/* Show it in red */
|
||||
color: var(--cpd-color-text-critical-primary);
|
||||
background-color: var(--cpd-color-bg-critical-subtle);
|
||||
|
||||
/* With a red border */
|
||||
border: 1px solid var(--cpd-color-border-critical-subtle);
|
||||
border-radius: $font-16px;
|
||||
|
||||
/* Some space inside the border */
|
||||
padding: var(--cpd-space-1x) var(--cpd-space-3x) var(--cpd-space-1x) var(--cpd-space-2x);
|
||||
|
||||
/* some space between the (!) icon and text */
|
||||
/* Formatting for errors due to sender trust requirement failures */
|
||||
.mx_DecryptionFailureSenderTrustRequirement > span {
|
||||
/* some space between the (/) icon and text */
|
||||
display: inline-flex;
|
||||
gap: var(--cpd-space-2x);
|
||||
gap: var(--cpd-space-1x);
|
||||
|
||||
/* Center vertically */
|
||||
align-items: center;
|
||||
|
||||
@@ -108,6 +108,10 @@ Please see LICENSE files in the repository root for full details.
|
||||
color: var(--cpd-color-icon-primary);
|
||||
}
|
||||
|
||||
&.mx_MessageActionBar_retryButton {
|
||||
--MessageActionBar-icon-size: 16px;
|
||||
}
|
||||
|
||||
&.mx_MessageActionBar_downloadButton {
|
||||
--MessageActionBar-icon-size: 14px;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: currentColor;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
mask-size: 100%;
|
||||
mask-repeat: no-repeat;
|
||||
float: right;
|
||||
|
||||
@@ -26,9 +26,9 @@ Please see LICENSE files in the repository root for full details.
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
padding: 4px;
|
||||
mask-image: url("$(res)/img/minimise.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-left.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: 7px center;
|
||||
mask-position: center;
|
||||
background-color: $header-panel-text-primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,9 @@ Please see LICENSE files in the repository root for full details.
|
||||
position: absolute;
|
||||
top: calc(50% - 8px); /* center */
|
||||
right: -8px;
|
||||
mask: url("$(res)/img/member_chevron.png");
|
||||
mask: url("@vector-im/compound-design-tokens/icons/chevron-right.svg");
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-color: $header-panel-text-primary-color;
|
||||
|
||||
18
res/css/views/rooms/_EventPreview.pcss
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
.mx_EventPreview {
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
.mx_EventPreview_prefix {
|
||||
font: var(--cpd-font-body-sm-semibold);
|
||||
}
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--RoomHeader-indicator-dot-size: 8px;
|
||||
--RoomHeader-indicator-dot-offset: -3px;
|
||||
--RoomHeader-indicator-pulseColor: $alert;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader {
|
||||
flex: 0 0 50px;
|
||||
border-bottom: 1px solid $primary-hairline-color;
|
||||
background-color: $background;
|
||||
|
||||
.mx_LegacyRoomHeader_icon {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
|
||||
&.mx_LegacyRoomHeader_icon_video {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
background-color: $secondary-content;
|
||||
mask-image: url("$(res)/img/element-icons/call/video-call.svg");
|
||||
mask-size: 100%;
|
||||
}
|
||||
|
||||
&.mx_E2EIcon {
|
||||
margin: 0;
|
||||
height: 100%; /* To give the tooltip room to breathe */
|
||||
}
|
||||
}
|
||||
|
||||
.mx_CallDuration {
|
||||
margin-top: calc(($font-15px - $font-13px) / 2); /* To align with the name */
|
||||
font-size: $font-13px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_wrapper {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
padding: 10px 20px 9px 16px;
|
||||
border-bottom: 1px solid $separator;
|
||||
|
||||
.mx_InviteOnlyIcon_large {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mx_BetaCard_betaPill {
|
||||
margin-right: $spacing-8;
|
||||
}
|
||||
|
||||
/* The container of E2EIcon in the legacy header needs to have its height set */
|
||||
& > span {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_name {
|
||||
flex: 0 1 auto;
|
||||
overflow: hidden;
|
||||
color: $primary-content;
|
||||
font: var(--cpd-font-heading-sm-semibold);
|
||||
font-weight: var(--cpd-font-weight-semibold);
|
||||
min-height: 24px;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
margin: 0 3px;
|
||||
padding: 1px 4px;
|
||||
display: flex;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: $quinary-content;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_nametext {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_chevron {
|
||||
align-self: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
mask-position: center;
|
||||
mask-size: 20px;
|
||||
mask-repeat: no-repeat;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
background-color: $tertiary-content;
|
||||
}
|
||||
|
||||
&.mx_LegacyRoomHeader_name--textonly {
|
||||
cursor: unset;
|
||||
|
||||
&:hover {
|
||||
background-color: unset;
|
||||
}
|
||||
}
|
||||
|
||||
&[aria-expanded="true"] {
|
||||
background-color: $separator;
|
||||
|
||||
.mx_LegacyRoomHeader_chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_settingsHint {
|
||||
color: $settings-grey-fg-color !important;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_searchStatus {
|
||||
font-weight: normal;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.mx_RoomTopic {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_topic {
|
||||
$lines: 2;
|
||||
|
||||
flex: 1;
|
||||
color: $secondary-content;
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
line-height: 1rem;
|
||||
max-height: calc(1rem * $lines);
|
||||
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: $lines; /* See: https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp */
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_topic .mx_Emoji {
|
||||
/* Undo font size increase to prevent vertical cropping and ensure the same size */
|
||||
/* as in plain text emojis */
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_avatar {
|
||||
flex: 0;
|
||||
margin: 0 7px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_button_unreadIndicator_bg {
|
||||
position: absolute;
|
||||
right: var(--RoomHeader-indicator-dot-offset);
|
||||
top: var(--RoomHeader-indicator-dot-offset);
|
||||
margin: 4px;
|
||||
width: var(--RoomHeader-indicator-dot-size);
|
||||
height: var(--RoomHeader-indicator-dot-size);
|
||||
border-radius: 50%;
|
||||
transform: scale(1.6);
|
||||
transform-origin: center center;
|
||||
background: $background;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_button_unreadIndicator {
|
||||
position: absolute;
|
||||
right: var(--RoomHeader-indicator-dot-offset);
|
||||
top: var(--RoomHeader-indicator-dot-offset);
|
||||
margin: 4px;
|
||||
|
||||
&.mx_Indicator_highlight {
|
||||
background: var(--cpd-color-icon-critical-primary);
|
||||
box-shadow: var(--cpd-color-icon-critical-primary);
|
||||
}
|
||||
|
||||
&.mx_Indicator_notification {
|
||||
background: var(--cpd-color-icon-success-primary);
|
||||
box-shadow: var(--cpd-color-icon-success-primary);
|
||||
}
|
||||
|
||||
&.mx_Indicator_activity {
|
||||
background: var(--cpd-color-icon-primary);
|
||||
box-shadow: var(--cpd-color-icon-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_forgetButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/leave.svg");
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_appsButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/room/apps.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_appsButton_highlight::before {
|
||||
background-color: $accent;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_searchButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/room/search-inset.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_inviteButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/room/invite.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_voiceCallButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/call/voice-call.svg");
|
||||
|
||||
/* The call button SVG is padded slightly differently, so match it up to the size */
|
||||
/* of the other icons */
|
||||
mask-size: 20px;
|
||||
mask-position: center;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_videoCallButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/call/video-call.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_layoutButton--freedom::before,
|
||||
.mx_LegacyRoomHeader_freedomIcon::before {
|
||||
mask-image: url("$(res)/img/element-icons/call/freedom.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_layoutButton--spotlight::before,
|
||||
.mx_LegacyRoomHeader_spotlightIcon::before {
|
||||
mask-image: url("$(res)/img/element-icons/call/spotlight.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_closeButton {
|
||||
&::before {
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/close.svg");
|
||||
mask-size: 20px;
|
||||
mask-position: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: unset; /* remove background color on hover */
|
||||
|
||||
&::before {
|
||||
background-color: $icon-button-color; /* set the default background color */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_minimiseButton::before {
|
||||
mask-image: url("$(res)/img/element-icons/reduce.svg");
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader_layoutMenu .mx_IconizedContextMenu_icon::before {
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: block;
|
||||
mask-position: center;
|
||||
mask-size: 20px;
|
||||
mask-repeat: no-repeat;
|
||||
background: $primary-content;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
.mx_LegacyRoomHeader_wrapper {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mx_LegacyRoomHeader {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .mx_LinkPreviewGroup_hide img,
|
||||
&:hover .mx_LinkPreviewGroup_hide svg,
|
||||
.mx_LinkPreviewGroup_hide:focus-visible:focus svg {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -81,15 +81,7 @@
|
||||
|
||||
.mx_PinnedMessageBanner_message {
|
||||
grid-area: message;
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
line-height: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
.mx_PinnedMessageBanner_prefix {
|
||||
font: var(--cpd-font-body-sm-semibold);
|
||||
}
|
||||
}
|
||||
|
||||
.mx_PinnedMessageBanner_redactedMessage {
|
||||
|
||||
@@ -88,3 +88,8 @@ Please see LICENSE files in the repository root for full details.
|
||||
.mx_RoomHeader .mx_BaseAvatar {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mx_RoomHeader_videoCallOption {
|
||||
/* Workaround for https://github.com/element-hq/compound/issues/331 */
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $tertiary-content;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
|
||||
&[aria-expanded="true"] {
|
||||
|
||||
@@ -160,7 +160,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: var(--cpd-color-icon-secondary);
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
|
||||
&.mx_RoomSublist_collapseBtn_collapsed::before {
|
||||
@@ -276,7 +276,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
.mx_RoomSublist_showMoreButtonChevron,
|
||||
.mx_RoomSublist_showLessButtonChevron {
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
|
||||
.mx_RoomSublist_showLessButtonChevron {
|
||||
|
||||
@@ -53,11 +53,11 @@ Please see LICENSE files in the repository root for full details.
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: $spacing-12;
|
||||
right: var(--cpd-space-1x);
|
||||
transform: translateY(-50%);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
mask-image: url("$(res)/img/compound/chevron-right-12px.svg");
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-right.svg");
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
|
||||
@@ -67,7 +67,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: 2px 3px;
|
||||
mask-size: 24px;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
&::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
mask-image: url("$(res)/img/feather-customised/chevron-down.svg");
|
||||
mask-image: url("@vector-im/compound-design-tokens/icons/chevron-down.svg");
|
||||
mask-size: 20px;
|
||||
mask-position: center;
|
||||
background-color: $call-primary-content;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="17px" height="15px" viewBox="-1 -1 16 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon_camera</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="06a-Room-settings" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="06_4-Room-settings-admin" sketch:type="MSArtboardGroup" transform="translate(-248.000000, -71.000000)" fill="#454545">
|
||||
<path d="M255.5,76.25 C256.119795,76.25 256.649737,76.4700499 257.089844,76.9101562 C257.52995,77.3502626 257.75,77.8802052 257.75,78.5 C257.75,79.1197948 257.52995,79.6497374 257.089844,80.0898438 C256.649737,80.5299501 256.119795,80.75 255.5,80.75 C254.880205,80.75 254.350263,80.5299501 253.910156,80.0898438 C253.47005,79.6497374 253.25,79.1197948 253.25,78.5 C253.25,77.8802052 253.47005,77.3502626 253.910156,76.9101562 C254.350263,76.4700499 254.880205,76.25 255.5,76.25 L255.5,76.25 Z M261,73 C261.552086,73 262.023436,73.1953105 262.414062,73.5859375 C262.804689,73.9765645 263,74.4479139 263,75 L263,82 C263,82.5520861 262.804689,83.0234355 262.414062,83.4140625 C262.023436,83.8046895 261.552086,84 261,84 L250,84 C249.447914,84 248.976564,83.8046895 248.585938,83.4140625 C248.195311,83.0234355 248,82.5520861 248,82 L248,75 C248,74.4479139 248.195311,73.9765645 248.585938,73.5859375 C248.976564,73.1953105 249.447914,73 250,73 L251.75,73 L252.148438,71.9375 C252.247396,71.6822904 252.428384,71.4622405 252.691406,71.2773438 C252.954428,71.092447 253.223957,71 253.5,71 L257.5,71 C257.776043,71 258.045572,71.092447 258.308594,71.2773438 C258.571616,71.4622405 258.752604,71.6822904 258.851562,71.9375 L259.25,73 L261,73 Z M255.5,82 C256.463546,82 257.287757,81.6575555 257.972656,80.9726562 C258.657556,80.287757 259,79.4635465 259,78.5 C259,77.5364535 258.657556,76.712243 257.972656,76.0273438 C257.287757,75.3424445 256.463546,75 255.5,75 C254.536454,75 253.712243,75.3424445 253.027344,76.0273438 C252.342444,76.712243 252,77.5364535 252,78.5 C252,79.4635465 252.342444,80.287757 253.027344,80.9726562 C253.712243,81.6575555 254.536454,82 255.5,82 L255.5,82 Z" id="icon_camera" sketch:type="MSShapeGroup"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1692_80)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.96967 10.7197C3.67678 10.4268 3.67601 9.95114 3.96795 9.6573L7.66823 5.933L3.95592 2.22069C3.66303 1.92779 3.66226 1.45215 3.9542 1.15831C4.24615 0.864473 4.72025 0.863706 5.01315 1.1566L9.25579 5.39924C9.54868 5.69213 9.54945 6.16777 9.2575 6.46161L5.02861 10.718C4.73667 11.0118 4.26256 11.0126 3.96967 10.7197Z" fill="#737D8C"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1692_80">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 629 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.02266 2.96455C5.11589 2.10004 6.49866 1.5835 8 1.5835C11.3187 1.5835 14.049 4.10294 14.3825 7.3335H15.6723C15.9336 7.3335 16.0894 7.62498 15.9445 7.8426L13.9388 10.8543C13.8094 11.0488 13.524 11.0488 13.3945 10.8543L11.3888 7.8426C11.2439 7.62498 11.3997 7.3335 11.661 7.3335H12.8719C12.5465 4.93343 10.4893 3.0835 8 3.0835C6.84828 3.0835 5.79092 3.47857 4.95308 4.14112C4.8969 4.18555 4.84851 4.22129 4.81295 4.24673C4.7951 4.2595 4.78032 4.26979 4.7692 4.27743L4.75529 4.28689L4.75051 4.2901L4.74868 4.29132L4.74791 4.29183L4.74756 4.29206L4.74739 4.29217L4.74731 4.29223L4.33341 3.66694L4.74723 4.29228C4.40181 4.52087 3.93648 4.42616 3.70788 4.08073C3.47976 3.736 3.57362 3.27185 3.91734 3.04277L3.92021 3.04081L3.94013 3.02682C3.95912 3.01323 3.988 2.99197 4.02266 2.96455ZM3.12815 8.66683H4.33901C4.60027 8.66683 4.7561 8.37534 4.61118 8.15772L2.60551 5.14598C2.47603 4.95156 2.19064 4.95156 2.06116 5.14598L0.0554881 8.15772C-0.0894338 8.37534 0.0663988 8.66683 0.327661 8.66683H1.61755C1.95103 11.8974 4.68129 14.4168 8 14.4168C9.56831 14.4168 11.0069 13.8532 12.1215 12.9184C12.4388 12.6522 12.4803 12.1791 12.2141 11.8617C11.9479 11.5444 11.4749 11.5029 11.1575 11.7691C10.303 12.4859 9.20281 12.9168 8 12.9168C5.51071 12.9168 3.4535 11.0669 3.12815 8.66683Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.28571 3.66667C6.28571 2.74619 7.03191 2 7.95238 2H11.7619C12.6824 2 13.4286 2.74619 13.4286 3.66667V7.47619C13.4286 8.39666 12.6824 9.14286 11.7619 9.14286H7.95238C7.03191 9.14286 6.28571 8.39667 6.28571 7.47619V3.66667ZM16.5238 2C15.6033 2 14.8571 2.74619 14.8571 3.66667V7.47619C14.8571 8.39667 15.6033 9.14286 16.5238 9.14286H20.3333C21.2538 9.14286 22 8.39666 22 7.47619V3.66667C22 2.74619 21.2538 2 20.3333 2H16.5238ZM16.5238 10.5714C15.6033 10.5714 14.8571 11.3176 14.8571 12.2381V16.0476C14.8571 16.9681 15.6033 17.7143 16.5238 17.7143H20.3333C21.2538 17.7143 22 16.9681 22 16.0476V12.2381C22 11.3176 21.2538 10.5714 20.3333 10.5714H16.5238ZM3.63265 10.5714C2.73096 10.5714 2 11.3024 2 12.2041V20.3673C2 21.269 2.73097 22 3.63266 22H11.7959C12.6976 22 13.4286 21.269 13.4286 20.3673V12.2041C13.4286 11.3024 12.6976 10.5714 11.7959 10.5714H3.63265Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 17.8689V2.51551C4 2.06669 4.53728 1.83452 4.86986 2.13591C8.18767 5.14263 10.9111 7.48209 13.102 9.36399L13.102 9.36403C18.3295 13.8544 20.5243 15.7398 20.5243 17.8689C20.5243 19.4181 19.6538 20.0153 18.1044 20.79C16.5549 21.5648 14.4534 22 12.2621 22C10.0709 22 7.96938 21.5648 6.41992 20.79C4.87047 20.0153 4 18.9646 4 17.8689ZM12.2621 20.9673C16.2548 20.9673 19.4915 19.5801 19.4915 17.869C19.4915 16.1578 16.2548 14.7707 12.2621 14.7707C8.26947 14.7707 5.03277 16.1578 5.03277 17.869C5.03277 19.5801 8.26947 20.9673 12.2621 20.9673ZM16.2618 8.67876C16.1718 8.64549 16.1718 8.51831 16.2618 8.48504L17.84 7.90103C17.8683 7.89057 17.8906 7.86828 17.901 7.84001L18.4851 6.26174C18.5183 6.17182 18.6455 6.17182 18.6788 6.26174L19.2628 7.84001C19.2733 7.86828 19.2955 7.89057 19.3238 7.90103L20.9021 8.48504C20.992 8.51831 20.992 8.64549 20.9021 8.67876L19.3238 9.26277C19.2955 9.27323 19.2733 9.29552 19.2628 9.32379L18.6788 10.9021C18.6455 10.992 18.5183 10.992 18.4851 10.9021L17.901 9.32379C17.8906 9.29552 17.8683 9.27323 17.84 9.26277L16.2618 8.67876ZM13.2618 5.45232C13.1718 5.48559 13.1718 5.61276 13.2618 5.64604L14.0862 5.95111C14.1145 5.96157 14.1368 5.98386 14.1472 6.01213L14.4523 6.83657C14.4856 6.92649 14.6127 6.92649 14.646 6.83657L14.9511 6.01213C14.9615 5.98386 14.9838 5.96157 15.0121 5.95111L15.8365 5.64603C15.9265 5.61276 15.9265 5.48559 15.8365 5.45232L15.0121 5.14725C14.9838 5.13679 14.9615 5.1145 14.9511 5.08623L14.646 4.26178C14.6127 4.17187 14.4856 4.17187 14.4523 4.26178L14.1472 5.08623C14.1368 5.1145 14.1145 5.13679 14.0862 5.14725L13.2618 5.45232Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.0759 13.6172C13.0273 13.7343 13.0004 13.8625 13 13.997C13 13.998 13 13.999 13 14L13 14.0007L13 20C13 20.5523 13.4477 21 14 21C14.5523 21 15 20.5523 15 20L15 16.4142L18.7929 20.2071C19.1834 20.5976 19.8166 20.5976 20.2071 20.2071C20.5976 19.8166 20.5976 19.1834 20.2071 18.7929L16.4142 15L20 15C20.5523 15 21 14.5523 21 14C21 13.4477 20.5523 13 20 13L14.0007 13L14 13C13.999 13 13.998 13 13.997 13C13.743 13.0008 13.4892 13.0977 13.295 13.2908C13.2943 13.2915 13.2936 13.2922 13.2929 13.2929C13.2922 13.2936 13.2915 13.2943 13.2908 13.295C13.196 13.3904 13.1243 13.5001 13.0759 13.6172ZM13.0759 13.6172C13.1262 13.4959 13.1996 13.3867 13.2908 13.295L13.0759 13.6172Z" fill="#737D8C"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.9241 10.3828C10.9727 10.2657 10.9996 10.1375 11 10.003C11 10.002 11 10.001 11 10V9.9993L11 4C11 3.44772 10.5523 3 10 3C9.44772 3 9 3.44772 9 4L9 7.58579L5.20711 3.79289C4.81658 3.40237 4.18342 3.40237 3.79289 3.79289C3.40237 4.18342 3.40237 4.81658 3.79289 5.20711L7.58579 9L4 9C3.44771 9 3 9.44771 3 10C3 10.5523 3.44771 11 4 11L9.9993 11H10C10.001 11 10.002 11 10.003 11C10.257 10.9992 10.5108 10.9023 10.705 10.7092C10.7057 10.7085 10.7064 10.7078 10.7071 10.7071C10.7078 10.7064 10.7085 10.7057 10.7092 10.705C10.804 10.6096 10.8757 10.4999 10.9241 10.3828ZM10.9241 10.3828C10.8738 10.5041 10.8004 10.6133 10.7092 10.705L10.9241 10.3828Z" fill="#737D8C"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="16" fill="none">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
d="M4.523 2.964a6.418 6.418 0 0 1 10.36 4.369h1.29c.26 0 .416.292.272.51l-2.006 3.011a.327.327 0 0 1-.544 0l-2.006-3.012a.327.327 0 0 1 .272-.509h1.21a4.918 4.918 0 0 0-7.918-3.192 3.684 3.684 0 0 1-.184.136l-.014.01-.004.003-.002.001h-.001v.001l-.415-.625.414.625a.75.75 0 0 1-.83-1.25l.003-.001.02-.014c.02-.014.048-.035.083-.063Zm-.895 5.703H4.84a.327.327 0 0 0 .272-.51L3.106 5.146a.327.327 0 0 0-.545 0L.555 8.157c-.144.218.011.51.273.51h1.29a6.418 6.418 0 0 0 10.503 4.251.75.75 0 0 0-.963-1.15 4.918 4.918 0 0 1-8.03-3.102Z"
|
||||
clip-rule="evenodd"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 703 B |
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
height="24"
|
||||
width="24">
|
||||
<metadata
|
||||
id="metadata14">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs12" />
|
||||
<path
|
||||
id="path2"
|
||||
d="M 12 2 C 6.47715 2 2 6.47715 2 12 C 2 17.5228 6.47715 22 12 22 C 17.5228 22 22 17.5228 22 12 C 22 6.47715 17.5228 2 12 2 z M 11.880859 5.5039062 C 12.720859 5.4439063 13.470547 6.0746875 13.560547 6.9296875 L 13.560547 7.1699219 L 13.080078 13.169922 C 13.035078 13.724922 12.570625 14.144531 12.015625 14.144531 L 11.925781 14.144531 C 11.400781 14.099531 10.996172 13.694922 10.951172 13.169922 L 10.470703 7.1699219 C 10.395703 6.3149219 11.025859 5.5639064 11.880859 5.5039062 z M 12 15.763672 C 12.729 15.763672 13.320312 16.354884 13.320312 17.083984 C 13.320313 17.812984 12.729 18.404297 12 18.404297 C 11.271 18.404297 10.679688 17.812984 10.679688 17.083984 C 10.679688 16.354884 11.271 15.763672 12 15.763672 z "
|
||||
style="fill:#ff5b55;fill-opacity:1" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16ZM6.9806 4.5101C6.9306 3.9401 7.3506 3.4401 7.9206 3.4001C8.4806 3.3601 8.9806 3.7801 9.0406 4.3501V4.5101L8.7206 8.5101C8.6906 8.8801 8.3806 9.1601 8.0106 9.1601H7.9506C7.6006 9.1301 7.3306 8.8601 7.3006 8.5101L6.9806 4.5101ZM8.88012 11.1202C8.88012 11.6062 8.48613 12.0002 8.00012 12.0002C7.51411 12.0002 7.12012 11.6062 7.12012 11.1202C7.12012 10.6342 7.51411 10.2402 8.00012 10.2402C8.48613 10.2402 8.88012 10.6342 8.88012 11.1202Z" fill="#8D99A5"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 713 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 7.5L9 10.5L12 7.5" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 217 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 2L18 6L7 17H3V13L14 2V2Z" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 22H21" stroke="#2E2F32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 333 B |
@@ -1,11 +0,0 @@
|
||||
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
||||
<g id="LifeBuoy" transform="translate(-1378.000000, -91.000000)" stroke="#61708b" stroke-width="1">
|
||||
<g id="search-copy" transform="translate(1379.000000, 92.000000)">
|
||||
<circle id="Oval" cx="6.22222222" cy="6.22222222" r="6.22222222"></circle>
|
||||
<path d="M14,14 L10.6166667,10.6166667" id="Path"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 674 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="9" height="4" viewBox="0 0 9 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.5 4L0.602887 0.25L8.39711 0.250001L4.5 4Z" fill="#0DBD8B"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 171 B |
@@ -1,3 +0,0 @@
|
||||
<svg height="45" viewBox="0 0 69 45" width="69" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m6 0h57c3.3137085 0 6 2.6862915 6 6v33c0 3.3137085-2.6862915 6-6 6h-57c-3.3137085 0-6-2.6862915-6-6v-33c0-3.3137085 2.6862915-6 6-6zm23.3703704 11c-.6518551 0-1.1841955.3860101-1.5970371 1.158042l-7.7244444 14.7006993-7.7896296-14.7006993c-.4128416-.7720319-.9560461-1.158042-1.6296297-1.158042-.4780271 0-.86913425.1554763-1.1733333.4664336-.30419906.3109572-.4562963.7130511-.4562963 1.2062937v19.7510489c0 .4717973.13580111.8524461.40740741 1.1419581.27160629.2895119.63555329.4342657 1.09185189.4342657.478027 0 .8474061-.1393925 1.1081481-.4181818.2607421-.2787893.3911111-.6647994.3911111-1.158042v-14.8293706l6.4207408 11.8699301c.4128415.7505865.9451819 1.1258741 1.597037 1.1258741s1.1841955-.3752876 1.597037-1.1258741l6.3881482-11.9986014v14.9580419c0 .4932426.130369.8792527.3911111 1.158042.260742.2787893.619257.4181818 1.0755555.4181818.4780271 0 .8528382-.1393925 1.1244445-.4181818s.4074074-.6647994.4074074-1.158042v-19.7510489c0-.4932426-.1520972-.8953365-.4562963-1.2062937-.304199-.3109573-.6953062-.4664336-1.1733333-.4664336zm18.1296296 17.8786797-7.3180195-7.3180195c-.5857864-.5857865-1.5355339-.5857865-2.1213203 0-.5857865.5857864-.5857865 1.5355339 0 2.1213203l9.8994949 9.899495c.3056756.3056756.7104567.4518432 1.1109127.438503.400456.0133402.8052371-.1328274 1.1109127-.438503l9.899495-9.899495c.5857864-.5857864.5857864-1.5355339 0-2.1213203-.5857865-.5857865-1.535534-.5857865-2.1213204 0l-7.4601551 7.4601551v-16.5208153c0-.8284271-.6715729-1.5-1.5-1.5s-1.5.6715729-1.5 1.5z" fill="#d8d8d8" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 271 B |
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="10px" height="16px" viewBox="-1 -1 10 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: sketchtool 3.5.1 (25234) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>minimise</title>
|
||||
<desc>Created with sketchtool.</desc>
|
||||
<defs></defs>
|
||||
<g id="02-Chat" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="02_1-Chat-collapsed-w-topic" sketch:type="MSArtboardGroup" transform="translate(-176.000000, -27.000000)" stroke-width="2" stroke="#9FA9BA">
|
||||
<g id="Room-list" sketch:type="MSLayerGroup">
|
||||
<g id="Room-list/Header" sketch:type="MSShapeGroup">
|
||||
<g id="minimise" transform="translate(172.000000, 25.000000)">
|
||||
<path d="M7,5 L15,5 L15,13" id="Path-53-Copy" transform="translate(11.000000, 9.000000) scale(-1, -1) rotate(-315.000000) translate(-11.000000, -9.000000) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,4 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2V2Z" stroke="#0DBD8B" stroke-width="2" stroke-linecap="square"/>
|
||||
<path d="M6.54549 12.8882L9.80306 16.2426L17.4546 8.36377" stroke="#0DBD8B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 442 B |
@@ -1,5 +0,0 @@
|
||||
<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect y="0.5" width="2.2" height="11" fill="#0DBD8B"/>
|
||||
<rect x="4.40015" y="2.70001" width="2.2" height="8.8" fill="#0DBD8B"/>
|
||||
<rect x="8.79993" y="7.10004" width="2.2" height="4.4" fill="#0DBD8B"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 302 B |
2
res/jitsi_external_api.min.js
vendored
@@ -37,6 +37,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
|
||||
public state: IState = {};
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.unmounted = false;
|
||||
this.props.prom
|
||||
.then((result) => {
|
||||
if (this.unmounted) return;
|
||||
|
||||
@@ -31,6 +31,8 @@ import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
||||
import { IConfigOptions } from "./IConfigOptions";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import { buildAndEncodePickleKey, encryptPickleKey } from "./utils/tokens/pickling";
|
||||
import Favicon from "./favicon.ts";
|
||||
import { getVectorConfig } from "./vector/getconfig.ts";
|
||||
|
||||
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
|
||||
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
|
||||
@@ -66,14 +68,20 @@ const UPDATE_DEFER_KEY = "mx_defer_update";
|
||||
export default abstract class BasePlatform {
|
||||
protected notificationCount = 0;
|
||||
protected errorDidOccur = false;
|
||||
protected _favicon?: Favicon;
|
||||
|
||||
protected constructor() {
|
||||
dis.register(this.onAction);
|
||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
||||
}
|
||||
|
||||
public abstract getConfig(): Promise<IConfigOptions | undefined>;
|
||||
public async getConfig(): Promise<IConfigOptions | undefined> {
|
||||
return getVectorConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sensible default display name for the device Element is running on
|
||||
*/
|
||||
public abstract getDefaultDeviceDisplayName(): string;
|
||||
|
||||
protected onAction = (payload: ActionPayload): void => {
|
||||
@@ -89,11 +97,15 @@ export default abstract class BasePlatform {
|
||||
public abstract getHumanReadableName(): string;
|
||||
|
||||
public setNotificationCount(count: number): void {
|
||||
if (this.notificationCount === count) return;
|
||||
this.notificationCount = count;
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
public setErrorStatus(errorDidOccur: boolean): void {
|
||||
if (this.errorDidOccur === errorDidOccur) return;
|
||||
this.errorDidOccur = errorDidOccur;
|
||||
this.updateFavicon();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,4 +468,34 @@ export default abstract class BasePlatform {
|
||||
url.hash = "";
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay creating the `Favicon` instance until first use (on the first notification) as
|
||||
* it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode.
|
||||
* See https://github.com/element-hq/element-web/issues/9605.
|
||||
*/
|
||||
public get favicon(): Favicon {
|
||||
if (this._favicon) {
|
||||
return this._favicon;
|
||||
}
|
||||
this._favicon = new Favicon();
|
||||
return this._favicon;
|
||||
}
|
||||
|
||||
private updateFavicon(): void {
|
||||
let bgColor = "#d00";
|
||||
let notif: string | number = this.notificationCount;
|
||||
|
||||
if (this.errorDidOccur) {
|
||||
notif = notif || "×";
|
||||
bgColor = "#f00";
|
||||
}
|
||||
|
||||
this.favicon.badge(notif, { bgColor });
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin update polling, if applicable
|
||||
*/
|
||||
public startUpdater(): void {}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ export class DecryptionFailureTracker {
|
||||
return "HistoricalMessage";
|
||||
case DecryptionFailureCode.HISTORICAL_MESSAGE_USER_NOT_JOINED:
|
||||
return "ExpectedDueToMembership";
|
||||
case DecryptionFailureCode.SENDER_IDENTITY_PREVIOUSLY_VERIFIED:
|
||||
return "ExpectedVerificationViolation";
|
||||
case DecryptionFailureCode.UNSIGNED_SENDER_DEVICE:
|
||||
return "ExpectedSentByInsecureDevice";
|
||||
default:
|
||||
return "UnknownError";
|
||||
}
|
||||
|
||||
@@ -113,13 +113,9 @@ export default class DeviceListener {
|
||||
this.client.removeListener(ClientEvent.Sync, this.onSync);
|
||||
this.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
}
|
||||
if (this.deviceClientInformationSettingWatcherRef) {
|
||||
SettingsStore.unwatchSetting(this.deviceClientInformationSettingWatcherRef);
|
||||
}
|
||||
if (this.dispatcherRef) {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this.dispatcherRef = undefined;
|
||||
}
|
||||
this.dismissed.clear();
|
||||
this.dismissedThisDeviceToast = false;
|
||||
this.keyBackupInfo = null;
|
||||
@@ -292,16 +288,11 @@ export default class DeviceListener {
|
||||
await crypto.getUserDeviceInfo([cli.getSafeUserId()]);
|
||||
|
||||
// cross signing isn't enabled - nag to enable it
|
||||
// There are 3 different toasts for:
|
||||
// There are 2 different toasts for:
|
||||
if (!(await crypto.getCrossSigningKeyId()) && (await crypto.userHasCrossSigningKeys())) {
|
||||
// Cross-signing on account but this device doesn't trust the master key (verify this session)
|
||||
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
|
||||
this.checkKeyBackupStatus();
|
||||
} else {
|
||||
const backupInfo = await this.getKeyBackupInfo();
|
||||
if (backupInfo) {
|
||||
// No cross-signing on account but key backup available (upgrade encryption)
|
||||
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
|
||||
} else {
|
||||
// No cross-signing or key backup on account (set up encryption)
|
||||
await cli.waitForClientWellKnown();
|
||||
@@ -315,7 +306,6 @@ export default class DeviceListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This needs to be done after awaiting on getUserDeviceInfo() above, so
|
||||
// we make sure we get the devices after the fetch is done.
|
||||
|
||||
@@ -383,6 +383,9 @@ export default class Markdown {
|
||||
if (isMultiLine(node) && node.next) this.lit("\n\n");
|
||||
};
|
||||
|
||||
return renderer.render(this.parsed);
|
||||
// We inhibit the default escape function as we escape the entire output string to correctly handle backslashes
|
||||
renderer.esc = (input: string) => input;
|
||||
|
||||
return escape(renderer.render(this.parsed));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import React, { StrictMode } from "react";
|
||||
import { createRoot, Root } from "react-dom/client";
|
||||
import classNames from "classnames";
|
||||
import { IDeferred, defer, sleep } from "matrix-js-sdk/src/utils";
|
||||
import { IDeferred, defer } from "matrix-js-sdk/src/utils";
|
||||
import { TypedEventEmitter } from "matrix-js-sdk/src/matrix";
|
||||
import { Glass, TooltipProvider } from "@vector-im/compound-web";
|
||||
|
||||
@@ -69,6 +69,16 @@ type HandlerMap = {
|
||||
|
||||
type ModalCloseReason = "backgroundClick";
|
||||
|
||||
function getOrCreateContainer(id: string): HTMLDivElement {
|
||||
let container = document.getElementById(id) as HTMLDivElement | null;
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = id;
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMap> {
|
||||
private counter = 0;
|
||||
// The modal to prioritise over all others. If this is set, only show
|
||||
@@ -83,28 +93,22 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
// Neither the static nor priority modal will be in this list.
|
||||
private modals: IModal<any>[] = [];
|
||||
|
||||
private static getOrCreateContainer(): HTMLElement {
|
||||
let container = document.getElementById(DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = DIALOG_CONTAINER_ID;
|
||||
document.body.appendChild(container);
|
||||
private static root?: Root;
|
||||
private static getOrCreateRoot(): Root {
|
||||
if (!ModalManager.root) {
|
||||
const container = getOrCreateContainer(DIALOG_CONTAINER_ID);
|
||||
ModalManager.root = createRoot(container);
|
||||
}
|
||||
return ModalManager.root;
|
||||
}
|
||||
|
||||
return container;
|
||||
private static staticRoot?: Root;
|
||||
private static getOrCreateStaticRoot(): Root {
|
||||
if (!ModalManager.staticRoot) {
|
||||
const container = getOrCreateContainer(STATIC_DIALOG_CONTAINER_ID);
|
||||
ModalManager.staticRoot = createRoot(container);
|
||||
}
|
||||
|
||||
private static getOrCreateStaticContainer(): HTMLElement {
|
||||
let container = document.getElementById(STATIC_DIALOG_CONTAINER_ID);
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = STATIC_DIALOG_CONTAINER_ID;
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
return container;
|
||||
return ModalManager.staticRoot;
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
@@ -389,19 +393,14 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
}
|
||||
|
||||
private async reRender(): Promise<void> {
|
||||
// TODO: We should figure out how to remove this weird sleep. It also makes testing harder
|
||||
//
|
||||
// await next tick because sometimes ReactDOM can race with itself and cause the modal to wrongly stick around
|
||||
await sleep(0);
|
||||
|
||||
if (this.modals.length === 0 && !this.priorityModal && !this.staticModal) {
|
||||
// If there is no modal to render, make all of Element available
|
||||
// to screen reader users again
|
||||
dis.dispatch({
|
||||
action: "aria_unhide_main_app",
|
||||
});
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateContainer());
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateRoot().render(<></>);
|
||||
ModalManager.getOrCreateStaticRoot().render(<></>);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -416,6 +415,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
const classes = classNames("mx_Dialog_wrapper mx_Dialog_staticWrapper", this.staticModal.className);
|
||||
|
||||
const staticDialog = (
|
||||
<StrictMode>
|
||||
<TooltipProvider>
|
||||
<div className={classes}>
|
||||
<Glass className="mx_Dialog_border">
|
||||
@@ -428,12 +428,13 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
/>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
ReactDOM.render(staticDialog, ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateStaticRoot().render(staticDialog);
|
||||
} else {
|
||||
// This is safe to call repeatedly if we happen to do that
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateStaticContainer());
|
||||
ModalManager.getOrCreateStaticRoot().render(<></>);
|
||||
}
|
||||
|
||||
const modal = this.getCurrentModal();
|
||||
@@ -443,6 +444,7 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
});
|
||||
|
||||
const dialog = (
|
||||
<StrictMode>
|
||||
<TooltipProvider>
|
||||
<div className={classes}>
|
||||
<Glass className="mx_Dialog_border">
|
||||
@@ -455,12 +457,13 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
|
||||
/>
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
setTimeout(() => ReactDOM.render(dialog, ModalManager.getOrCreateContainer()), 0);
|
||||
ModalManager.getOrCreateRoot().render(dialog);
|
||||
} else {
|
||||
// This is safe to call repeatedly if we happen to do that
|
||||
ReactDOM.unmountComponentAtNode(ModalManager.getOrCreateContainer());
|
||||
ModalManager.getOrCreateRoot().render(<></>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ export class PosthogAnalytics {
|
||||
if (this.enabled) {
|
||||
this.posthog.reset();
|
||||
}
|
||||
if (this.watchSettingRef) SettingsStore.unwatchSetting(this.watchSettingRef);
|
||||
SettingsStore.unwatchSetting(this.watchSettingRef);
|
||||
this.setAnonymity(Anonymity.Disabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import { ActionPayload } from "./dispatcher/payloads";
|
||||
const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins
|
||||
|
||||
class Presence {
|
||||
private unavailableTimer: Timer | null = null;
|
||||
private dispatcherRef: string | null = null;
|
||||
private state: SetPresence | null = null;
|
||||
private unavailableTimer?: Timer;
|
||||
private dispatcherRef?: string;
|
||||
private state?: SetPresence;
|
||||
|
||||
/**
|
||||
* Start listening the user activity to evaluate his presence state.
|
||||
@@ -46,14 +46,10 @@ class Presence {
|
||||
* Stop tracking user activity
|
||||
*/
|
||||
public stop(): void {
|
||||
if (this.dispatcherRef) {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this.dispatcherRef = null;
|
||||
}
|
||||
if (this.unavailableTimer) {
|
||||
this.unavailableTimer.abort();
|
||||
this.unavailableTimer = null;
|
||||
}
|
||||
this.dispatcherRef = undefined;
|
||||
this.unavailableTimer?.abort();
|
||||
this.unavailableTimer = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +57,7 @@ class Presence {
|
||||
* @returns {string} the presence state (see PRESENCE enum)
|
||||
*/
|
||||
public getState(): SetPresence | null {
|
||||
return this.state;
|
||||
return this.state ?? null;
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
|
||||
@@ -11,7 +11,7 @@ import React, { createRef } from "react";
|
||||
import FileSaver from "file-saver";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { AuthDict, CrossSigningKeys, MatrixError, UIAFlow, UIAResponse } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoEvent, BackupTrustInfo, GeneratedSecretStorageKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api";
|
||||
import classNames from "classnames";
|
||||
import CheckmarkIcon from "@vector-im/compound-design-tokens/assets/web/icons/check";
|
||||
|
||||
@@ -25,7 +25,6 @@ import StyledRadioButton from "../../../../components/views/elements/StyledRadio
|
||||
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
|
||||
import DialogButtons from "../../../../components/views/elements/DialogButtons";
|
||||
import InlineSpinner from "../../../../components/views/elements/InlineSpinner";
|
||||
import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog";
|
||||
import {
|
||||
getSecureBackupSetupMethods,
|
||||
isSecureBackupRequired,
|
||||
@@ -45,7 +44,6 @@ enum Phase {
|
||||
Loading = "loading",
|
||||
LoadError = "load_error",
|
||||
ChooseKeyPassphrase = "choose_key_passphrase",
|
||||
Migrate = "migrate",
|
||||
Passphrase = "passphrase",
|
||||
PassphraseConfirm = "passphrase_confirm",
|
||||
ShowKey = "show_key",
|
||||
@@ -72,24 +70,6 @@ interface IState {
|
||||
downloaded: boolean;
|
||||
setPassphrase: boolean;
|
||||
|
||||
/** Information on the current key backup version, as returned by the server.
|
||||
*
|
||||
* `null` could mean any of:
|
||||
* * we haven't yet requested the data from the server.
|
||||
* * we were unable to reach the server.
|
||||
* * the server returned key backup version data we didn't understand or was malformed.
|
||||
* * there is actually no backup on the server.
|
||||
*/
|
||||
backupInfo: KeyBackupInfo | null;
|
||||
|
||||
/**
|
||||
* Information on whether the backup in `backupInfo` is correctly signed, and whether we have the right key to
|
||||
* decrypt it.
|
||||
*
|
||||
* `undefined` if `backupInfo` is null, or if crypto is not enabled in the client.
|
||||
*/
|
||||
backupTrustInfo: BackupTrustInfo | undefined;
|
||||
|
||||
// does the server offer a UI auth flow with just m.login.password
|
||||
// for /keys/device_signing/upload?
|
||||
canUploadKeysWithPasswordOnly: boolean | null;
|
||||
@@ -137,20 +117,19 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
// signing key upload as well. This avoids hitting the server to
|
||||
// test auth flows, which may be slow under high load.
|
||||
canUploadKeysWithPasswordOnly = true;
|
||||
} else {
|
||||
this.queryKeyUploadAuth();
|
||||
}
|
||||
|
||||
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
|
||||
const phase = keyFromCustomisations ? Phase.Loading : Phase.ChooseKeyPassphrase;
|
||||
|
||||
this.state = {
|
||||
phase: Phase.Loading,
|
||||
phase,
|
||||
passPhrase: "",
|
||||
passPhraseValid: false,
|
||||
passPhraseConfirm: "",
|
||||
copied: false,
|
||||
downloaded: false,
|
||||
setPassphrase: false,
|
||||
backupInfo: null,
|
||||
backupTrustInfo: undefined,
|
||||
// does the server offer a UI auth flow with just m.login.password
|
||||
// for /keys/device_signing/upload?
|
||||
accountPasswordCorrect: null,
|
||||
@@ -159,61 +138,23 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
passPhraseKeySelected,
|
||||
accountPassword,
|
||||
};
|
||||
|
||||
cli.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);
|
||||
|
||||
this.getInitialPhase();
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
MatrixClientPeg.get()?.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);
|
||||
}
|
||||
|
||||
private getInitialPhase(): void {
|
||||
public componentDidMount(): void {
|
||||
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
|
||||
if (keyFromCustomisations) {
|
||||
if (keyFromCustomisations) this.initExtension(keyFromCustomisations);
|
||||
|
||||
if (this.state.canUploadKeysWithPasswordOnly === null) {
|
||||
this.queryKeyUploadAuth();
|
||||
}
|
||||
}
|
||||
|
||||
private initExtension(keyFromCustomisations: Uint8Array): void {
|
||||
logger.log("CryptoSetupExtension: Created key via extension, jumping to bootstrap step");
|
||||
this.recoveryKey = {
|
||||
privateKey: keyFromCustomisations,
|
||||
};
|
||||
this.bootstrapSecretStorage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetchBackupInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get information on the current backup from the server, and update the state.
|
||||
*
|
||||
* Updates {@link IState.backupInfo} and {@link IState.backupTrustInfo}, and picks an appropriate phase for
|
||||
* {@link IState.phase}.
|
||||
*
|
||||
* @returns If the backup data was retrieved successfully, the trust info for the backup. Otherwise, undefined.
|
||||
*/
|
||||
private async fetchBackupInfo(): Promise<BackupTrustInfo | undefined> {
|
||||
try {
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
const backupInfo = await cli.getKeyBackupVersion();
|
||||
const backupTrustInfo =
|
||||
// we may not have started crypto yet, in which case we definitely don't trust the backup
|
||||
backupInfo ? await cli.getCrypto()?.isKeyBackupTrusted(backupInfo) : undefined;
|
||||
|
||||
const { forceReset } = this.props;
|
||||
const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;
|
||||
|
||||
this.setState({
|
||||
phase,
|
||||
backupInfo,
|
||||
backupTrustInfo,
|
||||
});
|
||||
|
||||
return backupTrustInfo;
|
||||
} catch (e) {
|
||||
console.error("Error fetching backup data from server", e);
|
||||
this.setState({ phase: Phase.LoadError });
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async queryKeyUploadAuth(): Promise<void> {
|
||||
@@ -237,10 +178,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
}
|
||||
}
|
||||
|
||||
private onKeyBackupStatusChange = (): void => {
|
||||
if (this.state.phase === Phase.Migrate) this.fetchBackupInfo();
|
||||
};
|
||||
|
||||
private onKeyPassphraseChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({
|
||||
passPhraseKeySelected: e.target.value,
|
||||
@@ -265,15 +202,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
}
|
||||
};
|
||||
|
||||
private onMigrateFormSubmit = (e: React.FormEvent): void => {
|
||||
e.preventDefault();
|
||||
if (this.state.backupTrustInfo?.trusted) {
|
||||
this.bootstrapSecretStorage();
|
||||
} else {
|
||||
this.restoreBackup();
|
||||
}
|
||||
};
|
||||
|
||||
private onCopyClick = (): void => {
|
||||
const successful = copyNode(this.recoveryKeyNode.current);
|
||||
if (successful) {
|
||||
@@ -340,16 +268,28 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
};
|
||||
|
||||
private bootstrapSecretStorage = async (): Promise<void> => {
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
const crypto = cli.getCrypto()!;
|
||||
const { forceReset } = this.props;
|
||||
|
||||
let backupInfo;
|
||||
// First, unless we know we want to do a reset, we see if there is an existing key backup
|
||||
if (!forceReset) {
|
||||
try {
|
||||
this.setState({ phase: Phase.Loading });
|
||||
backupInfo = await cli.getKeyBackupVersion();
|
||||
} catch (e) {
|
||||
logger.error("Error fetching backup data from server", e);
|
||||
this.setState({ phase: Phase.LoadError });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
phase: Phase.Storing,
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
const crypto = cli.getCrypto()!;
|
||||
|
||||
const { forceReset } = this.props;
|
||||
|
||||
try {
|
||||
if (forceReset) {
|
||||
logger.log("Forcing secret storage reset");
|
||||
@@ -371,8 +311,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
});
|
||||
await crypto.bootstrapSecretStorage({
|
||||
createSecretStorageKey: async () => this.recoveryKey!,
|
||||
keyBackupInfo: this.state.backupInfo!,
|
||||
setupNewKeyBackup: !this.state.backupInfo,
|
||||
setupNewKeyBackup: !backupInfo,
|
||||
});
|
||||
}
|
||||
await initialiseDehydration(true);
|
||||
@@ -381,20 +320,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
phase: Phase.Stored,
|
||||
});
|
||||
} catch (e) {
|
||||
if (
|
||||
this.state.canUploadKeysWithPasswordOnly &&
|
||||
e instanceof MatrixError &&
|
||||
e.httpStatus === 401 &&
|
||||
e.data.flows
|
||||
) {
|
||||
this.setState({
|
||||
accountPassword: "",
|
||||
accountPasswordCorrect: false,
|
||||
phase: Phase.Migrate,
|
||||
});
|
||||
} else {
|
||||
this.setState({ error: true });
|
||||
}
|
||||
logger.error("Error bootstrapping secret storage", e);
|
||||
}
|
||||
};
|
||||
@@ -403,27 +329,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
this.props.onFinished(false);
|
||||
};
|
||||
|
||||
private restoreBackup = async (): Promise<void> => {
|
||||
const { finished } = Modal.createDialog(
|
||||
RestoreKeyBackupDialog,
|
||||
{
|
||||
showSummary: false,
|
||||
},
|
||||
undefined,
|
||||
/* priority = */ false,
|
||||
/* static = */ false,
|
||||
);
|
||||
|
||||
await finished;
|
||||
const backupTrustInfo = await this.fetchBackupInfo();
|
||||
if (backupTrustInfo?.trusted && this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) {
|
||||
this.bootstrapSecretStorage();
|
||||
}
|
||||
};
|
||||
|
||||
private onLoadRetryClick = (): void => {
|
||||
this.setState({ phase: Phase.Loading });
|
||||
this.fetchBackupInfo();
|
||||
this.bootstrapSecretStorage();
|
||||
};
|
||||
|
||||
private onShowKeyContinueClick = (): void => {
|
||||
@@ -495,12 +402,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
});
|
||||
};
|
||||
|
||||
private onAccountPasswordChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({
|
||||
accountPassword: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
private renderOptionKey(): JSX.Element {
|
||||
return (
|
||||
<StyledRadioButton
|
||||
@@ -565,55 +466,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
);
|
||||
}
|
||||
|
||||
private renderPhaseMigrate(): JSX.Element {
|
||||
let authPrompt;
|
||||
let nextCaption = _t("action|next");
|
||||
if (this.state.canUploadKeysWithPasswordOnly) {
|
||||
authPrompt = (
|
||||
<div>
|
||||
<div>{_t("settings|key_backup|setup_secure_backup|requires_password_confirmation")}</div>
|
||||
<div>
|
||||
<Field
|
||||
id="mx_CreateSecretStorageDialog_password"
|
||||
type="password"
|
||||
label={_t("common|password")}
|
||||
value={this.state.accountPassword}
|
||||
onChange={this.onAccountPasswordChange}
|
||||
forceValidity={this.state.accountPasswordCorrect === false ? false : undefined}
|
||||
autoFocus={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (!this.state.backupTrustInfo?.trusted) {
|
||||
authPrompt = (
|
||||
<div>
|
||||
<div>{_t("settings|key_backup|setup_secure_backup|requires_key_restore")}</div>
|
||||
</div>
|
||||
);
|
||||
nextCaption = _t("action|restore");
|
||||
} else {
|
||||
authPrompt = <p>{_t("settings|key_backup|setup_secure_backup|requires_server_authentication")}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.onMigrateFormSubmit}>
|
||||
<p>{_t("settings|key_backup|setup_secure_backup|session_upgrade_description")}</p>
|
||||
<div>{authPrompt}</div>
|
||||
<DialogButtons
|
||||
primaryButton={nextCaption}
|
||||
onPrimaryButtonClick={this.onMigrateFormSubmit}
|
||||
hasCancel={false}
|
||||
primaryDisabled={!!this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
|
||||
>
|
||||
<button type="button" className="danger" onClick={this.onCancelClick}>
|
||||
{_t("action|skip")}
|
||||
</button>
|
||||
</DialogButtons>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
private renderPhasePassPhrase(): JSX.Element {
|
||||
return (
|
||||
<form onSubmit={this.onPassPhraseNextClick}>
|
||||
@@ -829,8 +681,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
switch (phase) {
|
||||
case Phase.ChooseKeyPassphrase:
|
||||
return _t("encryption|set_up_toast_title");
|
||||
case Phase.Migrate:
|
||||
return _t("settings|key_backup|setup_secure_backup|title_upgrade_encryption");
|
||||
case Phase.Passphrase:
|
||||
return _t("settings|key_backup|setup_secure_backup|title_set_phrase");
|
||||
case Phase.PassphraseConfirm:
|
||||
@@ -889,9 +739,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
|
||||
case Phase.ChooseKeyPassphrase:
|
||||
content = this.renderPhaseChooseKeyPassphrase();
|
||||
break;
|
||||
case Phase.Migrate:
|
||||
content = this.renderPhaseMigrate();
|
||||
break;
|
||||
case Phase.Passphrase:
|
||||
content = this.renderPhasePassPhrase();
|
||||
break;
|
||||
|
||||
@@ -56,6 +56,10 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.unmounted = false;
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.unmounted = false;
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
||||
public static contextType = MatrixClientContext;
|
||||
public declare context: React.ContextType<typeof MatrixClientContext>;
|
||||
private unmounted = false;
|
||||
private dispatcherRef: string | null = null;
|
||||
private dispatcherRef?: string;
|
||||
|
||||
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
|
||||
super(props, context);
|
||||
@@ -100,7 +100,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.unmounted = true;
|
||||
if (this.dispatcherRef !== null) dis.unregister(this.dispatcherRef);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
|
||||
@@ -104,7 +104,11 @@ class FilePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
if (!this.state.timelineSet.eventIdToTimeline(ev.getId()!)) {
|
||||
this.state.timelineSet.addEventToTimeline(ev, timeline, false);
|
||||
this.state.timelineSet.addEventToTimeline(ev, timeline, {
|
||||
fromCache: false,
|
||||
addToState: false,
|
||||
toStartOfTimeline: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,8 +90,8 @@ interface IState {
|
||||
|
||||
export default class InteractiveAuthComponent<T> extends React.Component<InteractiveAuthProps<T>, IState> {
|
||||
private readonly authLogic: InteractiveAuth<T>;
|
||||
private readonly intervalId: number | null = null;
|
||||
private readonly stageComponent = createRef<IStageComponent>();
|
||||
private intervalId: number | null = null;
|
||||
|
||||
private unmounted = false;
|
||||
|
||||
@@ -126,15 +126,17 @@ export default class InteractiveAuthComponent<T> extends React.Component<Interac
|
||||
AuthType.SsoUnstable,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.unmounted = false;
|
||||
|
||||
if (this.props.poll) {
|
||||
this.intervalId = window.setInterval(() => {
|
||||
this.authLogic.poll();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.authLogic
|
||||
.attemptAuth()
|
||||
.then(async (result) => {
|
||||
|
||||
@@ -67,10 +67,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
activeSpace: SpaceStore.instance.activeSpace,
|
||||
showBreadcrumbs: LeftPanel.breadcrumbsMode,
|
||||
};
|
||||
|
||||
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||
}
|
||||
|
||||
private static get breadcrumbsMode(): BreadcrumbsMode {
|
||||
@@ -78,6 +74,10 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||
|
||||
if (this.listContainerRef.current) {
|
||||
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
|
||||
// Using the passive option to not block the main thread
|
||||
|
||||
@@ -228,9 +228,9 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||
this._matrixClient.removeListener(ClientEvent.Sync, this.onSync);
|
||||
this._matrixClient.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
OwnProfileStore.instance.off(UPDATE_EVENT, this.refreshBackgroundImage);
|
||||
if (this.layoutWatcherRef) SettingsStore.unwatchSetting(this.layoutWatcherRef);
|
||||
if (this.compactLayoutWatcherRef) SettingsStore.unwatchSetting(this.compactLayoutWatcherRef);
|
||||
if (this.backgroundImageWatcherRef) SettingsStore.unwatchSetting(this.backgroundImageWatcherRef);
|
||||
SettingsStore.unwatchSetting(this.layoutWatcherRef);
|
||||
SettingsStore.unwatchSetting(this.compactLayoutWatcherRef);
|
||||
SettingsStore.unwatchSetting(this.backgroundImageWatcherRef);
|
||||
this.timezoneProfileUpdateRef?.forEach((s) => SettingsStore.unwatchSetting(s));
|
||||
this.resizer?.detach();
|
||||
}
|
||||
|
||||
@@ -231,10 +231,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
private prevWindowWidth: number;
|
||||
private voiceBroadcastResumer?: VoiceBroadcastResumer;
|
||||
|
||||
private readonly loggedInView: React.RefObject<LoggedInViewType>;
|
||||
private readonly dispatcherRef: string;
|
||||
private readonly themeWatcher: ThemeWatcher;
|
||||
private readonly fontWatcher: FontWatcher;
|
||||
private readonly loggedInView = createRef<LoggedInViewType>();
|
||||
private dispatcherRef?: string;
|
||||
private themeWatcher?: ThemeWatcher;
|
||||
private fontWatcher?: FontWatcher;
|
||||
private readonly stores: SdkContextClass;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
@@ -256,8 +256,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
ready: false,
|
||||
};
|
||||
|
||||
this.loggedInView = createRef();
|
||||
|
||||
SdkConfig.put(this.props.config);
|
||||
|
||||
// Used by _viewRoom before getting state from sync
|
||||
@@ -282,32 +280,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
|
||||
this.prevWindowWidth = UIStore.instance.windowWidth || 1000;
|
||||
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
|
||||
|
||||
// For PersistentElement
|
||||
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
||||
|
||||
RoomNotificationStateStore.instance.on(UPDATE_STATUS_INDICATOR, this.onUpdateStatusIndicator);
|
||||
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
|
||||
this.themeWatcher = new ThemeWatcher();
|
||||
this.fontWatcher = new FontWatcher();
|
||||
this.themeWatcher.start();
|
||||
this.fontWatcher.start();
|
||||
|
||||
// object field used for tracking the status info appended to the title tag.
|
||||
// we don't do it as react state as i'm scared about triggering needless react refreshes.
|
||||
this.subTitleStatus = "";
|
||||
|
||||
initSentry(SdkConfig.get("sentry"));
|
||||
|
||||
if (!checkSessionLockFree()) {
|
||||
// another instance holds the lock; confirm its theft before proceeding
|
||||
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
||||
} else {
|
||||
this.startInitSession();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,6 +452,29 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
|
||||
|
||||
// For PersistentElement
|
||||
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
||||
|
||||
RoomNotificationStateStore.instance.on(UPDATE_STATUS_INDICATOR, this.onUpdateStatusIndicator);
|
||||
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
|
||||
this.themeWatcher = new ThemeWatcher();
|
||||
this.fontWatcher = new FontWatcher();
|
||||
this.themeWatcher.start();
|
||||
this.fontWatcher.start();
|
||||
|
||||
initSentry(SdkConfig.get("sentry"));
|
||||
|
||||
if (!checkSessionLockFree()) {
|
||||
// another instance holds the lock; confirm its theft before proceeding
|
||||
setTimeout(() => this.setState({ view: Views.CONFIRM_LOCK_THEFT }), 0);
|
||||
} else {
|
||||
this.startInitSession();
|
||||
}
|
||||
|
||||
window.addEventListener("resize", this.onWindowResized);
|
||||
}
|
||||
|
||||
@@ -497,8 +496,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
public componentWillUnmount(): void {
|
||||
Lifecycle.stopMatrixClient();
|
||||
dis.unregister(this.dispatcherRef);
|
||||
this.themeWatcher.stop();
|
||||
this.fontWatcher.stop();
|
||||
this.themeWatcher?.stop();
|
||||
this.fontWatcher?.stop();
|
||||
UIStore.destroy();
|
||||
this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
||||
window.removeEventListener("resize", this.onWindowResized);
|
||||
@@ -1011,7 +1010,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
|
||||
this.setStateForNewView(newState);
|
||||
ThemeController.isLogin = true;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
this.notifyNewScreen(isMobileRegistration ? "mobile_register" : "register");
|
||||
}
|
||||
|
||||
@@ -1088,7 +1087,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
},
|
||||
() => {
|
||||
ThemeController.isLogin = false;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
this.notifyNewScreen("room/" + presentedId, replaceLast);
|
||||
},
|
||||
);
|
||||
@@ -1113,7 +1112,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
this.notifyNewScreen("welcome");
|
||||
ThemeController.isLogin = true;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
}
|
||||
|
||||
private viewLogin(otherState?: any): void {
|
||||
@@ -1123,7 +1122,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
});
|
||||
this.notifyNewScreen("login");
|
||||
ThemeController.isLogin = true;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
}
|
||||
|
||||
private viewHome(justRegistered = false): void {
|
||||
@@ -1136,7 +1135,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
this.setPage(PageType.HomePage);
|
||||
this.notifyNewScreen("home");
|
||||
ThemeController.isLogin = false;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
}
|
||||
|
||||
private viewUser(userId: string, subAction: string): void {
|
||||
@@ -1357,7 +1356,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
*/
|
||||
private async onLoggedIn(): Promise<void> {
|
||||
ThemeController.isLogin = false;
|
||||
this.themeWatcher.recheck();
|
||||
this.themeWatcher?.recheck();
|
||||
StorageManager.tryPersistStorage();
|
||||
|
||||
await this.onShowPostLoginScreen();
|
||||
|
||||
@@ -240,13 +240,13 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
private readReceiptsByUserId: Map<string, IReadReceiptForUser> = new Map();
|
||||
|
||||
private readonly _showHiddenEvents: boolean;
|
||||
private isMounted = false;
|
||||
private unmounted = false;
|
||||
|
||||
private readMarkerNode = createRef<HTMLLIElement>();
|
||||
private whoIsTyping = createRef<WhoIsTypingTile>();
|
||||
public scrollPanel = createRef<ScrollPanel>();
|
||||
|
||||
private readonly showTypingNotificationsWatcherRef: string;
|
||||
private showTypingNotificationsWatcherRef?: string;
|
||||
private eventTiles: Record<string, UnwrappedEventTile> = {};
|
||||
|
||||
// A map to allow groupers to maintain consistent keys even if their first event is uprooted due to back-pagination.
|
||||
@@ -267,22 +267,21 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
// and we check this in a hot code path. This is also cached in our
|
||||
// RoomContext, however we still need a fallback for roomless MessagePanels.
|
||||
this._showHiddenEvents = SettingsStore.getValue("showHiddenEventsInTimeline");
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.unmounted = false;
|
||||
this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting(
|
||||
"showTypingNotifications",
|
||||
null,
|
||||
this.onShowTypingNotificationsChange,
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.calculateRoomMembersCount();
|
||||
this.props.room?.currentState.on(RoomStateEvent.Update, this.calculateRoomMembersCount);
|
||||
this.isMounted = true;
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.isMounted = false;
|
||||
this.unmounted = true;
|
||||
this.props.room?.currentState.off(RoomStateEvent.Update, this.calculateRoomMembersCount);
|
||||
SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef);
|
||||
this.readReceiptMap = {};
|
||||
@@ -441,7 +440,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
private isUnmounting = (): boolean => {
|
||||
return !this.isMounted;
|
||||
return this.unmounted;
|
||||
};
|
||||
|
||||
public get showHiddenEvents(): boolean {
|
||||
|
||||
@@ -25,7 +25,9 @@ export default class NonUrgentToastContainer extends React.PureComponent<IProps,
|
||||
this.state = {
|
||||
toasts: NonUrgentToastStore.instance.components,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
NonUrgentToastStore.instance.on(UPDATE_EVENT, this.onUpdateToasts);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,11 +22,9 @@ interface IProps {
|
||||
}
|
||||
|
||||
export default class RoomSearch extends React.PureComponent<IProps> {
|
||||
private readonly dispatcherRef: string;
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
private dispatcherRef?: string;
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||
}
|
||||
|
||||
|
||||