Compare commits
99 Commits
kittykat-p
...
t3chguy/no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a52d4aed9f | ||
|
|
66798c75b5 | ||
|
|
2ef6abbfb8 | ||
|
|
326a1a9056 | ||
|
|
341b0b469e | ||
|
|
0e8e472138 | ||
|
|
44eeb6fddc | ||
|
|
8383c021f1 | ||
|
|
7afa416ed5 | ||
|
|
bd5d22d0e9 | ||
|
|
93b57b2baa | ||
|
|
e356c38948 | ||
|
|
d1f7454dc0 | ||
|
|
3bf3237774 | ||
|
|
f0e6673fec | ||
|
|
8ac2e0100e | ||
|
|
f42c865878 | ||
|
|
2aae3de956 | ||
|
|
c61556e885 | ||
|
|
8891698745 | ||
|
|
ec4cc52b7e | ||
|
|
d2c2a51ce6 | ||
|
|
3e3d7566a6 | ||
|
|
5f355bf25e | ||
|
|
1708f7f1b8 | ||
|
|
fb686ec5b6 | ||
|
|
1d86a75a29 | ||
|
|
ee5b20e12e | ||
|
|
c8184e2497 | ||
|
|
4d00249d97 | ||
|
|
4c43daf336 | ||
|
|
e5dcb6e8c2 | ||
|
|
db89364395 | ||
|
|
6bd52ff6f5 | ||
|
|
d8124d37e4 | ||
|
|
8e841be393 | ||
|
|
1b164dbc42 | ||
|
|
5ae4d0b8c9 | ||
|
|
72ca95e97d | ||
|
|
151ef4d583 | ||
|
|
2d0becc8c5 | ||
|
|
a074636773 | ||
|
|
9009e62cc6 | ||
|
|
dca486ca10 | ||
|
|
fa966348ee | ||
|
|
981a64aac4 | ||
|
|
3eba2211ca | ||
|
|
a529afc133 | ||
|
|
2ba9c13165 | ||
|
|
40ba9c76b1 | ||
|
|
958f4d6b86 | ||
|
|
9ea7fa0518 | ||
|
|
7eb899b780 | ||
|
|
4552cb9778 | ||
|
|
51117fa11f | ||
|
|
fd40c7a24a | ||
|
|
c797c06f92 | ||
|
|
5ec96f5abe | ||
|
|
31b4dae26b | ||
|
|
287a73506c | ||
|
|
8de92bb14b | ||
|
|
991fee51c5 | ||
|
|
d1754559ad | ||
|
|
ec4c811a98 | ||
|
|
ac67e7220b | ||
|
|
b87ecc3ae5 | ||
|
|
fc8920a69a | ||
|
|
c4a1caedae | ||
|
|
fed77108e6 | ||
|
|
779f951c2f | ||
|
|
48562f96f5 | ||
|
|
461bd8c572 | ||
|
|
1617ab45db | ||
|
|
216059c2e5 | ||
|
|
60157fffe2 | ||
|
|
6e2f66987c | ||
|
|
75116b3361 | ||
|
|
a5e00ae57c | ||
|
|
f5ffd4dd77 | ||
|
|
226e189c4a | ||
|
|
665f532301 | ||
|
|
db3ca10c91 | ||
|
|
f9ee80d314 | ||
|
|
5814bcfd99 | ||
|
|
993ea317d7 | ||
|
|
e8aa7edbdc | ||
|
|
15f046a344 | ||
|
|
24947ad280 | ||
|
|
4e0c2382ff | ||
|
|
dcf41fc1a7 | ||
|
|
b279ebe97e | ||
|
|
c3d4bfc05e | ||
|
|
46dcd771f1 | ||
|
|
94efdd9f54 | ||
|
|
04882b603c | ||
|
|
92f6402b2a | ||
|
|
e30eb4de12 | ||
|
|
ae2c163441 | ||
|
|
351d5faa9b |
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@@ -25,6 +25,6 @@ jobs:
|
||||
steps:
|
||||
- uses: tibdex/backport@v2
|
||||
with:
|
||||
labels_template: "<%= JSON.stringify(labels) %>"
|
||||
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
|
||||
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
|
||||
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
- name: Install Dependencies
|
||||
run: "./scripts/layered.sh"
|
||||
|
||||
27
.github/workflows/build_develop.yml
vendored
27
.github/workflows/build_develop.yml
vendored
@@ -22,6 +22,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
- name: Install Dependencies
|
||||
run: "./scripts/layered.sh"
|
||||
@@ -35,19 +36,27 @@ jobs:
|
||||
SENTRY_ORG: element
|
||||
SENTRY_PROJECT: riot-web
|
||||
|
||||
- run: mv dist/element-*.tar.gz webapp.tar.gz
|
||||
|
||||
- run: mv dist/element-*.tar.gz dist/develop.tar.gz
|
||||
|
||||
# We keep the latest develop.tar.gz as the artifact uploaded later expires after 24 and requires auth to download
|
||||
# Element Desktop's fetch script uses this tarball to fetch latest develop to build Nightlies.
|
||||
- name: Deploy develop.tar.gz to Github Pages
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: dist
|
||||
single-commit: true
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
path: dist/develop.tar.gz
|
||||
retention-days: 1
|
||||
|
||||
- name: Wait for other steps to succeed
|
||||
uses: lewagon/wait-on-check-action@v1.0.0
|
||||
uses: lewagon/wait-on-check-action@v1.1.2
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
running-workflow-name: 'Build & Upload source maps to Sentry'
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
wait-interval: 10
|
||||
check-regexp: ^((?!SonarQube|issues|board).)*$
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
path: webapp.tar.gz
|
||||
retention-days: 1
|
||||
|
||||
2
.github/workflows/dockerhub.yaml
vendored
2
.github/workflows/dockerhub.yaml
vendored
@@ -40,6 +40,8 @@ jobs:
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
flavor: |
|
||||
latest=${{ contains(github.ref_name, '-rc.') && 'false' || 'auto' }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
|
||||
39
.github/workflows/static_analysis.yaml
vendored
39
.github/workflows/static_analysis.yaml
vendored
@@ -19,6 +19,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
- name: Install Dependencies
|
||||
run: "./scripts/layered.sh"
|
||||
@@ -39,6 +40,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
@@ -56,6 +58,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
# Needs branch matching as it inherits .stylelintrc.js from matrix-react-sdk
|
||||
- name: Install Dependencies
|
||||
@@ -73,44 +76,10 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
- name: Install Deps
|
||||
run: "scripts/layered.sh"
|
||||
|
||||
- name: Dead Code Analysis
|
||||
run: "yarn run analyse:unused-exports"
|
||||
|
||||
tsc-strict:
|
||||
name: Typescript Strict Error Checker
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get diff lines
|
||||
id: diff
|
||||
uses: Equip-Collaboration/diff-line-numbers@v1.0.0
|
||||
with:
|
||||
include: '["\\.tsx?$"]'
|
||||
|
||||
- name: Detecting files changed
|
||||
id: files
|
||||
uses: futuratrepadeira/changed-files@v3.2.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
pattern: '^.*\.tsx?$'
|
||||
|
||||
- uses: t3chguy/typescript-check-action@main
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
use-check: false
|
||||
check-fail-mode: added
|
||||
output-behaviour: annotate
|
||||
ts-extra-args: '--strict'
|
||||
files-changed: ${{ steps.files.outputs.files_updated }}
|
||||
files-added: ${{ steps.files.outputs.files_created }}
|
||||
files-deleted: ${{ steps.files.outputs.files_deleted }}
|
||||
line-numbers: ${{ steps.diff.outputs.lineNumbers }}
|
||||
|
||||
1
.github/workflows/tests.yaml
vendored
1
.github/workflows/tests.yaml
vendored
@@ -21,6 +21,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
node-version: 16
|
||||
|
||||
- name: Install Dependencies
|
||||
run: "./scripts/layered.sh"
|
||||
|
||||
2
.github/workflows/triage-assigned.yml
vendored
2
.github/workflows/triage-assigned.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
contains(github.event.issue.assignees.*.login, 't3chguy') ||
|
||||
contains(github.event.issue.assignees.*.login, 'turt2live')
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@be108970955040d35dd6d053c3aff3faaf678026
|
||||
with:
|
||||
project: Web App Team
|
||||
column: "In Progress"
|
||||
|
||||
2
.github/workflows/triage-incoming.yml
vendored
2
.github/workflows/triage-incoming.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
automate-project-columns:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@be108970955040d35dd6d053c3aff3faaf678026
|
||||
with:
|
||||
project: Issue triage
|
||||
column: Incoming
|
||||
|
||||
66
.github/workflows/triage-labelled.yml
vendored
66
.github/workflows/triage-labelled.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
name: X-Needs-Info issues to Need info column on triage board
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
|
||||
- uses: konradpabjan/move-labeled-or-milestoned-issue@190352295fe309fcb113b49193bc81d9aaa9cb01
|
||||
with:
|
||||
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
|
||||
project-url: "https://github.com/vector-im/element-web/projects/27"
|
||||
@@ -116,28 +116,28 @@ jobs:
|
||||
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
search_issues_to_board:
|
||||
name: Search issues to project board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-New-Search-Experience')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
Search_issues_to_board:
|
||||
name: Search issues to project board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-New-Search-Experience')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PN_kwDOAM0swc4ADtaO"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PN_kwDOAM0swc4ADtaO"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_voice-message_issues:
|
||||
name: A-Voice Messages to voice message board
|
||||
@@ -161,30 +161,6 @@ jobs:
|
||||
env:
|
||||
PROJECT_ID: "PN_kwDOAM0swc2KCw"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_threads_issues:
|
||||
name: A-Threads to Thread board
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'A-Threads')
|
||||
steps:
|
||||
- uses: octokit/graphql-action@v2.x
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
projectid: ${{ env.PROJECT_ID }}
|
||||
contentid: ${{ github.event.issue.node_id }}
|
||||
env:
|
||||
PROJECT_ID: "PN_kwDOAM0swc0rRA"
|
||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_message_bubbles_issues:
|
||||
name: A-Message-Bubbles to Message bubbles board
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/triage-priority-bugs.yml
vendored
2
.github/workflows/triage-priority-bugs.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
contains(github.event.issue.labels.*.name, 'A11y') &&
|
||||
contains(github.event.issue.labels.*.name, 'O-Frequent'))
|
||||
steps:
|
||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
- uses: alex-page/github-project-automation-plus@be108970955040d35dd6d053c3aff3faaf678026
|
||||
with:
|
||||
project: Crypto Team
|
||||
column: Ready
|
||||
|
||||
2
.github/workflows/triage-unlabelled.yml
vendored
2
.github/workflows/triage-unlabelled.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
- name: Move issue
|
||||
uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
||||
uses: alex-page/github-project-automation-plus@be108970955040d35dd6d053c3aff3faaf678026
|
||||
if: ${{ env.ALREADY_IN_BOARD == 'true' && env.SKIP_ACTION != 'true' }}
|
||||
with:
|
||||
project: Issue triage
|
||||
|
||||
104
CHANGELOG.md
104
CHANGELOG.md
@@ -1,3 +1,107 @@
|
||||
Changes in [1.11.10](https://github.com/vector-im/element-web/releases/tag/v1.11.10) (2022-10-11)
|
||||
=================================================================================================
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
* Use correct default for notification silencing ([\#9388](https://github.com/matrix-org/matrix-react-sdk/pull/9388)). Fixes vector-im/element-web#23456.
|
||||
|
||||
Changes in [1.11.9](https://github.com/vector-im/element-web/releases/tag/v1.11.9) (2022-10-11)
|
||||
===============================================================================================
|
||||
|
||||
## Deprecations
|
||||
* Legacy Piwik config.json option `piwik.policy_url` is deprecated in favour of `privacy_policy_url`. Support will be removed in the next release.
|
||||
|
||||
## ✨ Features
|
||||
* Device manager - select all devices ([\#9330](https://github.com/matrix-org/matrix-react-sdk/pull/9330)). Contributed by @kerryarchibald.
|
||||
* New group call experience: Call tiles ([\#9332](https://github.com/matrix-org/matrix-react-sdk/pull/9332)).
|
||||
* Add Shift key to FormatQuote keyboard shortcut ([\#9298](https://github.com/matrix-org/matrix-react-sdk/pull/9298)). Contributed by @owi92.
|
||||
* Device manager - sign out of multiple sessions ([\#9325](https://github.com/matrix-org/matrix-react-sdk/pull/9325)). Contributed by @kerryarchibald.
|
||||
* Display push toggle for web sessions (MSC3890) ([\#9327](https://github.com/matrix-org/matrix-react-sdk/pull/9327)).
|
||||
* Add device notifications enabled switch ([\#9324](https://github.com/matrix-org/matrix-react-sdk/pull/9324)).
|
||||
* Implement push notification toggle in device detail ([\#9308](https://github.com/matrix-org/matrix-react-sdk/pull/9308)).
|
||||
* New group call experience: Starting and ending calls ([\#9318](https://github.com/matrix-org/matrix-react-sdk/pull/9318)).
|
||||
* New group call experience: Room header call buttons ([\#9311](https://github.com/matrix-org/matrix-react-sdk/pull/9311)).
|
||||
* Make device ID copyable in device list ([\#9297](https://github.com/matrix-org/matrix-react-sdk/pull/9297)). Contributed by @duxovni.
|
||||
* Use display name instead of user ID when rendering power events ([\#9295](https://github.com/matrix-org/matrix-react-sdk/pull/9295)).
|
||||
* Read receipts for threads ([\#9239](https://github.com/matrix-org/matrix-react-sdk/pull/9239)). Fixes #23191.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
* Use the correct sender key when checking shared secret ([\#2730](https://github.com/matrix-org/matrix-js-sdk/pull/2730)). Fixes vector-im/element-web#23374.
|
||||
* Fix device selection in pre-join screen for Element Call video rooms ([\#9321](https://github.com/matrix-org/matrix-react-sdk/pull/9321)). Fixes #23331.
|
||||
* Don't render a 1px high room topic if the room topic is empty ([\#9317](https://github.com/matrix-org/matrix-react-sdk/pull/9317)). Contributed by @Arnei.
|
||||
* Don't show feedback prompts when that UIFeature is disabled ([\#9305](https://github.com/matrix-org/matrix-react-sdk/pull/9305)). Fixes #23327.
|
||||
* Fix soft crash around unknown room pills ([\#9301](https://github.com/matrix-org/matrix-react-sdk/pull/9301)). Fixes matrix-org/element-web-rageshakes#15465.
|
||||
* Fix spaces feedback prompt wrongly showing when feedback is disabled ([\#9302](https://github.com/matrix-org/matrix-react-sdk/pull/9302)). Fixes #23314.
|
||||
* Fix tile soft crash in ReplyInThreadButton ([\#9300](https://github.com/matrix-org/matrix-react-sdk/pull/9300)). Fixes matrix-org/element-web-rageshakes#15493.
|
||||
|
||||
Changes in [1.11.8](https://github.com/vector-im/element-web/releases/tag/v1.11.8) (2022-09-28)
|
||||
===============================================================================================
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
* Bump IDB crypto store version ([\#2705](https://github.com/matrix-org/matrix-js-sdk/pull/2705)).
|
||||
|
||||
Changes in [1.11.7](https://github.com/vector-im/element-web/releases/tag/v1.11.7) (2022-09-28)
|
||||
===============================================================================================
|
||||
|
||||
## 🔒 Security
|
||||
* Fix for [CVE-2022-39249](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D39249)
|
||||
* Fix for [CVE-2022-39250](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D39250)
|
||||
* Fix for [CVE-2022-39251](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D39251)
|
||||
* Fix for [CVE-2022-39236](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D39236)
|
||||
|
||||
Changes in [1.11.6](https://github.com/vector-im/element-web/releases/tag/v1.11.6) (2022-09-20)
|
||||
=========================================================================================================
|
||||
|
||||
## ✨ Features
|
||||
* Element Call video rooms ([\#9267](https://github.com/matrix-org/matrix-react-sdk/pull/9267)).
|
||||
* Device manager - rename session ([\#9282](https://github.com/matrix-org/matrix-react-sdk/pull/9282)).
|
||||
* Allow widgets to read related events ([\#9210](https://github.com/matrix-org/matrix-react-sdk/pull/9210)). Contributed by @dhenneke.
|
||||
* Device manager - logout of other session ([\#9280](https://github.com/matrix-org/matrix-react-sdk/pull/9280)).
|
||||
* Device manager - logout current session ([\#9275](https://github.com/matrix-org/matrix-react-sdk/pull/9275)).
|
||||
* Device manager - verify other devices ([\#9274](https://github.com/matrix-org/matrix-react-sdk/pull/9274)).
|
||||
* Allow integration managers to remove users ([\#9211](https://github.com/matrix-org/matrix-react-sdk/pull/9211)).
|
||||
* Device manager - add verify current session button ([\#9252](https://github.com/matrix-org/matrix-react-sdk/pull/9252)).
|
||||
* Add NotifPanel dot back. ([\#9242](https://github.com/matrix-org/matrix-react-sdk/pull/9242)). Fixes #17641.
|
||||
* Implement MSC3575: Sliding Sync ([\#8328](https://github.com/matrix-org/matrix-react-sdk/pull/8328)).
|
||||
* Add the clipboard read permission for widgets ([\#9250](https://github.com/matrix-org/matrix-react-sdk/pull/9250)). Contributed by @stefanmuhle.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
* Make autocomplete pop-up wider in thread view ([\#9289](https://github.com/matrix-org/matrix-react-sdk/pull/9289)).
|
||||
* Fix soft crash around inviting invalid MXIDs in start DM on first message flow ([\#9281](https://github.com/matrix-org/matrix-react-sdk/pull/9281)). Fixes matrix-org/element-web-rageshakes#15060 and matrix-org/element-web-rageshakes#15140.
|
||||
* Fix in-reply-to previews not disappearing when swapping rooms ([\#9278](https://github.com/matrix-org/matrix-react-sdk/pull/9278)).
|
||||
* Fix invalid instanceof operand window.OffscreenCanvas ([\#9276](https://github.com/matrix-org/matrix-react-sdk/pull/9276)). Fixes #23275.
|
||||
* Fix memory leak caused by unremoved listener ([\#9273](https://github.com/matrix-org/matrix-react-sdk/pull/9273)).
|
||||
* Fix thumbnail generation when offscreen canvas fails ([\#9272](https://github.com/matrix-org/matrix-react-sdk/pull/9272)). Fixes #23265.
|
||||
* Prevent sliding sync from showing a room under multiple sublists ([\#9266](https://github.com/matrix-org/matrix-react-sdk/pull/9266)).
|
||||
* Fix tile crash around tooltipify links ([\#9270](https://github.com/matrix-org/matrix-react-sdk/pull/9270)). Fixes #23253.
|
||||
* Device manager - filter out nulled metadatas in device tile properly ([\#9251](https://github.com/matrix-org/matrix-react-sdk/pull/9251)).
|
||||
* Fix a sliding sync bug which could cause rooms to loop ([\#9268](https://github.com/matrix-org/matrix-react-sdk/pull/9268)).
|
||||
* Remove the grey gradient on images in bubbles in the timeline ([\#9241](https://github.com/matrix-org/matrix-react-sdk/pull/9241)). Fixes #21651.
|
||||
* Fix html export not including images ([\#9260](https://github.com/matrix-org/matrix-react-sdk/pull/9260)). Fixes #22059.
|
||||
* Fix possible soft crash from a race condition in space hierarchies ([\#9254](https://github.com/matrix-org/matrix-react-sdk/pull/9254)). Fixes matrix-org/element-web-rageshakes#15225.
|
||||
* Disable all types of autocorrect, -complete, -capitalize, etc on Spotlight's search field ([\#9259](https://github.com/matrix-org/matrix-react-sdk/pull/9259)).
|
||||
* Handle M_INVALID_USERNAME on /register/available ([\#9237](https://github.com/matrix-org/matrix-react-sdk/pull/9237)). Fixes #23161.
|
||||
* Fix issue with quiet zone around QR code ([\#9243](https://github.com/matrix-org/matrix-react-sdk/pull/9243)). Fixes #23199.
|
||||
|
||||
Changes in [1.11.5](https://github.com/vector-im/element-web/releases/tag/v1.11.5) (2022-09-13)
|
||||
===============================================================================================
|
||||
|
||||
## ✨ Features
|
||||
* Device manager - hide unverified security recommendation when only current session is unverified ([\#9228](https://github.com/matrix-org/matrix-react-sdk/pull/9228)). Contributed by @kerryarchibald.
|
||||
* Device manager - scroll to filtered list from security recommendations ([\#9227](https://github.com/matrix-org/matrix-react-sdk/pull/9227)). Contributed by @kerryarchibald.
|
||||
* Device manager - updated dropdown style in filtered device list ([\#9226](https://github.com/matrix-org/matrix-react-sdk/pull/9226)). Contributed by @kerryarchibald.
|
||||
* Device manager - device type and verification icons on device tile ([\#9197](https://github.com/matrix-org/matrix-react-sdk/pull/9197)). Contributed by @kerryarchibald.
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
* Description of DM room with more than two other people is now being displayed correctly ([\#9231](https://github.com/matrix-org/matrix-react-sdk/pull/9231)). Fixes #23094.
|
||||
* Fix voice messages with multiple composers ([\#9208](https://github.com/matrix-org/matrix-react-sdk/pull/9208)). Fixes #23023. Contributed by @grimhilt.
|
||||
* Fix suggested rooms going missing ([\#9236](https://github.com/matrix-org/matrix-react-sdk/pull/9236)). Fixes #23190.
|
||||
* Fix tooltip infinitely recursing ([\#9235](https://github.com/matrix-org/matrix-react-sdk/pull/9235)). Fixes matrix-org/element-web-rageshakes#15107, matrix-org/element-web-rageshakes#15093 matrix-org/element-web-rageshakes#15092 and matrix-org/element-web-rageshakes#15077.
|
||||
* Fix plain text export saving ([\#9230](https://github.com/matrix-org/matrix-react-sdk/pull/9230)). Contributed by @jryans.
|
||||
* Add missing space in SecurityRoomSettingsTab ([\#9222](https://github.com/matrix-org/matrix-react-sdk/pull/9222)). Contributed by @gefgu.
|
||||
* Make use of js-sdk roomNameGenerator to handle i18n for generated room names ([\#9209](https://github.com/matrix-org/matrix-react-sdk/pull/9209)). Fixes #21369.
|
||||
* Fix progress bar regression throughout the app ([\#9219](https://github.com/matrix-org/matrix-react-sdk/pull/9219)). Fixes #23121.
|
||||
* Reuse empty string & space string logic for event types in devtools ([\#9218](https://github.com/matrix-org/matrix-react-sdk/pull/9218)). Fixes #23115.
|
||||
|
||||
Changes in [1.11.4](https://github.com/vector-im/element-web/releases/tag/v1.11.4) (2022-08-31)
|
||||
===============================================================================================
|
||||
|
||||
|
||||
@@ -117,6 +117,13 @@ add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Content-Security-Policy "frame-ancestors 'none'";
|
||||
```
|
||||
For Apache, the configuration looks like:
|
||||
```
|
||||
Header set X-Frame-Options SAMEORIGIN
|
||||
Header set X-Content-Type-Options nosniff
|
||||
Header set X-XSS-Protection "1; mode=block"
|
||||
Header set Content-Security-Policy "frame-ancestors 'none'"
|
||||
```
|
||||
|
||||
Note: In case you are already setting a `Content-Security-Policy` header
|
||||
elsewhere, you should modify it to include the `frame-ancestors` directive
|
||||
|
||||
@@ -44,5 +44,10 @@
|
||||
"jitsi": {
|
||||
"preferred_domain": "meet.element.io"
|
||||
},
|
||||
"element_call": {
|
||||
"url": "https://call.element.io",
|
||||
"participant_limit": 8,
|
||||
"brand": "Element Call"
|
||||
},
|
||||
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Configuration
|
||||
|
||||
You can configure the app by copying `config.sample.json` to `config.json` and customising it. The possible options are
|
||||
described here. If you run into issues, please visit [#element-web:matrix.org](https://matrix.to/#/#element-web:matrix.org)
|
||||
on Matrix.
|
||||
You can configure the app by copying `config.sample.json` to `config.json` or `config.$domain.json` and customising it.
|
||||
Element will attempt to load first `config.$domain.json` and if it fails `config.json`. This mechanism allows different
|
||||
configuration options depending on if you're hitting e.g. `app1.example.com` or `app2.example.com`. Configs are not mixed
|
||||
in any way, it either entirely uses the domain config, or entirely uses `config.json`.
|
||||
|
||||
The possible configuration options are described here. If you run into issues, please visit
|
||||
[#element-web:matrix.org](https://matrix.to/#/#element-web:matrix.org) on Matrix.
|
||||
|
||||
For a good example of a production-tuned config, see https://app.element.io/config.json
|
||||
|
||||
@@ -243,8 +247,9 @@ When Element is deployed alongside a homeserver with SSO-only login, some option
|
||||
|
||||
## VoIP / Jitsi calls
|
||||
|
||||
Currently, Element uses Jitsi to offer conference calls in rooms. A set of defaults are applied, pointing at our Jitsi instance,
|
||||
to ensure conference calling works, however you can point Element at your own Jitsi if you prefer.
|
||||
Currently, Element uses Jitsi to offer conference calls in rooms, with an experimental Element Call implementation in the works.
|
||||
A set of defaults are applied, pointing at our Jitsi and Element Call instances, to ensure conference calling works, however you
|
||||
can point Element at your own if you prefer.
|
||||
|
||||
More information about the Jitsi setup can be found [here](./jitsi.md).
|
||||
|
||||
@@ -313,6 +318,15 @@ The VoIP and Jitsi options are:
|
||||
as defined by the `io.element.widgets.layout` state event.
|
||||
5. `audio_stream_url`: Optional URL to pass to Jitsi to enable live streaming. This option is considered experimental and may be removed
|
||||
at any time without notice.
|
||||
6. `element_call`: Optional configuration for native group calls using Element Call, with the following subkeys:
|
||||
- `url`: The URL of the Element Call instance to use for native group calls. This option is considered experimental
|
||||
and may be removed at any time without notice. Defaults to `https://call.element.io`.
|
||||
- `use_exclusively`: A boolean specifying whether Element Call should be used exclusively as the only VoIP stack in
|
||||
the app, removing the ability to start legacy 1:1 calls or Jitsi calls. Defaults to `false`.
|
||||
- `participant_limit`: The maximum number of users who can join a call; if
|
||||
this number is exceeded, the user will not be able to join a given call.
|
||||
- `brand`: Optional name for the app. Defaults to `Element Call`. This is
|
||||
used throughout the application in various strings/locations.
|
||||
|
||||
## Bug reporting
|
||||
|
||||
|
||||
12
docs/labs.md
12
docs/labs.md
@@ -162,6 +162,18 @@ This feature might work in degraded mode if the homeserver a user is connected t
|
||||
|
||||
Enables support for creating and joining video rooms, which are persistent video chats that users can jump in and out of.
|
||||
|
||||
## Element Call video rooms (`feature_element_call_video_rooms`) [In Development]
|
||||
|
||||
Enables support for video rooms that use Element Call rather than Jitsi, and causes the 'New video room' option to create Element Call video rooms rather than Jitsi ones.
|
||||
|
||||
This flag will not have any effect unless `feature_video_rooms` is also enabled.
|
||||
|
||||
## New group call experience (`feature_group_calls`) [In Development]
|
||||
|
||||
This feature allows users to place and join native [MSC3401](https://github.com/matrix-org/matrix-spec-proposals/pull/3401) group calls in compatible rooms, using Element Call.
|
||||
|
||||
If you're enabling this at the deployment level, you may also want to reference the docs for the `element_call` config section.
|
||||
|
||||
## Rich text in room topics (`feature_html_topic`) [In Development]
|
||||
|
||||
Enables rendering of MD / HTML in room topics.
|
||||
|
||||
@@ -58,5 +58,8 @@
|
||||
"feature_spotlight": true,
|
||||
"feature_video_rooms": true
|
||||
},
|
||||
"element_call": {
|
||||
"url": "https://element-call.netlify.app"
|
||||
},
|
||||
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||
}
|
||||
|
||||
48
package.json
48
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-web",
|
||||
"version": "1.11.4",
|
||||
"version": "1.11.10",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "New Vector Ltd.",
|
||||
"repository": {
|
||||
@@ -60,15 +60,15 @@
|
||||
"browser-request": "^0.3.3",
|
||||
"gfm.css": "^1.1.2",
|
||||
"jsrsasign": "^10.5.25",
|
||||
"katex": "^0.12.0",
|
||||
"katex": "^0.16.0",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||
"matrix-react-sdk": "github:matrix-org/matrix-react-sdk#develop",
|
||||
"matrix-widget-api": "^1.0.0",
|
||||
"matrix-widget-api": "^1.1.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"sanitize-html": "^2.3.2",
|
||||
"ua-parser-js": "^0.7.24"
|
||||
"ua-parser-js": "^0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.10",
|
||||
@@ -90,26 +90,27 @@
|
||||
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
|
||||
"@sentry/webpack-plugin": "^1.18.1",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@testing-library/react": "^12.1.5",
|
||||
"@types/flux": "^3.1.9",
|
||||
"@types/jest": "^28.0.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"@types/modernizr": "^3.5.3",
|
||||
"@types/node": "^14.14.22",
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.9",
|
||||
"@types/node": "^14.18.28",
|
||||
"@types/react": "^17.0.49",
|
||||
"@types/react-dom": "^17.0.17",
|
||||
"@types/sanitize-html": "^2.3.1",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
||||
"@typescript-eslint/parser": "^5.6.0",
|
||||
"allchange": "^1.0.6",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"babel-jest": "^28.0.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"babel-jest": "^29.0.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"chokidar": "^3.5.1",
|
||||
"concurrently": "^5.3.0",
|
||||
"cpx": "^1.5.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"eslint": "8.9.0",
|
||||
"dotenv": "^16.0.2",
|
||||
"eslint": "8.23.1",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-deprecate": "^0.7.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
@@ -118,24 +119,28 @@
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"fake-indexeddb": "^3.1.2",
|
||||
"fetch-mock-jest": "^1.5.1",
|
||||
"file-loader": "^5.1.0",
|
||||
"fs-extra": "^0.30.0",
|
||||
"html-webpack-plugin": "^4.5.2",
|
||||
"jest": "^28.0.0",
|
||||
"jest-environment-jsdom": "^28.1.3",
|
||||
"jest": "^29.0.0",
|
||||
"jest-canvas-mock": "^2.3.0",
|
||||
"jest-environment-jsdom": "^29.0.0",
|
||||
"jest-mock": "^29.0.0",
|
||||
"jest-raw-loader": "^1.0.1",
|
||||
"jest-sonar-reporter": "^2.0.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"loader-utils": "^1.4.0",
|
||||
"matrix-mock-request": "^2.0.0",
|
||||
"matrix-mock-request": "^2.5.0",
|
||||
"matrix-react-test-utils": "^0.2.3",
|
||||
"matrix-web-i18n": "^1.3.0",
|
||||
"mini-css-extract-plugin": "^0.12.0",
|
||||
"mini-css-extract-plugin": "^1",
|
||||
"minimist": "^1.2.6",
|
||||
"mkdirp": "^1.0.4",
|
||||
"modernizr": "^3.12.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.4",
|
||||
"postcss": "^8.4.16",
|
||||
"postcss-easings": "^2.0.0",
|
||||
"postcss-hexrgba": "2.0.1",
|
||||
"postcss-import": "^12.0.1",
|
||||
@@ -143,7 +148,7 @@
|
||||
"postcss-mixins": "^6.2.3",
|
||||
"postcss-nested": "^4.2.3",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"postcss-scss": "^2.1.1",
|
||||
"postcss-scss": "^4.0.4",
|
||||
"postcss-simple-vars": "^5.0.2",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rimraf": "^3.0.2",
|
||||
@@ -157,7 +162,7 @@
|
||||
"stylelint-scss": "^4.2.0",
|
||||
"terser-webpack-plugin": "^2.3.8",
|
||||
"ts-prune": "^0.10.3",
|
||||
"typescript": "^4.7.4",
|
||||
"typescript": "4.7.4",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
@@ -165,9 +170,6 @@
|
||||
"worklet-loader": "^2.0.0",
|
||||
"yaml": "^2.0.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.14"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
"testEnvironmentOptions": {
|
||||
@@ -176,6 +178,9 @@
|
||||
"testMatch": [
|
||||
"<rootDir>/test/**/*-test.[tj]s?(x)"
|
||||
],
|
||||
"setupFiles": [
|
||||
"jest-canvas-mock"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/node_modules/matrix-react-sdk/test/setupTests.js"
|
||||
],
|
||||
@@ -184,7 +189,6 @@
|
||||
"\\.(gif|png|ttf|woff2)$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/imageMock.js",
|
||||
"\\.svg$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/svg.js",
|
||||
"\\$webapp/i18n/languages.json": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/languages.json",
|
||||
"^browser-request$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/browser-request.js",
|
||||
"^react$": "<rootDir>/node_modules/react",
|
||||
"^react-dom$": "<rootDir>/node_modules/react-dom",
|
||||
"^matrix-js-sdk$": "<rootDir>/node_modules/matrix-js-sdk/src",
|
||||
|
||||
63
release.sh
63
release.sh
@@ -1,68 +1,9 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to perform a release of element-web.
|
||||
#
|
||||
# Requires github-changelog-generator; to install, do
|
||||
# pip install git+https://github.com/matrix-org/github-changelog-generator.git
|
||||
|
||||
set -e
|
||||
|
||||
orig_args=$@
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# chomp any args starting with '-' as these need to go
|
||||
# through to the release script and otherwise we'll get
|
||||
# confused about what the version arg is.
|
||||
while [[ "$1" == -* ]]; do
|
||||
shift
|
||||
done
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
for i in matrix-js-sdk matrix-react-sdk
|
||||
do
|
||||
echo "Checking version of $i..."
|
||||
depver=`cat package.json | jq -r .dependencies[\"$i\"]`
|
||||
latestver=`yarn info -s $i dist-tags.next`
|
||||
if [ "$depver" != "$latestver" ]
|
||||
then
|
||||
echo "The latest version of $i is $latestver but package.json depends on $depver."
|
||||
echo -n "Type 'u' to auto-upgrade, 'c' to continue anyway, or 'a' to abort:"
|
||||
read resp
|
||||
if [ "$resp" != "u" ] && [ "$resp" != "c" ]
|
||||
then
|
||||
echo "Aborting."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$resp" == "u" ]
|
||||
then
|
||||
echo "Upgrading $i to $latestver..."
|
||||
yarn add -E $i@$latestver
|
||||
git add -u
|
||||
git commit -m "Upgrade $i to $latestver"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
./node_modules/matrix-js-sdk/release.sh -n "$orig_args"
|
||||
|
||||
release="${1#v}"
|
||||
tag="v${release}"
|
||||
prerelease=0
|
||||
# We check if this build is a prerelease by looking to
|
||||
# see if the version has a hyphen in it. Crude,
|
||||
# but semver doesn't support postreleases so anything
|
||||
# with a hyphen is a prerelease.
|
||||
echo $release | grep -q '-' && prerelease=1
|
||||
|
||||
if [ $prerelease -eq 0 ]
|
||||
then
|
||||
# For a release, reset SDK deps back to the `develop` branch.
|
||||
for i in matrix-js-sdk matrix-react-sdk
|
||||
do
|
||||
echo "Resetting $i to develop branch..."
|
||||
yarn add github:matrix-org/$i#develop
|
||||
git add -u
|
||||
git commit -m "Reset $i back to develop branch"
|
||||
done
|
||||
git push origin develop
|
||||
fi
|
||||
./node_modules/matrix-js-sdk/release.sh "$@"
|
||||
|
||||
@@ -2,3 +2,5 @@ signing_id: releases@riot.im
|
||||
subprojects:
|
||||
matrix-react-sdk:
|
||||
includeByDefault: true
|
||||
matrix-js-sdk:
|
||||
includeByDefault: false
|
||||
|
||||
@@ -36,10 +36,12 @@ limitations under the License.
|
||||
"Apple Color Emoji",
|
||||
"Segoe UI Emoji",
|
||||
"Segoe UI Symbol";
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
height: auto;
|
||||
color: #000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.mx_ErrorView_container {
|
||||
max-width: 680px;
|
||||
|
||||
@@ -7,8 +7,10 @@ DIST_VERSION=$(git describe --abbrev=0 --tags)
|
||||
|
||||
DIR=$(dirname "$0")
|
||||
|
||||
# If we're not using custom SDKs and on a branch other than master, generate a version akin go develop.element.io
|
||||
if [[ $USE_CUSTOM_SDKS == false ]] && [[ $BRANCH != 'master' ]]
|
||||
# If the branch comes out as HEAD then we're probably checked out to a tag, so if the thing is *not*
|
||||
# coming out as HEAD then we're on a branch. When we're on a branch, we want to resolve ourselves to
|
||||
# a few SHAs rather than a version.
|
||||
if [[ $BRANCH != HEAD && ! $BRANCH =~ heads/v.+ ]]
|
||||
then
|
||||
DIST_VERSION=$("$DIR"/get-version-from-git.sh)
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# the branch the current checkout is on, use that branch. Otherwise,
|
||||
# use develop.
|
||||
|
||||
set -ex
|
||||
set -x
|
||||
|
||||
GIT_CLONE_ARGS=("$@")
|
||||
[ -z "$defbranch" ] && defbranch="develop"
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
# all phonenumber.js-supported country flags (as SVGs) into
|
||||
# PNGs that can be used by CountryDropdown.js.
|
||||
|
||||
set -e
|
||||
|
||||
# Allow CTRL+C to terminate the script
|
||||
trap "echo Exited!; exit;" SIGINT SIGTERM
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# Echoes a version based on the git hashes of the element-web, react-sdk & js-sdk checkouts, for the case where
|
||||
# these dependencies are git checkouts.
|
||||
|
||||
set -e
|
||||
|
||||
# Since the deps are fetched from git, we can rev-parse
|
||||
REACT_SHA=$(git -C node_modules/matrix-react-sdk rev-parse --short=12 HEAD)
|
||||
JSSDK_SHA=$(git -C node_modules/matrix-js-sdk rev-parse --short=12 HEAD)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
# Creates a layered environment with the full repo for the app and SDKs cloned
|
||||
# and linked. This gives an element-web dev environment ready to build with
|
||||
|
||||
@@ -12,8 +12,7 @@ then
|
||||
exit
|
||||
fi
|
||||
|
||||
set -e
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
tmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'icontmp'`
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# If $1 looks like v1.2.3 or v1.2.3-foo, strip the leading v, then print it to stdout
|
||||
if [[ $1 =~ ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(-.+)?$ ]]; then
|
||||
echo ${1:1}
|
||||
|
||||
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import * as React from 'react';
|
||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
||||
|
||||
export default class VectorAuthHeaderLogo extends React.PureComponent {
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { CSSProperties } from 'react';
|
||||
import * as React from 'react';
|
||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
||||
|
||||
import VectorAuthFooter from "./VectorAuthFooter";
|
||||
@@ -47,12 +47,12 @@ export default class VectorAuthPage extends React.PureComponent {
|
||||
background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`,
|
||||
};
|
||||
|
||||
const modalStyle: CSSProperties = {
|
||||
const modalStyle: React.CSSProperties = {
|
||||
position: 'relative',
|
||||
background: 'initial',
|
||||
};
|
||||
|
||||
const blurStyle: CSSProperties = {
|
||||
const blurStyle: React.CSSProperties = {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
@@ -62,7 +62,7 @@ export default class VectorAuthPage extends React.PureComponent {
|
||||
background: pageStyle.background,
|
||||
};
|
||||
|
||||
const modalContentStyle: CSSProperties = {
|
||||
const modalContentStyle: React.CSSProperties = {
|
||||
display: 'flex',
|
||||
zIndex: 1,
|
||||
background: 'rgba(255, 255, 255, 0.59)',
|
||||
|
||||
@@ -84,12 +84,19 @@ export default class Favicon {
|
||||
}
|
||||
}
|
||||
|
||||
private reset() {
|
||||
private reset(): void {
|
||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
this.context.drawImage(this.baseImage, 0, 0, this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
private options(n: number | string, params: IParams) {
|
||||
private options(n: number | string, params: IParams): {
|
||||
n: string | number;
|
||||
len: number;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
} {
|
||||
const opt = {
|
||||
n: ((typeof n) === "number") ? Math.abs(n as number | 0) : n,
|
||||
len: ("" + n).length,
|
||||
@@ -124,7 +131,7 @@ export default class Favicon {
|
||||
return opt;
|
||||
}
|
||||
|
||||
private circle(n: number | string, opts?: Partial<IParams>) {
|
||||
private circle(n: number | string, opts?: Partial<IParams>): void {
|
||||
const params = { ...this.params, ...opts };
|
||||
const opt = this.options(n, params);
|
||||
|
||||
@@ -177,19 +184,19 @@ export default class Favicon {
|
||||
this.context.closePath();
|
||||
}
|
||||
|
||||
private ready() {
|
||||
private ready(): void {
|
||||
if (this.isReady) return;
|
||||
this.isReady = true;
|
||||
this.readyCb?.();
|
||||
}
|
||||
|
||||
private setIcon(canvas) {
|
||||
private setIcon(canvas: HTMLCanvasElement): void {
|
||||
setImmediate(() => {
|
||||
this.setIconSrc(canvas.toDataURL("image/png"));
|
||||
});
|
||||
}
|
||||
|
||||
private setIconSrc(url) {
|
||||
private setIconSrc(url: string): void {
|
||||
// if is attached to fav icon
|
||||
if (this.browser.ff || this.browser.opera) {
|
||||
// for FF we need to "recreate" element, attach to dom and remove old <link>
|
||||
@@ -200,9 +207,7 @@ export default class Favicon {
|
||||
newIcon.setAttribute("type", "image/png");
|
||||
window.document.getElementsByTagName("head")[0].appendChild(newIcon);
|
||||
newIcon.setAttribute("href", url);
|
||||
if (old.parentNode) {
|
||||
old.parentNode.removeChild(old);
|
||||
}
|
||||
old.parentNode?.removeChild(old);
|
||||
} else {
|
||||
this.icons.forEach(icon => {
|
||||
icon.setAttribute("href", url);
|
||||
@@ -210,7 +215,7 @@ export default class Favicon {
|
||||
}
|
||||
}
|
||||
|
||||
public badge(content: number | string, opts?: Partial<IParams>) {
|
||||
public badge(content: number | string, opts?: Partial<IParams>): void {
|
||||
if (!this.isReady) {
|
||||
this.readyCb = () => {
|
||||
this.badge(content, opts);
|
||||
@@ -227,7 +232,7 @@ export default class Favicon {
|
||||
this.setIcon(this.canvas);
|
||||
}
|
||||
|
||||
private static getLinks() {
|
||||
private static getLinks(): HTMLLinkElement[] {
|
||||
const icons: HTMLLinkElement[] = [];
|
||||
const links = window.document.getElementsByTagName("head")[0].getElementsByTagName("link");
|
||||
for (const link of links) {
|
||||
@@ -238,7 +243,7 @@ export default class Favicon {
|
||||
return icons;
|
||||
}
|
||||
|
||||
private static getIcons() {
|
||||
private static getIcons(): HTMLLinkElement[] {
|
||||
// get favicon link elements
|
||||
let elms = Favicon.getLinks();
|
||||
if (elms.length === 0) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"Sign In": "Anmelden",
|
||||
"Create Account": "Konto erstellen",
|
||||
"Explore rooms": "Räume erkunden",
|
||||
"Unexpected error preparing the app. See console for details.": "Unerwarteter Fehler bei der Vorbereitung der App. Siehe in die Konsole für mehr Details.",
|
||||
"Unexpected error preparing the app. See console for details.": "Unerwarteter Fehler bei der Vorbereitung der App; mehr Details in der Konsole.",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Ungültige Konfiguration: Es kann nur eine der Optionen default_server_config, default_server_name oder default_hs_url angegeben werden.",
|
||||
"Invalid configuration: no default server specified.": "Ungültige Konfiguration: Es wurde kein Standardserver angegeben.",
|
||||
"The message from the parser is: %(message)s": "Die Nachricht des Parsers ist: %(message)s",
|
||||
@@ -21,7 +21,7 @@
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Du kannst deinen aktuellen Browser weiterhin verwenden. Es ist aber möglich, dass nicht alles richtig funktioniert oder das Aussehen der App inkorrekt ist.",
|
||||
"I understand the risks and wish to continue": "Ich verstehe die Risiken und möchte fortfahren",
|
||||
"Your Element is misconfigured": "Dein Element ist falsch konfiguriert",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Deine Elementkonfiguration enthält ungültiges JSON. Bitte korrigiere das Problem und lade die Seite neu.",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Deine Element-Konfiguration enthält ungültiges JSON. Bitte korrigiere das Problem und lade die Seite neu.",
|
||||
"Download Completed": "Herunterladen fertiggestellt",
|
||||
"Open": "Öffnen",
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s verwendet erweiterte Browserfunktionen, die von deinem Browser nicht unterstützt werden.",
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
"Download Completed": "Download Completed",
|
||||
"Open": "Open",
|
||||
"Dismiss": "Dismiss",
|
||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)",
|
||||
"%(brand)s Desktop: %(platformName)s": "%(brand)s Desktop: %(platformName)s",
|
||||
"Go to your browser to complete Sign In": "Go to your browser to complete Sign In",
|
||||
"Unknown device": "Unknown device",
|
||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
||||
"%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s on %(osName)s",
|
||||
"Powered by Matrix": "Powered by Matrix",
|
||||
"Use %(brand)s on mobile": "Use %(brand)s on mobile",
|
||||
"Unsupported browser": "Unsupported browser",
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"Dismiss": "Abaikan",
|
||||
"Unknown device": "Perangkat tidak dikenal",
|
||||
"Unknown device": "Perangkat tidak diketahui",
|
||||
"Welcome to Element": "Selamat datang di Element",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Konfigurasi Element Anda berisi JSON yang tidak valid. Mohon perbaiki masalahnya dan muat ulang halamannya.",
|
||||
"Invalid configuration: no default server specified.": "Konfigurasi tidak valid: server bawaan belum ditentukan.",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Konfigurasi Element Anda berisi JSON yang tidak absah. Mohon perbaiki masalahnya dan muat ulang laman ini.",
|
||||
"Invalid configuration: no default server specified.": "Konfigurasi tidak absah: server bawaan belum ditentukan.",
|
||||
"Explore rooms": "Jelajahi ruangan",
|
||||
"Create Account": "Buat Akun",
|
||||
"Go to your browser to complete Sign In": "Buka browser Anda untuk menyelesaikan Sign In",
|
||||
"Go to your browser to complete Sign In": "Buka peramban Anda untuk menyelesaikan Sign In",
|
||||
"Sign In": "Masuk",
|
||||
"Failed to start": "Gagal untuk memulai",
|
||||
"Go to element.io": "Buka element.io",
|
||||
"I understand the risks and wish to continue": "Saya memahami risikonya dan ingin melanjutkan",
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Anda dapat lanjut menggunakan browser Anda saat ini, tetapi beberapa atau semua fitur mungkin tidak berfungsi dan tampilan serta nuansa aplikasi mungkin salah.",
|
||||
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Mohon instal <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, atau <safariLink>Safari</safariLink> untuk pengalaman yang terbaik.",
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s menggunakan fitur browser lanjutan yang tidak didukung oleh browser Anda saat ini.",
|
||||
"Your browser can't run %(brand)s": "Browser Anda tidak dapat menjalankan %(brand)s",
|
||||
"Unsupported browser": "Browser tidak didukung",
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Anda dapat melanjutkan menggunakan peramban Anda saat ini, tetapi beberapa atau semua fitur mungkin tidak berfungsi dan tampilan serta nuansa aplikasi mungkin tidak benar.",
|
||||
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Silakan instal <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, atau <safariLink>Safari</safariLink> untuk pengalaman yang terbaik.",
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s menggunakan fitur peramban tingkat lanjut yang tidak didukung oleh peramban Anda saat ini.",
|
||||
"Your browser can't run %(brand)s": "Peramban Anda tidak dapat menjalankan %(brand)s",
|
||||
"Unsupported browser": "Peramban tidak didukung",
|
||||
"Use %(brand)s on mobile": "Gunakan %(brand)s di ponsel",
|
||||
"Powered by Matrix": "Diberdayakan oleh Matrix",
|
||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
||||
@@ -23,10 +23,10 @@
|
||||
"Open": "Buka",
|
||||
"Download Completed": "Unduhan Selesai",
|
||||
"Unexpected error preparing the app. See console for details.": "Kesalahan tak terduga saat menyiapkan aplikasi. Lihat konsol untuk detail.",
|
||||
"Unable to load config file: please refresh the page to try again.": "Tidak dapat memuat file konfigurasi: mohon muat ulang halaman ini untuk mencoba lagi.",
|
||||
"Invalid JSON": "JSON tidak valid",
|
||||
"Unable to load config file: please refresh the page to try again.": "Tidak dapat memuat file konfigurasi: mohon muat ulang laman ini untuk mencoba lagi.",
|
||||
"Invalid JSON": "JSON tidak absah",
|
||||
"The message from the parser is: %(message)s": "Pesan dari pengurai adalah: %(message)s",
|
||||
"Your Element is misconfigured": "Anda mengatur Element dengan salah",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Konfigurasi tidak valid: hanya bisa menentukan satu dari default_server_config, default_server_name, atau default_hs_url.",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Obrolan & kolaborasi terdesentralisasi dan terenkripsi, diberdayakan oleh $matrixLogo"
|
||||
"Your Element is misconfigured": "Anda salah mengatur Element",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Konfigurasi tidak absah: hanya bisa menentukan satu dari default_server_config, default_server_name, atau default_hs_url.",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Obrolan & kolaborasi terdesentralisasi dan terenkripsi diberdayakan oleh $matrixLogo"
|
||||
}
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s naudoja išplėstines naršyklės funkcijas, kurių jūsų dabartinė naršyklė nepalaiko.",
|
||||
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Geriausiam veikimui suinstaliuokite <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, arba <safariLink>Safari</safariLink>.",
|
||||
"Powered by Matrix": "Veikia su Matrix",
|
||||
"Use %(brand)s on mobile": "Naudoti %(brand)s mobiliajame telefone"
|
||||
"Use %(brand)s on mobile": "Naudoti %(brand)s mobiliajame telefone",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizuotas, užšifruotų pokalbių & bendradarbiavimas, paremtas $matrixLogo"
|
||||
}
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
"Your Element is misconfigured": "Jūsu Element ir nokonfigurēts kļūdaini",
|
||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s Galdvirsmas (%(platformName)s)",
|
||||
"Use %(brand)s on mobile": "Mobilajā tālrunī izmanojiet %(brand)s"
|
||||
"Use %(brand)s on mobile": "Mobilajā tālrunī izmanojiet %(brand)s",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizēta, šifrēta saziņa & sadarbība, ko nodrošina $matrixLogo"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
||||
"Unsupported browser": "Niewspierana przeglądarka",
|
||||
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Zainstaluj <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, lub <safariLink>Safari</safariLink> w celu zapewnienia najlepszego działania.",
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Możesz kontynuować używanie obecnej przeglądarki, lecz niektóre lub wszystkie funkcje mogą nie działać oraz wygląd aplikacji może być niepoprawny.",
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Możesz kontynuować używając obecnej przeglądarki, lecz niektóre lub wszystkie funkcje mogą nie działać oraz wygląd aplikacji może być niepoprawny.",
|
||||
"I understand the risks and wish to continue": "Rozumiem ryzyko i chcę kontynuować",
|
||||
"Go to element.io": "Przejdź do element.io",
|
||||
"Failed to start": "Nie udało się wystartować",
|
||||
@@ -24,12 +24,12 @@
|
||||
"Open": "Otwórz",
|
||||
"Your browser can't run %(brand)s": "Twoja przeglądarka nie obsługuje %(brand)s",
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s używa zaawansowanych funkcji które nie są dostępne w obecnej przeglądarce.",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Konfiguracja Elementa zawiera niepoprawny JSON. Popraw konfiguracje i odśwież stronę.",
|
||||
"Your Element is misconfigured": "Element jest nieprawidłowo skonfigurowany",
|
||||
"Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Twoja konfiguracja Elementa zawiera niepoprawny JSON. Rozwiąż problem i odśwież stronę.",
|
||||
"Your Element is misconfigured": "Twój Element jest nieprawidłowo skonfigurowany",
|
||||
"Powered by Matrix": "Zasilane przez Matrix",
|
||||
"Use %(brand)s on mobile": "Użyj %(brand)s w telefonie",
|
||||
"Switch to space by number": "Przełącz na przestrzeń według numeru",
|
||||
"Next recently visited room or community": "Następne ostatnio odwiedzone pokoje i społeczności",
|
||||
"Previous recently visited room or community": "Ostatnio odwiedzone pokoje i społeczności",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Zdecentralizowany, szyfrowany czat i współpraca wspierana przez $matrixLogo"
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Zdecentralizowany, szyfrowany czat i współpraca oparte na $matrixLogo"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"Welcome to Element": "Добро пожаловать в Element",
|
||||
"Sign In": "Войти",
|
||||
"Create Account": "Создать учётную запись",
|
||||
"Explore rooms": "Список комнат",
|
||||
"Explore rooms": "Обзор комнат",
|
||||
"Unexpected error preparing the app. See console for details.": "Неожиданная ошибка при подготовке приложения. Подробности см. в консоли.",
|
||||
"Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Неверная конфигурация: можно указывать только один из следующих параметров: default_server_config, default_server_name или default_hs_url.",
|
||||
"Invalid configuration: no default server specified.": "Неверная конфигурация: сервер по умолчанию не указан.",
|
||||
|
||||
@@ -26,5 +26,6 @@
|
||||
"You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Lahko nadaljujete z uporabo vašega trenutnega brskalnika, vendar lahko to privede do manjkajočih funkcionalnosti ali napačnega izgleda aplikacije.",
|
||||
"I understand the risks and wish to continue": "Razumem riziko in želim vseeno nadaljevati",
|
||||
"Go to element.io": "Pojdi na element.io",
|
||||
"Failed to start": "Neuspel zagon"
|
||||
"Failed to start": "Neuspel zagon",
|
||||
"Use %(brand)s on mobile": "Uporabi %(brand)s na mobilni napravi"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"Go to your browser to complete Sign In": "Перейдіть у ваш браузер щоб завершити вхід",
|
||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
||||
"Powered by Matrix": "Працює на Matrix",
|
||||
"Your browser can't run %(brand)s": "Ваш переглядач неспроможний запустити %(brand)s",
|
||||
"Your browser can't run %(brand)s": "Ваш браузер не може запустити %(brand)s",
|
||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s використовує передові властивості, які ваш браузер не підтримує.",
|
||||
"Use %(brand)s on mobile": "Користуйтеся %(brand)s на мобільному",
|
||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Децентралізована, зашифрована бесіда та співпраця на основі $matrixLogo"
|
||||
|
||||
@@ -18,8 +18,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// To ensure we load the browser-request version
|
||||
import "matrix-js-sdk"; // eslint-disable-line no-restricted-imports
|
||||
// To ensure we load the browser-matrix version first
|
||||
import "matrix-js-sdk/src/browser-index";
|
||||
|
||||
import React from 'react';
|
||||
import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg';
|
||||
|
||||
@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import request from 'browser-request';
|
||||
|
||||
import type { IConfigOptions } from "matrix-react-sdk/src/IConfigOptions";
|
||||
|
||||
// Load the config file. First try to load up a domain-specific config of the
|
||||
@@ -32,44 +30,28 @@ export async function getVectorConfig(relativeLocation=''): Promise<IConfigOptio
|
||||
if (Object.keys(configJson).length === 0) {
|
||||
throw new Error(); // throw to enter the catch
|
||||
}
|
||||
return configJson as IConfigOptions;
|
||||
return configJson;
|
||||
} catch (e) {
|
||||
return await generalConfigPromise as IConfigOptions;
|
||||
return generalConfigPromise;
|
||||
}
|
||||
}
|
||||
|
||||
function getConfig(configJsonFilename: string): Promise<{}> {
|
||||
return new Promise(function(resolve, reject) {
|
||||
request(
|
||||
{ method: "GET", url: configJsonFilename, qs: { cachebuster: Date.now() } },
|
||||
(err, response, body) => {
|
||||
try {
|
||||
if (err || response.status < 200 || response.status >= 300) {
|
||||
// Lack of a config isn't an error, we should
|
||||
// just use the defaults.
|
||||
// Also treat a blank config as no config, assuming
|
||||
// the status code is 0, because we don't get 404s
|
||||
// from file: URIs so this is the only way we can
|
||||
// not fail if the file doesn't exist when loading
|
||||
// from a file:// URI.
|
||||
if (response) {
|
||||
if (response.status == 404 || (response.status == 0 && body == '')) {
|
||||
resolve({});
|
||||
}
|
||||
}
|
||||
reject({ err: err, response: response });
|
||||
return;
|
||||
}
|
||||
|
||||
// We parse the JSON ourselves rather than use the JSON
|
||||
// parameter, since this throws a parse error on empty
|
||||
// which breaks if there's no config.json and we're
|
||||
// loading from the filesystem (see above).
|
||||
resolve(JSON.parse(body));
|
||||
} catch (e) {
|
||||
reject({ err: e });
|
||||
}
|
||||
},
|
||||
);
|
||||
async function getConfig(configJsonFilename: string): Promise<IConfigOptions> {
|
||||
const url = new URL(configJsonFilename, window.location.href);
|
||||
url.searchParams.set("cachebuster", Date.now().toString());
|
||||
const res = await fetch(url, {
|
||||
cache: "no-cache",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (res.status === 404 || res.status === 0) {
|
||||
// Lack of a config isn't an error, we should just use the defaults.
|
||||
// Also treat a blank config as no config, assuming the status code is 0, because we don't get 404s from file:
|
||||
// URIs so this is the only way we can not fail if the file doesn't exist when loading from a file:// URI.
|
||||
return {} as IConfigOptions;
|
||||
}
|
||||
|
||||
if (res.ok) {
|
||||
return res.json();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ import VectorBasePlatform from './VectorBasePlatform';
|
||||
import { SeshatIndexManager } from "./SeshatIndexManager";
|
||||
import { IPCManager } from "./IPCManager";
|
||||
|
||||
const electron = window.electron;
|
||||
const isMac = navigator.platform.toUpperCase().includes('MAC');
|
||||
|
||||
function platformFriendlyName(): string {
|
||||
@@ -70,7 +69,7 @@ function platformFriendlyName(): string {
|
||||
function onAction(payload: ActionPayload): void {
|
||||
// Whitelist payload actions, no point sending most across
|
||||
if (['call_state'].includes(payload.action)) {
|
||||
electron.send('app_onAction', payload);
|
||||
window.electron.send('app_onAction', payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +102,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
false if there is not
|
||||
or the error if one is encountered
|
||||
*/
|
||||
electron.on('check_updates', (event, status) => {
|
||||
window.electron.on('check_updates', (event, status) => {
|
||||
dis.dispatch<CheckUpdatesPayload>({
|
||||
action: Action.CheckUpdates,
|
||||
...getUpdateCheckStatus(status),
|
||||
@@ -111,27 +110,27 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
});
|
||||
|
||||
// try to flush the rageshake logs to indexeddb before quit.
|
||||
electron.on('before-quit', function() {
|
||||
window.electron.on('before-quit', function() {
|
||||
logger.log('element-desktop closing');
|
||||
rageshake.flush();
|
||||
});
|
||||
|
||||
electron.on('update-downloaded', this.onUpdateDownloaded);
|
||||
window.electron.on('update-downloaded', this.onUpdateDownloaded);
|
||||
|
||||
electron.on('preferences', () => {
|
||||
window.electron.on('preferences', () => {
|
||||
dis.fire(Action.ViewUserSettings);
|
||||
});
|
||||
|
||||
electron.on('userDownloadCompleted', (ev, { id, name }) => {
|
||||
window.electron.on('userDownloadCompleted', (ev, { id, name }) => {
|
||||
const key = `DOWNLOAD_TOAST_${id}`;
|
||||
|
||||
const onAccept = () => {
|
||||
electron.send('userDownloadAction', { id, open: true });
|
||||
window.electron.send('userDownloadAction', { id, open: true });
|
||||
ToastStore.sharedInstance().dismissToast(key);
|
||||
};
|
||||
|
||||
const onDismiss = () => {
|
||||
electron.send('userDownloadAction', { id });
|
||||
window.electron.send('userDownloadAction', { id });
|
||||
};
|
||||
|
||||
ToastStore.sharedInstance().addOrReplaceToast({
|
||||
@@ -187,7 +186,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
if (this.notificationCount === count) return;
|
||||
super.setNotificationCount(count);
|
||||
|
||||
electron.send('setBadgeCount', count);
|
||||
window.electron.send('setBadgeCount', count);
|
||||
}
|
||||
|
||||
public supportsNotifications(): boolean {
|
||||
@@ -233,7 +232,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
}
|
||||
|
||||
public loudNotification(ev: MatrixEvent, room: Room) {
|
||||
electron.send('loudNotification');
|
||||
window.electron.send('loudNotification');
|
||||
}
|
||||
|
||||
public needsUrlTooltips(): boolean {
|
||||
@@ -269,19 +268,19 @@ export default class ElectronPlatform extends VectorBasePlatform {
|
||||
|
||||
public startUpdateCheck() {
|
||||
super.startUpdateCheck();
|
||||
electron.send('check_updates');
|
||||
window.electron.send('check_updates');
|
||||
}
|
||||
|
||||
public installUpdate() {
|
||||
// IPC to the main process to install the update, since quitAndInstall
|
||||
// doesn't fire the before-quit event so the main process needs to know
|
||||
// it should exit.
|
||||
electron.send('install_update');
|
||||
window.electron.send('install_update');
|
||||
}
|
||||
|
||||
public getDefaultDeviceDisplayName(): string {
|
||||
const brand = SdkConfig.get().brand;
|
||||
return _t('%(brand)s Desktop (%(platformName)s)', {
|
||||
return _t('%(brand)s Desktop: %(platformName)s', {
|
||||
brand,
|
||||
platformName: platformFriendlyName(),
|
||||
});
|
||||
|
||||
@@ -19,8 +19,6 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { ElectronChannel } from "../../@types/global";
|
||||
|
||||
const electron = window.electron;
|
||||
|
||||
interface IPCPayload {
|
||||
id?: number;
|
||||
error?: string;
|
||||
@@ -35,7 +33,7 @@ export class IPCManager {
|
||||
private readonly sendChannel: ElectronChannel = "ipcCall",
|
||||
private readonly recvChannel: ElectronChannel = "ipcReply",
|
||||
) {
|
||||
electron.on(this.recvChannel, this.onIpcReply);
|
||||
window.electron.on(this.recvChannel, this.onIpcReply);
|
||||
}
|
||||
|
||||
public async call(name: string, ...args: any[]): Promise<any> {
|
||||
|
||||
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { UpdateCheckStatus, UpdateStatus } from "matrix-react-sdk/src/BasePlatform";
|
||||
import request from 'browser-request';
|
||||
import dis from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
||||
import { _t } from 'matrix-react-sdk/src/languageHandler';
|
||||
import { hideToast as hideUpdateToast, showToast as showUpdateToast } from "matrix-react-sdk/src/toasts/UpdateToast";
|
||||
@@ -87,31 +86,18 @@ export default class WebPlatform extends VectorBasePlatform {
|
||||
});
|
||||
}
|
||||
|
||||
private getMostRecentVersion(): Promise<string> {
|
||||
// We add a cachebuster to the request to make sure that we know about
|
||||
// the most recent version on the origin server. That might not
|
||||
// actually be the version we'd get on a reload (particularly in the
|
||||
// presence of intermediate caching proxies), but still: we're trying
|
||||
// to tell the user that there is a new version.
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(
|
||||
{
|
||||
method: "GET",
|
||||
url: "version",
|
||||
qs: { cachebuster: Date.now() },
|
||||
},
|
||||
(err, response, body) => {
|
||||
if (err || response.status < 200 || response.status >= 300) {
|
||||
if (err === null) err = { status: response.status };
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(getNormalizedAppVersion(body.trim()));
|
||||
},
|
||||
);
|
||||
private async getMostRecentVersion(): Promise<string> {
|
||||
const res = await fetch("version", {
|
||||
method: "GET",
|
||||
cache: "no-cache",
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const text = await res.text();
|
||||
return getNormalizedAppVersion(text.trim());
|
||||
}
|
||||
|
||||
return Promise.reject({ status: res.status });
|
||||
}
|
||||
|
||||
public getAppVersion(): Promise<string> {
|
||||
@@ -210,7 +196,7 @@ export default class WebPlatform extends VectorBasePlatform {
|
||||
let osName = ua.getOS().name || "unknown OS";
|
||||
// Stylise the value from the parser to match Apple's current branding.
|
||||
if (osName === "Mac OS") osName = "macOS";
|
||||
return _t('%(appName)s (%(browserName)s, %(osName)s)', {
|
||||
return _t('%(appName)s: %(browserName)s on %(osName)s', {
|
||||
appName,
|
||||
browserName,
|
||||
osName,
|
||||
|
||||
@@ -41,6 +41,7 @@ import { RoomView as RoomViewClass } from 'matrix-react-sdk/src/components/struc
|
||||
import LoginComponent from 'matrix-react-sdk/src/components/structures/auth/Login';
|
||||
import WelcomeComponent from "matrix-react-sdk/src/components/views/auth/Welcome";
|
||||
import EmbeddedPage from "matrix-react-sdk/src/components/structures/EmbeddedPage";
|
||||
import { AutoDiscovery } from 'matrix-js-sdk/src/matrix';
|
||||
|
||||
const DEFAULT_HS_URL='http://my_server';
|
||||
const DEFAULT_IS_URL='http://my_is';
|
||||
@@ -60,7 +61,7 @@ describe('loading:', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
httpBackend = new MockHttpBackend();
|
||||
jssdk.request(httpBackend.requestFn);
|
||||
window.fetch = httpBackend.fetchFn;
|
||||
parentDiv = document.createElement('div');
|
||||
|
||||
// uncomment this to actually add the div to the UI, to help with
|
||||
@@ -73,21 +74,25 @@ describe('loading:', function() {
|
||||
|
||||
afterEach(async function() {
|
||||
console.log(`${Date.now()}: loading: afterEach`);
|
||||
if (parentDiv) {
|
||||
ReactDOM.unmountComponentAtNode(parentDiv);
|
||||
parentDiv.remove();
|
||||
parentDiv = null;
|
||||
try {
|
||||
if (matrixChat) {
|
||||
ReactDOM.unmountComponentAtNode(parentDiv);
|
||||
parentDiv.remove();
|
||||
parentDiv = null;
|
||||
}
|
||||
|
||||
// unmounting should have cleared the MatrixClientPeg
|
||||
expect(MatrixClientPeg.get()).toBe(null);
|
||||
|
||||
// clear the indexeddbs so we can start from a clean slate next time.
|
||||
await Promise.all([
|
||||
test_utils.deleteIndexedDB('matrix-js-sdk:crypto'),
|
||||
test_utils.deleteIndexedDB('matrix-js-sdk:riot-web-sync'),
|
||||
]);
|
||||
cleanLocalstorage();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
// unmounting should have cleared the MatrixClientPeg
|
||||
expect(MatrixClientPeg.get()).toBe(null);
|
||||
|
||||
// clear the indexeddbs so we can start from a clean slate next time.
|
||||
await Promise.all([
|
||||
test_utils.deleteIndexedDB('matrix-js-sdk:crypto'),
|
||||
test_utils.deleteIndexedDB('matrix-js-sdk:riot-web-sync'),
|
||||
]);
|
||||
cleanLocalstorage();
|
||||
console.log(`${Date.now()}: loading: afterEach complete`);
|
||||
});
|
||||
|
||||
@@ -421,7 +426,6 @@ describe('loading:', function() {
|
||||
|
||||
describe('Guest auto-registration:', function() {
|
||||
it('shows a welcome page by default', function() {
|
||||
|
||||
loadApp();
|
||||
|
||||
return sleep(1).then(() => {
|
||||
|
||||
431
test/unit-tests/__snapshots__/favicon-test.ts.snap
Normal file
431
test/unit-tests/__snapshots__/favicon-test.ts.snap
Normal file
@@ -0,0 +1,431 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Favicon should clear a badge if called with a zero value 1`] = `
|
||||
[
|
||||
{
|
||||
"props": {
|
||||
"height": 32,
|
||||
"width": 32,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "clearRect",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"dHeight": 32,
|
||||
"dWidth": 32,
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"img": <img
|
||||
height="32"
|
||||
width="32"
|
||||
/>,
|
||||
"sHeight": 32,
|
||||
"sWidth": 32,
|
||||
"sx": 0,
|
||||
"sy": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "drawImage",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"fillRule": "nonzero",
|
||||
"path": [
|
||||
{
|
||||
"props": {},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "beginPath",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 16.159999999999997,
|
||||
"y": 12.8,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "moveTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 22.4,
|
||||
"y": 12.8,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 31.999999999999996,
|
||||
"y": 22.4,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 9.92,
|
||||
"y": 32,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 0.3200000000000003,
|
||||
"y": 22.4,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
],
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "fill",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"path": [
|
||||
{
|
||||
"props": {},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "beginPath",
|
||||
},
|
||||
],
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "stroke",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"maxWidth": null,
|
||||
"text": "123",
|
||||
"x": 16,
|
||||
"y": 29,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "fillText",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"height": 32,
|
||||
"width": 32,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "clearRect",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"dHeight": 32,
|
||||
"dWidth": 32,
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"img": <img
|
||||
height="32"
|
||||
width="32"
|
||||
/>,
|
||||
"sHeight": 32,
|
||||
"sWidth": 32,
|
||||
"sx": 0,
|
||||
"sy": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "drawImage",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Favicon should draw a badge if called with a non-zero value 1`] = `
|
||||
[
|
||||
{
|
||||
"props": {
|
||||
"height": 32,
|
||||
"width": 32,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "clearRect",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"dHeight": 32,
|
||||
"dWidth": 32,
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"img": <img
|
||||
height="32"
|
||||
width="32"
|
||||
/>,
|
||||
"sHeight": 32,
|
||||
"sWidth": 32,
|
||||
"sx": 0,
|
||||
"sy": 0,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "drawImage",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"fillRule": "nonzero",
|
||||
"path": [
|
||||
{
|
||||
"props": {},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "beginPath",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 16.159999999999997,
|
||||
"y": 12.8,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "moveTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 22.4,
|
||||
"y": 12.8,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 31.999999999999996,
|
||||
"y": 22.4,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 9.92,
|
||||
"y": 32,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"x": 0.3200000000000003,
|
||||
"y": 22.4,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "lineTo",
|
||||
},
|
||||
],
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "fill",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"path": [
|
||||
{
|
||||
"props": {},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "beginPath",
|
||||
},
|
||||
],
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "stroke",
|
||||
},
|
||||
{
|
||||
"props": {
|
||||
"maxWidth": null,
|
||||
"text": "123",
|
||||
"x": 16,
|
||||
"y": 29,
|
||||
},
|
||||
"transform": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"type": "fillText",
|
||||
},
|
||||
]
|
||||
`;
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import ErrorView from "../../../../src/async-components/structures/ErrorView";
|
||||
|
||||
describe("<ErrorView />", () => {
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<ErrorView title="TITLE" messages={["MSG1", "MSG2"]} />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ErrorView /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_ErrorView"
|
||||
>
|
||||
<div
|
||||
class="mx_ErrorView_container"
|
||||
>
|
||||
<div
|
||||
class="mx_HomePage_header"
|
||||
>
|
||||
<span
|
||||
class="mx_HomePage_logo"
|
||||
>
|
||||
<img
|
||||
alt="Element"
|
||||
height="42"
|
||||
src="themes/element/img/logos/element-logo.svg"
|
||||
/>
|
||||
</span>
|
||||
<h1>
|
||||
Failed to start
|
||||
</h1>
|
||||
</div>
|
||||
<div
|
||||
class="mx_HomePage_col"
|
||||
>
|
||||
<div
|
||||
class="mx_HomePage_row"
|
||||
>
|
||||
<div>
|
||||
<h2
|
||||
id="step1_heading"
|
||||
>
|
||||
TITLE
|
||||
</h2>
|
||||
<p>
|
||||
MSG1
|
||||
</p>
|
||||
<p>
|
||||
MSG2
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mx_HomePage_row mx_Center mx_Spacer"
|
||||
>
|
||||
<p
|
||||
class="mx_Spacer"
|
||||
>
|
||||
<a
|
||||
class="mx_FooterLink"
|
||||
href="https://element.io"
|
||||
target="_blank"
|
||||
>
|
||||
Go to element.io
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import VectorAuthFooter from "../../../../../src/components/views/auth/VectorAuthFooter";
|
||||
|
||||
describe("<VectorAuthFooter />", () => {
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthFooter />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import VectorAuthHeaderLogo from "../../../../../src/components/views/auth/VectorAuthHeaderLogo";
|
||||
|
||||
describe("<VectorAuthHeaderLogo />", () => {
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthHeaderLogo />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "@testing-library/react";
|
||||
|
||||
import VectorAuthPage from "../../../../../src/components/views/auth/VectorAuthPage";
|
||||
|
||||
describe("<VectorAuthPage />", () => {
|
||||
it("should match snapshot", () => {
|
||||
const { asFragment } = render(<VectorAuthPage />);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthFooter /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<footer
|
||||
class="mx_AuthFooter"
|
||||
role="contentinfo"
|
||||
>
|
||||
<a
|
||||
href="https://element.io/blog"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
<a
|
||||
href="https://twitter.com/element_hq"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/vector-im/element-web"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<a
|
||||
href="https://matrix.org"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Powered by Matrix
|
||||
</a>
|
||||
</footer>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -0,0 +1,14 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthHeaderLogo /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<aside
|
||||
class="mx_AuthHeaderLogo"
|
||||
>
|
||||
<img
|
||||
alt="Element"
|
||||
src="themes/element/img/logos/element-logo.svg"
|
||||
/>
|
||||
</aside>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
@@ -0,0 +1,56 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<VectorAuthPage /> should match snapshot 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="mx_AuthPage"
|
||||
>
|
||||
<div
|
||||
class="mx_AuthPage_modal"
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="mx_AuthPage_modalBlur"
|
||||
style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; filter: blur(40px);"
|
||||
/>
|
||||
<div
|
||||
class="mx_AuthPage_modalContent"
|
||||
style="display: flex; z-index: 1; background: rgba(255, 255, 255, 0.59); border-radius: 8px;"
|
||||
/>
|
||||
</div>
|
||||
<footer
|
||||
class="mx_AuthFooter"
|
||||
role="contentinfo"
|
||||
>
|
||||
<a
|
||||
href="https://element.io/blog"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
<a
|
||||
href="https://twitter.com/element_hq"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Twitter
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/vector-im/element-web"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<a
|
||||
href="https://matrix.org"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Powered by Matrix
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
61
test/unit-tests/favicon-test.ts
Normal file
61
test/unit-tests/favicon-test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import "jest-canvas-mock";
|
||||
|
||||
import Favicon from "../../src/favicon";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe("Favicon", () => {
|
||||
beforeEach(() => {
|
||||
const head = document.createElement("head");
|
||||
window.document.documentElement.prepend(head);
|
||||
});
|
||||
|
||||
it("should create a link element if one doesn't yet exist", () => {
|
||||
const favicon = new Favicon();
|
||||
expect(favicon).toBeTruthy();
|
||||
const link = window.document.querySelector("link");
|
||||
expect(link.rel).toContain("icon");
|
||||
});
|
||||
|
||||
it("should draw a badge if called with a non-zero value", () => {
|
||||
const favicon = new Favicon();
|
||||
favicon.badge(123);
|
||||
jest.runAllTimers();
|
||||
expect(favicon["context"].__getDrawCalls()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should clear a badge if called with a zero value", () => {
|
||||
const favicon = new Favicon();
|
||||
favicon.badge(123);
|
||||
jest.runAllTimers();
|
||||
favicon.badge(0);
|
||||
expect(favicon["context"].__getDrawCalls()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should recreate link element for firefox and opera", () => {
|
||||
window["InstallTrigger"] = {};
|
||||
window["opera"] = {};
|
||||
const favicon = new Favicon();
|
||||
const originalLink = window.document.querySelector("link");
|
||||
favicon.badge(123);
|
||||
jest.runAllTimers();
|
||||
const newLink = window.document.querySelector("link");
|
||||
expect(originalLink).not.toStrictEqual(newLink);
|
||||
});
|
||||
});
|
||||
@@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import request from 'browser-request';
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
|
||||
import { getVectorConfig } from "../../../src/vector/getconfig";
|
||||
|
||||
describe('getVectorConfig()', () => {
|
||||
const setRequestMockImplementationOnce = (err?: unknown, response?: { status: number }, body?: string) =>
|
||||
request.mockImplementationOnce((_opts, callback) => callback(err, response, body));
|
||||
fetchMock.config.overwriteRoutes = true;
|
||||
|
||||
describe('getVectorConfig()', () => {
|
||||
const prevDocumentDomain = document.domain;
|
||||
const elementDomain = 'app.element.io';
|
||||
const now = 1234567890;
|
||||
@@ -38,6 +37,7 @@ describe('getVectorConfig()', () => {
|
||||
// stable value for cachebuster
|
||||
jest.spyOn(Date, 'now').mockReturnValue(now);
|
||||
jest.clearAllMocks();
|
||||
fetchMock.mockClear();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@@ -46,85 +46,67 @@ describe('getVectorConfig()', () => {
|
||||
});
|
||||
|
||||
it('requests specific config for document domain', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(specificConfig))
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", specificConfig);
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
await getVectorConfig();
|
||||
|
||||
expect(request.mock.calls[0][0]).toEqual({ method: "GET", url: 'config.app.element.io.json', qs: { cachebuster: now } })
|
||||
await expect(getVectorConfig()).resolves.toEqual(specificConfig);
|
||||
});
|
||||
|
||||
it('adds trailing slash to relativeLocation when not an empty string', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(specificConfig))
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:../config.app.element.io.json", specificConfig);
|
||||
fetchMock.getOnce("express:../config.json", generalConfig);
|
||||
|
||||
await getVectorConfig('..');
|
||||
|
||||
expect(request.mock.calls[0][0]).toEqual(expect.objectContaining({ url: '../config.app.element.io.json' }))
|
||||
expect(request.mock.calls[1][0]).toEqual(expect.objectContaining({ url: '../config.json' }))
|
||||
});
|
||||
|
||||
it('returns parsed specific config when it is non-empty', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(specificConfig))
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(specificConfig);
|
||||
await expect(getVectorConfig("..")).resolves.toEqual(specificConfig);
|
||||
});
|
||||
|
||||
it('returns general config when specific config succeeds but is empty', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify({}))
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", {});
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(generalConfig);
|
||||
await expect(getVectorConfig()).resolves.toEqual(generalConfig);
|
||||
});
|
||||
|
||||
it('returns general config when specific config 404s', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 404 })
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", { status: 404 });
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(generalConfig);
|
||||
await expect(getVectorConfig()).resolves.toEqual(generalConfig);
|
||||
});
|
||||
|
||||
it('returns general config when specific config is fetched from a file and is empty', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 0 }, '')
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", 0);
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(generalConfig);
|
||||
await expect(getVectorConfig()).resolves.toEqual(generalConfig);
|
||||
});
|
||||
|
||||
it('returns general config when specific config returns a non-200 status', async () => {
|
||||
setRequestMockImplementationOnce(undefined, { status: 401 })
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", { status: 401 });
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(generalConfig);
|
||||
await expect(getVectorConfig()).resolves.toEqual(generalConfig);
|
||||
});
|
||||
|
||||
it('returns general config when specific config returns an error', async () => {
|
||||
setRequestMockImplementationOnce('err1')
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, JSON.stringify(generalConfig))
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", { throws: "err1" });
|
||||
fetchMock.getOnce("express:/config.json", generalConfig);
|
||||
|
||||
const result = await getVectorConfig();
|
||||
expect(result).toEqual(generalConfig);
|
||||
await expect(getVectorConfig()).resolves.toEqual(generalConfig);
|
||||
});
|
||||
|
||||
it('rejects with an error when general config rejects', async () => {
|
||||
setRequestMockImplementationOnce('err-specific');
|
||||
setRequestMockImplementationOnce('err-general');
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", { throws: "err-specific" });
|
||||
fetchMock.getOnce("express:/config.json", { throws: "err-general" });
|
||||
|
||||
await expect(() => getVectorConfig()).rejects.toEqual({"err": "err-general", "response": undefined});
|
||||
await expect(getVectorConfig()).rejects.toBe("err-general");
|
||||
});
|
||||
|
||||
it('rejects with an error when config is invalid JSON', async () => {
|
||||
setRequestMockImplementationOnce('err-specific');
|
||||
setRequestMockImplementationOnce(undefined, { status: 200 }, '{"invalid": "json",}');
|
||||
fetchMock.getOnce("express:/config.app.element.io.json", { throws: "err-specific" });
|
||||
fetchMock.getOnce("express:/config.json", '{"invalid": "json",}');
|
||||
|
||||
await expect(() => getVectorConfig()).rejects.toEqual({
|
||||
err: new SyntaxError("Unexpected token } in JSON at position 19"),
|
||||
});
|
||||
// We can't assert it'll be a SyntaxError as node-fetch behaves differently
|
||||
// https://github.com/wheresrhys/fetch-mock/issues/270
|
||||
await expect(getVectorConfig()).rejects.toThrow("Unexpected token } in JSON at position 19");
|
||||
});
|
||||
});
|
||||
|
||||
279
test/unit-tests/vector/platform/ElectronPlatform-test.ts
Normal file
279
test/unit-tests/vector/platform/ElectronPlatform-test.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import request from 'browser-request';
|
||||
import EventEmitter from 'events';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { MatrixClient, MatrixEvent, Room } from 'matrix-js-sdk/src/matrix';
|
||||
import { UpdateCheckStatus } from 'matrix-react-sdk/src/BasePlatform';
|
||||
import { Action } from 'matrix-react-sdk/src/dispatcher/actions';
|
||||
import dispatcher from 'matrix-react-sdk/src/dispatcher/dispatcher';
|
||||
import { MatrixClientPeg } from 'matrix-react-sdk/src/MatrixClientPeg';
|
||||
import * as rageshake from 'matrix-react-sdk/src/rageshake/rageshake';
|
||||
|
||||
import ElectronPlatform from '../../../../src/vector/platform/ElectronPlatform';
|
||||
|
||||
jest.mock('matrix-react-sdk/src/rageshake/rageshake', () => ({
|
||||
flush: jest.fn()
|
||||
}))
|
||||
|
||||
|
||||
describe('ElectronPlatform', () => {
|
||||
const defaultUserAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36';
|
||||
const mockElectron = {
|
||||
on: jest.fn(),
|
||||
send: jest.fn()
|
||||
};
|
||||
|
||||
const dispatchSpy = jest.spyOn(dispatcher, 'dispatch');
|
||||
const dispatchFireSpy = jest.spyOn(dispatcher, 'fire');
|
||||
const logSpy = jest.spyOn(logger, 'log').mockImplementation(() => {});
|
||||
|
||||
const userId = '@alice:server.org';
|
||||
const deviceId = 'device-id';
|
||||
|
||||
window.electron = mockElectron;
|
||||
beforeEach(() => {
|
||||
window.electron = mockElectron;
|
||||
jest.clearAllMocks();
|
||||
delete window.navigator;
|
||||
window.navigator = { userAgent: defaultUserAgent } as unknown as Navigator;
|
||||
});
|
||||
|
||||
const getElectronEventHandlerCall = (eventType: string): [type: string, handler: Function] | undefined =>
|
||||
mockElectron.on.mock.calls.find(([type]) => type === eventType);
|
||||
|
||||
it('flushes rageshake before quitting', () => {
|
||||
new ElectronPlatform();
|
||||
const [event, handler] = getElectronEventHandlerCall('before-quit');
|
||||
// correct event bound
|
||||
expect(event).toBeTruthy();
|
||||
|
||||
handler();
|
||||
|
||||
expect(logSpy).toHaveBeenCalled();
|
||||
expect(rageshake.flush).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('dispatches view settings action on preferences event', () => {
|
||||
new ElectronPlatform();
|
||||
const [event, handler] = getElectronEventHandlerCall('preferences');
|
||||
// correct event bound
|
||||
expect(event).toBeTruthy();
|
||||
|
||||
handler();
|
||||
|
||||
expect(dispatchFireSpy).toHaveBeenCalledWith(Action.ViewUserSettings);
|
||||
});
|
||||
|
||||
describe('updates', () => {
|
||||
it('dispatches on check updates action', () => {
|
||||
new ElectronPlatform();
|
||||
const [event, handler] = getElectronEventHandlerCall('check_updates');
|
||||
// correct event bound
|
||||
expect(event).toBeTruthy();
|
||||
|
||||
handler({}, true);
|
||||
expect(dispatchSpy).toHaveBeenCalledWith({
|
||||
action: Action.CheckUpdates,
|
||||
status: UpdateCheckStatus.Downloading
|
||||
})
|
||||
});
|
||||
|
||||
it('dispatches on check updates action when update not available', () => {
|
||||
new ElectronPlatform();
|
||||
const [, handler] = getElectronEventHandlerCall('check_updates');
|
||||
|
||||
handler({}, false);
|
||||
expect(dispatchSpy).toHaveBeenCalledWith({
|
||||
action: Action.CheckUpdates,
|
||||
status: UpdateCheckStatus.NotAvailable
|
||||
})
|
||||
});
|
||||
|
||||
it('starts update check', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
platform.startUpdateCheck();
|
||||
expect(mockElectron.send).toHaveBeenCalledWith('check_updates')
|
||||
});
|
||||
|
||||
it('installs update', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
platform.installUpdate();
|
||||
expect(mockElectron.send).toHaveBeenCalledWith('install_update')
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('returns human readable name', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.getHumanReadableName()).toEqual('Electron Platform');
|
||||
});
|
||||
|
||||
describe("getDefaultDeviceDisplayName", () => {
|
||||
it.each([[
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
|
||||
"Element Desktop: macOS",
|
||||
],
|
||||
[
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) electron/1.0.0 Chrome/53.0.2785.113 Electron/1.4.3 Safari/537.36",
|
||||
"Element Desktop: Windows",
|
||||
],
|
||||
[
|
||||
"Mozilla/5.0 (X11; Linux i686; rv:21.0) Gecko/20100101 Firefox/21.0",
|
||||
"Element Desktop: Linux",
|
||||
],
|
||||
[
|
||||
"Mozilla/5.0 (X11; FreeBSD i686; rv:21.0) Gecko/20100101 Firefox/21.0",
|
||||
"Element Desktop: FreeBSD",
|
||||
],
|
||||
[
|
||||
"Mozilla/5.0 (X11; OpenBSD i686; rv:21.0) Gecko/20100101 Firefox/21.0",
|
||||
"Element Desktop: OpenBSD",
|
||||
],
|
||||
[
|
||||
"Mozilla/5.0 (X11; SunOS i686; rv:21.0) Gecko/20100101 Firefox/21.0",
|
||||
"Element Desktop: SunOS",
|
||||
],
|
||||
[
|
||||
"custom user agent",
|
||||
"Element Desktop: Unknown",
|
||||
],
|
||||
|
||||
])("%s = %s", (userAgent, result) => {
|
||||
delete window.navigator;
|
||||
window.navigator = { userAgent } as unknown as Navigator;
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.getDefaultDeviceDisplayName()).toEqual(result);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns true for needsUrlTooltips', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.needsUrlTooltips()).toBe(true);
|
||||
});
|
||||
|
||||
it('should override browser shortcuts', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.overrideBrowserShortcuts()).toBe(true);
|
||||
});
|
||||
|
||||
it('allows overriding native context menus', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.allowOverridingNativeContextMenus()).toBe(true);
|
||||
});
|
||||
|
||||
it('indicates support for desktop capturer', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.supportsDesktopCapturer()).toBe(true);
|
||||
});
|
||||
|
||||
it('indicates no support for jitsi screensharing', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.supportsJitsiScreensharing()).toBe(false);
|
||||
});
|
||||
|
||||
describe('notifications', () => {
|
||||
it('indicates support for notifications', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.supportsNotifications()).toBe(true);
|
||||
});
|
||||
|
||||
it('may send notifications', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.maySendNotifications()).toBe(true);
|
||||
});
|
||||
|
||||
it('pretends to request notification permission', async () => {
|
||||
const platform = new ElectronPlatform();
|
||||
const result = await platform.requestNotificationPermission();
|
||||
expect(result).toEqual('granted');
|
||||
});
|
||||
|
||||
it('creates a loud notification', async () => {
|
||||
const platform = new ElectronPlatform();
|
||||
platform.loudNotification(new MatrixEvent(), new Room('!room:server', {} as any, userId));
|
||||
expect(mockElectron.send).toHaveBeenCalledWith('loudNotification');
|
||||
});
|
||||
|
||||
it('sets notification count when count is changing', async () => {
|
||||
const platform = new ElectronPlatform();
|
||||
platform.setNotificationCount(0);
|
||||
// not called because matches internal notificaiton count
|
||||
expect(mockElectron.send).not.toHaveBeenCalledWith('setBadgeCount', 0);
|
||||
platform.setNotificationCount(1);
|
||||
expect(mockElectron.send).toHaveBeenCalledWith('setBadgeCount', 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('spellcheck', () => {
|
||||
it('indicates support for spellcheck settings', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
expect(platform.supportsSpellCheckSettings()).toBe(true);
|
||||
});
|
||||
|
||||
it('gets available spellcheck languages', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
mockElectron.send.mockClear();
|
||||
platform.getAvailableSpellCheckLanguages();
|
||||
|
||||
const [channel, { name }] = mockElectron.send.mock.calls[0];
|
||||
expect(channel).toEqual("ipcCall");
|
||||
expect(name).toEqual('getAvailableSpellCheckLanguages')
|
||||
});
|
||||
});
|
||||
|
||||
describe('pickle key', () => {
|
||||
it('makes correct ipc call to get pickle key', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
mockElectron.send.mockClear();
|
||||
platform.getPickleKey(userId, deviceId);
|
||||
|
||||
const [, { name, args }] = mockElectron.send.mock.calls[0];
|
||||
expect(name).toEqual('getPickleKey')
|
||||
expect(args).toEqual([userId, deviceId])
|
||||
});
|
||||
|
||||
it('makes correct ipc call to create pickle key', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
mockElectron.send.mockClear();
|
||||
platform.createPickleKey(userId, deviceId);
|
||||
|
||||
const [, { name, args }] = mockElectron.send.mock.calls[0];
|
||||
expect(name).toEqual('createPickleKey')
|
||||
expect(args).toEqual([userId, deviceId])
|
||||
});
|
||||
|
||||
it('makes correct ipc call to destroy pickle key', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
mockElectron.send.mockClear();
|
||||
platform.destroyPickleKey(userId, deviceId);
|
||||
|
||||
const [, { name, args }] = mockElectron.send.mock.calls[0];
|
||||
expect(name).toEqual('destroyPickleKey')
|
||||
expect(args).toEqual([userId, deviceId])
|
||||
});
|
||||
});
|
||||
|
||||
describe('versions', () => {
|
||||
it('calls install update', () => {
|
||||
const platform = new ElectronPlatform();
|
||||
platform.installUpdate();
|
||||
|
||||
expect(mockElectron.send).toHaveBeenCalledWith('install_update');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,12 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import PWAPlatform from "../../../../src/vector/platform/PWAPlatform";
|
||||
import WebPlatform from "../../../../src/vector/platform/WebPlatform";
|
||||
|
||||
jest.mock("../../../../src/vector/platform/WebPlatform");
|
||||
|
||||
describe('PWAPlatform', () => {
|
||||
beforeEach(() => {
|
||||
@@ -29,5 +34,29 @@ describe('PWAPlatform', () => {
|
||||
platform.setNotificationCount(123);
|
||||
expect(navigator.setAppBadge).toHaveBeenCalledWith(123);
|
||||
});
|
||||
|
||||
it("should no-op if the badge count isn't changing", () => {
|
||||
navigator.setAppBadge = jest.fn().mockResolvedValue(undefined);
|
||||
const platform = new PWAPlatform();
|
||||
platform.setNotificationCount(123);
|
||||
expect(navigator.setAppBadge).toHaveBeenCalledTimes(1);
|
||||
platform.setNotificationCount(123);
|
||||
expect(navigator.setAppBadge).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should fall back to WebPlatform::setNotificationCount if no Navigator::setAppBadge", () => {
|
||||
navigator.setAppBadge = undefined;
|
||||
const platform = new PWAPlatform();
|
||||
const superMethod = mocked(WebPlatform.prototype.setNotificationCount);
|
||||
expect(superMethod).not.toHaveBeenCalled();
|
||||
platform.setNotificationCount(123);
|
||||
expect(superMethod).toHaveBeenCalledWith(123);
|
||||
});
|
||||
|
||||
it("should handle Navigator::setAppBadge rejecting gracefully", () => {
|
||||
navigator.setAppBadge = jest.fn().mockRejectedValue(new Error);
|
||||
const platform = new PWAPlatform();
|
||||
expect(() => platform.setNotificationCount(123)).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,12 +14,14 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import request from 'browser-request';
|
||||
import fetchMock from "fetch-mock-jest";
|
||||
import { UpdateCheckStatus } from 'matrix-react-sdk/src/BasePlatform';
|
||||
import { MatrixClientPeg } from 'matrix-react-sdk/src/MatrixClientPeg';
|
||||
|
||||
import WebPlatform from '../../../../src/vector/platform/WebPlatform';
|
||||
|
||||
fetchMock.config.overwriteRoutes = true;
|
||||
|
||||
describe('WebPlatform', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -37,6 +39,45 @@ describe('WebPlatform', () => {
|
||||
expect(navigator.serviceWorker.register).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call reload on window location object", () => {
|
||||
delete window.location;
|
||||
window.location = {
|
||||
reload: jest.fn(),
|
||||
} as unknown as Location;
|
||||
|
||||
const platform = new WebPlatform();
|
||||
expect(window.location.reload).not.toHaveBeenCalled();
|
||||
platform.reload();
|
||||
expect(window.location.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call reload to install update", () => {
|
||||
delete window.location;
|
||||
window.location = {
|
||||
reload: jest.fn(),
|
||||
} as unknown as Location;
|
||||
|
||||
const platform = new WebPlatform();
|
||||
expect(window.location.reload).not.toHaveBeenCalled();
|
||||
platform.installUpdate();
|
||||
expect(window.location.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("getDefaultDeviceDisplayName", () => {
|
||||
it.each([[
|
||||
"https://develop.element.io/#/room/!foo:bar",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
|
||||
"develop.element.io: Chrome on macOS",
|
||||
]])("%s & %s = %s", (url, userAgent, result) => {
|
||||
delete window.navigator;
|
||||
window.navigator = { userAgent } as unknown as Navigator;
|
||||
delete window.location;
|
||||
window.location = { href: url } as unknown as Location;
|
||||
const platform = new WebPlatform();
|
||||
expect(platform.getDefaultDeviceDisplayName()).toEqual(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe('notification support', () => {
|
||||
const mockNotification = {
|
||||
requestPermission: jest.fn(),
|
||||
@@ -81,9 +122,6 @@ describe('WebPlatform', () => {
|
||||
const envVersion = process.env.VERSION;
|
||||
const prodVersion = '1.10.13';
|
||||
|
||||
const setRequestMockImplementation = (err?: unknown, response?: { status: number }, body?: string) =>
|
||||
request.mockImplementation((_opts, callback) => callback(err, response, body));
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(MatrixClientPeg, 'userRegisteredWithinLastHours').mockReturnValue(false);
|
||||
})
|
||||
@@ -118,7 +156,7 @@ describe('WebPlatform', () => {
|
||||
describe('pollForUpdate()', () => {
|
||||
it('should return not available and call showNoUpdate when current version matches most recent version', async () => {
|
||||
process.env.VERSION = prodVersion;
|
||||
setRequestMockImplementation(undefined, { status: 200}, prodVersion);
|
||||
fetchMock.getOnce("/version", prodVersion);
|
||||
const platform = new WebPlatform();
|
||||
|
||||
const showUpdate = jest.fn();
|
||||
@@ -132,7 +170,7 @@ describe('WebPlatform', () => {
|
||||
|
||||
it('should strip v prefix from versions before comparing', async () => {
|
||||
process.env.VERSION = prodVersion;
|
||||
setRequestMockImplementation(undefined, { status: 200}, `v${prodVersion}`);
|
||||
fetchMock.getOnce("/version", `v${prodVersion}`);
|
||||
const platform = new WebPlatform();
|
||||
|
||||
const showUpdate = jest.fn();
|
||||
@@ -147,7 +185,7 @@ describe('WebPlatform', () => {
|
||||
|
||||
it('should return ready and call showUpdate when current version differs from most recent version', async () => {
|
||||
process.env.VERSION = '0.0.0'; // old version
|
||||
setRequestMockImplementation(undefined, { status: 200}, prodVersion);
|
||||
fetchMock.getOnce("/version", prodVersion);
|
||||
const platform = new WebPlatform();
|
||||
|
||||
const showUpdate = jest.fn();
|
||||
@@ -162,7 +200,7 @@ describe('WebPlatform', () => {
|
||||
it('should return ready without showing update when user registered in last 24', async () => {
|
||||
process.env.VERSION = '0.0.0'; // old version
|
||||
jest.spyOn(MatrixClientPeg, 'userRegisteredWithinLastHours').mockReturnValue(true);
|
||||
setRequestMockImplementation(undefined, { status: 200}, prodVersion);
|
||||
fetchMock.getOnce("/version", prodVersion);
|
||||
const platform = new WebPlatform();
|
||||
|
||||
const showUpdate = jest.fn();
|
||||
@@ -175,7 +213,7 @@ describe('WebPlatform', () => {
|
||||
});
|
||||
|
||||
it('should return error when version check fails', async () => {
|
||||
setRequestMockImplementation('oups');
|
||||
fetchMock.getOnce("/version", { throws: "oups" });
|
||||
const platform = new WebPlatform();
|
||||
|
||||
const showUpdate = jest.fn();
|
||||
|
||||
43
test/unit-tests/vector/routing-test.ts
Normal file
43
test/unit-tests/vector/routing-test.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { onNewScreen } from "../../../src/vector/routing";
|
||||
|
||||
describe("onNewScreen", () => {
|
||||
it("should replace history if stripping via fields", () => {
|
||||
delete window.location;
|
||||
window.location = {
|
||||
hash: "#/room/!room:server?via=abc",
|
||||
replace: jest.fn(),
|
||||
assign: jest.fn(),
|
||||
} as unknown as Location;
|
||||
onNewScreen("room/!room:server");
|
||||
expect(window.location.assign).not.toHaveBeenCalled();
|
||||
expect(window.location.replace).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not replace history if changing rooms", () => {
|
||||
delete window.location;
|
||||
window.location = {
|
||||
hash: "#/room/!room1:server?via=abc",
|
||||
replace: jest.fn(),
|
||||
assign: jest.fn(),
|
||||
} as unknown as Location;
|
||||
onNewScreen("room/!room2:server");
|
||||
expect(window.location.assign).toHaveBeenCalled();
|
||||
expect(window.location.replace).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { parseQsFromFragment, parseQs } from "../../src/vector/url_utils";
|
||||
import { parseQsFromFragment, parseQs } from "../../../src/vector/url_utils";
|
||||
|
||||
describe("url_utils.ts", function() {
|
||||
// @ts-ignore
|
||||
Reference in New Issue
Block a user