Merge branch 'develop' into feature/default-pin-drop
This commit is contained in:
commit
c614c5bf13
208 changed files with 10776 additions and 8178 deletions
134
.eslintrc.js
134
.eslintrc.js
|
@ -1,70 +1,90 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: ["matrix-org"],
|
plugins: ["matrix-org"],
|
||||||
extends: [
|
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react"],
|
||||||
"plugin:matrix-org/babel",
|
|
||||||
"plugin:matrix-org/react",
|
|
||||||
],
|
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// Things we do that break the ideal style
|
// Things we do that break the ideal style
|
||||||
"quotes": "off",
|
quotes: "off",
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: 'detect'
|
version: "detect",
|
||||||
}
|
|
||||||
},
|
|
||||||
overrides: [{
|
|
||||||
files: ["src/**/*.{ts,tsx}", "module_system/**/*.{ts,tsx}"],
|
|
||||||
extends: [
|
|
||||||
"plugin:matrix-org/typescript",
|
|
||||||
"plugin:matrix-org/react",
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
// Things we do that break the ideal style
|
|
||||||
"prefer-promise-reject-errors": "off",
|
|
||||||
"quotes": "off",
|
|
||||||
|
|
||||||
// We disable this while we're transitioning
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
// We're okay with assertion errors when we ask for them
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
|
||||||
|
|
||||||
// Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell.
|
|
||||||
"no-restricted-imports": ["error", {
|
|
||||||
"paths": [{
|
|
||||||
"name": "matrix-js-sdk",
|
|
||||||
"message": "Please use matrix-js-sdk/src/matrix instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-js-sdk/",
|
|
||||||
"message": "Please use matrix-js-sdk/src/matrix instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-js-sdk/src",
|
|
||||||
"message": "Please use matrix-js-sdk/src/matrix instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-js-sdk/src/",
|
|
||||||
"message": "Please use matrix-js-sdk/src/matrix instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-js-sdk/src/index",
|
|
||||||
"message": "Please use matrix-js-sdk/src/matrix instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-react-sdk",
|
|
||||||
"message": "Please use matrix-react-sdk/src/index instead",
|
|
||||||
}, {
|
|
||||||
"name": "matrix-react-sdk/",
|
|
||||||
"message": "Please use matrix-react-sdk/src/index instead",
|
|
||||||
}],
|
|
||||||
"patterns": [{
|
|
||||||
"group": ["matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**"],
|
|
||||||
"message": "Please use matrix-js-sdk/src/* instead",
|
|
||||||
}, {
|
|
||||||
"group": ["matrix-react-sdk/lib", "matrix-react-sdk/lib/", "matrix-react-sdk/lib/**"],
|
|
||||||
"message": "Please use matrix-react-sdk/src/* instead",
|
|
||||||
}],
|
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
}],
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}", "module_system/**/*.{ts,tsx}"],
|
||||||
|
extends: ["plugin:matrix-org/typescript", "plugin:matrix-org/react"],
|
||||||
|
// NOTE: These rules are frozen and new rules should not be added here.
|
||||||
|
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
|
||||||
|
rules: {
|
||||||
|
// Things we do that break the ideal style
|
||||||
|
"prefer-promise-reject-errors": "off",
|
||||||
|
"quotes": "off",
|
||||||
|
|
||||||
|
// We disable this while we're transitioning
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
// We're okay with assertion errors when we ask for them
|
||||||
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
|
||||||
|
// Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell.
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
name: "matrix-js-sdk",
|
||||||
|
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-js-sdk/",
|
||||||
|
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-js-sdk/src",
|
||||||
|
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-js-sdk/src/",
|
||||||
|
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-js-sdk/src/index",
|
||||||
|
message: "Please use matrix-js-sdk/src/matrix instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-react-sdk",
|
||||||
|
message: "Please use matrix-react-sdk/src/index instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matrix-react-sdk/",
|
||||||
|
message: "Please use matrix-react-sdk/src/index instead",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
group: ["matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**"],
|
||||||
|
message: "Please use matrix-js-sdk/src/* instead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: ["matrix-react-sdk/lib", "matrix-react-sdk/lib/", "matrix-react-sdk/lib/**"],
|
||||||
|
message: "Please use matrix-react-sdk/src/* instead",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ["test/**/*.{ts,tsx}"],
|
||||||
|
rules: {
|
||||||
|
// We don't need super strict typing in test utilities
|
||||||
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
2
.git-blame-ignore-revs
Normal file
2
.git-blame-ignore-revs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# prettier
|
||||||
|
7921a6cbf86b035d2b0c1daecb4c24beaf5a5abc
|
5
.github/CODEOWNERS
vendored
5
.github/CODEOWNERS
vendored
|
@ -1 +1,4 @@
|
||||||
* @vector-im/element-web
|
* @vector-im/element-web
|
||||||
|
/.github/workflows/** @vector-im/element-web-app-team
|
||||||
|
/package.json @vector-im/element-web-app-team
|
||||||
|
/yarn.lock @vector-im/element-web-app-team
|
||||||
|
|
140
.github/ISSUE_TEMPLATE/bug-desktop.yml
vendored
140
.github/ISSUE_TEMPLATE/bug-desktop.yml
vendored
|
@ -2,75 +2,75 @@ name: Bug report for the Element desktop app (not in a browser)
|
||||||
description: File a bug report if you are using the desktop Element application.
|
description: File a bug report if you are using the desktop Element application.
|
||||||
labels: [T-Defect]
|
labels: [T-Defect]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for taking the time to fill out this bug report!
|
Thanks for taking the time to fill out this bug report!
|
||||||
|
|
||||||
Please report security issues by email to security@matrix.org
|
Please report security issues by email to security@matrix.org
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: reproduction-steps
|
id: reproduction-steps
|
||||||
attributes:
|
attributes:
|
||||||
label: Steps to reproduce
|
label: Steps to reproduce
|
||||||
description: Please attach screenshots, videos or logs if you can.
|
description: Please attach screenshots, videos or logs if you can.
|
||||||
placeholder: Tell us what you see!
|
placeholder: Tell us what you see!
|
||||||
value: |
|
value: |
|
||||||
1. Where are you starting? What can you see?
|
1. Where are you starting? What can you see?
|
||||||
2. What do you click?
|
2. What do you click?
|
||||||
3. More steps…
|
3. More steps…
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: result
|
id: result
|
||||||
attributes:
|
attributes:
|
||||||
label: Outcome
|
label: Outcome
|
||||||
placeholder: Tell us what went wrong
|
placeholder: Tell us what went wrong
|
||||||
value: |
|
value: |
|
||||||
#### What did you expect?
|
#### What did you expect?
|
||||||
|
|
||||||
#### What happened instead?
|
#### What happened instead?
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: os
|
id: os
|
||||||
attributes:
|
attributes:
|
||||||
label: Operating system
|
label: Operating system
|
||||||
placeholder: Windows, macOS, Ubuntu, Arch Linux…
|
placeholder: Windows, macOS, Ubuntu, Arch Linux…
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: Application version
|
label: Application version
|
||||||
description: You can find the version information in Settings -> Help & About.
|
description: You can find the version information in Settings -> Help & About.
|
||||||
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
|
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: source
|
id: source
|
||||||
attributes:
|
attributes:
|
||||||
label: How did you install the app?
|
label: How did you install the app?
|
||||||
description: Where did you install the app from? Please give a link or a description.
|
description: Where did you install the app from? Please give a link or a description.
|
||||||
placeholder: e.g. From https://element.io/get-started
|
placeholder: e.g. From https://element.io/get-started
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: homeserver
|
id: homeserver
|
||||||
attributes:
|
attributes:
|
||||||
label: Homeserver
|
label: Homeserver
|
||||||
description: |
|
description: |
|
||||||
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
||||||
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: rageshake
|
id: rageshake
|
||||||
attributes:
|
attributes:
|
||||||
label: Will you send logs?
|
label: Will you send logs?
|
||||||
description: |
|
description: |
|
||||||
Did you know that you can send a /rageshake command from your application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
|
Did you know that you can send a /rageshake command from your application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
|
||||||
options:
|
options:
|
||||||
- 'Yes'
|
- "Yes"
|
||||||
- 'No'
|
- "No"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
156
.github/ISSUE_TEMPLATE/bug-web.yml
vendored
156
.github/ISSUE_TEMPLATE/bug-web.yml
vendored
|
@ -2,83 +2,83 @@ name: Bug report for Element Web (in browser)
|
||||||
description: File a bug report if you are using Element in a web browser like Firefox, Chrome, Edge, and so on.
|
description: File a bug report if you are using Element in a web browser like Firefox, Chrome, Edge, and so on.
|
||||||
labels: [T-Defect]
|
labels: [T-Defect]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for taking the time to fill out this bug report!
|
Thanks for taking the time to fill out this bug report!
|
||||||
|
|
||||||
Please report security issues by email to security@matrix.org
|
Please report security issues by email to security@matrix.org
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: reproduction-steps
|
id: reproduction-steps
|
||||||
attributes:
|
attributes:
|
||||||
label: Steps to reproduce
|
label: Steps to reproduce
|
||||||
description: Please attach screenshots, videos or logs if you can.
|
description: Please attach screenshots, videos or logs if you can.
|
||||||
placeholder: Tell us what you see!
|
placeholder: Tell us what you see!
|
||||||
value: |
|
value: |
|
||||||
1. Where are you starting? What can you see?
|
1. Where are you starting? What can you see?
|
||||||
2. What do you click?
|
2. What do you click?
|
||||||
3. More steps…
|
3. More steps…
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: result
|
id: result
|
||||||
attributes:
|
attributes:
|
||||||
label: Outcome
|
label: Outcome
|
||||||
placeholder: Tell us what went wrong
|
placeholder: Tell us what went wrong
|
||||||
value: |
|
value: |
|
||||||
#### What did you expect?
|
#### What did you expect?
|
||||||
|
|
||||||
#### What happened instead?
|
#### What happened instead?
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: os
|
id: os
|
||||||
attributes:
|
attributes:
|
||||||
label: Operating system
|
label: Operating system
|
||||||
placeholder: Windows, macOS, Ubuntu, Arch Linux…
|
placeholder: Windows, macOS, Ubuntu, Arch Linux…
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: browser
|
id: browser
|
||||||
attributes:
|
attributes:
|
||||||
label: Browser information
|
label: Browser information
|
||||||
description: Which browser are you using? Which version?
|
description: Which browser are you using? Which version?
|
||||||
placeholder: e.g. Chromium Version 92.0.4515.131
|
placeholder: e.g. Chromium Version 92.0.4515.131
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: webapp-url
|
id: webapp-url
|
||||||
attributes:
|
attributes:
|
||||||
label: URL for webapp
|
label: URL for webapp
|
||||||
description: Which URL are you using to access the webapp? If a private server, tell us what version of Element Web you are using.
|
description: Which URL are you using to access the webapp? If a private server, tell us what version of Element Web you are using.
|
||||||
placeholder: e.g. develop.element.io, app.element.io
|
placeholder: e.g. develop.element.io, app.element.io
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: version
|
id: version
|
||||||
attributes:
|
attributes:
|
||||||
label: Application version
|
label: Application version
|
||||||
description: You can find the version information in Settings -> Help & About.
|
description: You can find the version information in Settings -> Help & About.
|
||||||
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
|
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: input
|
- type: input
|
||||||
id: homeserver
|
id: homeserver
|
||||||
attributes:
|
attributes:
|
||||||
label: Homeserver
|
label: Homeserver
|
||||||
description: |
|
description: |
|
||||||
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
||||||
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: rageshake
|
id: rageshake
|
||||||
attributes:
|
attributes:
|
||||||
label: Will you send logs?
|
label: Will you send logs?
|
||||||
description: |
|
description: |
|
||||||
Did you know that you can send a /rageshake command from the web application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
|
Did you know that you can send a /rageshake command from the web application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
|
||||||
options:
|
options:
|
||||||
- 'Yes'
|
- "Yes"
|
||||||
- 'No'
|
- "No"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,5 +1,5 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Questions & support
|
- name: Questions & support
|
||||||
url: https://matrix.to/#/#element-web:matrix.org
|
url: https://matrix.to/#/#element-web:matrix.org
|
||||||
about: Please ask and answer questions here.
|
about: Please ask and answer questions here.
|
||||||
|
|
60
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
60
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
|
@ -2,35 +2,35 @@ name: Enhancement request
|
||||||
description: Do you have a suggestion or feature request?
|
description: Do you have a suggestion or feature request?
|
||||||
labels: [T-Enhancement]
|
labels: [T-Enhancement]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for taking the time to propose a new feature or make a suggestion.
|
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: usecase
|
id: usecase
|
||||||
attributes:
|
attributes:
|
||||||
label: Your use case
|
label: Your use case
|
||||||
description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
|
description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
|
||||||
placeholder: Tell us what you would like to do!
|
placeholder: Tell us what you would like to do!
|
||||||
value: |
|
value: |
|
||||||
#### What would you like to do?
|
#### What would you like to do?
|
||||||
|
|
||||||
#### Why would you like to do it?
|
#### Why would you like to do it?
|
||||||
|
|
||||||
#### How would you like to achieve it?
|
#### How would you like to achieve it?
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: alternative
|
id: alternative
|
||||||
attributes:
|
attributes:
|
||||||
label: Have you considered any alternatives?
|
label: Have you considered any alternatives?
|
||||||
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: additional-context
|
id: additional-context
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional context
|
label: Additional context
|
||||||
placeholder: Is there anything else you'd like to add?
|
placeholder: Is there anything else you'd like to add?
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
* [ ] Tests written for new code (and old code if feasible)
|
- [ ] Tests written for new code (and old code if feasible)
|
||||||
* [ ] Linter and other CI checks pass
|
- [ ] Linter and other CI checks pass
|
||||||
* [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md))
|
- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md))
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If you would like to specify text for the changelog entry other than your PR title, add the following:
|
If you would like to specify text for the changelog entry other than your PR title, add the following:
|
||||||
|
|
10
.github/cfp_headers
vendored
Normal file
10
.github/cfp_headers
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
X-XSS-Protection: 1; mode=block
|
||||||
|
X-Content-Type-Options: nosniff
|
||||||
|
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
|
||||||
|
|
||||||
|
/version
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
/apple-app-site-association
|
||||||
|
Content-Type: application/json
|
6
.github/renovate.json
vendored
6
.github/renovate.json
vendored
|
@ -1,6 +1,4 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["github>matrix-org/renovate-config-element-web"]
|
||||||
"github>matrix-org/renovate-config-element-web"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
30
.github/workflows/backport.yml
vendored
Normal file
30
.github/workflows/backport.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
name: Backport
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
- labeled
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backport:
|
||||||
|
name: Backport
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Only react to merged PRs for security reasons.
|
||||||
|
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
|
||||||
|
if: >
|
||||||
|
github.event.pull_request.merged
|
||||||
|
&& (
|
||||||
|
github.event.action == 'closed'
|
||||||
|
|| (
|
||||||
|
github.event.action == 'labeled'
|
||||||
|
&& contains(github.event.label.name, 'backport')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
steps:
|
||||||
|
- uses: tibdex/backport@v2
|
||||||
|
with:
|
||||||
|
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 }}
|
36
.github/workflows/build.yml
vendored
36
.github/workflows/build.yml
vendored
|
@ -1,26 +1,26 @@
|
||||||
name: Build
|
name: Build
|
||||||
on:
|
on:
|
||||||
pull_request: { }
|
pull_request: {}
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
# develop pushes and repository_dispatch handled in build_develop.yaml
|
# develop pushes and repository_dispatch handled in build_develop.yaml
|
||||||
env:
|
env:
|
||||||
# These must be set for fetchdep.sh to get the right branch
|
# These must be set for fetchdep.sh to get the right branch
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: "Build"
|
name: "Build"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
cache: 'yarn'
|
cache: "yarn"
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: "./scripts/layered.sh"
|
run: "./scripts/layered.sh"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: "yarn build"
|
run: "yarn build"
|
||||||
|
|
149
.github/workflows/build_develop.yml
vendored
149
.github/workflows/build_develop.yml
vendored
|
@ -1,49 +1,114 @@
|
||||||
# Separate to the main build workflow for access to develop
|
# Separate to the main build workflow for access to develop
|
||||||
# environment secrets, largely similar to build.yaml.
|
# environment secrets, largely similar to build.yaml.
|
||||||
name: Build and Package develop
|
name: Build and Deploy develop
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ develop ]
|
branches: [develop]
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
types: [ element-web-notify ]
|
types: [element-web-notify]
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.repository_owner }}-${{ github.workflow }}-${{ github.ref_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: "Build & Upload source maps to Sentry"
|
name: "Build & Deploy develop.element.io"
|
||||||
# Only respect triggers from our develop branch, ignore that of forks
|
# Only respect triggers from our develop branch, ignore that of forks
|
||||||
if: github.repository == 'vector-im/element-web'
|
if: github.repository == 'vector-im/element-web'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: develop
|
environment: develop
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
cache: 'yarn'
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: "./scripts/layered.sh"
|
|
||||||
|
|
||||||
- name: Build, Package & Upload sourcemaps
|
|
||||||
run: "./scripts/ci_package.sh"
|
|
||||||
env:
|
env:
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
R2_BUCKET: "element-web-develop"
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
R2_URL: ${{ secrets.CF_R2_S3_API }}
|
||||||
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
R2_PUBLIC_URL: "https://element-web-develop.element.io"
|
||||||
SENTRY_ORG: element
|
steps:
|
||||||
SENTRY_PROJECT: riot-web
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- run: mv dist/element-*.tar.gz webapp.tar.gz
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
- name: Wait for other steps to succeed
|
cache: "yarn"
|
||||||
uses: lewagon/wait-on-check-action@v1.0.0
|
|
||||||
with:
|
|
||||||
ref: ${{ github.ref }}
|
|
||||||
running-workflow-name: 'Build & Upload source maps to Sentry'
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
wait-interval: 10
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- name: Install Dependencies
|
||||||
with:
|
run: "./scripts/layered.sh"
|
||||||
name: webapp
|
|
||||||
path: webapp.tar.gz
|
- name: Build, Package & Upload sourcemaps
|
||||||
retention-days: 1
|
run: "./scripts/ci_package.sh"
|
||||||
|
env:
|
||||||
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
|
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
||||||
|
SENTRY_ORG: element
|
||||||
|
SENTRY_PROJECT: riot-web
|
||||||
|
# We only deploy the latest bundles to Cloudflare Pages and use _redirects to fallback to R2 for
|
||||||
|
# older ones. This redirect means that 'self' is insufficient in the CSP,
|
||||||
|
# and we have to add the R2 URL.
|
||||||
|
# Once Cloudflare redirects support proxying mode we will be able to ditch this.
|
||||||
|
# See Proxying in support table at https://developers.cloudflare.com/pages/platform/redirects
|
||||||
|
CSP_EXTRA_SOURCE: ${{ env.R2_PUBLIC_URL }}
|
||||||
|
|
||||||
|
- run: mv dist/element-*.tar.gz dist/develop.tar.gz
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: webapp
|
||||||
|
path: dist/develop.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
- name: Extract webapp
|
||||||
|
run: |
|
||||||
|
mkdir _deploy
|
||||||
|
tar xf dist/develop.tar.gz -C _deploy --strip-components=1
|
||||||
|
|
||||||
|
- name: Copy config
|
||||||
|
run: cp element.io/develop/config.json _deploy/config.json
|
||||||
|
|
||||||
|
- name: Populate 404.html
|
||||||
|
run: echo "404 Not Found" > _deploy/404.html
|
||||||
|
|
||||||
|
- name: Populate _headers
|
||||||
|
run: cp .github/cfp_headers _deploy/_headers
|
||||||
|
|
||||||
|
# Redirect requests for the develop tarball and the historical bundles to R2
|
||||||
|
- name: Populate _redirects
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo "/develop.tar.gz $R2_PUBLIC_URL/develop.tar.gz 301"
|
||||||
|
for bundle in $(aws s3 ls s3://$R2_BUCKET/bundles/ --endpoint-url $R2_URL --region=auto | awk '{print $2}'); do
|
||||||
|
echo "/bundles/${bundle}* $R2_PUBLIC_URL/bundles/${bundle}:splat 301"
|
||||||
|
done
|
||||||
|
} | tee _deploy/_redirects
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
|
||||||
|
|
||||||
|
- name: Wait for other steps to succeed
|
||||||
|
uses: lewagon/wait-on-check-action@v1.2.0
|
||||||
|
with:
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
running-workflow-name: "Build & Deploy develop.element.io"
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
wait-interval: 10
|
||||||
|
check-regexp: ^((?!SonarCloud|SonarQube|issues|board).)*$
|
||||||
|
|
||||||
|
# We keep the latest develop.tar.gz on R2 instead of relying on the github artifact uploaded earlier
|
||||||
|
# as the expires after 24h and requires auth to download.
|
||||||
|
# Element Desktop's fetch script uses this tarball to fetch latest develop to build Nightlies.
|
||||||
|
- name: Deploy to R2
|
||||||
|
run: |
|
||||||
|
aws s3 cp dist/develop.tar.gz s3://$R2_BUCKET/develop.tar.gz --endpoint-url $R2_URL --region=auto
|
||||||
|
aws s3 cp _deploy/ s3://$R2_BUCKET/ --recursive --endpoint-url $R2_URL --region=auto
|
||||||
|
env:
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Cloudflare Pages
|
||||||
|
id: cfp
|
||||||
|
uses: cloudflare/pages-action@1
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CF_PAGES_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CF_PAGES_ACCOUNT_ID }}
|
||||||
|
projectName: element-web-develop
|
||||||
|
directory: _deploy
|
||||||
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- run: |
|
||||||
|
echo "Deployed to ${{ steps.cfp.outputs.url }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
100
.github/workflows/dockerhub.yaml
vendored
100
.github/workflows/dockerhub.yaml
vendored
|
@ -1,59 +1,61 @@
|
||||||
name: Dockerhub
|
name: Dockerhub
|
||||||
on:
|
on:
|
||||||
workflow_dispatch: { }
|
workflow_dispatch: {}
|
||||||
push:
|
push:
|
||||||
tags: [ v* ]
|
tags: [v*]
|
||||||
schedule:
|
schedule:
|
||||||
# This job can take a while, and we have usage limits, so just publish develop only twice a day
|
# This job can take a while, and we have usage limits, so just publish develop only twice a day
|
||||||
- cron: '0 7/12 * * *'
|
- cron: "0 7/12 * * *"
|
||||||
concurrency: ${{ github.ref_name }}
|
concurrency: ${{ github.ref_name }}
|
||||||
jobs:
|
jobs:
|
||||||
buildx:
|
buildx:
|
||||||
name: Docker Buildx
|
name: Docker Buildx
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: dockerhub
|
environment: dockerhub
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # needed for docker-package to be able to calculate the version
|
fetch-depth: 0 # needed for docker-package to be able to calculate the version
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v3
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
vectorim/element-web
|
vectorim/element-web
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=ref,event=tag
|
type=ref,event=tag
|
||||||
|
flavor: |
|
||||||
|
latest=${{ contains(github.ref_name, '-rc.') && 'false' || 'auto' }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v3
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
|
||||||
- name: Update repo description
|
- name: Update repo description
|
||||||
uses: peter-evans/dockerhub-description@v2
|
uses: peter-evans/dockerhub-description@v3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
repository: vectorim/element-web
|
repository: vectorim/element-web
|
||||||
|
|
270
.github/workflows/issue_closed.yml
vendored
270
.github/workflows/issue_closed.yml
vendored
|
@ -2,147 +2,155 @@
|
||||||
# For all closed (completed) issues, cascade the closure onto any referenced rageshakes
|
# For all closed (completed) issues, cascade the closure onto any referenced rageshakes
|
||||||
# For all closed (not planned) issues, comment on rageshakes to move them into the canonical issue if one exists
|
# For all closed (not planned) issues, comment on rageshakes to move them into the canonical issue if one exists
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [ closed ]
|
types: [closed]
|
||||||
jobs:
|
jobs:
|
||||||
tidy:
|
tidy:
|
||||||
name: Tidy closed issues
|
name: Tidy closed issues
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/github-script@v5
|
- uses: actions/github-script@v6
|
||||||
with:
|
id: main
|
||||||
# PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org)
|
with:
|
||||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
# PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org)
|
||||||
script: |
|
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
const variables = {
|
script: |
|
||||||
owner: context.repo.owner,
|
const variables = {
|
||||||
name: context.repo.repo,
|
owner: context.repo.owner,
|
||||||
number: context.issue.number,
|
name: context.repo.repo,
|
||||||
};
|
number: context.issue.number,
|
||||||
|
};
|
||||||
|
|
||||||
const query = `query($owner:String!, $name:String!, $number:Int!) {
|
const query = `query($owner:String!, $name:String!, $number:Int!) {
|
||||||
repository(owner: $owner, name: $name) {
|
repository(owner: $owner, name: $name) {
|
||||||
issue(number: $number) {
|
issue(number: $number) {
|
||||||
stateReason,
|
stateReason,
|
||||||
timelineItems(first: 100, itemTypes: [MARKED_AS_DUPLICATE_EVENT, UNMARKED_AS_DUPLICATE_EVENT, CROSS_REFERENCED_EVENT]) {
|
timelineItems(first: 100, itemTypes: [MARKED_AS_DUPLICATE_EVENT, UNMARKED_AS_DUPLICATE_EVENT, CROSS_REFERENCED_EVENT]) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
__typename
|
__typename
|
||||||
... on MarkedAsDuplicateEvent {
|
... on MarkedAsDuplicateEvent {
|
||||||
canonical {
|
canonical {
|
||||||
... on Issue {
|
... on Issue {
|
||||||
repository {
|
repository {
|
||||||
nameWithOwner
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
... on PullRequest {
|
||||||
|
repository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on UnmarkedAsDuplicateEvent {
|
||||||
|
canonical {
|
||||||
|
... on Issue {
|
||||||
|
repository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
... on PullRequest {
|
||||||
|
repository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on CrossReferencedEvent {
|
||||||
|
source {
|
||||||
|
... on Issue {
|
||||||
|
repository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
... on PullRequest {
|
||||||
|
repository {
|
||||||
|
nameWithOwner
|
||||||
|
}
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
number
|
|
||||||
}
|
|
||||||
... on PullRequest {
|
|
||||||
repository {
|
|
||||||
nameWithOwner
|
|
||||||
}
|
|
||||||
number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
... on UnmarkedAsDuplicateEvent {
|
}`;
|
||||||
canonical {
|
|
||||||
... on Issue {
|
const result = await github.graphql(query, variables);
|
||||||
repository {
|
const { stateReason, timelineItems: { edges } } = result.repository.issue;
|
||||||
nameWithOwner
|
|
||||||
}
|
const RAGESHAKE_OWNER = "matrix-org";
|
||||||
number
|
const RAGESHAKE_REPO = "element-web-rageshakes";
|
||||||
|
const rageshakes = new Set();
|
||||||
|
const duplicateOf = new Set();
|
||||||
|
|
||||||
|
console.log("Edges: ", JSON.stringify(edges));
|
||||||
|
|
||||||
|
for (const { node } of edges) {
|
||||||
|
switch(node.__typename) {
|
||||||
|
case "MarkedAsDuplicateEvent":
|
||||||
|
duplicateOf.add(node.canonical.repository.nameWithOwner + "#" + node.canonical.number);
|
||||||
|
break;
|
||||||
|
case "UnmarkedAsDuplicateEvent":
|
||||||
|
duplicateOf.remove(node.canonical.repository.nameWithOwner + "#" + node.canonical.number);
|
||||||
|
break;
|
||||||
|
case "CrossReferencedEvent":
|
||||||
|
if (node.source.repository.nameWithOwner === (RAGESHAKE_OWNER + "/" + RAGESHAKE_REPO)) {
|
||||||
|
rageshakes.add(node.source.number);
|
||||||
}
|
}
|
||||||
... on PullRequest {
|
break;
|
||||||
repository {
|
|
||||||
nameWithOwner
|
|
||||||
}
|
|
||||||
number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
... on CrossReferencedEvent {
|
|
||||||
source {
|
|
||||||
... on Issue {
|
|
||||||
repository {
|
|
||||||
nameWithOwner
|
|
||||||
}
|
|
||||||
number
|
|
||||||
}
|
|
||||||
... on PullRequest {
|
|
||||||
repository {
|
|
||||||
nameWithOwner
|
|
||||||
}
|
|
||||||
number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const result = await github.graphql(query, variables);
|
console.log("Duplicate of: ", duplicateOf);
|
||||||
const { stateReason, timelineItems: { edges } } = result.repository.issue;
|
console.log("Found rageshakes: ", rageshakes);
|
||||||
|
|
||||||
const RAGESHAKE_OWNER = "matrix-org";
|
if (duplicateOf.size) {
|
||||||
const RAGESHAKE_REPO = "element-web-rageshakes";
|
const body = Array.from(duplicateOf).join("\n");
|
||||||
const rageshakes = new Set();
|
|
||||||
const duplicateOf = new Set();
|
|
||||||
|
|
||||||
console.log("Edges: ", JSON.stringify(edges));
|
// Comment on all rageshakes to create relationship to the issue this was closed as duplicate of
|
||||||
|
for (const rageshake of rageshakes) {
|
||||||
|
github.rest.issues.createComment({
|
||||||
|
owner: RAGESHAKE_OWNER,
|
||||||
|
repo: RAGESHAKE_REPO,
|
||||||
|
issue_number: rageshake,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const { node } of edges) {
|
// Duplicate was closed with wrong reason, fix it
|
||||||
switch(node.__typename) {
|
if (stateReason === "COMPLETED") {
|
||||||
case "MarkedAsDuplicateEvent":
|
core.setOutput("closeAsNotPlanned", "true");
|
||||||
duplicateOf.add(node.canonical.repository.nameWithOwner + "#" + node.canonical.number);
|
}
|
||||||
break;
|
} else {
|
||||||
case "UnmarkedAsDuplicateEvent":
|
// This issue was closed, close all related rageshakes
|
||||||
duplicateOf.remove(node.canonical.repository.nameWithOwner + "#" + node.canonical.number);
|
for (const rageshake of rageshakes) {
|
||||||
break;
|
github.rest.issues.update({
|
||||||
case "CrossReferencedEvent":
|
owner: RAGESHAKE_OWNER,
|
||||||
if (node.source.repository.nameWithOwner === (RAGESHAKE_OWNER + "/" + RAGESHAKE_REPO)) {
|
repo: RAGESHAKE_REPO,
|
||||||
rageshakes.add(node.source.number);
|
issue_number: rageshake,
|
||||||
}
|
state: "closed",
|
||||||
break;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
- uses: actions/github-script@v6
|
||||||
console.log("Duplicate of: ", duplicateOf);
|
name: Close duplicate as Not Planned
|
||||||
console.log("Found rageshakes: ", rageshakes);
|
if: steps.main.outputs.closeAsNotPlanned
|
||||||
|
with:
|
||||||
if (duplicateOf.size) {
|
# We do this step separately, and with the default token so as to not re-trigger this workflow when re-closing
|
||||||
const body = Array.from(duplicateOf).join("\n");
|
script: |
|
||||||
|
await github.graphql(`mutation($id:ID!) {
|
||||||
// Comment on all rageshakes to create relationship to the issue this was closed as duplicate of
|
closeIssue(input: { issueId:$id, stateReason:NOT_PLANNED }) {
|
||||||
for (const rageshake of rageshakes) {
|
clientMutationId
|
||||||
github.rest.issues.createComment({
|
}
|
||||||
owner: RAGESHAKE_OWNER,
|
}`, {
|
||||||
repo: RAGESHAKE_REPO,
|
id: context.payload.issue.node_id,
|
||||||
issue_number: rageshake,
|
});
|
||||||
body,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate was closed with wrong reason, fix it
|
|
||||||
if (stateReason === "COMPLETED") {
|
|
||||||
await github.graphql(`mutation($id:ID!) {
|
|
||||||
closeIssue(input: { issueId:$id, stateReason:NOT_PLANNED }) {
|
|
||||||
clientMutationId
|
|
||||||
}
|
|
||||||
}`, {
|
|
||||||
id: context.payload.issue.node_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This issue was closed, close all related rageshakes
|
|
||||||
for (const rageshake of rageshakes) {
|
|
||||||
github.rest.issues.update({
|
|
||||||
owner: RAGESHAKE_OWNER,
|
|
||||||
repo: RAGESHAKE_REPO,
|
|
||||||
issue_number: rageshake,
|
|
||||||
state: "closed",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
16
.github/workflows/pull_request.yaml
vendored
16
.github/workflows/pull_request.yaml
vendored
|
@ -1,12 +1,12 @@
|
||||||
name: Pull Request
|
name: Pull Request
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ opened, edited, labeled, unlabeled, synchronize ]
|
types: [opened, edited, labeled, unlabeled, synchronize]
|
||||||
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref }}
|
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref }}
|
||||||
jobs:
|
jobs:
|
||||||
action:
|
action:
|
||||||
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
|
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
|
||||||
with:
|
with:
|
||||||
labels: "T-Defect,T-Enhancement,T-Task"
|
labels: "T-Defect,T-Enhancement,T-Task"
|
||||||
secrets:
|
secrets:
|
||||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
22
.github/workflows/sonarqube.yml
vendored
22
.github/workflows/sonarqube.yml
vendored
|
@ -1,15 +1,15 @@
|
||||||
name: SonarQube
|
name: SonarQube
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
workflows: [ "Tests" ]
|
workflows: ["Tests"]
|
||||||
types:
|
types:
|
||||||
- completed
|
- completed
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
|
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
jobs:
|
jobs:
|
||||||
sonarqube:
|
sonarqube:
|
||||||
name: 🩻 SonarQube
|
name: 🩻 SonarQube
|
||||||
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
|
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
|
||||||
secrets:
|
secrets:
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
|
152
.github/workflows/static_analysis.yaml
vendored
152
.github/workflows/static_analysis.yaml
vendored
|
@ -1,65 +1,119 @@
|
||||||
name: Static Analysis
|
name: Static Analysis
|
||||||
on:
|
on:
|
||||||
pull_request: { }
|
pull_request: {}
|
||||||
push:
|
push:
|
||||||
branches: [ develop, master ]
|
branches: [develop, master]
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
types: [ element-web-notify ]
|
types: [element-web-notify]
|
||||||
env:
|
env:
|
||||||
# These must be set for fetchdep.sh to get the right branch
|
# These must be set for fetchdep.sh to get the right branch
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
jobs:
|
jobs:
|
||||||
ts_lint:
|
ts_lint:
|
||||||
name: "Typescript Syntax Check"
|
name: "Typescript Syntax Check"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
cache: 'yarn'
|
cache: "yarn"
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: "./scripts/layered.sh"
|
run: "./scripts/layered.sh"
|
||||||
|
|
||||||
- name: Typecheck
|
- name: Typecheck
|
||||||
run: "yarn run lint:types"
|
run: "yarn run lint:types"
|
||||||
|
|
||||||
i18n_lint:
|
tsc-strict:
|
||||||
name: "i18n Check"
|
name: Typescript Strict Error Checker
|
||||||
uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
|
if: github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: read
|
||||||
|
checks: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
js_lint:
|
- name: Install Deps
|
||||||
name: "ESLint"
|
run: "scripts/layered.sh"
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- name: Get diff lines
|
||||||
with:
|
id: diff
|
||||||
cache: 'yarn'
|
uses: Equip-Collaboration/diff-line-numbers@v1.0.0
|
||||||
|
with:
|
||||||
|
include: '["\\.tsx?$"]'
|
||||||
|
|
||||||
# Does not need branch matching as only analyses this layer
|
- name: Detecting files changed
|
||||||
- name: Install Deps
|
id: files
|
||||||
run: "yarn install --pure-lockfile"
|
uses: futuratrepadeira/changed-files@v4.0.0
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
pattern: '^.*\.tsx?$'
|
||||||
|
|
||||||
- name: Run Linter
|
- uses: t3chguy/typescript-check-action@main
|
||||||
run: "yarn run lint:js"
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
use-check: false
|
||||||
|
check-fail-mode: added
|
||||||
|
output-behaviour: annotate
|
||||||
|
ts-extra-args: "--strict --noImplicitAny"
|
||||||
|
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 }}
|
||||||
|
|
||||||
style_lint:
|
i18n_lint:
|
||||||
name: "Style Lint"
|
name: "i18n Check"
|
||||||
runs-on: ubuntu-latest
|
uses: matrix-org/matrix-react-sdk/.github/workflows/i18n_check.yml@develop
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
js_lint:
|
||||||
with:
|
name: "ESLint"
|
||||||
cache: 'yarn'
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
# Needs branch matching as it inherits .stylelintrc.js from matrix-react-sdk
|
- uses: actions/setup-node@v3
|
||||||
- name: Install Dependencies
|
with:
|
||||||
run: "./scripts/layered.sh"
|
cache: "yarn"
|
||||||
|
|
||||||
- name: Run Linter
|
# Does not need branch matching as only analyses this layer
|
||||||
run: "yarn run lint:style"
|
- name: Install Deps
|
||||||
|
run: "yarn install --pure-lockfile"
|
||||||
|
|
||||||
|
- name: Run Linter
|
||||||
|
run: "yarn run lint:js"
|
||||||
|
|
||||||
|
style_lint:
|
||||||
|
name: "Style Lint"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: "yarn"
|
||||||
|
|
||||||
|
# Needs branch matching as it inherits .stylelintrc.js from matrix-react-sdk
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: "./scripts/layered.sh"
|
||||||
|
|
||||||
|
- name: Run Linter
|
||||||
|
run: "yarn run lint:style"
|
||||||
|
|
||||||
|
analyse_dead_code:
|
||||||
|
name: "Analyse Dead Code"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: "yarn"
|
||||||
|
|
||||||
|
- name: Install Deps
|
||||||
|
run: "scripts/layered.sh"
|
||||||
|
|
||||||
|
- name: Dead Code Analysis
|
||||||
|
run: "yarn run analyse:unused-exports"
|
||||||
|
|
62
.github/workflows/tests.yaml
vendored
62
.github/workflows/tests.yaml
vendored
|
@ -1,37 +1,41 @@
|
||||||
name: Tests
|
name: Tests
|
||||||
on:
|
on:
|
||||||
pull_request: { }
|
pull_request: {}
|
||||||
push:
|
push:
|
||||||
branches: [ develop, master ]
|
branches: [develop, master]
|
||||||
repository_dispatch:
|
repository_dispatch:
|
||||||
types: [ element-web-notify ]
|
types: [element-web-notify]
|
||||||
env:
|
env:
|
||||||
# These must be set for fetchdep.sh to get the right branch
|
# These must be set for fetchdep.sh to get the right branch
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
jobs:
|
jobs:
|
||||||
jest:
|
jest:
|
||||||
name: Jest
|
name: Jest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Yarn cache
|
- name: Yarn cache
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
cache: 'yarn'
|
cache: "yarn"
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: "./scripts/layered.sh"
|
run: "./scripts/layered.sh"
|
||||||
|
|
||||||
- name: Run tests with coverage
|
- name: Get number of CPU cores
|
||||||
run: "yarn coverage --ci"
|
id: cpu-cores
|
||||||
|
uses: SimenB/github-actions-cpu-cores@v1
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Run tests with coverage
|
||||||
uses: actions/upload-artifact@v2
|
run: "yarn coverage --ci --reporters github-actions --max-workers ${{ steps.cpu-cores.outputs.count }}"
|
||||||
with:
|
|
||||||
name: coverage
|
- name: Upload Artifact
|
||||||
path: |
|
uses: actions/upload-artifact@v3
|
||||||
coverage
|
with:
|
||||||
!coverage/lcov-report
|
name: coverage
|
||||||
|
path: |
|
||||||
|
coverage
|
||||||
|
!coverage/lcov-report
|
||||||
|
|
38
.github/workflows/triage-assigned.yml
vendored
38
.github/workflows/triage-assigned.yml
vendored
|
@ -1,18 +1,30 @@
|
||||||
name: Move issued assigned to specific team members to their boards
|
name: Move issued assigned to specific team members to their boards
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [ assigned ]
|
types: [assigned]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
web-app-team:
|
web-app-team:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: |
|
if: |
|
||||||
contains(github.event.issue.assignees.*.login, 't3chguy') ||
|
contains(github.event.issue.assignees.*.login, 't3chguy') ||
|
||||||
contains(github.event.issue.assignees.*.login, 'turt2live')
|
contains(github.event.issue.assignees.*.login, 'andybalaam')
|
||||||
steps:
|
steps:
|
||||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
id: add_to_project
|
||||||
project: Web App Team
|
with:
|
||||||
column: "In Progress"
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
query: |
|
||||||
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
|
item {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc4AKjJS"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
20
.github/workflows/triage-incoming.yml
vendored
20
.github/workflows/triage-incoming.yml
vendored
|
@ -1,15 +1,15 @@
|
||||||
name: Move new issues into Issue triage board
|
name: Move new issues into Issue triage board
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [ opened ]
|
types: [opened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
automate-project-columns:
|
automate-project-columns:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
- uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||||
with:
|
with:
|
||||||
project: Issue triage
|
project: Issue triage
|
||||||
column: Incoming
|
column: Incoming
|
||||||
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
535
.github/workflows/triage-labelled.yml
vendored
535
.github/workflows/triage-labelled.yml
vendored
|
@ -1,232 +1,331 @@
|
||||||
name: Move labelled issues to correct projects
|
name: Move labelled issues to correct projects
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [labeled]
|
types: [labeled]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
apply_Z-Labs_label:
|
apply_Z-Labs_label:
|
||||||
name: Add Z-Labs label for features behind labs flags
|
name: Add Z-Labs label for features behind labs flags
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'A-Maths') ||
|
contains(github.event.issue.labels.*.name, 'A-Maths') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Pinning') ||
|
contains(github.event.issue.labels.*.name, 'A-Message-Pinning') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Location-Sharing') ||
|
contains(github.event.issue.labels.*.name, 'A-Location-Sharing') ||
|
||||||
contains(github.event.issue.labels.*.name, 'Z-IA') ||
|
contains(github.event.issue.labels.*.name, 'Z-IA') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Themes-Custom') ||
|
contains(github.event.issue.labels.*.name, 'A-Themes-Custom') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
|
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Tags') ||
|
contains(github.event.issue.labels.*.name, 'A-Tags') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Video-Rooms') ||
|
contains(github.event.issue.labels.*.name, 'A-Video-Rooms') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Starring')
|
contains(github.event.issue.labels.*.name, 'A-Message-Starring') ||
|
||||||
steps:
|
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor') ||
|
||||||
- uses: actions/github-script@v5
|
contains(github.event.issue.labels.*.name, 'A-Element-Call')
|
||||||
with:
|
steps:
|
||||||
script: |
|
- uses: actions/github-script@v6
|
||||||
github.rest.issues.addLabels({
|
with:
|
||||||
issue_number: context.issue.number,
|
script: |
|
||||||
owner: context.repo.owner,
|
github.rest.issues.addLabels({
|
||||||
repo: context.repo.repo,
|
issue_number: context.issue.number,
|
||||||
labels: ['Z-Labs']
|
owner: context.repo.owner,
|
||||||
})
|
repo: context.repo.repo,
|
||||||
|
labels: ['Z-Labs']
|
||||||
|
})
|
||||||
|
|
||||||
move_needs_info_issues:
|
apply_Help-Wanted_label:
|
||||||
name: X-Needs-Info issues to Need info column on triage board
|
name: Add "Help Wanted" label to all "good first issue" and Hacktoberfest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
if: >
|
||||||
- uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338
|
contains(github.event.issue.labels.*.name, 'good first issue') ||
|
||||||
with:
|
contains(github.event.issue.labels.*.name, 'Hacktoberfest')
|
||||||
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
|
steps:
|
||||||
project-url: "https://github.com/vector-im/element-web/projects/27"
|
- uses: actions/github-script@v6
|
||||||
column-name: "Need info"
|
with:
|
||||||
label-name: "X-Needs-Info"
|
script: |
|
||||||
|
github.rest.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: ['Help Wanted']
|
||||||
|
})
|
||||||
|
|
||||||
add_priority_design_issues_to_project:
|
move_needs_info_issues:
|
||||||
name: P1 X-Needs-Design to Design project board
|
name: X-Needs-Info issues to Need info column on triage board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
steps:
|
||||||
contains(github.event.issue.labels.*.name, 'X-Needs-Design')
|
- uses: konradpabjan/move-labeled-or-milestoned-issue@190352295fe309fcb113b49193bc81d9aaa9cb01
|
||||||
steps:
|
with:
|
||||||
- uses: octokit/graphql-action@v2.x
|
action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}"
|
||||||
id: add_to_project
|
project-url: "https://github.com/vector-im/element-web/projects/27"
|
||||||
with:
|
column-name: "Need info"
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
label-name: "X-Needs-Info"
|
||||||
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_kwDOAM0swc0sUA"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
|
||||||
|
|
||||||
add_product_issues:
|
add_priority_design_issues_to_project:
|
||||||
name: X-Needs-Product to Design project board
|
name: P1 X-Needs-Design to Design project board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'X-Needs-Product')
|
contains(github.event.issue.labels.*.name, 'X-Needs-Design') &&
|
||||||
steps:
|
(contains(github.event.issue.labels.*.name, 'S-Critical') &&
|
||||||
- uses: octokit/graphql-action@v2.x
|
(contains(github.event.issue.labels.*.name, 'O-Frequent') ||
|
||||||
id: add_to_project
|
contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
|
||||||
with:
|
contains(github.event.issue.labels.*.name, 'S-Major') &&
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
contains(github.event.issue.labels.*.name, 'O-Frequent') ||
|
||||||
query: |
|
contains(github.event.issue.labels.*.name, 'A11y'))
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
steps:
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
- uses: octokit/graphql-action@v2.x
|
||||||
projectNextItem {
|
id: add_to_project
|
||||||
id
|
with:
|
||||||
}
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
}
|
query: |
|
||||||
}
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
item {
|
||||||
env:
|
id
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
|
}
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
Delight_issues_to_board:
|
add_product_issues:
|
||||||
name: Delight issues to project board
|
name: X-Needs-Product to product project board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'A-New-Search-Experience') ||
|
contains(github.event.issue.labels.*.name, 'X-Needs-Product')
|
||||||
(contains(github.event.issue.labels.*.name, 'A-Threads') &&
|
steps:
|
||||||
(contains(github.event.issue.labels.*.name, 'S-Major') ||
|
- uses: octokit/graphql-action@v2.x
|
||||||
contains(github.event.issue.labels.*.name, 'S-Critical'))) ||
|
id: add_to_project
|
||||||
contains(github.event.issue.labels.*.name, 'Team: Delight') ||
|
with:
|
||||||
contains(github.event.issue.labels.*.name, 'Z-NewUserJourney')
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
steps:
|
query: |
|
||||||
- uses: octokit/graphql-action@v2.x
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
with:
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
item {
|
||||||
query: |
|
id
|
||||||
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: "PVT_kwDOAM0swc4AAg6N"
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
|
||||||
env:
|
|
||||||
PROJECT_ID: "PN_kwDOAM0swc1HvQ"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
|
||||||
|
|
||||||
move_voice-message_issues:
|
Search_issues_to_board:
|
||||||
name: A-Voice Messages to voice message board
|
name: Search issues to project board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'A-Voice Messages')
|
contains(github.event.issue.labels.*.name, 'A-New-Search-Experience')
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc2KCw"
|
PROJECT_ID: "PVT_kwDOAM0swc4ADtaO"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_threads_issues:
|
move_voice-message_issues:
|
||||||
name: A-Threads to Thread board
|
name: A-Voice Messages to voice message board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'A-Threads')
|
contains(github.event.issue.labels.*.name, 'A-Voice Messages')
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc0rRA"
|
PROJECT_ID: "PVT_kwDOAM0swc2KCw"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_message_bubbles_issues:
|
move_message_bubbles_issues:
|
||||||
name: A-Message-Bubbles to Message bubbles board
|
name: A-Message-Bubbles to Message bubbles board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles')
|
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles')
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc3m-g"
|
PROJECT_ID: "PVT_kwDOAM0swc3m-g"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_ftue_issues:
|
move_ftue_issues:
|
||||||
name: Z-FTUE issues to the FTUE project board
|
name: Z-FTUE issues to the FTUE project board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'Z-FTUE')
|
contains(github.event.issue.labels.*.name, 'Z-FTUE')
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAqVx"
|
PROJECT_ID: "PVT_kwDOAM0swc4AAqVx"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
move_WTF_issues:
|
move_WTF_issues:
|
||||||
name: Z-WTF issues to the WTF project board
|
name: Z-WTF issues to the WTF project board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
contains(github.event.issue.labels.*.name, 'Z-WTF')
|
contains(github.event.issue.labels.*.name, 'Z-WTF')
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.issue.node_id }}
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AArk0"
|
PROJECT_ID: "PVT_kwDOAM0swc4AArk0"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
ps_features1:
|
||||||
|
name: Add labelled issues to PS features team 1
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-Polls') ||
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-Location-Sharing') ||
|
||||||
|
(contains(github.event.issue.labels.*.name, 'A-Voice-Messages') &&
|
||||||
|
!contains(github.event.issue.labels.*.name, 'A-Broadcast')) ||
|
||||||
|
(contains(github.event.issue.labels.*.name, 'A-Session-Mgmt') &&
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-User-Settings'))
|
||||||
|
steps:
|
||||||
|
- uses: octokit/graphql-action@v2.x
|
||||||
|
id: add_to_project
|
||||||
|
with:
|
||||||
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
|
query: |
|
||||||
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
|
item {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc4AHJKF"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
ps_features2:
|
||||||
|
name: Add labelled issues to PS features team 2
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-DM-Start') ||
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-Broadcast')
|
||||||
|
steps:
|
||||||
|
- uses: octokit/graphql-action@v2.x
|
||||||
|
id: add_to_project
|
||||||
|
with:
|
||||||
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
|
query: |
|
||||||
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
|
item {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc4AHJKd"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
ps_features3:
|
||||||
|
name: Add labelled issues to PS features team 3
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor')
|
||||||
|
steps:
|
||||||
|
- uses: octokit/graphql-action@v2.x
|
||||||
|
id: add_to_project
|
||||||
|
with:
|
||||||
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
|
query: |
|
||||||
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
|
item {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc4AHJKW"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
|
voip:
|
||||||
|
name: Add labelled issues to VoIP project board
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: >
|
||||||
|
contains(github.event.issue.labels.*.name, 'Team: VoIP')
|
||||||
|
steps:
|
||||||
|
- uses: octokit/graphql-action@v2.x
|
||||||
|
id: add_to_project
|
||||||
|
with:
|
||||||
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
|
query: |
|
||||||
|
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||||
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
|
item {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
|
contentid: ${{ github.event.issue.node_id }}
|
||||||
|
env:
|
||||||
|
PROJECT_ID: "PVT_kwDOAM0swc4ABMIk"
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
260
.github/workflows/triage-move-review-requests.yml
vendored
260
.github/workflows/triage-move-review-requests.yml
vendored
|
@ -1,139 +1,139 @@
|
||||||
name: Move pull requests asking for review to the relevant project
|
name: Move pull requests asking for review to the relevant project
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [ review_requested ]
|
types: [review_requested]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
add_design_pr_to_project:
|
add_design_pr_to_project:
|
||||||
name: Move PRs asking for design review to the design board
|
name: Move PRs asking for design review to the design board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
id: find_team_members
|
id: find_team_members
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
query find_team_members($team: String!) {
|
query find_team_members($team: String!) {
|
||||||
organization(login: "vector-im") {
|
organization(login: "vector-im") {
|
||||||
team(slug: $team) {
|
team(slug: $team) {
|
||||||
members {
|
members {
|
||||||
nodes {
|
nodes {
|
||||||
login
|
login
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
team: ${{ env.TEAM }}
|
team: ${{ env.TEAM }}
|
||||||
env:
|
env:
|
||||||
TEAM: "design"
|
TEAM: "design"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
- id: any_matching_reviewers
|
- id: any_matching_reviewers
|
||||||
run: |
|
run: |
|
||||||
# Fetch requested reviewers, and people who are on the team
|
# Fetch requested reviewers, and people who are on the team
|
||||||
echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json
|
echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json
|
||||||
echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json
|
echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json
|
||||||
jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt
|
jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt
|
||||||
jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt
|
jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt
|
||||||
|
|
||||||
# Fetch requested team reviewers, and the name of the team
|
# Fetch requested team reviewers, and the name of the team
|
||||||
echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json
|
echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json
|
||||||
jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt
|
jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt
|
||||||
echo '${{ env.TEAM }}' | tee /tmp/team.txt
|
echo '${{ env.TEAM }}' | tee /tmp/team.txt
|
||||||
|
|
||||||
# If either a reviewer matches a team member, or a team matches our team, say "true"
|
# If either a reviewer matches a team member, or a team matches our team, say "true"
|
||||||
if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then
|
if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then
|
||||||
echo "::set-output name=match::true"
|
echo "::set-output name=match::true"
|
||||||
elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then
|
elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then
|
||||||
echo "::set-output name=match::true"
|
echo "::set-output name=match::true"
|
||||||
else
|
else
|
||||||
echo "::set-output name=match::false"
|
echo "::set-output name=match::false"
|
||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
TEAM: "design"
|
TEAM: "design"
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
id: add_to_project
|
id: add_to_project
|
||||||
if: steps.any_matching_reviewers.outputs.match == 'true'
|
if: steps.any_matching_reviewers.outputs.match == 'true'
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!, $contentid:ID!) {
|
mutation add_to_project($projectid:ID!, $contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.pull_request.node_id }}
|
contentid: ${{ github.event.pull_request.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc0sUA"
|
PROJECT_ID: "PVT_kwDOAM0swc0sUA"
|
||||||
TEAM: "design"
|
TEAM: "design"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
add_product_pr_to_project:
|
add_product_pr_to_project:
|
||||||
name: Move PRs asking for design review to the design board
|
name: Move PRs asking for design review to the design board
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
id: find_team_members
|
id: find_team_members
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
query find_team_members($team: String!) {
|
query find_team_members($team: String!) {
|
||||||
organization(login: "vector-im") {
|
organization(login: "vector-im") {
|
||||||
team(slug: $team) {
|
team(slug: $team) {
|
||||||
members {
|
members {
|
||||||
nodes {
|
nodes {
|
||||||
login
|
login
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
team: ${{ env.TEAM }}
|
team: ${{ env.TEAM }}
|
||||||
env:
|
env:
|
||||||
TEAM: "product"
|
TEAM: "product"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
- id: any_matching_reviewers
|
- id: any_matching_reviewers
|
||||||
run: |
|
run: |
|
||||||
# Fetch requested reviewers, and people who are on the team
|
# Fetch requested reviewers, and people who are on the team
|
||||||
echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json
|
echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json
|
||||||
echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json
|
echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json
|
||||||
jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt
|
jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt
|
||||||
jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt
|
jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt
|
||||||
|
|
||||||
# Fetch requested team reviewers, and the name of the team
|
# Fetch requested team reviewers, and the name of the team
|
||||||
echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json
|
echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json
|
||||||
jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt
|
jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt
|
||||||
echo '${{ env.TEAM }}' | tee /tmp/team.txt
|
echo '${{ env.TEAM }}' | tee /tmp/team.txt
|
||||||
|
|
||||||
# If either a reviewer matches a team member, or a team matches our team, say "true"
|
# If either a reviewer matches a team member, or a team matches our team, say "true"
|
||||||
if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then
|
if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then
|
||||||
echo "::set-output name=match::true"
|
echo "::set-output name=match::true"
|
||||||
elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then
|
elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then
|
||||||
echo "::set-output name=match::true"
|
echo "::set-output name=match::true"
|
||||||
else
|
else
|
||||||
echo "::set-output name=match::false"
|
echo "::set-output name=match::false"
|
||||||
fi
|
fi
|
||||||
env:
|
env:
|
||||||
TEAM: "product"
|
TEAM: "product"
|
||||||
- uses: octokit/graphql-action@v2.x
|
- uses: octokit/graphql-action@v2.x
|
||||||
id: add_to_project
|
id: add_to_project
|
||||||
if: steps.any_matching_reviewers.outputs.match == 'true'
|
if: steps.any_matching_reviewers.outputs.match == 'true'
|
||||||
with:
|
with:
|
||||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||||
query: |
|
query: |
|
||||||
mutation add_to_project($projectid:ID!, $contentid:ID!) {
|
mutation add_to_project($projectid:ID!, $contentid:ID!) {
|
||||||
addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) {
|
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||||
projectNextItem {
|
item {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
projectid: ${{ env.PROJECT_ID }}
|
projectid: ${{ env.PROJECT_ID }}
|
||||||
contentid: ${{ github.event.pull_request.node_id }}
|
contentid: ${{ github.event.pull_request.node_id }}
|
||||||
env:
|
env:
|
||||||
PROJECT_ID: "PN_kwDOAM0swc4AAg6N"
|
PROJECT_ID: "PVT_kwDOAM0swc4AAg6N"
|
||||||
TEAM: "product"
|
TEAM: "product"
|
||||||
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
30
.github/workflows/triage-priority-bugs.yml
vendored
30
.github/workflows/triage-priority-bugs.yml
vendored
|
@ -1,30 +0,0 @@
|
||||||
name: Move P1 bugs to boards
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [labeled, unlabeled]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
P1_issues_to_crypto_team_workboard:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: >
|
|
||||||
contains(github.event.issue.labels.*.name, 'Z-UISI') ||
|
|
||||||
(contains(github.event.issue.labels.*.name, 'A-E2EE') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-Cross-Signing') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-Key-Backup') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-SAS-Verification')) &&
|
|
||||||
(contains(github.event.issue.labels.*.name, 'T-Defect') &&
|
|
||||||
contains(github.event.issue.labels.*.name, 'S-Critical') &&
|
|
||||||
(contains(github.event.issue.labels.*.name, 'O-Frequent') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'O-Occasional')) ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'S-Major') &&
|
|
||||||
contains(github.event.issue.labels.*.name, 'O-Frequent') ||
|
|
||||||
contains(github.event.issue.labels.*.name, 'A11y') &&
|
|
||||||
contains(github.event.issue.labels.*.name, 'O-Frequent'))
|
|
||||||
steps:
|
|
||||||
- uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
|
||||||
with:
|
|
||||||
project: Crypto Team
|
|
||||||
column: Ready
|
|
||||||
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
|
129
.github/workflows/triage-unlabelled.yml
vendored
129
.github/workflows/triage-unlabelled.yml
vendored
|
@ -1,71 +1,70 @@
|
||||||
name: Move unlabelled from needs info columns to triaged
|
name: Move unlabelled from needs info columns to triaged
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [ unlabeled ]
|
types: [unlabeled]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Move_Unabeled_Issue_On_Project_Board:
|
Move_Unabeled_Issue_On_Project_Board:
|
||||||
name: Move no longer X-Needs-Info issues to Triaged
|
name: Move no longer X-Needs-Info issues to Triaged
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
${{
|
${{
|
||||||
!contains(github.event.issue.labels.*.name, 'X-Needs-Info') }}
|
!contains(github.event.issue.labels.*.name, 'X-Needs-Info') }}
|
||||||
env:
|
env:
|
||||||
BOARD_NAME: "Issue triage"
|
BOARD_NAME: "Issue triage"
|
||||||
OWNER: ${{ github.repository_owner }}
|
OWNER: ${{ github.repository_owner }}
|
||||||
REPO: ${{ github.event.repository.name }}
|
REPO: ${{ github.event.repository.name }}
|
||||||
ISSUE: ${{ github.event.issue.number }}
|
ISSUE: ${{ github.event.issue.number }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check if issue is already in "${{ env.BOARD_NAME }}"
|
- name: Check if issue is already in "${{ env.BOARD_NAME }}"
|
||||||
run: |
|
run: |
|
||||||
json=$(curl -s -H 'Content-Type: application/json' -H "Authorization: bearer ${{ secrets.GITHUB_TOKEN }}" -X POST -d '{"query": "query($issue: Int!, $owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issue(number: $issue) { projectCards { nodes { project { name } isArchived } } } } } ", "variables" : "{ \"issue\": '${ISSUE}', \"owner\": \"'${OWNER}'\", \"repo\": \"'${REPO}'\" }" }' https://api.github.com/graphql)
|
json=$(curl -s -H 'Content-Type: application/json' -H "Authorization: bearer ${{ secrets.GITHUB_TOKEN }}" -X POST -d '{"query": "query($issue: Int!, $owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issue(number: $issue) { projectCards { nodes { project { name } isArchived } } } } } ", "variables" : "{ \"issue\": '${ISSUE}', \"owner\": \"'${OWNER}'\", \"repo\": \"'${REPO}'\" }" }' https://api.github.com/graphql)
|
||||||
if echo $json | jq '.data.repository.issue.projectCards.nodes | length'; then
|
if echo $json | jq '.data.repository.issue.projectCards.nodes | length'; then
|
||||||
if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].project.name') =~ "${BOARD_NAME}" ]]; then
|
if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].project.name') =~ "${BOARD_NAME}" ]]; then
|
||||||
if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].isArchived') == 'true' ]]; then
|
if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].isArchived') == 'true' ]]; then
|
||||||
echo "Issue is already in Project '$BOARD_NAME', but is archived - skipping workflow";
|
echo "Issue is already in Project '$BOARD_NAME', but is archived - skipping workflow";
|
||||||
echo "SKIP_ACTION=true" >> $GITHUB_ENV
|
echo "SKIP_ACTION=true" >> $GITHUB_ENV
|
||||||
else
|
else
|
||||||
echo "Issue is already in Project '$BOARD_NAME', proceeding";
|
echo "Issue is already in Project '$BOARD_NAME', proceeding";
|
||||||
echo "ALREADY_IN_BOARD=true" >> $GITHUB_ENV
|
echo "ALREADY_IN_BOARD=true" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Issue is not in project '$BOARD_NAME', cancelling this workflow"
|
echo "Issue is not in project '$BOARD_NAME', cancelling this workflow"
|
||||||
echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV
|
echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
- name: Move issue
|
- name: Move issue
|
||||||
uses: alex-page/github-project-automation-plus@bb266ff4dde9242060e2d5418e120a133586d488
|
uses: alex-page/github-project-automation-plus@1f8873e97e3c8f58161a323b7c568c1f623a1c4d
|
||||||
if: ${{ env.ALREADY_IN_BOARD == 'true' && env.SKIP_ACTION != 'true' }}
|
if: ${{ env.ALREADY_IN_BOARD == 'true' && env.SKIP_ACTION != 'true' }}
|
||||||
with:
|
with:
|
||||||
project: Issue triage
|
project: Issue triage
|
||||||
column: Triaged
|
column: Triaged
|
||||||
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
||||||
remove_Z-Labs_label:
|
remove_Z-Labs_label:
|
||||||
name: Remove Z-Labs label when features behind labs flags are removed
|
name: Remove Z-Labs label when features behind labs flags are removed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: >
|
if: >
|
||||||
!(contains(github.event.issue.labels.*.name, 'A-Maths') ||
|
!(contains(github.event.issue.labels.*.name, 'A-Maths') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Pinning') ||
|
contains(github.event.issue.labels.*.name, 'A-Message-Pinning') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Threads') ||
|
contains(github.event.issue.labels.*.name, 'A-Location-Sharing') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Polls') ||
|
contains(github.event.issue.labels.*.name, 'Z-IA') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Location-Sharing') ||
|
contains(github.event.issue.labels.*.name, 'A-Themes-Custom') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Bubbles') ||
|
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
|
||||||
contains(github.event.issue.labels.*.name, 'Z-IA') ||
|
contains(github.event.issue.labels.*.name, 'A-Tags') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Themes-Custom') ||
|
contains(github.event.issue.labels.*.name, 'A-Video-Rooms') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') ||
|
contains(github.event.issue.labels.*.name, 'A-Message-Starring') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Tags') ||
|
contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor') ||
|
||||||
contains(github.event.issue.labels.*.name, 'A-Video-Rooms') ||
|
contains(github.event.issue.labels.*.name, 'A-Element-Call')) &&
|
||||||
contains(github.event.issue.labels.*.name, 'A-Message-Starring')) &&
|
contains(github.event.issue.labels.*.name, 'Z-Labs')
|
||||||
contains(github.event.issue.labels.*.name, 'Z-Labs')
|
steps:
|
||||||
steps:
|
- uses: actions/github-script@v6
|
||||||
- uses: actions/github-script@v5
|
with:
|
||||||
with:
|
script: |
|
||||||
script: |
|
github.rest.issues.removeLabel({
|
||||||
github.rest.issues.removeLabel({
|
issue_number: context.issue.number,
|
||||||
issue_number: context.issue.number,
|
owner: context.repo.owner,
|
||||||
owner: context.repo.owner,
|
repo: context.repo.repo,
|
||||||
repo: context.repo.repo,
|
name: ['Z-Labs']
|
||||||
name: ['Z-Labs']
|
})
|
||||||
})
|
|
||||||
|
|
10
.github/workflows/upgrade_dependencies.yml
vendored
10
.github/workflows/upgrade_dependencies.yml
vendored
|
@ -1,8 +1,8 @@
|
||||||
name: Upgrade Dependencies
|
name: Upgrade Dependencies
|
||||||
on:
|
on:
|
||||||
workflow_dispatch: { }
|
workflow_dispatch: {}
|
||||||
jobs:
|
jobs:
|
||||||
upgrade:
|
upgrade:
|
||||||
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
|
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
|
||||||
secrets:
|
secrets:
|
||||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
{
|
{
|
||||||
"minify": true,
|
"minify": true,
|
||||||
"enableClasses": false,
|
"enableClasses": false,
|
||||||
"feature-detects": [
|
"feature-detects": [
|
||||||
"test/css/animations",
|
"test/css/animations",
|
||||||
"test/css/displaytable",
|
"test/css/displaytable",
|
||||||
"test/css/filters",
|
"test/css/filters",
|
||||||
"test/css/flexbox",
|
"test/css/flexbox",
|
||||||
"test/css/objectfit",
|
"test/css/objectfit",
|
||||||
|
|
||||||
"test/es5/date",
|
"test/es5/date",
|
||||||
"test/es5/function",
|
"test/es5/function",
|
||||||
"test/es5/object",
|
"test/es5/object",
|
||||||
"test/es5/undefined",
|
"test/es5/undefined",
|
||||||
|
|
||||||
"test/es6/array",
|
"test/es6/array",
|
||||||
"test/es6/collections",
|
"test/es6/collections",
|
||||||
"test/es6/promises",
|
"test/es6/promises",
|
||||||
"test/es6/string",
|
"test/es6/string",
|
||||||
|
|
||||||
"test/svg",
|
"test/svg",
|
||||||
"test/svg/asimg",
|
"test/svg/asimg",
|
||||||
"test/svg/filters",
|
"test/svg/filters",
|
||||||
|
|
||||||
"test/url/parser",
|
"test/url/parser",
|
||||||
"test/url/urlsearchparams",
|
"test/url/urlsearchparams",
|
||||||
|
|
||||||
"test/cors",
|
"test/cors",
|
||||||
"test/crypto",
|
"test/crypto",
|
||||||
"test/iframe/sandbox",
|
"test/iframe/sandbox",
|
||||||
"test/json",
|
"test/json",
|
||||||
"test/network/fetch",
|
"test/network/fetch",
|
||||||
"test/storage/localstorage",
|
"test/storage/localstorage",
|
||||||
"test/window/resizeobserver"
|
"test/window/resizeobserver"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
27
.prettierignore
Normal file
27
.prettierignore
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/build
|
||||||
|
/dist
|
||||||
|
/lib
|
||||||
|
/node_modules
|
||||||
|
/packages/
|
||||||
|
/webapp
|
||||||
|
/*.log
|
||||||
|
yarn.lock
|
||||||
|
electron/dist
|
||||||
|
electron/pub
|
||||||
|
**/.idea
|
||||||
|
/.tmp
|
||||||
|
/webpack-stats.json
|
||||||
|
.vscode
|
||||||
|
.vscode/
|
||||||
|
.env
|
||||||
|
/coverage
|
||||||
|
# Auto-generated file
|
||||||
|
/src/modules.ts
|
||||||
|
/src/i18n/strings
|
||||||
|
/build_config.yaml
|
||||||
|
# Raises an error because it contains a template var breaking the script tag
|
||||||
|
src/vector/index.html
|
||||||
|
src/vector/modernizr.js
|
||||||
|
|
||||||
|
# This file is owned, parsed, and generated by allchange, which doesn't comply with prettier
|
||||||
|
/CHANGELOG.md
|
1
.prettierrc.js
Normal file
1
.prettierrc.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = require("eslint-plugin-matrix-org/.prettierrc.js");
|
|
@ -1,3 +1,4 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...require("matrix-react-sdk/.stylelintrc.js"),
|
...require("matrix-react-sdk/.stylelintrc.js"),
|
||||||
|
extends: ["stylelint-config-standard", "stylelint-config-prettier"],
|
||||||
};
|
};
|
||||||
|
|
452
CHANGELOG.md
452
CHANGELOG.md
|
@ -1,3 +1,455 @@
|
||||||
|
Changes in [1.11.20](https://github.com/vector-im/element-web/releases/tag/v1.11.20) (2023-01-20)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* (Part 2) of prevent crash on older browsers (replace .at() with array.length-1)
|
||||||
|
|
||||||
|
Changes in [1.11.19](https://github.com/vector-im/element-web/releases/tag/v1.11.19) (2023-01-18)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* fix crash on browsers that don't support `Array.at` ([\#9935](https://github.com/matrix-org/matrix-react-sdk/pull/9935)). Contributed by @andybalaam.
|
||||||
|
|
||||||
|
Changes in [1.11.18](https://github.com/vector-im/element-web/releases/tag/v1.11.18) (2023-01-18)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Switch threads on for everyone ([\#9879](https://github.com/matrix-org/matrix-react-sdk/pull/9879)).
|
||||||
|
* Make threads use new Unable to Decrypt UI ([\#9876](https://github.com/matrix-org/matrix-react-sdk/pull/9876)). Fixes #24060.
|
||||||
|
* Add edit and remove actions to link in RTE [Labs] ([\#9864](https://github.com/matrix-org/matrix-react-sdk/pull/9864)).
|
||||||
|
* Remove extensible events v1 experimental rendering ([\#9881](https://github.com/matrix-org/matrix-react-sdk/pull/9881)).
|
||||||
|
* Make create poll dialog scale better (PSG-929) ([\#9873](https://github.com/matrix-org/matrix-react-sdk/pull/9873)). Fixes #21855.
|
||||||
|
* Change RTE mode icons ([\#9861](https://github.com/matrix-org/matrix-react-sdk/pull/9861)).
|
||||||
|
* Device manager - prune client information events after remote sign out ([\#9874](https://github.com/matrix-org/matrix-react-sdk/pull/9874)).
|
||||||
|
* Check connection before starting broadcast ([\#9857](https://github.com/matrix-org/matrix-react-sdk/pull/9857)).
|
||||||
|
* Enable sent receipt for poll start events (PSG-962) ([\#9870](https://github.com/matrix-org/matrix-react-sdk/pull/9870)).
|
||||||
|
* Change clear notifications to have more readable copy ([\#9867](https://github.com/matrix-org/matrix-react-sdk/pull/9867)).
|
||||||
|
* combine search results when the query is present in multiple successive messages ([\#9855](https://github.com/matrix-org/matrix-react-sdk/pull/9855)). Fixes #3977. Contributed by @grimhilt.
|
||||||
|
* Disable bubbles for broadcasts ([\#9860](https://github.com/matrix-org/matrix-react-sdk/pull/9860)). Fixes #24140.
|
||||||
|
* Enable reactions and replies for broadcasts ([\#9856](https://github.com/matrix-org/matrix-react-sdk/pull/9856)). Fixes #24042.
|
||||||
|
* Improve switching between rich and plain editing modes ([\#9776](https://github.com/matrix-org/matrix-react-sdk/pull/9776)).
|
||||||
|
* Redesign the picture-in-picture window ([\#9800](https://github.com/matrix-org/matrix-react-sdk/pull/9800)). Fixes #23980.
|
||||||
|
* User on-boarding tasks now appear in a static order. ([\#9799](https://github.com/matrix-org/matrix-react-sdk/pull/9799)). Contributed by @GoodGuyMarco.
|
||||||
|
* Device manager - contextual menus ([\#9832](https://github.com/matrix-org/matrix-react-sdk/pull/9832)).
|
||||||
|
* If listening a non-live broadcast and changing the room, the broadcast will be paused ([\#9825](https://github.com/matrix-org/matrix-react-sdk/pull/9825)). Fixes #24078.
|
||||||
|
* Consider own broadcasts from other device as a playback ([\#9821](https://github.com/matrix-org/matrix-react-sdk/pull/9821)). Fixes #24068.
|
||||||
|
* Add link creation to rich text editor ([\#9775](https://github.com/matrix-org/matrix-react-sdk/pull/9775)).
|
||||||
|
* Add mark as read option in room setting ([\#9798](https://github.com/matrix-org/matrix-react-sdk/pull/9798)). Fixes #24053.
|
||||||
|
* Device manager - current device design and copy tweaks ([\#9801](https://github.com/matrix-org/matrix-react-sdk/pull/9801)).
|
||||||
|
* Unify notifications panel event design ([\#9754](https://github.com/matrix-org/matrix-react-sdk/pull/9754)).
|
||||||
|
* Add actions for integration manager to send and read certain events ([\#9740](https://github.com/matrix-org/matrix-react-sdk/pull/9740)).
|
||||||
|
* Device manager - design tweaks ([\#9768](https://github.com/matrix-org/matrix-react-sdk/pull/9768)).
|
||||||
|
* Change room list sorting to activity and unread first by default ([\#9773](https://github.com/matrix-org/matrix-react-sdk/pull/9773)). Fixes #24014.
|
||||||
|
* Add a config flag to enable the rust crypto-sdk ([\#9759](https://github.com/matrix-org/matrix-react-sdk/pull/9759)).
|
||||||
|
* Improve decryption error UI by consolidating error messages and providing instructions when possible ([\#9544](https://github.com/matrix-org/matrix-react-sdk/pull/9544)). Contributed by @duxovni.
|
||||||
|
* Honor font settings in Element Call ([\#9751](https://github.com/matrix-org/matrix-react-sdk/pull/9751)). Fixes #23661.
|
||||||
|
* Device manager - use deleteAccountData to prune device manager client information events ([\#9734](https://github.com/matrix-org/matrix-react-sdk/pull/9734)).
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Display rooms & threads as unread (bold) if threads have unread messages. ([\#9763](https://github.com/matrix-org/matrix-react-sdk/pull/9763)). Fixes #23907.
|
||||||
|
* Don't prefer STIXGeneral over the default font ([\#9711](https://github.com/matrix-org/matrix-react-sdk/pull/9711)). Fixes #23899.
|
||||||
|
* Use the same avatar colour when creating 1:1 DM rooms ([\#9850](https://github.com/matrix-org/matrix-react-sdk/pull/9850)). Fixes #23476.
|
||||||
|
* Fix space lock icon size ([\#9854](https://github.com/matrix-org/matrix-react-sdk/pull/9854)). Fixes #24128.
|
||||||
|
* Make calls automatically disconnect if the widget disappears ([\#9862](https://github.com/matrix-org/matrix-react-sdk/pull/9862)). Fixes #23664.
|
||||||
|
* Fix emoji in RTE editing ([\#9827](https://github.com/matrix-org/matrix-react-sdk/pull/9827)).
|
||||||
|
* Fix export with attachments on formats txt and json ([\#9851](https://github.com/matrix-org/matrix-react-sdk/pull/9851)). Fixes #24130. Contributed by @grimhilt.
|
||||||
|
* Fixed empty `Content-Type` for encrypted uploads ([\#9848](https://github.com/matrix-org/matrix-react-sdk/pull/9848)). Contributed by @K3das.
|
||||||
|
* Fix sign-in instead link on password reset page ([\#9820](https://github.com/matrix-org/matrix-react-sdk/pull/9820)). Fixes #24087.
|
||||||
|
* The seekbar now initially shows the current position ([\#9796](https://github.com/matrix-org/matrix-react-sdk/pull/9796)). Fixes #24051.
|
||||||
|
* Fix: Editing a poll will silently change it to a closed poll ([\#9809](https://github.com/matrix-org/matrix-react-sdk/pull/9809)). Fixes #23176.
|
||||||
|
* Make call tiles look less broken in the right panel ([\#9808](https://github.com/matrix-org/matrix-react-sdk/pull/9808)). Fixes #23716.
|
||||||
|
* Prevent unnecessary m.direct updates ([\#9805](https://github.com/matrix-org/matrix-react-sdk/pull/9805)). Fixes #24059.
|
||||||
|
* Fix checkForPreJoinUISI for thread roots ([\#9803](https://github.com/matrix-org/matrix-react-sdk/pull/9803)). Fixes #24054.
|
||||||
|
* Snap in PiP widget when content changed ([\#9797](https://github.com/matrix-org/matrix-react-sdk/pull/9797)). Fixes #24050.
|
||||||
|
* Load RTE components only when RTE labs is enabled ([\#9804](https://github.com/matrix-org/matrix-react-sdk/pull/9804)).
|
||||||
|
* Ensure that events are correctly updated when they are edited. ([\#9789](https://github.com/matrix-org/matrix-react-sdk/pull/9789)).
|
||||||
|
* When stopping a broadcast also stop the playback ([\#9795](https://github.com/matrix-org/matrix-react-sdk/pull/9795)). Fixes #24052.
|
||||||
|
* Prevent to start two broadcasts at the same time ([\#9744](https://github.com/matrix-org/matrix-react-sdk/pull/9744)). Fixes #23973.
|
||||||
|
* Correctly handle limited sync responses by resetting the thread timeline ([\#3056](https://github.com/matrix-org/matrix-js-sdk/pull/3056)). Fixes vector-im/element-web#23952.
|
||||||
|
* Fix failure to start in firefox private browser ([\#3058](https://github.com/matrix-org/matrix-js-sdk/pull/3058)). Fixes vector-im/element-web#24216.
|
||||||
|
|
||||||
|
Changes in [1.11.17](https://github.com/vector-im/element-web/releases/tag/v1.11.17) (2022-12-21)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Add inline code formatting to rich text editor ([\#9720](https://github.com/matrix-org/matrix-react-sdk/pull/9720)).
|
||||||
|
* Add emoji handling for plain text mode of the new rich text editor ([\#9727](https://github.com/matrix-org/matrix-react-sdk/pull/9727)).
|
||||||
|
* Overlay virtual room call events into main timeline ([\#9626](https://github.com/matrix-org/matrix-react-sdk/pull/9626)). Fixes #22929.
|
||||||
|
* Adds a new section under "Room Settings" > "Roles & Permissions" which adds the possibility to multiselect users from this room and grant them more permissions. ([\#9596](https://github.com/matrix-org/matrix-react-sdk/pull/9596)). Contributed by @GoodGuyMarco.
|
||||||
|
* Add emoji handling for rich text mode ([\#9661](https://github.com/matrix-org/matrix-react-sdk/pull/9661)).
|
||||||
|
* Add setting to hide bold notifications ([\#9705](https://github.com/matrix-org/matrix-react-sdk/pull/9705)).
|
||||||
|
* Further password reset flow enhancements ([\#9662](https://github.com/matrix-org/matrix-react-sdk/pull/9662)).
|
||||||
|
* Snooze the bulk unverified sessions reminder on dismiss ([\#9706](https://github.com/matrix-org/matrix-react-sdk/pull/9706)).
|
||||||
|
* Honor advanced audio processing settings when recording voice messages ([\#9610](https://github.com/matrix-org/matrix-react-sdk/pull/9610)). Contributed by @MrAnno.
|
||||||
|
* Improve the visual balance of bubble layout ([\#9704](https://github.com/matrix-org/matrix-react-sdk/pull/9704)).
|
||||||
|
* Add config setting to disable bulk unverified sessions nag ([\#9657](https://github.com/matrix-org/matrix-react-sdk/pull/9657)).
|
||||||
|
* Only display bulk unverified sessions nag when current sessions is verified ([\#9656](https://github.com/matrix-org/matrix-react-sdk/pull/9656)).
|
||||||
|
* Separate labs and betas more clearly ([\#8969](https://github.com/matrix-org/matrix-react-sdk/pull/8969)). Fixes #22706.
|
||||||
|
* Show user an error if we fail to create a DM for verification. ([\#9624](https://github.com/matrix-org/matrix-react-sdk/pull/9624)).
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Prevent unnecessary m.direct updates ([\#9805](https://github.com/matrix-org/matrix-react-sdk/pull/9805)). Fixes #24059.
|
||||||
|
* Fix checkForPreJoinUISI for thread roots ([\#9803](https://github.com/matrix-org/matrix-react-sdk/pull/9803)). Fixes #24054.
|
||||||
|
* Load RTE components only when RTE labs is enabled ([\#9804](https://github.com/matrix-org/matrix-react-sdk/pull/9804)).
|
||||||
|
* Fix issue where thread panel did not update correctly ([\#9746](https://github.com/matrix-org/matrix-react-sdk/pull/9746)). Fixes #23971.
|
||||||
|
* Remove async call to get virtual room from room load ([\#9743](https://github.com/matrix-org/matrix-react-sdk/pull/9743)). Fixes #23968.
|
||||||
|
* Check each thread for unread messages. ([\#9723](https://github.com/matrix-org/matrix-react-sdk/pull/9723)).
|
||||||
|
* Device manage - handle sessions that don't support encryption ([\#9717](https://github.com/matrix-org/matrix-react-sdk/pull/9717)). Fixes #23722.
|
||||||
|
* Fix hover state for formatting buttons (Rich text editor) (fix vector-im/element-web/issues/23832) ([\#9715](https://github.com/matrix-org/matrix-react-sdk/pull/9715)).
|
||||||
|
* Don't allow group calls to be unterminated ([\#9710](https://github.com/matrix-org/matrix-react-sdk/pull/9710)).
|
||||||
|
* Fix replies to emotes not showing as inline ([\#9707](https://github.com/matrix-org/matrix-react-sdk/pull/9707)). Fixes #23903.
|
||||||
|
* Update copy of 'Change layout' button to match Element Call ([\#9703](https://github.com/matrix-org/matrix-react-sdk/pull/9703)).
|
||||||
|
* Fix call splitbrains when switching between rooms ([\#9692](https://github.com/matrix-org/matrix-react-sdk/pull/9692)).
|
||||||
|
* bugfix: fix an issue where the Notifier would incorrectly fire for non-timeline events ([\#9664](https://github.com/matrix-org/matrix-react-sdk/pull/9664)). Fixes #17263.
|
||||||
|
* Fix power selector being wrongly disabled for admins themselves ([\#9681](https://github.com/matrix-org/matrix-react-sdk/pull/9681)). Fixes #23882.
|
||||||
|
* Show day counts in call durations ([\#9641](https://github.com/matrix-org/matrix-react-sdk/pull/9641)).
|
||||||
|
|
||||||
|
Changes in [1.11.16](https://github.com/vector-im/element-web/releases/tag/v1.11.16) (2022-12-06)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Further improve replies ([\#6396](https://github.com/matrix-org/matrix-react-sdk/pull/6396)). Fixes #19074, #18194 #18027 and #19179.
|
||||||
|
* Enable users to join group calls from multiple devices ([\#9625](https://github.com/matrix-org/matrix-react-sdk/pull/9625)).
|
||||||
|
* fix(visual): make cursor a pointer for summaries ([\#9419](https://github.com/matrix-org/matrix-react-sdk/pull/9419)). Contributed by @r00ster91.
|
||||||
|
* Add placeholder for rich text editor ([\#9613](https://github.com/matrix-org/matrix-react-sdk/pull/9613)).
|
||||||
|
* Consolidate public room search experience ([\#9605](https://github.com/matrix-org/matrix-react-sdk/pull/9605)). Fixes #22846.
|
||||||
|
* New password reset flow ([\#9581](https://github.com/matrix-org/matrix-react-sdk/pull/9581)). Fixes #23131.
|
||||||
|
* Device manager - add tooltip to device details toggle ([\#9594](https://github.com/matrix-org/matrix-react-sdk/pull/9594)).
|
||||||
|
* sliding sync: add lazy-loading member support ([\#9530](https://github.com/matrix-org/matrix-react-sdk/pull/9530)).
|
||||||
|
* Limit formatting bar offset to top of composer ([\#9365](https://github.com/matrix-org/matrix-react-sdk/pull/9365)). Fixes #12359. Contributed by @owi92.
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Fix issues around up arrow event edit shortcut ([\#9645](https://github.com/matrix-org/matrix-react-sdk/pull/9645)). Fixes #18497 and #18964.
|
||||||
|
* Fix search not being cleared when clicking on a result ([\#9635](https://github.com/matrix-org/matrix-react-sdk/pull/9635)). Fixes #23845.
|
||||||
|
* Fix screensharing in 1:1 calls ([\#9612](https://github.com/matrix-org/matrix-react-sdk/pull/9612)). Fixes #23808.
|
||||||
|
* Fix the background color flashing when joining a call ([\#9640](https://github.com/matrix-org/matrix-react-sdk/pull/9640)).
|
||||||
|
* Fix the size of the 'Private space' icon ([\#9638](https://github.com/matrix-org/matrix-react-sdk/pull/9638)).
|
||||||
|
* Fix reply editing in rich text editor (https ([\#9615](https://github.com/matrix-org/matrix-react-sdk/pull/9615)).
|
||||||
|
* Fix thread list jumping back down while scrolling ([\#9606](https://github.com/matrix-org/matrix-react-sdk/pull/9606)). Fixes #23727.
|
||||||
|
* Fix regression with TimelinePanel props updates not taking effect ([\#9608](https://github.com/matrix-org/matrix-react-sdk/pull/9608)). Fixes #23794.
|
||||||
|
* Fix form tooltip positioning ([\#9598](https://github.com/matrix-org/matrix-react-sdk/pull/9598)). Fixes #22861.
|
||||||
|
* Extract Search handling from RoomView into its own Component ([\#9574](https://github.com/matrix-org/matrix-react-sdk/pull/9574)). Fixes #498.
|
||||||
|
* Fix call splitbrains when switching between rooms ([\#9692](https://github.com/matrix-org/matrix-react-sdk/pull/9692)).
|
||||||
|
* [Backport staging] Fix replies to emotes not showing as inline ([\#9708](https://github.com/matrix-org/matrix-react-sdk/pull/9708)).
|
||||||
|
|
||||||
|
Changes in [1.11.15](https://github.com/vector-im/element-web/releases/tag/v1.11.15) (2022-11-22)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Make clear notifications work with threads ([\#9575](https://github.com/matrix-org/matrix-react-sdk/pull/9575)). Fixes #23751.
|
||||||
|
* Change "None" to "Off" in notification options ([\#9539](https://github.com/matrix-org/matrix-react-sdk/pull/9539)). Contributed by @Arnei.
|
||||||
|
* Advanced audio processing settings ([\#8759](https://github.com/matrix-org/matrix-react-sdk/pull/8759)). Fixes #6278. Contributed by @MrAnno.
|
||||||
|
* Add way to create a user notice via config.json ([\#9559](https://github.com/matrix-org/matrix-react-sdk/pull/9559)).
|
||||||
|
* Improve design of the rich text editor ([\#9533](https://github.com/matrix-org/matrix-react-sdk/pull/9533)). Contributed by @florianduros.
|
||||||
|
* Enable user to zoom beyond image size ([\#5949](https://github.com/matrix-org/matrix-react-sdk/pull/5949)). Contributed by @jaiwanth-v.
|
||||||
|
* Fix: Move "Leave Space" option to the bottom of space context menu ([\#9535](https://github.com/matrix-org/matrix-react-sdk/pull/9535)). Contributed by @hanadi92.
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Make build scripts work on NixOS ([\#23740](https://github.com/vector-im/element-web/pull/23740)).
|
||||||
|
* Fix integration manager `get_open_id_token` action and add E2E tests ([\#9520](https://github.com/matrix-org/matrix-react-sdk/pull/9520)).
|
||||||
|
* Fix links being mangled by markdown processing ([\#9570](https://github.com/matrix-org/matrix-react-sdk/pull/9570)). Fixes #23743.
|
||||||
|
* Fix: inline links selecting radio button ([\#9543](https://github.com/matrix-org/matrix-react-sdk/pull/9543)). Contributed by @hanadi92.
|
||||||
|
* Fix wrong error message in registration when phone number threepid is in use. ([\#9571](https://github.com/matrix-org/matrix-react-sdk/pull/9571)). Contributed by @bagvand.
|
||||||
|
* Fix missing avatar for show current profiles ([\#9563](https://github.com/matrix-org/matrix-react-sdk/pull/9563)). Fixes #23733.
|
||||||
|
* Fix read receipts trickling down correctly ([\#9567](https://github.com/matrix-org/matrix-react-sdk/pull/9567)). Fixes #23746.
|
||||||
|
* Resilience fix for homeserver without thread notification support ([\#9565](https://github.com/matrix-org/matrix-react-sdk/pull/9565)).
|
||||||
|
* Don't switch to the home page needlessly after leaving a room ([\#9477](https://github.com/matrix-org/matrix-react-sdk/pull/9477)).
|
||||||
|
* Differentiate download and decryption errors when showing images ([\#9562](https://github.com/matrix-org/matrix-react-sdk/pull/9562)). Fixes #3892.
|
||||||
|
* Close context menu when a modal is opened to prevent user getting stuck ([\#9560](https://github.com/matrix-org/matrix-react-sdk/pull/9560)). Fixes #15610 and #10781.
|
||||||
|
* Fix TimelineReset handling when no room associated ([\#9553](https://github.com/matrix-org/matrix-react-sdk/pull/9553)).
|
||||||
|
* Always use current profile on thread events ([\#9524](https://github.com/matrix-org/matrix-react-sdk/pull/9524)). Fixes #23648.
|
||||||
|
* Fix `ThreadView` tests not using thread flag ([\#9547](https://github.com/matrix-org/matrix-react-sdk/pull/9547)). Contributed by @MadLittleMods.
|
||||||
|
* Handle deletion of `m.call` events ([\#9540](https://github.com/matrix-org/matrix-react-sdk/pull/9540)). Fixes #23663.
|
||||||
|
* Fix incorrect notification count after leaving a room with notifications ([\#9518](https://github.com/matrix-org/matrix-react-sdk/pull/9518)). Contributed by @Arnei.
|
||||||
|
|
||||||
|
Changes in [1.11.14](https://github.com/vector-im/element-web/releases/tag/v1.11.14) (2022-11-08)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Loading threads with server-side assistance ([\#9356](https://github.com/matrix-org/matrix-react-sdk/pull/9356)). Fixes #21807, #21799, #21911, #22141, #22157, #22641, #22501 #22438 and #21678. Contributed by @justjanne.
|
||||||
|
* Make thread replies trigger a room list re-ordering ([\#9510](https://github.com/matrix-org/matrix-react-sdk/pull/9510)). Fixes #21700.
|
||||||
|
* Device manager - add extra details to device security and renaming ([\#9501](https://github.com/matrix-org/matrix-react-sdk/pull/9501)). Contributed by @kerryarchibald.
|
||||||
|
* Add plain text mode to the wysiwyg composer ([\#9503](https://github.com/matrix-org/matrix-react-sdk/pull/9503)). Contributed by @florianduros.
|
||||||
|
* Sliding Sync: improve sort order, show subspace rooms, better tombstoned room handling ([\#9484](https://github.com/matrix-org/matrix-react-sdk/pull/9484)).
|
||||||
|
* Device manager - add learn more popups to filtered sessions section ([\#9497](https://github.com/matrix-org/matrix-react-sdk/pull/9497)). Contributed by @kerryarchibald.
|
||||||
|
* Show thread notification if thread timeline is closed ([\#9495](https://github.com/matrix-org/matrix-react-sdk/pull/9495)). Fixes #23589.
|
||||||
|
* Add message editing to wysiwyg composer ([\#9488](https://github.com/matrix-org/matrix-react-sdk/pull/9488)). Contributed by @florianduros.
|
||||||
|
* Device manager - confirm sign out of other sessions ([\#9487](https://github.com/matrix-org/matrix-react-sdk/pull/9487)). Contributed by @kerryarchibald.
|
||||||
|
* Automatically request logs from other users in a call when submitting logs ([\#9492](https://github.com/matrix-org/matrix-react-sdk/pull/9492)).
|
||||||
|
* Add thread notification with server assistance (MSC3773) ([\#9400](https://github.com/matrix-org/matrix-react-sdk/pull/9400)). Fixes #21114, #21413, #21416, #21433, #21481, #21798, #21823 #23192 and #21765.
|
||||||
|
* Support for login + E2EE set up with QR ([\#9403](https://github.com/matrix-org/matrix-react-sdk/pull/9403)). Contributed by @hughns.
|
||||||
|
* Allow pressing Enter to send messages in new composer ([\#9451](https://github.com/matrix-org/matrix-react-sdk/pull/9451)). Contributed by @andybalaam.
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Fix regressions around media uploads failing and causing soft crashes ([\#9549](https://github.com/matrix-org/matrix-react-sdk/pull/9549)). Fixes matrix-org/element-web-rageshakes#16831, matrix-org/element-web-rageshakes#16824 matrix-org/element-web-rageshakes#16810 and vector-im/element-web#23641.
|
||||||
|
* Fix /myroomavatar slash command ([\#9536](https://github.com/matrix-org/matrix-react-sdk/pull/9536)). Fixes matrix-org/synapse#14321.
|
||||||
|
* Fix config.json failing to load for Jitsi wrapper in non-root deployment ([\#23577](https://github.com/vector-im/element-web/pull/23577)).
|
||||||
|
* Fix NotificationBadge unsent color ([\#9522](https://github.com/matrix-org/matrix-react-sdk/pull/9522)). Fixes #23646.
|
||||||
|
* Fix room list sorted by recent on app startup ([\#9515](https://github.com/matrix-org/matrix-react-sdk/pull/9515)). Fixes #23635.
|
||||||
|
* Reset custom power selector when blurred on empty ([\#9508](https://github.com/matrix-org/matrix-react-sdk/pull/9508)). Fixes #23481.
|
||||||
|
* Reinstate timeline/redaction callbacks when updating notification state ([\#9494](https://github.com/matrix-org/matrix-react-sdk/pull/9494)). Fixes #23554.
|
||||||
|
* Only render NotificationBadge when needed ([\#9493](https://github.com/matrix-org/matrix-react-sdk/pull/9493)). Fixes #23584.
|
||||||
|
* Fix embedded Element Call screen sharing ([\#9485](https://github.com/matrix-org/matrix-react-sdk/pull/9485)). Fixes #23571.
|
||||||
|
* Send Content-Type: application/json header for integration manager /register API ([\#9490](https://github.com/matrix-org/matrix-react-sdk/pull/9490)). Fixes #23580.
|
||||||
|
* Fix joining calls without audio or video inputs ([\#9486](https://github.com/matrix-org/matrix-react-sdk/pull/9486)). Fixes #23511.
|
||||||
|
* Ensure spaces in the spotlight dialog have rounded square avatars ([\#9480](https://github.com/matrix-org/matrix-react-sdk/pull/9480)). Fixes #23515.
|
||||||
|
* Only show mini avatar uploader in room intro when no avatar yet exists ([\#9479](https://github.com/matrix-org/matrix-react-sdk/pull/9479)). Fixes #23552.
|
||||||
|
* Fix threads fallback incorrectly targets root event ([\#9229](https://github.com/matrix-org/matrix-react-sdk/pull/9229)). Fixes #23147.
|
||||||
|
* Align video call icon with banner text ([\#9460](https://github.com/matrix-org/matrix-react-sdk/pull/9460)).
|
||||||
|
* Set relations helper when creating event tile context menu ([\#9253](https://github.com/matrix-org/matrix-react-sdk/pull/9253)). Fixes #22018.
|
||||||
|
* Device manager - put client/browser device metadata in correct section ([\#9447](https://github.com/matrix-org/matrix-react-sdk/pull/9447)). Contributed by @kerryarchibald.
|
||||||
|
* Update the room unread notification counter when the server changes the value without any related read receipt ([\#9438](https://github.com/matrix-org/matrix-react-sdk/pull/9438)).
|
||||||
|
|
||||||
|
Changes in [1.11.13](https://github.com/vector-im/element-web/releases/tag/v1.11.13) (2022-11-01)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Fix default behavior of Room.getBlacklistUnverifiedDevices ([\#2830](https://github.com/matrix-org/matrix-js-sdk/pull/2830)). Contributed by @duxovni.
|
||||||
|
* Catch server versions API call exception when starting the client ([\#2828](https://github.com/matrix-org/matrix-js-sdk/pull/2828)). Fixes vector-im/element-web#23634.
|
||||||
|
* Fix authedRequest including `Authorization: Bearer undefined` for password resets ([\#2822](https://github.com/matrix-org/matrix-js-sdk/pull/2822)). Fixes vector-im/element-web#23655.
|
||||||
|
|
||||||
|
Changes in [1.11.12](https://github.com/vector-im/element-web/releases/tag/v1.11.12) (2022-10-26)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Fix config.json failing to load for Jitsi wrapper in non-root deployment ([\#23577](https://github.com/vector-im/element-web/pull/23577)).
|
||||||
|
|
||||||
|
Changes in [1.11.11](https://github.com/vector-im/element-web/releases/tag/v1.11.11) (2022-10-25)
|
||||||
|
=================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Device manager - tweak string formatting of default device name ([\#23457](https://github.com/vector-im/element-web/pull/23457)).
|
||||||
|
* Add Element Call participant limit ([\#23431](https://github.com/vector-im/element-web/pull/23431)).
|
||||||
|
* Add Element Call `brand` ([\#23443](https://github.com/vector-im/element-web/pull/23443)).
|
||||||
|
* Include a file-safe room name and ISO date in chat exports ([\#9440](https://github.com/matrix-org/matrix-react-sdk/pull/9440)). Fixes #21812 and #19724.
|
||||||
|
* Room call banner ([\#9378](https://github.com/matrix-org/matrix-react-sdk/pull/9378)). Fixes #23453. Contributed by @toger5.
|
||||||
|
* Device manager - spinners while devices are signing out ([\#9433](https://github.com/matrix-org/matrix-react-sdk/pull/9433)). Fixes #15865.
|
||||||
|
* Device manager - silence call ringers when local notifications are silenced ([\#9420](https://github.com/matrix-org/matrix-react-sdk/pull/9420)).
|
||||||
|
* Pass the current language to Element Call ([\#9427](https://github.com/matrix-org/matrix-react-sdk/pull/9427)).
|
||||||
|
* Hide screen-sharing button in Element Call on desktop ([\#9423](https://github.com/matrix-org/matrix-react-sdk/pull/9423)).
|
||||||
|
* Add reply support to WysiwygComposer ([\#9422](https://github.com/matrix-org/matrix-react-sdk/pull/9422)). Contributed by @florianduros.
|
||||||
|
* Disconnect other connected devices (of the same user) when joining an Element call ([\#9379](https://github.com/matrix-org/matrix-react-sdk/pull/9379)).
|
||||||
|
* Device manager - device tile main click target ([\#9409](https://github.com/matrix-org/matrix-react-sdk/pull/9409)).
|
||||||
|
* Add formatting buttons to the rich text editor ([\#9410](https://github.com/matrix-org/matrix-react-sdk/pull/9410)). Contributed by @florianduros.
|
||||||
|
* Device manager - current session context menu ([\#9386](https://github.com/matrix-org/matrix-react-sdk/pull/9386)).
|
||||||
|
* Remove piwik config fallback for privacy policy URL ([\#9390](https://github.com/matrix-org/matrix-react-sdk/pull/9390)).
|
||||||
|
* Add the first step to integrate the matrix wysiwyg composer ([\#9374](https://github.com/matrix-org/matrix-react-sdk/pull/9374)). Contributed by @florianduros.
|
||||||
|
* Device manager - UA parsing tweaks ([\#9382](https://github.com/matrix-org/matrix-react-sdk/pull/9382)).
|
||||||
|
* Device manager - remove client information events when disabling setting ([\#9384](https://github.com/matrix-org/matrix-react-sdk/pull/9384)).
|
||||||
|
* Add Element Call participant limit ([\#9358](https://github.com/matrix-org/matrix-react-sdk/pull/9358)).
|
||||||
|
* Add Element Call room settings ([\#9347](https://github.com/matrix-org/matrix-react-sdk/pull/9347)).
|
||||||
|
* Device manager - render extended device information ([\#9360](https://github.com/matrix-org/matrix-react-sdk/pull/9360)).
|
||||||
|
* New group call experience: Room header and PiP designs ([\#9351](https://github.com/matrix-org/matrix-react-sdk/pull/9351)).
|
||||||
|
* Pass language to Jitsi Widget ([\#9346](https://github.com/matrix-org/matrix-react-sdk/pull/9346)). Contributed by @Fox32.
|
||||||
|
* Add notifications and toasts for Element Call calls ([\#9337](https://github.com/matrix-org/matrix-react-sdk/pull/9337)).
|
||||||
|
* Device manager - device type icon ([\#9355](https://github.com/matrix-org/matrix-react-sdk/pull/9355)).
|
||||||
|
* Delete the remainder of groups ([\#9357](https://github.com/matrix-org/matrix-react-sdk/pull/9357)). Fixes #22770.
|
||||||
|
* Device manager - display client information in device details ([\#9315](https://github.com/matrix-org/matrix-react-sdk/pull/9315)).
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Send Content-Type: application/json header for integration manager /register API ([\#9490](https://github.com/matrix-org/matrix-react-sdk/pull/9490)). Fixes #23580.
|
||||||
|
* Make ErrorView & CompatibilityView scrollable ([\#23468](https://github.com/vector-im/element-web/pull/23468)). Fixes #23376.
|
||||||
|
* Device manager - put client/browser device metadata in correct section ([\#9447](https://github.com/matrix-org/matrix-react-sdk/pull/9447)).
|
||||||
|
* update the room unread notification counter when the server changes the value without any related read receipt ([\#9438](https://github.com/matrix-org/matrix-react-sdk/pull/9438)).
|
||||||
|
* Don't show call banners in video rooms ([\#9441](https://github.com/matrix-org/matrix-react-sdk/pull/9441)).
|
||||||
|
* Prevent useContextMenu isOpen from being true if the button ref goes away ([\#9418](https://github.com/matrix-org/matrix-react-sdk/pull/9418)). Fixes matrix-org/element-web-rageshakes#15637.
|
||||||
|
* Automatically focus the WYSIWYG composer when you enter a room ([\#9412](https://github.com/matrix-org/matrix-react-sdk/pull/9412)).
|
||||||
|
* Improve the tooltips on the call lobby join button ([\#9428](https://github.com/matrix-org/matrix-react-sdk/pull/9428)).
|
||||||
|
* Pass the homeserver's base URL to Element Call ([\#9429](https://github.com/matrix-org/matrix-react-sdk/pull/9429)). Fixes #23301.
|
||||||
|
* Better accommodate long room names in call toasts ([\#9426](https://github.com/matrix-org/matrix-react-sdk/pull/9426)).
|
||||||
|
* Hide virtual widgets from the room info panel ([\#9424](https://github.com/matrix-org/matrix-react-sdk/pull/9424)). Fixes #23494.
|
||||||
|
* Inhibit clicking on sender avatar in threads list ([\#9417](https://github.com/matrix-org/matrix-react-sdk/pull/9417)). Fixes #23482.
|
||||||
|
* Correct the dir parameter of MSC3715 ([\#9391](https://github.com/matrix-org/matrix-react-sdk/pull/9391)). Contributed by @dhenneke.
|
||||||
|
* Use a more correct subset of users in `/remakeolm` developer command ([\#9402](https://github.com/matrix-org/matrix-react-sdk/pull/9402)).
|
||||||
|
* use correct default for notification silencing ([\#9388](https://github.com/matrix-org/matrix-react-sdk/pull/9388)). Fixes #23456.
|
||||||
|
* Device manager - eagerly create `m.local_notification_settings` events ([\#9353](https://github.com/matrix-org/matrix-react-sdk/pull/9353)).
|
||||||
|
* Close incoming Element call toast when viewing the call lobby ([\#9375](https://github.com/matrix-org/matrix-react-sdk/pull/9375)).
|
||||||
|
* Always allow enabling sending read receipts ([\#9367](https://github.com/matrix-org/matrix-react-sdk/pull/9367)). Fixes #23433.
|
||||||
|
* Fixes (vector-im/element-web/issues/22609) where the white theme is not applied when `white -> dark -> white` sequence is done. ([\#9320](https://github.com/matrix-org/matrix-react-sdk/pull/9320)). Contributed by @florianduros.
|
||||||
|
* Fix applying programmatically set height for "top" room layout ([\#9339](https://github.com/matrix-org/matrix-react-sdk/pull/9339)). Contributed by @Fox32.
|
||||||
|
|
||||||
|
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)
|
||||||
|
===============================================================================================
|
||||||
|
|
||||||
|
## 🔒 Security
|
||||||
|
* Fixes for [CVE-2022-36059](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D36059) and [CVE-2022-36060](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE%2D2022%2D36060)
|
||||||
|
|
||||||
|
Learn more about what we've been up to at https://element.io/blog/element-web-desktop-1-11-4-a-security-update-deferred-dms-and-more/
|
||||||
|
Find more details of the vulnerabilities at https://matrix.org/blog/2022/08/31/security-releases-matrix-js-sdk-19-4-0-and-matrix-react-sdk-3-53-0
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* 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.
|
||||||
|
* Ignore unreads in low priority rooms in the space panel ([\#6518](https://github.com/matrix-org/matrix-react-sdk/pull/6518)). Fixes #16836.
|
||||||
|
* Release message right-click context menu out of labs ([\#8613](https://github.com/matrix-org/matrix-react-sdk/pull/8613)).
|
||||||
|
* Device manager - expandable session details in device list ([\#9188](https://github.com/matrix-org/matrix-react-sdk/pull/9188)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager - device list filtering ([\#9181](https://github.com/matrix-org/matrix-react-sdk/pull/9181)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager - add verification details to session details ([\#9187](https://github.com/matrix-org/matrix-react-sdk/pull/9187)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager - current session expandable details ([\#9185](https://github.com/matrix-org/matrix-react-sdk/pull/9185)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager - security recommendations section ([\#9179](https://github.com/matrix-org/matrix-react-sdk/pull/9179)). Contributed by @kerryarchibald.
|
||||||
|
* The Welcome Home Screen: Return Button ([\#9089](https://github.com/matrix-org/matrix-react-sdk/pull/9089)). Fixes #22917. Contributed by @justjanne.
|
||||||
|
* Device manager - label devices as inactive ([\#9175](https://github.com/matrix-org/matrix-react-sdk/pull/9175)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager - other sessions list ([\#9155](https://github.com/matrix-org/matrix-react-sdk/pull/9155)). Contributed by @kerryarchibald.
|
||||||
|
* Implement MSC3846: Allowing widgets to access TURN servers ([\#9061](https://github.com/matrix-org/matrix-react-sdk/pull/9061)).
|
||||||
|
* Allow widgets to send/receive to-device messages ([\#8885](https://github.com/matrix-org/matrix-react-sdk/pull/8885)).
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Add super cool feature ([\#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.
|
||||||
|
* Reduce amount of requests done by the onboarding task list ([\#9194](https://github.com/matrix-org/matrix-react-sdk/pull/9194)). Fixes #23085. Contributed by @justjanne.
|
||||||
|
* Avoid hardcoding branding in user onboarding ([\#9206](https://github.com/matrix-org/matrix-react-sdk/pull/9206)). Fixes #23111. Contributed by @justjanne.
|
||||||
|
* End jitsi call when member is banned ([\#8879](https://github.com/matrix-org/matrix-react-sdk/pull/8879)). Contributed by @maheichyk.
|
||||||
|
* Fix context menu being opened when clicking message action bar buttons ([\#9200](https://github.com/matrix-org/matrix-react-sdk/pull/9200)). Fixes #22279 and #23100.
|
||||||
|
* Add gap between checkbox and text in report dialog following the same pattern (8px) used in the gap between the two buttons. It fixes vector-im/element-web#23060 ([\#9195](https://github.com/matrix-org/matrix-react-sdk/pull/9195)). Contributed by @gefgu.
|
||||||
|
* Fix url preview AXE and layout issue & add percy test ([\#9189](https://github.com/matrix-org/matrix-react-sdk/pull/9189)). Fixes #23083.
|
||||||
|
* Wrap long space names ([\#9201](https://github.com/matrix-org/matrix-react-sdk/pull/9201)). Fixes #23095.
|
||||||
|
* Attempt to fix `Failed to execute 'removeChild' on 'Node'` ([\#9196](https://github.com/matrix-org/matrix-react-sdk/pull/9196)).
|
||||||
|
* Fix soft crash around space hierarchy changing between spaces ([\#9191](https://github.com/matrix-org/matrix-react-sdk/pull/9191)). Fixes matrix-org/element-web-rageshakes#14613.
|
||||||
|
* Fix soft crash around room view store metrics ([\#9190](https://github.com/matrix-org/matrix-react-sdk/pull/9190)). Fixes matrix-org/element-web-rageshakes#14361.
|
||||||
|
* Fix the same person appearing multiple times when searching for them. ([\#9177](https://github.com/matrix-org/matrix-react-sdk/pull/9177)). Fixes #22851.
|
||||||
|
* Fix space panel subspace indentation going missing ([\#9167](https://github.com/matrix-org/matrix-react-sdk/pull/9167)). Fixes #23049.
|
||||||
|
* Fix invisible power levels tile when showing hidden events ([\#9162](https://github.com/matrix-org/matrix-react-sdk/pull/9162)). Fixes #23013.
|
||||||
|
* Space panel accessibility improvements ([\#9157](https://github.com/matrix-org/matrix-react-sdk/pull/9157)). Fixes #22995.
|
||||||
|
* Fix inverted logic for showing UserWelcomeTop component ([\#9164](https://github.com/matrix-org/matrix-react-sdk/pull/9164)). Fixes #23037.
|
||||||
|
|
||||||
|
Changes in [1.11.3](https://github.com/vector-im/element-web/releases/tag/v1.11.3) (2022-08-16)
|
||||||
|
===============================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Improve auth aria attributes and semantics ([\#22948](https://github.com/vector-im/element-web/pull/22948)).
|
||||||
|
* Device manager - New device tile info design ([\#9122](https://github.com/matrix-org/matrix-react-sdk/pull/9122)). Contributed by @kerryarchibald.
|
||||||
|
* Device manager generic settings subsection component ([\#9147](https://github.com/matrix-org/matrix-react-sdk/pull/9147)). Contributed by @kerryarchibald.
|
||||||
|
* Migrate the hidden read receipts flag to new "send read receipts" option ([\#9141](https://github.com/matrix-org/matrix-react-sdk/pull/9141)).
|
||||||
|
* Live location sharing - share location at most every 5 seconds ([\#9148](https://github.com/matrix-org/matrix-react-sdk/pull/9148)). Contributed by @kerryarchibald.
|
||||||
|
* Increase max length of voice messages to 15m ([\#9133](https://github.com/matrix-org/matrix-react-sdk/pull/9133)). Fixes #18620.
|
||||||
|
* Move pin drop out of labs ([\#9135](https://github.com/matrix-org/matrix-react-sdk/pull/9135)).
|
||||||
|
* Start DM on first message ([\#8612](https://github.com/matrix-org/matrix-react-sdk/pull/8612)). Fixes #14736.
|
||||||
|
* Remove "Add Space" button from RoomListHeader when user cannot create spaces ([\#9129](https://github.com/matrix-org/matrix-react-sdk/pull/9129)).
|
||||||
|
* The Welcome Home Screen: Dedicated Download Apps Dialog ([\#9120](https://github.com/matrix-org/matrix-react-sdk/pull/9120)). Fixes #22921. Contributed by @justjanne.
|
||||||
|
* The Welcome Home Screen: "Submit Feedback" pane ([\#9090](https://github.com/matrix-org/matrix-react-sdk/pull/9090)). Fixes #22918. Contributed by @justjanne.
|
||||||
|
* New User Onboarding Task List ([\#9083](https://github.com/matrix-org/matrix-react-sdk/pull/9083)). Fixes #22919. Contributed by @justjanne.
|
||||||
|
* Add support for disabling spell checking ([\#8604](https://github.com/matrix-org/matrix-react-sdk/pull/8604)). Fixes #21901.
|
||||||
|
* Live location share - leave maximised map open when beacons expire ([\#9098](https://github.com/matrix-org/matrix-react-sdk/pull/9098)). Contributed by @kerryarchibald.
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Some slash-commands (`/myroomnick`) have temporarily been disabled before the first message in a DM is sent. ([\#9193](https://github.com/matrix-org/matrix-react-sdk/pull/9193)).
|
||||||
|
* Use stable reference for active tab in tabbedView ([\#9145](https://github.com/matrix-org/matrix-react-sdk/pull/9145)). Contributed by @kerryarchibald.
|
||||||
|
* Fix pillification sometimes doubling up ([\#9152](https://github.com/matrix-org/matrix-react-sdk/pull/9152)). Fixes #23036.
|
||||||
|
* Fix highlights not being applied to plaintext messages ([\#9126](https://github.com/matrix-org/matrix-react-sdk/pull/9126)). Fixes #22787.
|
||||||
|
* Fix dismissing edit composer when change was undone ([\#9109](https://github.com/matrix-org/matrix-react-sdk/pull/9109)). Fixes #22932.
|
||||||
|
* 1-to-1 DM rooms with bots now act like DM rooms instead of multi-user-rooms before ([\#9124](https://github.com/matrix-org/matrix-react-sdk/pull/9124)). Fixes #22894.
|
||||||
|
* Apply inline start padding to selected lines on modern layout only ([\#9006](https://github.com/matrix-org/matrix-react-sdk/pull/9006)). Fixes #22768. Contributed by @luixxiul.
|
||||||
|
* Peek into world-readable rooms from spotlight ([\#9115](https://github.com/matrix-org/matrix-react-sdk/pull/9115)). Fixes #22862.
|
||||||
|
* Use default styling on nested numbered lists due to MD being sensitive ([\#9110](https://github.com/matrix-org/matrix-react-sdk/pull/9110)). Fixes #22935.
|
||||||
|
* Fix replying using chat effect commands ([\#9101](https://github.com/matrix-org/matrix-react-sdk/pull/9101)). Fixes #22824.
|
||||||
|
|
||||||
Changes in [1.11.2](https://github.com/vector-im/element-web/releases/tag/v1.11.2) (2022-08-03)
|
Changes in [1.11.2](https://github.com/vector-im/element-web/releases/tag/v1.11.2) (2022-08-03)
|
||||||
===============================================================================================
|
===============================================================================================
|
||||||
|
|
||||||
|
|
284
CONTRIBUTING.md
284
CONTRIBUTING.md
|
@ -1,4 +1,282 @@
|
||||||
Contributing code to Element
|
# Contributing code to Element Web
|
||||||
============================
|
|
||||||
|
|
||||||
Element follows the same pattern as the [matrix-js-sdk](https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md).
|
Everyone is welcome to contribute code to Element Web, provided that they are
|
||||||
|
willing to license their contributions under the same license as the project
|
||||||
|
itself. We follow a simple 'inbound=outbound' model for contributions: the act
|
||||||
|
of submitting an 'inbound' contribution means that the contributor agrees to
|
||||||
|
license the code under the same terms as the project's overall 'outbound'
|
||||||
|
license - in this case, Apache Software License v2 (see
|
||||||
|
[LICENSE](LICENSE)).
|
||||||
|
|
||||||
|
## How to contribute
|
||||||
|
|
||||||
|
The preferred and easiest way to contribute changes to the project is to fork
|
||||||
|
it on github, and then create a pull request to ask us to pull your changes
|
||||||
|
into our repo (https://help.github.com/articles/using-pull-requests/)
|
||||||
|
|
||||||
|
We use GitHub's pull request workflow to review the contribution, and either
|
||||||
|
ask you to make any refinements needed or merge it and make them ourselves.
|
||||||
|
|
||||||
|
Things that should go into your PR description:
|
||||||
|
|
||||||
|
- A changelog entry in the `Notes` section (see below)
|
||||||
|
- References to any bugs fixed by the change (in GitHub's `Fixes` notation)
|
||||||
|
- Describe the why and what is changing in the PR description so it's easy for
|
||||||
|
onlookers and reviewers to onboard and context switch. This information is
|
||||||
|
also helpful when we come back to look at this in 6 months and ask "why did
|
||||||
|
we do it like that?" we have a chance of finding out.
|
||||||
|
- Why didn't it work before? Why does it work now? What use cases does it
|
||||||
|
unlock?
|
||||||
|
- If you find yourself adding information on how the code works or why you
|
||||||
|
chose to do it the way you did, make sure this information is instead
|
||||||
|
written as comments in the code itself.
|
||||||
|
- Sometimes a PR can change considerably as it is developed. In this case,
|
||||||
|
the description should be updated to reflect the most recent state of
|
||||||
|
the PR. (It can be helpful to retain the old content under a suitable
|
||||||
|
heading, for additional context.)
|
||||||
|
- Include both **before** and **after** screenshots to easily compare and discuss
|
||||||
|
what's changing.
|
||||||
|
- Include a step-by-step testing strategy so that a reviewer can check out the
|
||||||
|
code locally and easily get to the point of testing your change.
|
||||||
|
- Add comments to the diff for the reviewer that might help them to understand
|
||||||
|
why the change is necessary or how they might better understand and review it.
|
||||||
|
|
||||||
|
We rely on information in pull request to populate the information that goes into
|
||||||
|
the changelogs our users see, both for Element Web itself and other projects on
|
||||||
|
which it is based. This is picked up from both labels on the pull request and
|
||||||
|
the `Notes:` annotation in the description. By default, the PR title will be
|
||||||
|
used for the changelog entry, but you can specify more options, as follows.
|
||||||
|
|
||||||
|
To add a longer, more detailed description of the change for the changelog:
|
||||||
|
|
||||||
|
_Fix llama herding bug_
|
||||||
|
|
||||||
|
```
|
||||||
|
Notes: Fix a bug (https://github.com/matrix-org/notaproject/issues/123) where the 'Herd' button would not herd more than 8 Llamas if the moon was in the waxing gibbous phase
|
||||||
|
```
|
||||||
|
|
||||||
|
For some PRs, it's not useful to have an entry in the user-facing changelog (this is
|
||||||
|
the default for PRs labelled with `T-Task`):
|
||||||
|
|
||||||
|
_Remove outdated comment from `Ungulates.ts`_
|
||||||
|
|
||||||
|
```
|
||||||
|
Notes: none
|
||||||
|
```
|
||||||
|
|
||||||
|
Sometimes, you're fixing a bug in a downstream project, in which case you want
|
||||||
|
an entry in that project's changelog. You can do that too:
|
||||||
|
|
||||||
|
_Fix another herding bug_
|
||||||
|
|
||||||
|
```
|
||||||
|
Notes: Fix a bug where the `herd()` function would only work on Tuesdays
|
||||||
|
element-web notes: Fix a bug where the 'Herd' button only worked on Tuesdays
|
||||||
|
```
|
||||||
|
|
||||||
|
This example is for Element Web. You can specify:
|
||||||
|
|
||||||
|
- matrix-react-sdk
|
||||||
|
- element-web
|
||||||
|
- element-desktop
|
||||||
|
|
||||||
|
If your PR introduces a breaking change, use the `Notes` section in the same
|
||||||
|
way, additionally adding the `X-Breaking-Change` label (see below). There's no need
|
||||||
|
to specify in the notes that it's a breaking change - this will be added
|
||||||
|
automatically based on the label - but remember to tell the developer how to
|
||||||
|
migrate:
|
||||||
|
|
||||||
|
_Remove legacy class_
|
||||||
|
|
||||||
|
```
|
||||||
|
Notes: Remove legacy `Camelopard` class. `Giraffe` should be used instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
Other metadata can be added using labels.
|
||||||
|
|
||||||
|
- `X-Breaking-Change`: A breaking change - adding this label will mean the change causes a _major_ version bump.
|
||||||
|
- `T-Enhancement`: A new feature - adding this label will mean the change causes a _minor_ version bump.
|
||||||
|
- `T-Defect`: A bug fix (in either code or docs).
|
||||||
|
- `T-Task`: No user-facing changes, eg. code comments, CI fixes, refactors or tests. Won't have a changelog entry unless you specify one.
|
||||||
|
|
||||||
|
If you don't have permission to add labels, your PR reviewer(s) can work with you
|
||||||
|
to add them: ask in the PR description or comments.
|
||||||
|
|
||||||
|
We use continuous integration, and all pull requests get automatically tested:
|
||||||
|
if your change breaks the build, then the PR will show that there are failed
|
||||||
|
checks, so please check back after a few minutes.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
Your PR should include tests.
|
||||||
|
|
||||||
|
For new user facing features in `matrix-js-sdk`, `matrix-react-sdk` or `element-web`, you
|
||||||
|
must include:
|
||||||
|
|
||||||
|
1. Comprehensive unit tests written in Jest. These are located in `/test`.
|
||||||
|
2. "happy path" end-to-end tests.
|
||||||
|
These are located in `/cypress/e2e` in `matrix-react-sdk`, and
|
||||||
|
are run using `element-web`. Ideally, you would also include tests for edge
|
||||||
|
and error cases.
|
||||||
|
|
||||||
|
Unit tests are expected even when the feature is in labs. It's good practice
|
||||||
|
to write tests alongside the code as it ensures the code is testable from
|
||||||
|
the start, and gives you a fast feedback loop while you're developing the
|
||||||
|
functionality. End-to-end tests should be added prior to the feature
|
||||||
|
leaving labs, but don't have to be present from the start (although it might
|
||||||
|
be beneficial to have some running early, so you can test things faster).
|
||||||
|
|
||||||
|
For bugs in those repos, your change must include at least one unit test or
|
||||||
|
end-to-end test; which is best depends on what sort of test most concisely
|
||||||
|
exercises the area.
|
||||||
|
|
||||||
|
Changes to must be accompanied by unit tests written in Jest.
|
||||||
|
These are located in `/spec/` in `matrix-js-sdk` or `/test/` in `element-web`
|
||||||
|
and `matrix-react-sdk`.
|
||||||
|
|
||||||
|
When writing unit tests, please aim for a high level of test coverage
|
||||||
|
for new code - 80% or greater. If you cannot achieve that, please document
|
||||||
|
why it's not possible in your PR.
|
||||||
|
|
||||||
|
Some sections of code are not sensible to add coverage for, such as those
|
||||||
|
which explicitly inhibit noisy logging for tests. Which can be hidden using
|
||||||
|
an istanbul magic comment as [documented here][1]. See example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (process.env.NODE_ENV !== "test") {
|
||||||
|
logger.error("Log line that is noisy enough in tests to want to skip");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Tests validate that your change works as intended and also document
|
||||||
|
concisely what is being changed. Ideally, your new tests fail
|
||||||
|
prior to your change, and succeed once it has been applied. You may
|
||||||
|
find this simpler to achieve if you write the tests first.
|
||||||
|
|
||||||
|
If you're spiking some code that's experimental and not being used to support
|
||||||
|
production features, exceptions can be made to requirements for tests.
|
||||||
|
Note that tests will still be required in order to ship the feature, and it's
|
||||||
|
strongly encouraged to think about tests early in the process, as adding
|
||||||
|
tests later will become progressively more difficult.
|
||||||
|
|
||||||
|
If you're not sure how to approach writing tests for your change, ask for help
|
||||||
|
in [#element-dev](https://matrix.to/#/#element-dev:matrix.org).
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
Element Web aims to target TypeScript/ES6. All new files should be written in
|
||||||
|
TypeScript and existing files should use ES6 principles where possible.
|
||||||
|
|
||||||
|
Members should not be exported as a default export in general - it causes problems
|
||||||
|
with the architecture of the SDK (index file becomes less clear) and could
|
||||||
|
introduce naming problems (as default exports get aliased upon import). In
|
||||||
|
general, avoid using `export default`.
|
||||||
|
|
||||||
|
The remaining code style is documented in [code_style.md](./code_style.md).
|
||||||
|
Contributors are encouraged to it and follow the principles set out there.
|
||||||
|
|
||||||
|
Please ensure your changes match the cosmetic style of the existing project,
|
||||||
|
and **_never_** mix cosmetic and functional changes in the same commit, as it
|
||||||
|
makes it horribly hard to review otherwise.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
Everyone who contributes anything to Matrix is welcome to be listed in the
|
||||||
|
AUTHORS.rst file for the project in question. Please feel free to include a
|
||||||
|
change to AUTHORS.rst in your pull request to list yourself and a short
|
||||||
|
description of the area(s) you've worked on. Also, we sometimes have swag to
|
||||||
|
give away to contributors - if you feel that Matrix-branded apparel is missing
|
||||||
|
from your life, please mail us your shipping address to matrix at matrix.org
|
||||||
|
and we'll try to fix it :)
|
||||||
|
|
||||||
|
## Sign off
|
||||||
|
|
||||||
|
In order to have a concrete record that your contribution is intentional
|
||||||
|
and you agree to license it under the same terms as the project's license, we've
|
||||||
|
adopted the same lightweight approach that the Linux Kernel
|
||||||
|
(https://www.kernel.org/doc/Documentation/SubmittingPatches), Docker
|
||||||
|
(https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other
|
||||||
|
projects use: the DCO (Developer Certificate of Origin:
|
||||||
|
http://developercertificate.org/). This is a simple declaration that you wrote
|
||||||
|
the contribution or otherwise have the right to contribute it to Matrix:
|
||||||
|
|
||||||
|
```
|
||||||
|
Developer Certificate of Origin
|
||||||
|
Version 1.1
|
||||||
|
|
||||||
|
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||||
|
660 York Street, Suite 102,
|
||||||
|
San Francisco, CA 94110 USA
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Developer's Certificate of Origin 1.1
|
||||||
|
|
||||||
|
By making a contribution to this project, I certify that:
|
||||||
|
|
||||||
|
(a) The contribution was created in whole or in part by me and I
|
||||||
|
have the right to submit it under the open source license
|
||||||
|
indicated in the file; or
|
||||||
|
|
||||||
|
(b) The contribution is based upon previous work that, to the best
|
||||||
|
of my knowledge, is covered under an appropriate open source
|
||||||
|
license and I have the right under that license to submit that
|
||||||
|
work with modifications, whether created in whole or in part
|
||||||
|
by me, under the same open source license (unless I am
|
||||||
|
permitted to submit under a different license), as indicated
|
||||||
|
in the file; or
|
||||||
|
|
||||||
|
(c) The contribution was provided directly to me by some other
|
||||||
|
person who certified (a), (b) or (c) and I have not modified
|
||||||
|
it.
|
||||||
|
|
||||||
|
(d) I understand and agree that this project and the contribution
|
||||||
|
are public and that a record of the contribution (including all
|
||||||
|
personal information I submit with it, including my sign-off) is
|
||||||
|
maintained indefinitely and may be redistributed consistent with
|
||||||
|
this project or the open source license(s) involved.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you agree to this for your contribution, then all that's needed is to
|
||||||
|
include the line in your commit or pull request comment:
|
||||||
|
|
||||||
|
```
|
||||||
|
Signed-off-by: Your Name <your@email.example.org>
|
||||||
|
```
|
||||||
|
|
||||||
|
We accept contributions under a legally identifiable name, such as your name on
|
||||||
|
government documentation or common-law names (names claimed by legitimate usage
|
||||||
|
or repute). Unfortunately, we cannot accept anonymous contributions at this
|
||||||
|
time.
|
||||||
|
|
||||||
|
Git allows you to add this signoff automatically when using the `-s` flag to
|
||||||
|
`git commit`, which uses the name and email set in your `user.name` and
|
||||||
|
`user.email` git configs.
|
||||||
|
|
||||||
|
If you forgot to sign off your commits before making your pull request and are
|
||||||
|
on Git 2.17+ you can mass signoff using rebase:
|
||||||
|
|
||||||
|
```
|
||||||
|
git rebase --signoff origin/develop
|
||||||
|
```
|
||||||
|
|
||||||
|
# Review expectations
|
||||||
|
|
||||||
|
See https://github.com/vector-im/element-meta/wiki/Review-process
|
||||||
|
|
||||||
|
# Merge Strategy
|
||||||
|
|
||||||
|
The preferred method for merging pull requests is squash merging to keep the
|
||||||
|
commit history trim, but it is up to the discretion of the team member merging
|
||||||
|
the change. We do not support rebase merges due to `allchange` being unable to
|
||||||
|
handle them. When merging make sure to leave the default commit title, or
|
||||||
|
at least leave the PR number at the end in brackets like by default.
|
||||||
|
When stacking pull requests, you may wish to do the following:
|
||||||
|
|
||||||
|
1. Branch from develop to your branch (branch1), push commits onto it and open a pull request
|
||||||
|
2. Branch from your base branch (branch1) to your work branch (branch2), push commits and open a pull request configuring the base to be branch1, saying in the description that it is based on your other PR.
|
||||||
|
3. Merge the first PR using a merge commit otherwise your stacked PR will need a rebase. Github will automatically adjust the base branch of your other PR to be develop.
|
||||||
|
|
||||||
|
[1]: https://github.com/gotwarlost/istanbul/blob/master/ignoring-code-for-coverage.md
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Builder
|
# Builder
|
||||||
FROM node:14-buster as builder
|
FROM --platform=$BUILDPLATFORM node:16-buster as builder
|
||||||
|
|
||||||
# Support custom branches of the react-sdk and js-sdk. This also helps us build
|
# Support custom branches of the react-sdk and js-sdk. This also helps us build
|
||||||
# images of element-web develop.
|
# images of element-web develop.
|
||||||
|
|
140
README.md
140
README.md
|
@ -7,37 +7,34 @@
|
||||||
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-web)
|
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-web)
|
||||||
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-web)
|
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-web)
|
||||||
|
|
||||||
Element
|
# Element
|
||||||
=======
|
|
||||||
|
|
||||||
Element (formerly known as Vector and Riot) is a Matrix web client built using the [Matrix
|
Element (formerly known as Vector and Riot) is a Matrix web client built using the [Matrix
|
||||||
React SDK](https://github.com/matrix-org/matrix-react-sdk).
|
React SDK](https://github.com/matrix-org/matrix-react-sdk).
|
||||||
|
|
||||||
Supported Environments
|
# Supported Environments
|
||||||
======================
|
|
||||||
|
|
||||||
Element has several tiers of support for different environments:
|
Element has several tiers of support for different environments:
|
||||||
|
|
||||||
* Supported
|
- Supported
|
||||||
* Definition: Issues **actively triaged**, regressions **block** the release
|
- Definition: Issues **actively triaged**, regressions **block** the release
|
||||||
* Last 2 major versions of Chrome, Firefox, Safari, and Edge on desktop OSes
|
- Last 2 major versions of Chrome, Firefox, Safari, and Edge on desktop OSes
|
||||||
* Latest release of official Element Desktop app on desktop OSes
|
- Latest release of official Element Desktop app on desktop OSes
|
||||||
* Desktop OSes means macOS, Windows, and Linux versions for desktop devices
|
- Desktop OSes means macOS, Windows, and Linux versions for desktop devices
|
||||||
that are actively supported by the OS vendor and receive security updates
|
that are actively supported by the OS vendor and receive security updates
|
||||||
* Experimental
|
- Experimental
|
||||||
* Definition: Issues **accepted**, regressions **do not block** the release
|
- Definition: Issues **accepted**, regressions **do not block** the release
|
||||||
* Element as an installed PWA via current stable version of Chrome, Firefox, and Safari
|
- Element as an installed PWA via current stable version of Chrome, Firefox, and Safari
|
||||||
* Mobile web for current stable version of Chrome, Firefox, and Safari on Android, iOS, and iPadOS
|
- Mobile web for current stable version of Chrome, Firefox, and Safari on Android, iOS, and iPadOS
|
||||||
* Not supported
|
- Not supported
|
||||||
* Definition: Issues only affecting unsupported environments are **closed**
|
- Definition: Issues only affecting unsupported environments are **closed**
|
||||||
* Everything else
|
- Everything else
|
||||||
|
|
||||||
For accessing Element on an Android or iOS device, we currently recommend the
|
For accessing Element on an Android or iOS device, we currently recommend the
|
||||||
native apps [element-android](https://github.com/vector-im/element-android)
|
native apps [element-android](https://github.com/vector-im/element-android)
|
||||||
and [element-ios](https://github.com/vector-im/element-ios).
|
and [element-ios](https://github.com/vector-im/element-ios).
|
||||||
|
|
||||||
Getting Started
|
# Getting Started
|
||||||
===============
|
|
||||||
|
|
||||||
The easiest way to test Element is to just use the hosted copy at <https://app.element.io>.
|
The easiest way to test Element is to just use the hosted copy at <https://app.element.io>.
|
||||||
The `develop` branch is continuously deployed to <https://develop.element.io>
|
The `develop` branch is continuously deployed to <https://develop.element.io>
|
||||||
|
@ -67,47 +64,39 @@ and thus allowed.
|
||||||
To install Element as a desktop application, see [Running as a desktop
|
To install Element as a desktop application, see [Running as a desktop
|
||||||
app](#running-as-a-desktop-app) below.
|
app](#running-as-a-desktop-app) below.
|
||||||
|
|
||||||
Important Security Notes
|
# Important Security Notes
|
||||||
========================
|
|
||||||
|
|
||||||
Separate domains
|
## Separate domains
|
||||||
----------------
|
|
||||||
|
|
||||||
We do not recommend running Element from the same domain name as your Matrix
|
We do not recommend running Element from the same domain name as your Matrix
|
||||||
homeserver. The reason is the risk of XSS (cross-site-scripting)
|
homeserver. The reason is the risk of XSS (cross-site-scripting)
|
||||||
vulnerabilities that could occur if someone caused Element to load and render
|
vulnerabilities that could occur if someone caused Element to load and render
|
||||||
malicious user generated content from a Matrix API which then had trusted
|
malicious user generated content from a Matrix API which then had trusted
|
||||||
access to Element (or other apps) due to sharing the same domain.
|
access to Element (or other apps) due to sharing the same domain.
|
||||||
|
|
||||||
We have put some coarse mitigations into place to try to protect against this
|
We have put some coarse mitigations into place to try to protect against this
|
||||||
situation, but it's still not good practice to do it in the first place. See
|
situation, but it's still not good practice to do it in the first place. See
|
||||||
<https://github.com/vector-im/element-web/issues/1977> for more details.
|
<https://github.com/vector-im/element-web/issues/1977> for more details.
|
||||||
|
|
||||||
Configuration best practices
|
## Configuration best practices
|
||||||
----------------------------
|
|
||||||
|
|
||||||
Unless you have special requirements, you will want to add the following to
|
Unless you have special requirements, you will want to add the following to
|
||||||
your web server configuration when hosting Element Web:
|
your web server configuration when hosting Element Web:
|
||||||
|
|
||||||
* The `X-Frame-Options: SAMEORIGIN` header, to prevent Element Web from being
|
- The `X-Frame-Options: SAMEORIGIN` header, to prevent Element Web from being
|
||||||
framed and protect from [clickjacking][owasp-clickjacking].
|
framed and protect from [clickjacking][owasp-clickjacking].
|
||||||
* The `frame-ancestors 'none'` directive to your `Content-Security-Policy`
|
- The `frame-ancestors 'none'` directive to your `Content-Security-Policy`
|
||||||
header, as the modern replacement for `X-Frame-Options` (though both should be
|
header, as the modern replacement for `X-Frame-Options` (though both should be
|
||||||
included since not all browsers support it yet, see
|
included since not all browsers support it yet, see
|
||||||
[this][owasp-clickjacking-csp]).
|
[this][owasp-clickjacking-csp]).
|
||||||
* The `X-Content-Type-Options: nosniff` header, to [disable MIME
|
- The `X-Content-Type-Options: nosniff` header, to [disable MIME
|
||||||
sniffing][mime-sniffing].
|
sniffing][mime-sniffing].
|
||||||
* The `X-XSS-Protection: 1; mode=block;` header, for basic XSS protection in
|
- The `X-XSS-Protection: 1; mode=block;` header, for basic XSS protection in
|
||||||
legacy browsers.
|
legacy browsers.
|
||||||
|
|
||||||
[mime-sniffing]:
|
[mime-sniffing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing
|
||||||
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing>
|
[owasp-clickjacking-csp]: https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html#content-security-policy-frame-ancestors-examples
|
||||||
|
[owasp-clickjacking]: https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html
|
||||||
[owasp-clickjacking-csp]:
|
|
||||||
<https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html#content-security-policy-frame-ancestors-examples>
|
|
||||||
|
|
||||||
[owasp-clickjacking]:
|
|
||||||
<https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html>
|
|
||||||
|
|
||||||
If you are using nginx, this would look something like the following:
|
If you are using nginx, this would look something like the following:
|
||||||
|
|
||||||
|
@ -118,12 +107,20 @@ add_header X-XSS-Protection "1; mode=block";
|
||||||
add_header Content-Security-Policy "frame-ancestors 'none'";
|
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
|
Note: In case you are already setting a `Content-Security-Policy` header
|
||||||
elsewhere, you should modify it to include the `frame-ancestors` directive
|
elsewhere, you should modify it to include the `frame-ancestors` directive
|
||||||
instead of adding that last line.
|
instead of adding that last line.
|
||||||
|
|
||||||
Building From Source
|
# Building From Source
|
||||||
====================
|
|
||||||
|
|
||||||
Element is a modular webapp built with modern ES6 and uses a Node.js build system.
|
Element is a modular webapp built with modern ES6 and uses a Node.js build system.
|
||||||
Ensure you have the latest LTS version of Node.js installed.
|
Ensure you have the latest LTS version of Node.js installed.
|
||||||
|
@ -136,7 +133,7 @@ guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it alread
|
||||||
1. Clone the repo: `git clone https://github.com/vector-im/element-web.git`.
|
1. Clone the repo: `git clone https://github.com/vector-im/element-web.git`.
|
||||||
1. Switch to the element-web directory: `cd element-web`.
|
1. Switch to the element-web directory: `cd element-web`.
|
||||||
1. Install the prerequisites: `yarn install`.
|
1. Install the prerequisites: `yarn install`.
|
||||||
* If you're using the `develop` branch, then it is recommended to set up a
|
- If you're using the `develop` branch, then it is recommended to set up a
|
||||||
proper development environment (see [Setting up a dev
|
proper development environment (see [Setting up a dev
|
||||||
environment](#setting-up-a-dev-environment) below). Alternatively, you
|
environment](#setting-up-a-dev-environment) below). Alternatively, you
|
||||||
can use <https://develop.element.io> - the continuous integration release of
|
can use <https://develop.element.io> - the continuous integration release of
|
||||||
|
@ -153,8 +150,7 @@ will not appear in Settings without using the dist script. You can then mount th
|
||||||
`webapp` directory on your web server to actually serve up the app, which is
|
`webapp` directory on your web server to actually serve up the app, which is
|
||||||
entirely static content.
|
entirely static content.
|
||||||
|
|
||||||
Running as a Desktop app
|
# Running as a Desktop app
|
||||||
========================
|
|
||||||
|
|
||||||
Element can also be run as a desktop app, wrapped in Electron. You can download a
|
Element can also be run as a desktop app, wrapped in Electron. You can download a
|
||||||
pre-built version from <https://element.io/get-started> or, if you prefer,
|
pre-built version from <https://element.io/get-started> or, if you prefer,
|
||||||
|
@ -166,7 +162,7 @@ Many thanks to @aviraldg for the initial work on the Electron integration.
|
||||||
|
|
||||||
Other options for running as a desktop app:
|
Other options for running as a desktop app:
|
||||||
|
|
||||||
* @asdf:matrix.org points out that you can use nativefier and it just works(tm)
|
- @asdf:matrix.org points out that you can use nativefier and it just works(tm)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yarn global add nativefier
|
yarn global add nativefier
|
||||||
|
@ -176,8 +172,7 @@ nativefier https://app.element.io/
|
||||||
The [configuration docs](docs/config.md#desktop-app-configuration) show how to
|
The [configuration docs](docs/config.md#desktop-app-configuration) show how to
|
||||||
override the desktop app's default settings if desired.
|
override the desktop app's default settings if desired.
|
||||||
|
|
||||||
Running from Docker
|
# Running from Docker
|
||||||
===================
|
|
||||||
|
|
||||||
The Docker image can be used to serve element-web as a web server. The easiest way to use
|
The Docker image can be used to serve element-web as a web server. The easiest way to use
|
||||||
it is to use the prebuilt image:
|
it is to use the prebuilt image:
|
||||||
|
@ -216,26 +211,22 @@ docker build -t \
|
||||||
.
|
.
|
||||||
```
|
```
|
||||||
|
|
||||||
Running in Kubernetes
|
# Running in Kubernetes
|
||||||
=====================
|
|
||||||
|
|
||||||
The provided element-web docker image can also be run from within a Kubernetes cluster.
|
The provided element-web docker image can also be run from within a Kubernetes cluster.
|
||||||
See the [Kubernetes example](docs/kubernetes.md) for more details.
|
See the [Kubernetes example](docs/kubernetes.md) for more details.
|
||||||
|
|
||||||
config.json
|
# config.json
|
||||||
===========
|
|
||||||
|
|
||||||
Element supports a variety of settings to configure default servers, behaviour, themes, etc.
|
Element supports a variety of settings to configure default servers, behaviour, themes, etc.
|
||||||
See the [configuration docs](docs/config.md) for more details.
|
See the [configuration docs](docs/config.md) for more details.
|
||||||
|
|
||||||
Labs Features
|
# Labs Features
|
||||||
=============
|
|
||||||
|
|
||||||
Some features of Element may be enabled by flags in the `Labs` section of the settings.
|
Some features of Element may be enabled by flags in the `Labs` section of the settings.
|
||||||
Some of these features are described in [labs.md](https://github.com/vector-im/element-web/blob/develop/docs/labs.md).
|
Some of these features are described in [labs.md](https://github.com/vector-im/element-web/blob/develop/docs/labs.md).
|
||||||
|
|
||||||
Caching requirements
|
# Caching requirements
|
||||||
====================
|
|
||||||
|
|
||||||
Element requires the following URLs not to be cached, when/if you are serving Element from your own webserver:
|
Element requires the following URLs not to be cached, when/if you are serving Element from your own webserver:
|
||||||
|
|
||||||
|
@ -252,8 +243,7 @@ webserver to return `Cache-Control: no-cache` for `/`. This ensures the browser
|
||||||
the next page load after it's been deployed. Note that this is already configured for you in the nginx config of our
|
the next page load after it's been deployed. Note that this is already configured for you in the nginx config of our
|
||||||
Dockerfile.
|
Dockerfile.
|
||||||
|
|
||||||
Development
|
# Development
|
||||||
===========
|
|
||||||
|
|
||||||
Before attempting to develop on Element you **must** read the [developer guide
|
Before attempting to develop on Element you **must** read the [developer guide
|
||||||
for `matrix-react-sdk`](https://github.com/matrix-org/matrix-react-sdk#developer-guide), which
|
for `matrix-react-sdk`](https://github.com/matrix-org/matrix-react-sdk#developer-guide), which
|
||||||
|
@ -275,7 +265,7 @@ higher and lower level React components useful for building Matrix communication
|
||||||
apps using React.
|
apps using React.
|
||||||
|
|
||||||
Please note that Element is intended to run correctly without access to the public
|
Please note that Element is intended to run correctly without access to the public
|
||||||
internet. So please don't depend on resources (JS libs, CSS, images, fonts)
|
internet. So please don't depend on resources (JS libs, CSS, images, fonts)
|
||||||
hosted by external CDNs or servers but instead please package all dependencies
|
hosted by external CDNs or servers but instead please package all dependencies
|
||||||
into Element itself.
|
into Element itself.
|
||||||
|
|
||||||
|
@ -283,8 +273,7 @@ CSS hot-reload is available as an opt-in development feature. You can enable it
|
||||||
by defining a `CSS_HOT_RELOAD` environment variable, in a `.env` file in the root
|
by defining a `CSS_HOT_RELOAD` environment variable, in a `.env` file in the root
|
||||||
of the repository. See `.env.example` for documentation and an example.
|
of the repository. See `.env.example` for documentation and an example.
|
||||||
|
|
||||||
Setting up a dev environment
|
# Setting up a dev environment
|
||||||
============================
|
|
||||||
|
|
||||||
Much of the functionality in Element is actually in the `matrix-react-sdk` and
|
Much of the functionality in Element is actually in the `matrix-react-sdk` and
|
||||||
`matrix-js-sdk` modules. It is possible to set these up in a way that makes it
|
`matrix-js-sdk` modules. It is possible to set these up in a way that makes it
|
||||||
|
@ -293,7 +282,7 @@ having to manually rebuild each time.
|
||||||
|
|
||||||
First clone and build `matrix-js-sdk`:
|
First clone and build `matrix-js-sdk`:
|
||||||
|
|
||||||
``` bash
|
```bash
|
||||||
git clone https://github.com/matrix-org/matrix-js-sdk.git
|
git clone https://github.com/matrix-org/matrix-js-sdk.git
|
||||||
pushd matrix-js-sdk
|
pushd matrix-js-sdk
|
||||||
yarn link
|
yarn link
|
||||||
|
@ -340,9 +329,9 @@ Wait a few seconds for the initial build to finish; you should see something lik
|
||||||
[element-js] ℹ 「wdm」: Compiled successfully.
|
[element-js] ℹ 「wdm」: Compiled successfully.
|
||||||
```
|
```
|
||||||
|
|
||||||
Remember, the command will not terminate since it runs the web server
|
Remember, the command will not terminate since it runs the web server
|
||||||
and rebuilds source files when they change. This development server also
|
and rebuilds source files when they change. This development server also
|
||||||
disables caching, so do NOT use it in production.
|
disables caching, so do NOT use it in production.
|
||||||
|
|
||||||
Open <http://127.0.0.1:8080/> in your browser to see your newly built Element.
|
Open <http://127.0.0.1:8080/> in your browser to see your newly built Element.
|
||||||
|
|
||||||
|
@ -370,7 +359,7 @@ echo fs.inotify.max_user_instances=512 | sudo tee -a /etc/sysctl.conf
|
||||||
sudo sysctl -p
|
sudo sysctl -p
|
||||||
```
|
```
|
||||||
|
|
||||||
___
|
---
|
||||||
|
|
||||||
When you make changes to `matrix-react-sdk` or `matrix-js-sdk` they should be
|
When you make changes to `matrix-react-sdk` or `matrix-js-sdk` they should be
|
||||||
automatically picked up by webpack and built.
|
automatically picked up by webpack and built.
|
||||||
|
@ -379,8 +368,7 @@ If any of these steps error with, `file table overflow`, you are probably on a m
|
||||||
which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again.
|
which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again.
|
||||||
You'll need to do this in each new terminal you open before building Element.
|
You'll need to do this in each new terminal you open before building Element.
|
||||||
|
|
||||||
Running the tests
|
## Running the tests
|
||||||
-----------------
|
|
||||||
|
|
||||||
There are a number of application-level tests in the `tests` directory; these
|
There are a number of application-level tests in the `tests` directory; these
|
||||||
are designed to run with Jest and JSDOM. To run them
|
are designed to run with Jest and JSDOM. To run them
|
||||||
|
@ -393,8 +381,7 @@ yarn test
|
||||||
|
|
||||||
See [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk/#end-to-end-tests) for how to run the end-to-end tests.
|
See [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk/#end-to-end-tests) for how to run the end-to-end tests.
|
||||||
|
|
||||||
Translations
|
# Translations
|
||||||
============
|
|
||||||
|
|
||||||
To add a new translation, head to the [translating doc](docs/translating.md).
|
To add a new translation, head to the [translating doc](docs/translating.md).
|
||||||
|
|
||||||
|
@ -402,8 +389,7 @@ For a developer guide, see the [translating dev doc](docs/translating-dev.md).
|
||||||
|
|
||||||
[<img src="https://translate.element.io/widgets/element-web/-/multi-auto.svg" alt="translationsstatus" width="340">](https://translate.element.io/engage/element-web/?utm_source=widget)
|
[<img src="https://translate.element.io/widgets/element-web/-/multi-auto.svg" alt="translationsstatus" width="340">](https://translate.element.io/engage/element-web/?utm_source=widget)
|
||||||
|
|
||||||
Triaging issues
|
# Triaging issues
|
||||||
===============
|
|
||||||
|
|
||||||
Issues are triaged by community members and the Web App Team, following the [triage process](https://github.com/vector-im/element-meta/wiki/Triage-process).
|
Issues are triaged by community members and the Web App Team, following the [triage process](https://github.com/vector-im/element-meta/wiki/Triage-process).
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,34 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"sourceMaps": true,
|
sourceMaps: true,
|
||||||
"presets": [
|
presets: [
|
||||||
["@babel/preset-env", {
|
[
|
||||||
"targets": [
|
"@babel/preset-env",
|
||||||
"last 2 Chrome versions",
|
{
|
||||||
"last 2 Firefox versions",
|
targets: [
|
||||||
"last 2 Safari versions",
|
"last 2 Chrome versions",
|
||||||
"last 2 Edge versions",
|
"last 2 Firefox versions",
|
||||||
],
|
"last 2 Safari versions",
|
||||||
}],
|
"last 2 Edge versions",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
"@babel/preset-typescript",
|
"@babel/preset-typescript",
|
||||||
"@babel/preset-react",
|
"@babel/preset-react",
|
||||||
],
|
],
|
||||||
"plugins": [
|
plugins: [
|
||||||
"@babel/plugin-proposal-export-default-from",
|
"@babel/plugin-proposal-export-default-from",
|
||||||
"@babel/plugin-proposal-numeric-separator",
|
"@babel/plugin-proposal-numeric-separator",
|
||||||
"@babel/plugin-proposal-class-properties",
|
"@babel/plugin-proposal-class-properties",
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
|
|
||||||
|
// transform logical assignment (??=, ||=, &&=). preset-env doesn't
|
||||||
|
// normally bother with these (presumably because all the target
|
||||||
|
// browsers support it natively), but they make our webpack version (or
|
||||||
|
// something downstream of babel, at least) fall over.
|
||||||
|
"@babel/plugin-proposal-logical-assignment-operators",
|
||||||
|
|
||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-transform-runtime",
|
"@babel/plugin-transform-runtime",
|
||||||
],
|
],
|
||||||
|
|
360
code_style.md
Normal file
360
code_style.md
Normal file
|
@ -0,0 +1,360 @@
|
||||||
|
# Element Web/Desktop code style guide
|
||||||
|
|
||||||
|
This code style applies to projects which the element-web team directly maintains or is reasonably
|
||||||
|
adjacent to. As of writing, these are:
|
||||||
|
|
||||||
|
- element-desktop
|
||||||
|
- element-web
|
||||||
|
- matrix-react-sdk
|
||||||
|
- matrix-js-sdk
|
||||||
|
|
||||||
|
Other projects might extend this code style for increased strictness. For example, matrix-events-sdk
|
||||||
|
has stricter code organization to reduce the maintenance burden. These projects will declare their code
|
||||||
|
style within their own repos.
|
||||||
|
|
||||||
|
Note that some requirements will be layer-specific. Where the requirements don't make sense for the
|
||||||
|
project, they are used to the best of their ability, used in spirit, or ignored if not applicable,
|
||||||
|
in that order.
|
||||||
|
|
||||||
|
## Guiding principles
|
||||||
|
|
||||||
|
1. We want the lint rules to feel natural for most team members. No one should have to think too much
|
||||||
|
about the linter.
|
||||||
|
2. We want to stay relatively close to [industry standards](https://google.github.io/styleguide/tsguide.html)
|
||||||
|
to make onboarding easier.
|
||||||
|
3. We describe what good code looks like rather than point out bad examples. We do this to avoid
|
||||||
|
excessively punishing people for writing code which fails the linter.
|
||||||
|
4. When something isn't covered by the style guide, we come up with a reasonable rule rather than
|
||||||
|
claim that it "passes the linter". We update the style guide and linter accordingly.
|
||||||
|
5. While we aim to improve readability, understanding, and other aspects of the code, we deliberately
|
||||||
|
do not let solely our personal preferences drive decisions.
|
||||||
|
6. We aim to have an understandable guide.
|
||||||
|
|
||||||
|
## Coding practices
|
||||||
|
|
||||||
|
1. Lint rules enforce decisions made by this guide. The lint rules and this guide are kept in
|
||||||
|
perfect sync.
|
||||||
|
2. Commit messages are descriptive for the changes. When the project supports squash merging,
|
||||||
|
only the squashed commit needs to have a descriptive message.
|
||||||
|
3. When there is disagreement with a code style approved by the linter, a PR is opened against
|
||||||
|
the lint rules rather than making exceptions on the responsible code PR.
|
||||||
|
4. Rules which are intentionally broken (via eslint-ignore, @ts-ignore, etc) have a comment
|
||||||
|
included in the immediate vicinity for why. Determination of whether this is valid applies at
|
||||||
|
code review time.
|
||||||
|
5. When editing a file, nearby code is updated to meet the modern standards. "Nearby" is subjective,
|
||||||
|
but should be whatever is reasonable at review time. Such an example might be to update the
|
||||||
|
class's code style, but not the file's.
|
||||||
|
1. These changes should be minor enough to include in the same commit without affecting a code
|
||||||
|
reviewer's job.
|
||||||
|
|
||||||
|
## All code
|
||||||
|
|
||||||
|
Unless otherwise specified, the following applies to all code:
|
||||||
|
|
||||||
|
1. Files must be formatted with Prettier.
|
||||||
|
2. 120 character limit per line. Match existing code in the file if it is using a lower guide.
|
||||||
|
3. A tab/indentation is 4 spaces.
|
||||||
|
4. Newlines are Unix.
|
||||||
|
5. A file has a single empty line at the end.
|
||||||
|
6. Lines are trimmed of all excess whitespace, including blank lines.
|
||||||
|
7. Long lines are broken up for readability.
|
||||||
|
|
||||||
|
## TypeScript / JavaScript {#typescript-javascript}
|
||||||
|
|
||||||
|
1. Write TypeScript. Turn JavaScript into TypeScript when working in the area.
|
||||||
|
2. Use named exports.
|
||||||
|
3. Use semicolons for block/line termination.
|
||||||
|
1. Except when defining interfaces, classes, and non-arrow functions specifically.
|
||||||
|
4. When a statement's body is a single line, it must be written without curly braces, so long as the body is placed on
|
||||||
|
the same line as the statement.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
if (x) doThing();
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Blocks for `if`, `for`, `switch` and so on must have a space surrounding the condition, but not
|
||||||
|
within the condition.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
if (x) {
|
||||||
|
doThing();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
6. lowerCamelCase is used for function and variable naming.
|
||||||
|
7. UpperCamelCase is used for general naming.
|
||||||
|
8. Interface names should not be marked with an uppercase `I`.
|
||||||
|
9. One variable declaration per line.
|
||||||
|
10. If a variable is not receiving a value on declaration, its type must be defined.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let errorMessage: Optional<string>;
|
||||||
|
```
|
||||||
|
|
||||||
|
11. Objects can use shorthand declarations, including mixing of types.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
room,
|
||||||
|
prop: this.prop,
|
||||||
|
}
|
||||||
|
// ... or ...
|
||||||
|
{ room, prop: this.prop }
|
||||||
|
```
|
||||||
|
|
||||||
|
12. Object keys should always be non-strings when possible.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
property: "value",
|
||||||
|
"m.unavoidable": true,
|
||||||
|
[EventType.RoomMessage]: true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
13. Explicitly cast to a boolean.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
!!stringVar || Boolean(stringVar);
|
||||||
|
```
|
||||||
|
|
||||||
|
14. Use `switch` statements when checking against more than a few enum-like values.
|
||||||
|
15. Use `const` for constants, `let` for mutability.
|
||||||
|
16. Describe types exhaustively (ensure noImplictAny would pass).
|
||||||
|
1. Notable exceptions are arrow functions used as parameters, when a void return type is
|
||||||
|
obvious, and when declaring and assigning a variable in the same line.
|
||||||
|
17. Declare member visibility (public/private/protected).
|
||||||
|
18. Private members are private and not prefixed unless required for naming conflicts.
|
||||||
|
1. Convention is to use an underscore or the word "internal" to denote conflicted member names.
|
||||||
|
2. "Conflicted" typically refers to a getter which wants the same name as the underlying variable.
|
||||||
|
19. Prefer readonly members over getters backed by a variable, unless an internal setter is required.
|
||||||
|
20. Prefer Interfaces for object definitions, and types for parameter-value-only declarations.
|
||||||
|
|
||||||
|
1. Note that an explicit type is optional if not expected to be used outside of the function call,
|
||||||
|
unlike in this example:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface MyObject {
|
||||||
|
hasString: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options = MyObject | string;
|
||||||
|
|
||||||
|
function doThing(arg: Options) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
21. Variables/properties which are `public static` should also be `readonly` when possible.
|
||||||
|
22. Interface and type properties are terminated with semicolons, not commas.
|
||||||
|
23. Prefer arrow formatting when declaring functions for interfaces/types:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Test {
|
||||||
|
myCallback: (arg: string) => Promise<void>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
24. Prefer a type definition over an inline type. For example, define an interface.
|
||||||
|
25. Always prefer to add types or declare a type over the use of `any`. Prefer inferred types
|
||||||
|
when they are not `any`.
|
||||||
|
1. When using `any`, a comment explaining why must be present.
|
||||||
|
26. `import` should be used instead of `require`, as `require` does not have types.
|
||||||
|
27. Export only what can be reused.
|
||||||
|
28. Prefer a type like `Optional<X>` (`type Optional<T> = T | null | undefined`) instead
|
||||||
|
of truly optional parameters.
|
||||||
|
|
||||||
|
1. A notable exception is when the likelihood of a bug is minimal, such as when a function
|
||||||
|
takes an argument that is more often not required than required. An example where the
|
||||||
|
`?` operator is inappropriate is when taking a room ID: typically the caller should
|
||||||
|
supply the room ID if it knows it, otherwise deliberately acknowledge that it doesn't
|
||||||
|
have one with `null`.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function doThingWithRoom(
|
||||||
|
thing: string,
|
||||||
|
room: Optional<string>, // require the caller to specify
|
||||||
|
) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
29. There should be approximately one interface, class, or enum per file unless the file is named
|
||||||
|
"types.ts", "global.d.ts", or ends with "-types.ts".
|
||||||
|
1. The file name should match the interface, class, or enum name.
|
||||||
|
30. Bulk functions can be declared in a single file, though named as "foo-utils.ts" or "utils/foo.ts".
|
||||||
|
31. Imports are grouped by external module imports first, then by internal imports.
|
||||||
|
32. File ordering is not strict, but should generally follow this sequence:
|
||||||
|
1. Licence header
|
||||||
|
2. Imports
|
||||||
|
3. Constants
|
||||||
|
4. Enums
|
||||||
|
5. Interfaces
|
||||||
|
6. Functions
|
||||||
|
7. Classes
|
||||||
|
1. Public/protected/private static properties
|
||||||
|
2. Public/protected/private properties
|
||||||
|
3. Constructors
|
||||||
|
4. Public/protected/private getters & setters
|
||||||
|
5. Protected and abstract functions
|
||||||
|
6. Public/private functions
|
||||||
|
7. Public/protected/private static functions
|
||||||
|
33. Variable names should be noticeably unique from their types. For example, "str: string" instead
|
||||||
|
of "string: string".
|
||||||
|
34. Use double quotes to enclose strings. You may use single quotes if the string contains double quotes.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const example1 = "simple string";
|
||||||
|
const example2 = 'string containing "double quotes"';
|
||||||
|
```
|
||||||
|
|
||||||
|
35. Prefer async-await to promise-chaining
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async function () {
|
||||||
|
const result = await anotherAsyncFunction();
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## React
|
||||||
|
|
||||||
|
Inheriting all the rules of TypeScript, the following additionally apply:
|
||||||
|
|
||||||
|
1. Types for lifecycle functions are not required (render, componentDidMount, and so on).
|
||||||
|
2. Class components must always have a `Props` interface declared immediately above them. It can be
|
||||||
|
empty if the component accepts no props.
|
||||||
|
3. Class components should have an `State` interface declared immediately above them, but after `Props`.
|
||||||
|
4. Props and State should not be exported. Use `React.ComponentProps<typeof ComponentNameHere>`
|
||||||
|
instead.
|
||||||
|
5. One component per file, except when a component is a utility component specifically for the "primary"
|
||||||
|
component. The utility component should not be exported.
|
||||||
|
6. Exported constants, enums, interfaces, functions, etc must be separate from files containing components
|
||||||
|
or stores.
|
||||||
|
7. Stores should use a singleton pattern with a static instance property:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
class FooStore {
|
||||||
|
public static readonly instance = new FooStore();
|
||||||
|
|
||||||
|
// or if the instance can't be created eagerly:
|
||||||
|
private static _instance: FooStore;
|
||||||
|
public static get instance(): FooStore {
|
||||||
|
if (!FooStore._instance) {
|
||||||
|
FooStore._instance = new FooStore();
|
||||||
|
}
|
||||||
|
return FooStore._instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
8. Stores must support using an alternative MatrixClient and dispatcher instance.
|
||||||
|
9. Utilities which require JSX must be split out from utilities which do not. This is to prevent import
|
||||||
|
cycles during runtime where components accidentally include more of the app than they intended.
|
||||||
|
10. Interdependence between stores should be kept to a minimum. Break functions and constants out to utilities
|
||||||
|
if at all possible.
|
||||||
|
11. A component should only use CSS class names in line with the component name.
|
||||||
|
|
||||||
|
1. When knowingly using a class name from another component, document it.
|
||||||
|
|
||||||
|
12. Curly braces within JSX should be padded with a space, however properties on those components should not.
|
||||||
|
See above code example.
|
||||||
|
13. Functions used as properties should either be defined on the class or stored in a variable. They should not
|
||||||
|
be inline unless mocking/short-circuiting the value.
|
||||||
|
14. Prefer hooks (functional components) over class components. Be consistent with the existing area if unsure
|
||||||
|
which should be used.
|
||||||
|
1. Unless the component is considered a "structure", in which case use classes.
|
||||||
|
15. Write more views than structures. Structures are chunks of functionality like MatrixChat while views are
|
||||||
|
isolated components.
|
||||||
|
16. Components should serve a single, or near-single, purpose.
|
||||||
|
17. Prefer to derive information from component properties rather than establish state.
|
||||||
|
18. Do not use `React.Component::forceUpdate`.
|
||||||
|
|
||||||
|
## Stylesheets (\*.pcss = PostCSS + Plugins)
|
||||||
|
|
||||||
|
Note: We use PostCSS + some plugins to process our styles. It looks like SCSS, but actually it is not.
|
||||||
|
|
||||||
|
1. Class names must be prefixed with "mx\_".
|
||||||
|
2. Class names should denote the component which defines them, followed by any context:
|
||||||
|
1. mx_MyFoo
|
||||||
|
2. mx_MyFoo_avatar
|
||||||
|
3. mx_MyFoo_avatar--user
|
||||||
|
3. Use the `$font` and `$spacing` variables instead of manual values.
|
||||||
|
4. Keep indentation/nesting to a minimum. Maximum suggested nesting is 5 layers.
|
||||||
|
5. Use the whole class name instead of shortcuts:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.mx_MyFoo {
|
||||||
|
& .mx_MyFoo_avatar {
|
||||||
|
// instead of &_avatar
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Break multiple selectors over multiple lines this way:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.mx_MyFoo,
|
||||||
|
.mx_MyBar,
|
||||||
|
.mx_MyFooBar {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Non-shared variables should use $lowerCamelCase. Shared variables use $dashed-naming.
|
||||||
|
8. Overrides to Z indexes, adjustments of dimensions/padding with pixels, and so on should all be
|
||||||
|
documented for what the values mean:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.mx_MyFoo {
|
||||||
|
width: calc(100% - 12px); // 12px for read receipts
|
||||||
|
top: -2px; // visually centred vertically
|
||||||
|
z-index: 10; // above user avatar, but below dialogs
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
9. Avoid the use of `!important`. If necessary, add a comment.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
1. Tests must be written in TypeScript.
|
||||||
|
2. Jest mocks are declared below imports, but above everything else.
|
||||||
|
3. Use the following convention template:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Describe the class, component, or file name.
|
||||||
|
describe("FooComponent", () => {
|
||||||
|
// all test inspecific variables go here
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// exclude if not used.
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// exclude if not used.
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use "it should..." terminology
|
||||||
|
it("should call the correct API", async () => {
|
||||||
|
// test-specific variables go here
|
||||||
|
// function calls/state changes go here
|
||||||
|
// expectations go here
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the file being tested is a utility class:
|
||||||
|
describe("foo-utils", () => {
|
||||||
|
describe("firstUtilFunction", () => {
|
||||||
|
it("should...", async () => {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("secondUtilFunction", () => {
|
||||||
|
it("should...", async () => {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
|
@ -26,13 +26,11 @@
|
||||||
"uisi_autorageshake_app": "element-auto-uisi",
|
"uisi_autorageshake_app": "element-auto-uisi",
|
||||||
"default_country_code": "GB",
|
"default_country_code": "GB",
|
||||||
"show_labs_settings": false,
|
"show_labs_settings": false,
|
||||||
"features": { },
|
"features": {},
|
||||||
"default_federate": true,
|
"default_federate": true,
|
||||||
"default_theme": "light",
|
"default_theme": "light",
|
||||||
"room_directory": {
|
"room_directory": {
|
||||||
"servers": [
|
"servers": ["matrix.org"]
|
||||||
"matrix.org"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"enable_presence_by_hs_url": {
|
"enable_presence_by_hs_url": {
|
||||||
"https://matrix.org": false,
|
"https://matrix.org": false,
|
||||||
|
@ -44,5 +42,10 @@
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"preferred_domain": "meet.element.io"
|
"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"
|
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "Element",
|
"name": "Element",
|
||||||
"description": "A glossy Matrix collaboration client for the web.",
|
"description": "A glossy Matrix collaboration client for the web.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "https://github.com/vector-im/element-web",
|
"url": "https://github.com/vector-im/element-web",
|
||||||
"license": "Apache License 2.0"
|
"license": "Apache License 2.0"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"list": "https://github.com/vector-im/element-web/issues",
|
"list": "https://github.com/vector-im/element-web/issues",
|
||||||
"report": "https://github.com/vector-im/element-web/issues/new/choose"
|
"report": "https://github.com/vector-im/element-web/issues/new/choose"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": ["chat", "riot", "matrix"]
|
||||||
"chat",
|
|
||||||
"riot",
|
|
||||||
"matrix"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ Current more parallel flow:
|
||||||
digraph G {
|
digraph G {
|
||||||
node [shape=box];
|
node [shape=box];
|
||||||
|
|
||||||
subgraph cluster_0 {
|
subgraph cluster_0 {
|
||||||
color=orange;
|
color=orange;
|
||||||
node [style=filled];
|
node [style=filled];
|
||||||
label = "index.ts";
|
label = "index.ts";
|
||||||
|
|
||||||
entrypoint, s0, ready [shape=point];
|
entrypoint, s0, ready [shape=point];
|
||||||
rageshake, config, i18n, theme, skin, olm [shape=parallelogram];
|
rageshake, config, i18n, theme, skin, olm [shape=parallelogram];
|
||||||
|
@ -52,33 +52,38 @@ digraph G {
|
||||||
skin -> ready [color=red];
|
skin -> ready [color=red];
|
||||||
theme -> ready [color=red];
|
theme -> ready [color=red];
|
||||||
i18n -> ready [color=red];
|
i18n -> ready [color=red];
|
||||||
}
|
|
||||||
|
|
||||||
subgraph cluster_1 {
|
}
|
||||||
color = green;
|
|
||||||
node [style=filled];
|
subgraph cluster_1 {
|
||||||
label = "init.tsx";
|
color = green;
|
||||||
|
node [style=filled];
|
||||||
|
label = "init.tsx";
|
||||||
|
|
||||||
ready -> loadApp;
|
ready -> loadApp;
|
||||||
loadApp -> matrixchat;
|
loadApp -> matrixchat;
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
Key:
|
Key:
|
||||||
+ Parallelogram: async/await task
|
|
||||||
+ Box: sync task
|
- Parallelogram: async/await task
|
||||||
+ Diamond: conditional branch
|
- Box: sync task
|
||||||
+ Egg: user interaction
|
- Diamond: conditional branch
|
||||||
+ Blue arrow: async task is allowed to settle but allowed to fail
|
- Egg: user interaction
|
||||||
+ Red arrow: async task success is asserted
|
- Blue arrow: async task is allowed to settle but allowed to fail
|
||||||
|
- Red arrow: async task success is asserted
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
+ A task begins when all its dependencies (arrows going into it) are fulfilled.
|
|
||||||
+ The success of setting up rageshake is never asserted, element-web has a fallback path for running without IDB (and thus rageshake).
|
- A task begins when all its dependencies (arrows going into it) are fulfilled.
|
||||||
+ Everything is awaited to be settled before the Modernizr check, to allow it to make use of things like i18n if they are successful.
|
- The success of setting up rageshake is never asserted, element-web has a fallback path for running without IDB (and thus rageshake).
|
||||||
|
- Everything is awaited to be settled before the Modernizr check, to allow it to make use of things like i18n if they are successful.
|
||||||
|
|
||||||
Underlying dependencies:
|
Underlying dependencies:
|
||||||
![image](https://user-images.githubusercontent.com/2403652/73848977-08624500-4821-11ea-9830-bb0317c41086.png)
|
![image](https://user-images.githubusercontent.com/2403652/73848977-08624500-4821-11ea-9830-bb0317c41086.png)
|
||||||
|
|
29
docs/betas.md
Normal file
29
docs/betas.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Beta features
|
||||||
|
|
||||||
|
Beta features are features that are not ready for production yet but the team
|
||||||
|
wants more people to try the features and give feedback on them.
|
||||||
|
|
||||||
|
Before a feature gets into its beta phase, it is often a labs feature (see
|
||||||
|
[Labs](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)).
|
||||||
|
|
||||||
|
**Be warned! Beta features may not be completely finalised or stable!**
|
||||||
|
|
||||||
|
## Threaded Messaging (`feature_thread`)
|
||||||
|
|
||||||
|
Threading allows users to branch out a new conversation from the main timeline
|
||||||
|
of a room. This is particularly useful in high traffic rooms where multiple
|
||||||
|
conversations can happen in parallel or when a single discussion might stretch
|
||||||
|
over a very long period of time.
|
||||||
|
|
||||||
|
Threads can be access by clicking their summary below the root event on the room
|
||||||
|
timeline. Users can find a comprehensive list of threads by click the icon on
|
||||||
|
the room header button.
|
||||||
|
|
||||||
|
This feature might work in degraded mode if the homeserver a user is connected
|
||||||
|
to does not advertise support for the unstable feature `org.matrix.msc3440` when
|
||||||
|
calling the `/versions` API endpoint.
|
||||||
|
|
||||||
|
## Video rooms (`feature_video_rooms`)
|
||||||
|
|
||||||
|
Enables support for creating and joining video rooms, which are persistent video
|
||||||
|
chats that users can jump in and out of.
|
|
@ -33,19 +33,19 @@ someone to add something.
|
||||||
When you're looking through the list, here are some things that might make an
|
When you're looking through the list, here are some things that might make an
|
||||||
issue a **GOOD** choice:
|
issue a **GOOD** choice:
|
||||||
|
|
||||||
* It is a problem or feature you care about.
|
- It is a problem or feature you care about.
|
||||||
* It concerns a type of code you know a little about.
|
- It concerns a type of code you know a little about.
|
||||||
* You think you can understand what's needed.
|
- You think you can understand what's needed.
|
||||||
* It already has approval from Element Web's designers (look for comments from
|
- It already has approval from Element Web's designers (look for comments from
|
||||||
members of the
|
members of the
|
||||||
[Product](https://github.com/orgs/vector-im/teams/product/members) or
|
[Product](https://github.com/orgs/vector-im/teams/product/members) or
|
||||||
[Design](https://github.com/orgs/vector-im/teams/design/members) teams).
|
[Design](https://github.com/orgs/vector-im/teams/design/members) teams).
|
||||||
|
|
||||||
Here are some things that might make it a **BAD** choice:
|
Here are some things that might make it a **BAD** choice:
|
||||||
|
|
||||||
* You don't understand it (maybe add a comment asking a clarifying question).
|
- You don't understand it (maybe add a comment asking a clarifying question).
|
||||||
* It sounds difficult, or is part of a larger change you don't know about.
|
- It sounds difficult, or is part of a larger change you don't know about.
|
||||||
* **It is tagged with `X-Needs-Design` or `X-Needs-Product`.**
|
- **It is tagged with `X-Needs-Design` or `X-Needs-Product`.**
|
||||||
|
|
||||||
**Element Web's Design and Product teams tend to be very busy**, so if you make
|
**Element Web's Design and Product teams tend to be very busy**, so if you make
|
||||||
changes that require approval from one of those teams, you will probably have
|
changes that require approval from one of those teams, you will probably have
|
||||||
|
|
411
docs/config.md
411
docs/config.md
|
@ -1,8 +1,12 @@
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
You can configure the app by copying `config.sample.json` to `config.json` and customising it. The possible options are
|
You can configure the app by copying `config.sample.json` to `config.json` or `config.$domain.json` and customising it.
|
||||||
described here. If you run into issues, please visit [#element-web:matrix.org](https://matrix.to/#/#element-web:matrix.org)
|
Element will attempt to load first `config.$domain.json` and if it fails `config.json`. This mechanism allows different
|
||||||
on Matrix.
|
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
|
For a good example of a production-tuned config, see https://app.element.io/config.json
|
||||||
|
|
||||||
|
@ -13,7 +17,7 @@ for the desktop app the application will need to be exited fully (including via
|
||||||
|
|
||||||
## Homeserver configuration
|
## Homeserver configuration
|
||||||
|
|
||||||
In order for Element to even start you will need to tell it what homeserver to connect to *by default*. Users will be
|
In order for Element to even start you will need to tell it what homeserver to connect to _by default_. Users will be
|
||||||
able to use a different homeserver if they like, though this can be disabled with `"disable_custom_urls": true` in your
|
able to use a different homeserver if they like, though this can be disabled with `"disable_custom_urls": true` in your
|
||||||
config.
|
config.
|
||||||
|
|
||||||
|
@ -22,18 +26,18 @@ One of the following options **must** be supplied:
|
||||||
1. `default_server_config`: The preferred method of setting the homeserver connection information. Simply copy/paste
|
1. `default_server_config`: The preferred method of setting the homeserver connection information. Simply copy/paste
|
||||||
your [`/.well-known/matrix/client`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient)
|
your [`/.well-known/matrix/client`](https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient)
|
||||||
into this field. For example:
|
into this field. For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"default_server_config": {
|
"default_server_config": {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
"base_url": "https://matrix-client.matrix.org"
|
"base_url": "https://matrix-client.matrix.org"
|
||||||
},
|
},
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
"base_url": "https://vector.im"
|
"base_url": "https://vector.im"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
2. `default_server_name`: A different method of connecting to the homeserver by looking up the connection information
|
2. `default_server_name`: A different method of connecting to the homeserver by looking up the connection information
|
||||||
using `.well-known`. When using this option, simply use your server's domain name (the part at the end of user IDs):
|
using `.well-known`. When using this option, simply use your server's domain name (the part at the end of user IDs):
|
||||||
`"default_server_name": "matrix.org"`
|
`"default_server_name": "matrix.org"`
|
||||||
|
@ -54,10 +58,10 @@ To force a labs flag on or off, use the following:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"features": {
|
"features": {
|
||||||
"feature_you_want_to_turn_on": true,
|
"feature_you_want_to_turn_on": true,
|
||||||
"feature_you_want_to_keep_off": false
|
"feature_you_want_to_keep_off": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -78,25 +82,25 @@ instance. As of writing those settings are not fully documented, however a few a
|
||||||
inputs.
|
inputs.
|
||||||
3. `room_directory`: Optionally defines how the room directory component behaves. Currently only a single property, `servers`
|
3. `room_directory`: Optionally defines how the room directory component behaves. Currently only a single property, `servers`
|
||||||
is supported to add additional servers to the dropdown. For example:
|
is supported to add additional servers to the dropdown. For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"room_directory": {
|
"room_directory": {
|
||||||
"servers": ["matrix.org", "example.org"]
|
"servers": ["matrix.org", "example.org"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
4. `setting_defaults`: Optional configuration for settings which are not described by this document and support the `config`
|
4. `setting_defaults`: Optional configuration for settings which are not described by this document and support the `config`
|
||||||
level. This list is incomplete. For example:
|
level. This list is incomplete. For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"setting_defaults": {
|
"setting_defaults": {
|
||||||
"MessageComposerInput.showStickersButton": false,
|
"MessageComposerInput.showStickersButton": false,
|
||||||
"MessageComposerInput.showPollsButton": false
|
"MessageComposerInput.showPollsButton": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
These values will take priority over the hardcoded defaults for the settings. For a list of available settings, see
|
These values will take priority over the hardcoded defaults for the settings. For a list of available settings, see
|
||||||
[Settings.tsx](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.tsx).
|
[Settings.tsx](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.tsx).
|
||||||
|
|
||||||
## Customisation & branding
|
## Customisation & branding
|
||||||
|
|
||||||
|
@ -135,6 +139,11 @@ complete re-branding/private labeling, a more personalised experience can be ach
|
||||||
to hide this dropdown.
|
to hide this dropdown.
|
||||||
16. `disable_guests`: When `false` (default), **enable** guest-related functionality (peeking/previewing rooms, etc) for unregistered
|
16. `disable_guests`: When `false` (default), **enable** guest-related functionality (peeking/previewing rooms, etc) for unregistered
|
||||||
users. Set to `true` to disable this functionality.
|
users. Set to `true` to disable this functionality.
|
||||||
|
17. `user_notice`: Optional notice to show to the user, e.g. for sunsetting a deployment and pushing users to move in their own time.
|
||||||
|
Takes a configuration object as below:
|
||||||
|
1. `title`: Required. Title to show at the top of the notice.
|
||||||
|
2. `description`: Required. The description to use for the notice.
|
||||||
|
3. `show_once`: Optional. If true then the notice will only be shown once per device.
|
||||||
|
|
||||||
### `desktop_builds` and `mobile_builds`
|
### `desktop_builds` and `mobile_builds`
|
||||||
|
|
||||||
|
@ -161,16 +170,16 @@ Together, these two options might look like the following in your config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"desktop_builds": {
|
"desktop_builds": {
|
||||||
"available": true,
|
"available": true,
|
||||||
"logo": "https://example.org/assets/logo-small.svg",
|
"logo": "https://example.org/assets/logo-small.svg",
|
||||||
"url": "https://example.org/not_element/download"
|
"url": "https://example.org/not_element/download"
|
||||||
},
|
},
|
||||||
"mobile_builds": {
|
"mobile_builds": {
|
||||||
"ios": null,
|
"ios": null,
|
||||||
"android": "https://example.org/not_element/android",
|
"android": "https://example.org/not_element/android",
|
||||||
"fdroid": "https://example.org/not_element/fdroid"
|
"fdroid": "https://example.org/not_element/fdroid"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -201,18 +210,18 @@ Together, the options might look like this in your config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"branding": {
|
"branding": {
|
||||||
"welcome_background_url": "https://example.org/assets/background.jpg",
|
"welcome_background_url": "https://example.org/assets/background.jpg",
|
||||||
"auth_header_logo_url": "https://example.org/assets/logo.svg",
|
"auth_header_logo_url": "https://example.org/assets/logo.svg",
|
||||||
"auth_footer_links": [
|
"auth_footer_links": [
|
||||||
{"text": "FAQ", "url": "https://example.org/faq"},
|
{ "text": "FAQ", "url": "https://example.org/faq" },
|
||||||
{"text": "Donate", "url": "https://example.org/donate"}
|
{ "text": "Donate", "url": "https://example.org/donate" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"embedded_pages": {
|
"embedded_pages": {
|
||||||
"welcome_url": "https://example.org/assets/welcome.html",
|
"welcome_url": "https://example.org/assets/welcome.html",
|
||||||
"home_url": "https://example.org/assets/home.html"
|
"home_url": "https://example.org/assets/home.html"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -231,88 +240,98 @@ When Element is deployed alongside a homeserver with SSO-only login, some option
|
||||||
2. `sso_redirect_options`: Options to define how to handle unauthenticated users. If the object contains `"immediate": true`, then
|
2. `sso_redirect_options`: Options to define how to handle unauthenticated users. If the object contains `"immediate": true`, then
|
||||||
all unauthenticated users will be automatically redirected to the SSO system to start their login. If instead you'd only like to
|
all unauthenticated users will be automatically redirected to the SSO system to start their login. If instead you'd only like to
|
||||||
have users which land on the welcome page to be redirected, use `"on_welcome_page": true`. As an example:
|
have users which land on the welcome page to be redirected, use `"on_welcome_page": true`. As an example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"sso_redirect_options": {
|
"sso_redirect_options": {
|
||||||
"immediate": false,
|
"immediate": false,
|
||||||
"on_welcome_page": true
|
"on_welcome_page": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
It is most common to use the `immediate` flag instead of `on_welcome_page`.
|
It is most common to use the `immediate` flag instead of `on_welcome_page`.
|
||||||
|
|
||||||
## VoIP / Jitsi calls
|
## VoIP / Jitsi calls
|
||||||
|
|
||||||
Currently, Element uses Jitsi to offer conference calls in rooms. A set of defaults are applied, pointing at our Jitsi instance,
|
Currently, Element uses Jitsi to offer conference calls in rooms, with an experimental Element Call implementation in the works.
|
||||||
to ensure conference calling works, however you can point Element at your own Jitsi if you prefer.
|
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).
|
More information about the Jitsi setup can be found [here](./jitsi.md).
|
||||||
|
|
||||||
The VoIP and Jitsi options are:
|
The VoIP and Jitsi options are:
|
||||||
|
|
||||||
1. `jitsi`: Optional configuration for how to start Jitsi conferences. Currently can only contain a single `preferred_domain`
|
1. `jitsi`: Optional configuration for how to start Jitsi conferences. Currently can only contain a single `preferred_domain`
|
||||||
value which points at the domain of the Jitsi instance. Defaults to `meet.element.io`. This is *not* used if the Jitsi widget
|
value which points at the domain of the Jitsi instance. Defaults to `meet.element.io`. This is _not_ used if the Jitsi widget
|
||||||
was created by an integration manager, or if the homeserver provides Jitsi information in `/.well-known/matrix/client`. For
|
was created by an integration manager, or if the homeserver provides Jitsi information in `/.well-known/matrix/client`. For
|
||||||
example:
|
example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"preferred_domain": "meet.jit.si"
|
"preferred_domain": "meet.jit.si"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
2. `jitsi_widget`: Optional configuration for the built-in Jitsi widget. Currently can only contain a single `skip_built_in_welcome_screen`
|
2. `jitsi_widget`: Optional configuration for the built-in Jitsi widget. Currently can only contain a single `skip_built_in_welcome_screen`
|
||||||
value, denoting whether the "Join Conference" button should be shown. When `true` (default `false`), Jitsi calls will skip to
|
value, denoting whether the "Join Conference" button should be shown. When `true` (default `false`), Jitsi calls will skip to
|
||||||
the call instead of having a screen with a single button on it. This is most useful if the Jitsi instance being used already
|
the call instead of having a screen with a single button on it. This is most useful if the Jitsi instance being used already
|
||||||
has a landing page for users to test audio and video before joining the call, otherwise users will automatically join the call.
|
has a landing page for users to test audio and video before joining the call, otherwise users will automatically join the call.
|
||||||
For example:
|
For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jitsi_widget": {
|
"jitsi_widget": {
|
||||||
"skip_built_in_welcome_screen": true
|
"skip_built_in_welcome_screen": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
3. `voip`: Optional configuration for various VoIP features. Currently can only contain a single `obey_asserted_identity` value to
|
3. `voip`: Optional configuration for various VoIP features. Currently can only contain a single `obey_asserted_identity` value to
|
||||||
send MSC3086-style asserted identity messages during VoIP calls in the room corresponding to the asserted identity. This *must*
|
send MSC3086-style asserted identity messages during VoIP calls in the room corresponding to the asserted identity. This _must_
|
||||||
only be set in trusted environments. The option defaults to `false`. For example:
|
only be set in trusted environments. The option defaults to `false`. For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"voip": {
|
"voip": {
|
||||||
"obey_asserted_identity": false
|
"obey_asserted_identity": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
4. `widget_build_url`: Optional URL to have Element make a request to when a user presses the voice/video call buttons in the app,
|
4. `widget_build_url`: Optional URL to have Element make a request to when a user presses the voice/video call buttons in the app,
|
||||||
if a call would normally be started by the action. The URL will be called with a `roomId` query parameter to identify the room
|
if a call would normally be started by the action. The URL will be called with a `roomId` query parameter to identify the room
|
||||||
being called in. The URL must respond with a JSON object similar to the following:
|
being called in. The URL must respond with a JSON object similar to the following:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"widget_id": "$arbitrary_string",
|
"widget_id": "$arbitrary_string",
|
||||||
"widget": {
|
"widget": {
|
||||||
"creatorUserId": "@user:example.org",
|
"creatorUserId": "@user:example.org",
|
||||||
"id": "$the_same_widget_id",
|
"id": "$the_same_widget_id",
|
||||||
"type": "m.custom",
|
"type": "m.custom",
|
||||||
"waitForIframeLoad": true,
|
"waitForIframeLoad": true,
|
||||||
"name": "My Widget Name Here",
|
"name": "My Widget Name Here",
|
||||||
"avatar_url": "mxc://example.org/abc123",
|
"avatar_url": "mxc://example.org/abc123",
|
||||||
"url": "https://example.org/widget.html",
|
"url": "https://example.org/widget.html",
|
||||||
"data": {
|
"data": {
|
||||||
"title": "Subtitle goes here"
|
"title": "Subtitle goes here"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
"container": "top",
|
"container": "top",
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"width": 65,
|
"width": 65,
|
||||||
"height": 50
|
"height": 50
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
The `widget` is the `content` of a normal widget state event. The `layout` is the layout specifier for the widget being created,
|
The `widget` is the `content` of a normal widget state event. The `layout` is the layout specifier for the widget being created,
|
||||||
as defined by the `io.element.widgets.layout` state event.
|
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
|
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.
|
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
|
## Bug reporting
|
||||||
|
|
||||||
|
@ -322,10 +341,8 @@ If you run your own rageshake server to collect bug reports, the following optio
|
||||||
not present in the config, the app will disable all rageshake functionality. Set to `https://element.io/bugreports/submit` to submit
|
not present in the config, the app will disable all rageshake functionality. Set to `https://element.io/bugreports/submit` to submit
|
||||||
rageshakes to us, or use your own rageshake server.
|
rageshakes to us, or use your own rageshake server.
|
||||||
2. `uisi_autorageshake_app`: If a user has enabled the "automatically send debug logs on decryption errors" flag, this option will be sent
|
2. `uisi_autorageshake_app`: If a user has enabled the "automatically send debug logs on decryption errors" flag, this option will be sent
|
||||||
alongside the rageshake so the rageshake server can filter them by app name. By default, this will be `element-web`, as with any other
|
alongside the rageshake so the rageshake server can filter them by app name. By default, this will be `element-auto-uisi`
|
||||||
rageshake submitted by the app.
|
(in contrast to other rageshakes submitted by the app, which use `element-web`).
|
||||||
|
|
||||||
If you are using the element.io rageshake server, please set this to `element-auto-uisi` so we can better filter them.
|
|
||||||
|
|
||||||
If you would like to use [Sentry](https://sentry.io/) for rageshake data, add a `sentry` object to your config with the following values:
|
If you would like to use [Sentry](https://sentry.io/) for rageshake data, add a `sentry` object to your config with the following values:
|
||||||
|
|
||||||
|
@ -336,18 +353,17 @@ For example:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"sentry": {
|
"sentry": {
|
||||||
"dsn": "dsn-goes-here",
|
"dsn": "dsn-goes-here",
|
||||||
"environment": "production"
|
"environment": "production"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Integration managers
|
## Integration managers
|
||||||
|
|
||||||
Integration managers are embedded applications within Element to help the user configure bots, bridges, and widgets. An integration manager
|
Integration managers are embedded applications within Element to help the user configure bots, bridges, and widgets. An integration manager
|
||||||
is a separate piece of software not typically available with your homeserver. To disable integrations, leave the options defined here out of
|
is a separate piece of software not typically available with your homeserver. To disable integrations, set the options defined here to `null`.
|
||||||
your config.
|
|
||||||
|
|
||||||
1. `integrations_ui_url`: The UI URL for the integration manager.
|
1. `integrations_ui_url`: The UI URL for the integration manager.
|
||||||
2. `integrations_rest_url`: The REST interface URL for the integration manager.
|
2. `integrations_rest_url`: The REST interface URL for the integration manager.
|
||||||
|
@ -357,15 +373,15 @@ If you would like to use Scalar, the integration manager maintained by Element,
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"integrations_ui_url": "https://scalar.vector.im/",
|
"integrations_ui_url": "https://scalar.vector.im/",
|
||||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||||
"integrations_widgets_urls": [
|
"integrations_widgets_urls": [
|
||||||
"https://scalar.vector.im/_matrix/integrations/v1",
|
"https://scalar.vector.im/_matrix/integrations/v1",
|
||||||
"https://scalar.vector.im/api",
|
"https://scalar.vector.im/api",
|
||||||
"https://scalar-staging.vector.im/_matrix/integrations/v1",
|
"https://scalar-staging.vector.im/_matrix/integrations/v1",
|
||||||
"https://scalar-staging.vector.im/api",
|
"https://scalar-staging.vector.im/api",
|
||||||
"https://scalar-staging.riot.im/scalar/api"
|
"https://scalar-staging.riot.im/scalar/api"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -375,9 +391,9 @@ If you would like to include a custom message when someone is reporting an event
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"report_event": {
|
"report_event": {
|
||||||
"admin_message_md": "Please be sure to review our [terms of service](https://example.org/terms) before reporting a message."
|
"admin_message_md": "Please be sure to review our [terms of service](https://example.org/terms) before reporting a message."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -385,9 +401,7 @@ To add additional "terms and conditions" links throughout the app, use the follo
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"terms_and_conditions_links": [
|
"terms_and_conditions_links": [{ "text": "Code of conduct", "url": "https://example.org/code-of-conduct" }]
|
||||||
{ "text": "Code of conduct", "url": "https://example.org/code-of-conduct" }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -404,7 +418,7 @@ analytics are deemed impossible and the user won't be asked to opt in to the sys
|
||||||
There are additional root-level options which can be specified:
|
There are additional root-level options which can be specified:
|
||||||
|
|
||||||
1. `analytics_owner`: the company name used in dialogs talking about analytics - this defaults to `brand`,
|
1. `analytics_owner`: the company name used in dialogs talking about analytics - this defaults to `brand`,
|
||||||
and is useful when the provider of analytics is different from the provider of the Element instance.
|
and is useful when the provider of analytics is different from the provider of the Element instance.
|
||||||
2. `privacy_policy_url`: URL to the privacy policy including the analytics collection policy.
|
2. `privacy_policy_url`: URL to the privacy policy including the analytics collection policy.
|
||||||
|
|
||||||
## Server hosting links
|
## Server hosting links
|
||||||
|
@ -417,26 +431,26 @@ will not be shown to the user.
|
||||||
of `utm_campaign` to denote which link the user clicked on within the app. Only ever applies to matrix.org users specifically.
|
of `utm_campaign` to denote which link the user clicked on within the app. Only ever applies to matrix.org users specifically.
|
||||||
2. `host_signup`: Optional configuration for an account importer to your hosting platform. The API surface of this is not documented
|
2. `host_signup`: Optional configuration for an account importer to your hosting platform. The API surface of this is not documented
|
||||||
at the moment, but can be configured with the following subproperties:
|
at the moment, but can be configured with the following subproperties:
|
||||||
1. `brand`: The brand name to use.
|
1. `brand`: The brand name to use.
|
||||||
2. `url`: The iframe URL for the importer.
|
2. `url`: The iframe URL for the importer.
|
||||||
3. `domains`: The homeserver domains to show the importer to.
|
3. `domains`: The homeserver domains to show the importer to.
|
||||||
4. `cookie_policy_url`: The URL to the cookie policy for the importer.
|
4. `cookie_policy_url`: The URL to the cookie policy for the importer.
|
||||||
5. `privacy_policy_url`: The URL to the privacy policy for the importer.
|
5. `privacy_policy_url`: The URL to the privacy policy for the importer.
|
||||||
6. `terms_of_service_url`: The URL to the terms of service for the importer.
|
6. `terms_of_service_url`: The URL to the terms of service for the importer.
|
||||||
|
|
||||||
If you're looking to mirror a setup from our production/development environments, the following config should be used:
|
If you're looking to mirror a setup from our production/development environments, the following config should be used:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
|
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
|
||||||
"host_signup": {
|
"host_signup": {
|
||||||
"brand": "Element Home",
|
"brand": "Element Home",
|
||||||
"domains": [ "matrix.org" ],
|
"domains": ["matrix.org"],
|
||||||
"url": "https://ems.element.io/element-home/in-app-loader",
|
"url": "https://ems.element.io/element-home/in-app-loader",
|
||||||
"cookie_policy_url": "https://element.io/cookie-policy",
|
"cookie_policy_url": "https://element.io/cookie-policy",
|
||||||
"privacy_policy_url": "https://element.io/privacy",
|
"privacy_policy_url": "https://element.io/privacy",
|
||||||
"terms_of_service_url": "https://element.io/terms-of-service"
|
"terms_of_service_url": "https://element.io/terms-of-service"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -449,10 +463,10 @@ set this value to the following at a minimum:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"enable_presence_by_hs_url": {
|
"enable_presence_by_hs_url": {
|
||||||
"https://matrix.org": false,
|
"https://matrix.org": false,
|
||||||
"https://matrix-client.matrix.org": false
|
"https://matrix-client.matrix.org": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -469,8 +483,8 @@ Element will check multiple sources when looking for an identity server to use i
|
||||||
the following order of preference:
|
the following order of preference:
|
||||||
|
|
||||||
1. The identity server set in the user's account data
|
1. The identity server set in the user's account data
|
||||||
* For a new user, no value is present in their account data. It is only set
|
- For a new user, no value is present in their account data. It is only set
|
||||||
if the user visits Settings and manually changes their identity server.
|
if the user visits Settings and manually changes their identity server.
|
||||||
2. The identity server provided by the `.well-known` lookup that occurred at
|
2. The identity server provided by the `.well-known` lookup that occurred at
|
||||||
login
|
login
|
||||||
3. The identity server provided by the Riot config file
|
3. The identity server provided by the Riot config file
|
||||||
|
@ -496,38 +510,40 @@ preferences.
|
||||||
|
|
||||||
Currently, the following UI feature flags are supported:
|
Currently, the following UI feature flags are supported:
|
||||||
|
|
||||||
* `UIFeature.urlPreviews` - Whether URL previews are enabled across the entire application.
|
- `UIFeature.urlPreviews` - Whether URL previews are enabled across the entire application.
|
||||||
* `UIFeature.feedback` - Whether prompts to supply feedback are shown.
|
- `UIFeature.feedback` - Whether prompts to supply feedback are shown.
|
||||||
* `UIFeature.voip` - Whether or not VoIP is shown readily to the user. When disabled,
|
- `UIFeature.voip` - Whether or not VoIP is shown readily to the user. When disabled,
|
||||||
Jitsi widgets will still work though they cannot easily be added.
|
Jitsi widgets will still work though they cannot easily be added.
|
||||||
* `UIFeature.widgets` - Whether or not widgets will be shown.
|
- `UIFeature.widgets` - Whether or not widgets will be shown.
|
||||||
* `UIFeature.flair` - Whether or not community flair is shown in rooms.
|
- `UIFeature.flair` - Whether or not community flair is shown in rooms.
|
||||||
* `UIFeature.communities` - Whether or not to show any UI related to communities. Implicitly
|
- `UIFeature.communities` - Whether or not to show any UI related to communities. Implicitly
|
||||||
disables `UIFeature.flair` when disabled.
|
disables `UIFeature.flair` when disabled.
|
||||||
* `UIFeature.advancedSettings` - Whether or not sections titled "advanced" in room and
|
- `UIFeature.advancedSettings` - Whether or not sections titled "advanced" in room and
|
||||||
user settings are shown to the user.
|
user settings are shown to the user.
|
||||||
* `UIFeature.shareQrCode` - Whether or not the QR code on the share room/event dialog
|
- `UIFeature.shareQrCode` - Whether or not the QR code on the share room/event dialog
|
||||||
is shown.
|
is shown.
|
||||||
* `UIFeature.shareSocial` - Whether or not the social icons on the share room/event dialog
|
- `UIFeature.shareSocial` - Whether or not the social icons on the share room/event dialog
|
||||||
are shown.
|
are shown.
|
||||||
* `UIFeature.identityServer` - Whether or not functionality requiring an identity server
|
- `UIFeature.identityServer` - Whether or not functionality requiring an identity server
|
||||||
is shown. When disabled, the user will not be able to interact with the identity
|
is shown. When disabled, the user will not be able to interact with the identity
|
||||||
server (sharing email addresses, 3PID invites, etc).
|
server (sharing email addresses, 3PID invites, etc).
|
||||||
* `UIFeature.thirdPartyId` - Whether or not UI relating to third party identifiers (3PIDs)
|
- `UIFeature.thirdPartyId` - Whether or not UI relating to third party identifiers (3PIDs)
|
||||||
is shown. Typically this is considered "contact information" on the homeserver, and is
|
is shown. Typically this is considered "contact information" on the homeserver, and is
|
||||||
not directly related to the identity server.
|
not directly related to the identity server.
|
||||||
* `UIFeature.registration` - Whether or not the registration page is accessible. Typically
|
- `UIFeature.registration` - Whether or not the registration page is accessible. Typically
|
||||||
useful if accounts are managed externally.
|
useful if accounts are managed externally.
|
||||||
* `UIFeature.passwordReset` - Whether or not the password reset page is accessible. Typically
|
- `UIFeature.passwordReset` - Whether or not the password reset page is accessible. Typically
|
||||||
useful if accounts are managed externally.
|
useful if accounts are managed externally.
|
||||||
* `UIFeature.deactivate` - Whether or not the deactivate account button is accessible. Typically
|
- `UIFeature.deactivate` - Whether or not the deactivate account button is accessible. Typically
|
||||||
useful if accounts are managed externally.
|
useful if accounts are managed externally.
|
||||||
* `UIFeature.advancedEncryption` - Whether or not advanced encryption options are shown to the
|
- `UIFeature.advancedEncryption` - Whether or not advanced encryption options are shown to the
|
||||||
user.
|
user.
|
||||||
* `UIFeature.roomHistorySettings` - Whether or not the room history settings are shown to the user.
|
- `UIFeature.roomHistorySettings` - Whether or not the room history settings are shown to the user.
|
||||||
This should only be used if the room history visibility options are managed by the server.
|
This should only be used if the room history visibility options are managed by the server.
|
||||||
* `UIFeature.TimelineEnableRelativeDates` - Display relative date separators (eg: 'Today', 'Yesterday') in the
|
- `UIFeature.TimelineEnableRelativeDates` - Display relative date separators (eg: 'Today', 'Yesterday') in the
|
||||||
timeline for recent messages. When false day dates will be used.
|
timeline for recent messages. When false day dates will be used.
|
||||||
|
- `UIFeature.BulkUnverifiedSessionsReminder` - Display popup reminders to verify or remove unverified sessions. Defaults
|
||||||
|
to true.
|
||||||
|
|
||||||
## Undocumented / developer options
|
## Undocumented / developer options
|
||||||
|
|
||||||
|
@ -537,3 +553,4 @@ The following are undocumented or intended for developer use only.
|
||||||
2. `sync_timeline_limit`
|
2. `sync_timeline_limit`
|
||||||
3. `dangerously_allow_unsafe_and_insecure_passwords`
|
3. `dangerously_allow_unsafe_and_insecure_passwords`
|
||||||
4. `latex_maths_delims`: An optional setting to override the default delimiters used for maths parsing. See https://github.com/matrix-org/matrix-react-sdk/pull/5939 for details. Only used when `feature_latex_maths` is enabled.
|
4. `latex_maths_delims`: An optional setting to override the default delimiters used for maths parsing. See https://github.com/matrix-org/matrix-react-sdk/pull/5939 for details. Only used when `feature_latex_maths` is enabled.
|
||||||
|
5. `voice_broadcast.chunk_length`: Target chunk length in seconds for the Voice Broadcast feature currently under development.
|
||||||
|
|
|
@ -26,7 +26,6 @@ The home page can be overridden in `config.json` to provide all users of an elem
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## `home.html` Example
|
## `home.html` Example
|
||||||
|
|
||||||
The following is a simple example for a custom `home.html`:
|
The following is a simple example for a custom `home.html`:
|
||||||
|
@ -62,4 +61,3 @@ It may be needed to set CORS headers for the `home.html` to enable element-deskt
|
||||||
```
|
```
|
||||||
add_header Access-Control-Allow-Origin *;
|
add_header Access-Control-Allow-Origin *;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ maintenance.
|
||||||
|
|
||||||
**Note**: The project deliberately does not exclude `customisations.json` from Git.
|
**Note**: The project deliberately does not exclude `customisations.json` from Git.
|
||||||
This is to ensure that in shared projects it's possible to have a common config. By
|
This is to ensure that in shared projects it's possible to have a common config. By
|
||||||
default, Element Web does *not* ship with this file to prevent conflicts.
|
default, Element Web does _not_ ship with this file to prevent conflicts.
|
||||||
|
|
||||||
### Custom components
|
### Custom components
|
||||||
|
|
||||||
|
@ -41,9 +41,10 @@ that properties/state machines won't change.
|
||||||
### Component visibility customisation
|
### Component visibility customisation
|
||||||
|
|
||||||
UI for some actions can be hidden via the ComponentVisibility customisation:
|
UI for some actions can be hidden via the ComponentVisibility customisation:
|
||||||
- inviting users to rooms and spaces,
|
|
||||||
- creating rooms,
|
- inviting users to rooms and spaces,
|
||||||
- creating spaces,
|
- creating rooms,
|
||||||
|
- creating spaces,
|
||||||
|
|
||||||
To customise visibility create a customisation module from [ComponentVisibility](https://github.com/matrix-org/matrix-react-sdk/blob/master/src/customisations/ComponentVisibility.ts) following the instructions above.
|
To customise visibility create a customisation module from [ComponentVisibility](https://github.com/matrix-org/matrix-react-sdk/blob/master/src/customisations/ComponentVisibility.ts) following the instructions above.
|
||||||
|
|
||||||
|
@ -55,6 +56,7 @@ might be shown to the user, but they won't have permission to invite users to
|
||||||
the current room: the button will appear disabled.
|
the current room: the button will appear disabled.
|
||||||
|
|
||||||
For example, to only allow users who meet a certain condition to create spaces:
|
For example, to only allow users who meet a certain condition to create spaces:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
function shouldShowComponent(component: UIComponent): boolean {
|
function shouldShowComponent(component: UIComponent): boolean {
|
||||||
if (component === UIComponent.CreateSpaces) {
|
if (component === UIComponent.CreateSpaces) {
|
||||||
|
@ -65,4 +67,5 @@ function shouldShowComponent(component: UIComponent): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, all UI related to creating a space will be hidden unless the users meets the custom condition.
|
In this example, all UI related to creating a space will be hidden unless the users meets the custom condition.
|
||||||
|
|
18
docs/e2ee.md
18
docs/e2ee.md
|
@ -10,9 +10,9 @@ Set the following on your homeserver's
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"io.element.e2ee": {
|
"io.element.e2ee": {
|
||||||
"default": false
|
"default": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,9 +29,9 @@ following on your homeserver's `/.well-known/matrix/client` config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"io.element.e2ee": {
|
"io.element.e2ee": {
|
||||||
"secure_backup_required": true
|
"secure_backup_required": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -44,9 +44,9 @@ only offer one of these, you can signal this via the
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"io.element.e2ee": {
|
"io.element.e2ee": {
|
||||||
"secure_backup_setup_methods": ["passphrase"]
|
"secure_backup_setup_methods": ["passphrase"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@ flexibility and control over when and where those features are enabled.
|
||||||
|
|
||||||
For example, flags make the following things possible:
|
For example, flags make the following things possible:
|
||||||
|
|
||||||
* Extended testing of a feature via labs on develop
|
- Extended testing of a feature via labs on develop
|
||||||
* Enabling features when ready instead of the first moment the code is released
|
- Enabling features when ready instead of the first moment the code is released
|
||||||
* Testing a feature with a specific set of users (by enabling only on a specific
|
- Testing a feature with a specific set of users (by enabling only on a specific
|
||||||
Element instance)
|
Element instance)
|
||||||
|
|
||||||
The size of the feature controlled by a feature flag may vary widely: it could
|
The size of the feature controlled by a feature flag may vary widely: it could
|
||||||
be a large project like reactions or a smaller change to an existing algorithm.
|
be a large project like reactions or a smaller change to an existing algorithm.
|
||||||
|
@ -37,6 +37,7 @@ When starting work on a feature, we should create a matching feature flag:
|
||||||
1. Add a new
|
1. Add a new
|
||||||
[setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.tsx)
|
[setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.tsx)
|
||||||
of the form:
|
of the form:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
"feature_cats": {
|
"feature_cats": {
|
||||||
isFeature: true,
|
isFeature: true,
|
||||||
|
@ -45,10 +46,13 @@ When starting work on a feature, we should create a matching feature flag:
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Check whether the feature is enabled as appropriate:
|
2. Check whether the feature is enabled as appropriate:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
SettingsStore.getValue("feature_cats")
|
SettingsStore.getValue("feature_cats");
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Document the feature in the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
3. Document the feature in the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
||||||
|
|
||||||
With these steps completed, the feature is disabled by default, but can be
|
With these steps completed, the feature is disabled by default, but can be
|
||||||
|
@ -88,12 +92,14 @@ cover these cases, change the setting's `default` in `Settings.tsx` to `true`.
|
||||||
Once we're confident that a feature is working well, we should remove or convert the flag.
|
Once we're confident that a feature is working well, we should remove or convert the flag.
|
||||||
|
|
||||||
If the feature is meant to be turned off/on by the user:
|
If the feature is meant to be turned off/on by the user:
|
||||||
|
|
||||||
1. Remove `isFeature` from the [setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.ts)
|
1. Remove `isFeature` from the [setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.ts)
|
||||||
2. Change the `default` to `true` (if desired).
|
2. Change the `default` to `true` (if desired).
|
||||||
3. Remove the feature from the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
3. Remove the feature from the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
||||||
4. Celebrate! 🥳
|
4. Celebrate! 🥳
|
||||||
|
|
||||||
If the feature is meant to be forced on (non-configurable):
|
If the feature is meant to be forced on (non-configurable):
|
||||||
|
|
||||||
1. Remove the [setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.ts)
|
1. Remove the [setting](https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.ts)
|
||||||
2. Remove all `getValue` lines that test for the feature.
|
2. Remove all `getValue` lines that test for the feature.
|
||||||
3. Remove the feature from the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
3. Remove the feature from the [labs documentation](https://github.com/vector-im/element-web/blob/develop/docs/labs.md)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Jitsi wrapper developer docs
|
# Jitsi wrapper developer docs
|
||||||
|
|
||||||
*If you're looking for information on how to set up Jitsi in your Element, see
|
_If you're looking for information on how to set up Jitsi in your Element, see
|
||||||
[jitsi.md](./jitsi.md) instead.*
|
[jitsi.md](./jitsi.md) instead._
|
||||||
|
|
||||||
These docs are for developers wondering how the different conference buttons work
|
These docs are for developers wondering how the different conference buttons work
|
||||||
within Element. If you're not a developer, you're probably looking for [jitsi.md](./jitsi.md).
|
within Element. If you're not a developer, you're probably looking for [jitsi.md](./jitsi.md).
|
||||||
|
@ -46,24 +46,24 @@ end up creating a widget with a URL like `https://integrations.example.org?widge
|
||||||
The integration manager's wrapper will typically have another iframe to isolate the
|
The integration manager's wrapper will typically have another iframe to isolate the
|
||||||
widget from the client by yet another layer. The wrapper often provides other functionality
|
widget from the client by yet another layer. The wrapper often provides other functionality
|
||||||
which might not be available on the embedded site, such as a fullscreen button or the
|
which might not be available on the embedded site, such as a fullscreen button or the
|
||||||
communication layer with the client (all widgets *should* be talking to the client
|
communication layer with the client (all widgets _should_ be talking to the client
|
||||||
over `postMessage`, even if they aren't going to be using the widget APIs).
|
over `postMessage`, even if they aren't going to be using the widget APIs).
|
||||||
|
|
||||||
Widgets added with the `/addwidget` command will *not* be wrapped as they are not going
|
Widgets added with the `/addwidget` command will _not_ be wrapped as they are not going
|
||||||
through an integration manager. The widgets themselves *should* also work outside of
|
through an integration manager. The widgets themselves _should_ also work outside of
|
||||||
Element. Widgets currently have a "pop out" button which opens them in a new tab and
|
Element. Widgets currently have a "pop out" button which opens them in a new tab and
|
||||||
therefore have no connection back to Riot.
|
therefore have no connection back to Riot.
|
||||||
|
|
||||||
## Jitsi widgets from integration managers
|
## Jitsi widgets from integration managers
|
||||||
|
|
||||||
Integration managers will create an entire widget event and send it over `postMessage`
|
Integration managers will create an entire widget event and send it over `postMessage`
|
||||||
for the client to add to the room. This means that the integration manager gets to
|
for the client to add to the room. This means that the integration manager gets to
|
||||||
decide the conference domain, conference name, and other aspects of the widget. As
|
decide the conference domain, conference name, and other aspects of the widget. As
|
||||||
a result, users can end up with a Jitsi widget that does not use the same conference
|
a result, users can end up with a Jitsi widget that does not use the same conference
|
||||||
server they specified in their config.json - this is expected.
|
server they specified in their config.json - this is expected.
|
||||||
|
|
||||||
Some integration managers allow the user to change the conference name while others
|
Some integration managers allow the user to change the conference name while others
|
||||||
will generate one for the user.
|
will generate one for the user.
|
||||||
|
|
||||||
## Jitsi widgets generated by Element itself
|
## Jitsi widgets generated by Element itself
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ The Jitsi widget created by Element uses a local `jitsi.html` wrapper (or one ho
|
||||||
required `postMessage` calls are fulfilled.
|
required `postMessage` calls are fulfilled.
|
||||||
|
|
||||||
**Note**: Per [jitsi.md](./jitsi.md) the `preferredDomain` can also come from the server's
|
**Note**: Per [jitsi.md](./jitsi.md) the `preferredDomain` can also come from the server's
|
||||||
client .well-known data.
|
client .well-known data.
|
||||||
|
|
||||||
## The Jitsi wrapper in Element
|
## The Jitsi wrapper in Element
|
||||||
|
|
||||||
|
@ -92,9 +92,9 @@ and less risky to load. The local wrapper URL is populated with the conference i
|
||||||
from the original widget (which could be a v1 or v2 widget) so the user joins the right
|
from the original widget (which could be a v1 or v2 widget) so the user joins the right
|
||||||
call.
|
call.
|
||||||
|
|
||||||
Critically, when the widget URL is reconstructed it does *not* take into account the
|
Critically, when the widget URL is reconstructed it does _not_ take into account the
|
||||||
config.json's `preferredDomain` for Jitsi. If it did this, users would end up on different
|
config.json's `preferredDomain` for Jitsi. If it did this, users would end up on different
|
||||||
conference servers and therefore different calls entirely.
|
conference servers and therefore different calls entirely.
|
||||||
|
|
||||||
**Note**: Per [jitsi.md](./jitsi.md) the `preferredDomain` can also come from the server's
|
**Note**: Per [jitsi.md](./jitsi.md) the `preferredDomain` can also come from the server's
|
||||||
client .well-known data.
|
client .well-known data.
|
||||||
|
|
|
@ -24,13 +24,14 @@ Element will use the Jitsi server that is embedded in the widget, even if it is
|
||||||
one you configured. This is because conference calls must be held on a single Jitsi
|
one you configured. This is because conference calls must be held on a single Jitsi
|
||||||
server and cannot be split over multiple servers.
|
server and cannot be split over multiple servers.
|
||||||
|
|
||||||
However, you can configure Element to *start* a conference with your Jitsi server by adding
|
However, you can configure Element to _start_ a conference with your Jitsi server by adding
|
||||||
to your [config](./config.md) the following:
|
to your [config](./config.md) the following:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"preferredDomain": "your.jitsi.example.org"
|
"preferredDomain": "your.jitsi.example.org"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -46,11 +47,12 @@ domain will appear later in the URL as a configuration parameter.
|
||||||
**Hint**: If you want everyone on your homeserver to use the same Jitsi server by
|
**Hint**: If you want everyone on your homeserver to use the same Jitsi server by
|
||||||
default, and you are using element-web 1.6 or newer, set the following on your homeserver's
|
default, and you are using element-web 1.6 or newer, set the following on your homeserver's
|
||||||
`/.well-known/matrix/client` config:
|
`/.well-known/matrix/client` config:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"im.vector.riot.jitsi": {
|
"im.vector.riot.jitsi": {
|
||||||
"preferredDomain": "your.jitsi.example.org"
|
"preferredDomain": "your.jitsi.example.org"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
Running in Kubernetes
|
# Running in Kubernetes
|
||||||
=====================
|
|
||||||
|
|
||||||
In case you would like to deploy element-web in a kubernetes cluster you can use
|
In case you would like to deploy element-web in a kubernetes cluster you can use
|
||||||
the provided Kubernetes example below as a starting point. Note that this example assumes the
|
the provided Kubernetes example below as a starting point. Note that this example assumes the
|
||||||
|
@ -178,4 +177,3 @@ Then you can deploy it to your cluster with something like `kubectl apply -f my-
|
||||||
number: 80
|
number: 80
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
39
docs/labs.md
39
docs/labs.md
|
@ -4,6 +4,9 @@ If Labs is enabled in the [Element config](config.md), you can enable some of th
|
||||||
to `Settings->Labs`. This list is non-exhaustive and subject to change, chat in
|
to `Settings->Labs`. This list is non-exhaustive and subject to change, chat in
|
||||||
[#element-web:matrix.org](https://matrix.to/#/#element-web:matrix.org) for more information.
|
[#element-web:matrix.org](https://matrix.to/#/#element-web:matrix.org) for more information.
|
||||||
|
|
||||||
|
If a labs features gets more stable, it _may_ be promoted to a beta feature
|
||||||
|
(see [Betas](https://github.com/vector-im/element-web/blob/develop/docs/betas.md)).
|
||||||
|
|
||||||
**Be warned! Labs features are not finalised, they may be fragile, they may change, they may be
|
**Be warned! Labs features are not finalised, they may be fragile, they may change, they may be
|
||||||
dropped. Ask in the room if you are unclear about any details here.**
|
dropped. Ask in the room if you are unclear about any details here.**
|
||||||
|
|
||||||
|
@ -108,10 +111,6 @@ To enable message previews for reactions in DMs only, enable `feature_roomlist_p
|
||||||
Allows users to receive encrypted messages by creating a device that is stored
|
Allows users to receive encrypted messages by creating a device that is stored
|
||||||
encrypted on the server, as described in [MSC2697](https://github.com/matrix-org/matrix-doc/pull/2697).
|
encrypted on the server, as described in [MSC2697](https://github.com/matrix-org/matrix-doc/pull/2697).
|
||||||
|
|
||||||
## Hidden read receipts (`feature_hidden_read_receipts`)
|
|
||||||
|
|
||||||
Enables sending hidden read receipts as per [MSC2285](https://github.com/matrix-org/matrix-doc/pull/2285)
|
|
||||||
|
|
||||||
## Breadcrumbs v2 (`feature_breadcrumbs_v2`)
|
## Breadcrumbs v2 (`feature_breadcrumbs_v2`)
|
||||||
|
|
||||||
Instead of showing the horizontal list of breadcrumbs under the filter field, the new UX is an interactive context menu
|
Instead of showing the horizontal list of breadcrumbs under the filter field, the new UX is an interactive context menu
|
||||||
|
@ -123,7 +122,7 @@ Switches to a new room search experience.
|
||||||
|
|
||||||
## Extensible events rendering (`feature_extensible_events`) [In Development]
|
## Extensible events rendering (`feature_extensible_events`) [In Development]
|
||||||
|
|
||||||
*Intended for developer use only at the moment.*
|
_Intended for developer use only at the moment._
|
||||||
|
|
||||||
Extensible Events are a [new event format](https://github.com/matrix-org/matrix-doc/pull/1767) which
|
Extensible Events are a [new event format](https://github.com/matrix-org/matrix-doc/pull/1767) which
|
||||||
supports graceful fallback in unknown event types. Instead of rendering nothing or a blank space, events
|
supports graceful fallback in unknown event types. Instead of rendering nothing or a blank space, events
|
||||||
|
@ -146,14 +145,6 @@ If no right panel state is known for the room or it was closed on the last room
|
||||||
visit, it will default to the room member list. Otherwise, the saved card last
|
visit, it will default to the room member list. Otherwise, the saved card last
|
||||||
used in that room is shown.
|
used in that room is shown.
|
||||||
|
|
||||||
## Show current profile of users on historical messages (`feature_use_only_current_profiles`)
|
|
||||||
|
|
||||||
An experimental flag to determine how the app would behave if a user's current display
|
|
||||||
name and avatar (profile) were shown on historical messages instead of the profile details
|
|
||||||
at the time when the message was sent.
|
|
||||||
|
|
||||||
When enabled, historical messages will use the current profile for the sender.
|
|
||||||
|
|
||||||
## Live location sharing (`feature_location_share_live`) [In Development]
|
## Live location sharing (`feature_location_share_live`) [In Development]
|
||||||
|
|
||||||
Enables sharing your current location to the timeline, with live updates.
|
Enables sharing your current location to the timeline, with live updates.
|
||||||
|
@ -164,18 +155,24 @@ Threading allows users to branch out a new conversation from the main timeline o
|
||||||
|
|
||||||
Threads can be access by clicking their summary below the root event on the room timeline. Users can find a comprehensive list of threads by click the icon on the room header button.
|
Threads can be access by clicking their summary below the root event on the room timeline. Users can find a comprehensive list of threads by click the icon on the room header button.
|
||||||
|
|
||||||
This feature might work in degraded mode if the homeserver a user is connected to does not advertise support for the unstable feature `org.matrix.msc3440` when calling the `/versions` API endpoint.
|
This feature might work in degraded mode if the homeserver a user is connected to does not advertise support for the unstable feature `org.matrix.msc3440` when calling the `/versions` API endpoint.
|
||||||
|
|
||||||
## Right-click Message Context Menu (`feature_message_right_click_context_menu`)
|
|
||||||
|
|
||||||
Enables showing a right-click context menu when right-clicking messages in the
|
|
||||||
timeline. This menu shows options that can usually be found in the message
|
|
||||||
action bar or in the message options.
|
|
||||||
|
|
||||||
## Video rooms (`feature_video_rooms`)
|
## Video rooms (`feature_video_rooms`)
|
||||||
|
|
||||||
Enables support for creating and joining video rooms, which are persistent video chats that users can jump in and out of.
|
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]
|
## Rich text in room topics (`feature_html_topic`) [In Development]
|
||||||
|
|
||||||
Enables rendering of MD / HTML in room topics.
|
Enables rendering of MD / HTML in room topics.
|
||||||
|
@ -187,4 +184,4 @@ have [MSC3827](https://github.com/matrix-org/matrix-spec-proposals/pull/3827) en
|
||||||
|
|
||||||
## Favourite Messages (`feature_favourite_messages`) [In Development]
|
## Favourite Messages (`feature_favourite_messages`) [In Development]
|
||||||
|
|
||||||
Enables users to bookmark a message or content for a later reference.
|
Enables users to bookmark a message or content for a later reference.
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
## Memory leaks
|
## Memory leaks
|
||||||
|
|
||||||
Element usually emits slow behaviour just before it is about to crash. Getting a
|
Element usually emits slow behaviour just before it is about to crash. Getting a
|
||||||
memory snapshot (below) just before that happens is ideal in figuring out what
|
memory snapshot (below) just before that happens is ideal in figuring out what
|
||||||
is going wrong.
|
is going wrong.
|
||||||
|
|
||||||
Common symptoms are clicking on a room and it feels like the tab froze and scrolling
|
Common symptoms are clicking on a room and it feels like the tab froze and scrolling
|
||||||
becoming jumpy/staggered.
|
becoming jumpy/staggered.
|
||||||
|
|
||||||
If you receive a white screen (electron) or the chrome crash page, it is likely
|
If you receive a white screen (electron) or the chrome crash page, it is likely
|
||||||
run out of memory and it is too late for a memory profile. Please do report when
|
run out of memory and it is too late for a memory profile. Please do report when
|
||||||
|
@ -22,8 +22,8 @@ and anything newer is still in the warmup stages of the app.
|
||||||
|
|
||||||
**Memory profiles can contain sensitive information.** If you are submitting a memory
|
**Memory profiles can contain sensitive information.** If you are submitting a memory
|
||||||
profile to us for debugging purposes, please pick the appropriate Element developer and
|
profile to us for debugging purposes, please pick the appropriate Element developer and
|
||||||
send them over an encrypted private message. *Do not share your memory profile in
|
send them over an encrypted private message. _Do not share your memory profile in
|
||||||
public channels or with people you do not trust.*
|
public channels or with people you do not trust._
|
||||||
|
|
||||||
### Taking a memory profile (Firefox)
|
### Taking a memory profile (Firefox)
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ our [ILAG module](https://github.com/vector-im/element-web-ilag-module) which wi
|
||||||
structure of a module is and how it works.
|
structure of a module is and how it works.
|
||||||
|
|
||||||
The following requirements are key for any module:
|
The following requirements are key for any module:
|
||||||
|
|
||||||
1. The module must depend on `@matrix-org/react-sdk-module-api` (usually as a dev dependency).
|
1. The module must depend on `@matrix-org/react-sdk-module-api` (usually as a dev dependency).
|
||||||
2. The module's `main` entrypoint must have a `default` export for the `RuntimeModule` instance, supporting a constructor
|
2. The module's `main` entrypoint must have a `default` export for the `RuntimeModule` instance, supporting a constructor
|
||||||
which takes a single parameter: a `ModuleApi` instance. This instance is passed to `super()`.
|
which takes a single parameter: a `ModuleApi` instance. This instance is passed to `super()`.
|
||||||
|
|
|
@ -10,53 +10,53 @@ When reviewing code, here are some things we look for and also things we avoid:
|
||||||
|
|
||||||
### We review for
|
### We review for
|
||||||
|
|
||||||
* Correctness
|
- Correctness
|
||||||
* Performance
|
- Performance
|
||||||
* Accessibility
|
- Accessibility
|
||||||
* Security
|
- Security
|
||||||
* Quality via automated and manual testing
|
- Quality via automated and manual testing
|
||||||
* Comments and documentation where needed
|
- Comments and documentation where needed
|
||||||
* Sharing knowledge of different areas among the team
|
- Sharing knowledge of different areas among the team
|
||||||
* Ensuring it's something we're comfortable maintaining for the long term
|
- Ensuring it's something we're comfortable maintaining for the long term
|
||||||
* Progress indicators and local echo where appropriate with network activity
|
- Progress indicators and local echo where appropriate with network activity
|
||||||
|
|
||||||
### We should avoid
|
### We should avoid
|
||||||
|
|
||||||
* Style nits that are already handled by the linter
|
- Style nits that are already handled by the linter
|
||||||
* Dramatically increasing scope
|
- Dramatically increasing scope
|
||||||
|
|
||||||
### Good practices
|
### Good practices
|
||||||
|
|
||||||
* Use empathetic language
|
- Use empathetic language
|
||||||
* See also [Mindful Communication in Code
|
- See also [Mindful Communication in Code
|
||||||
Reviews](https://kickstarter.engineering/a-guide-to-mindful-communication-in-code-reviews-48aab5282e5e)
|
Reviews](https://kickstarter.engineering/a-guide-to-mindful-communication-in-code-reviews-48aab5282e5e)
|
||||||
and [How to Do Code Reviews Like a Human](https://mtlynch.io/human-code-reviews-1/)
|
and [How to Do Code Reviews Like a Human](https://mtlynch.io/human-code-reviews-1/)
|
||||||
* Authors should prefer smaller commits for easier reviewing and bisection
|
- Authors should prefer smaller commits for easier reviewing and bisection
|
||||||
* Reviewers should be explicit about required versus optional changes
|
- Reviewers should be explicit about required versus optional changes
|
||||||
* Reviews are conversations and the PR author should feel comfortable
|
- Reviews are conversations and the PR author should feel comfortable
|
||||||
discussing and pushing back on changes before making them
|
discussing and pushing back on changes before making them
|
||||||
* Reviewers are encouraged to ask for tests where they believe it is reasonable
|
- Reviewers are encouraged to ask for tests where they believe it is reasonable
|
||||||
* Core team should lead by example through their tone and language
|
- Core team should lead by example through their tone and language
|
||||||
* Take the time to thank and point out good code changes
|
- Take the time to thank and point out good code changes
|
||||||
* Using softer language like "please" and "what do you think?" goes a long way
|
- Using softer language like "please" and "what do you think?" goes a long way
|
||||||
towards making others feel like colleagues working towards a common goal
|
towards making others feel like colleagues working towards a common goal
|
||||||
|
|
||||||
### Workflow
|
### Workflow
|
||||||
|
|
||||||
* Authors should request review from the element-web team by default (if someone on
|
- Authors should request review from the element-web team by default (if someone on
|
||||||
the team is clearly the expert in an area, a direct review request to them may
|
the team is clearly the expert in an area, a direct review request to them may
|
||||||
be more appropriate)
|
be more appropriate)
|
||||||
* Reviewers should remove the team review request and request review from
|
- Reviewers should remove the team review request and request review from
|
||||||
themselves when starting a review to avoid double review
|
themselves when starting a review to avoid double review
|
||||||
* If there are multiple related PRs authors should reference each of the PRs in
|
- If there are multiple related PRs authors should reference each of the PRs in
|
||||||
the others before requesting review. Reviewers might start reviewing from
|
the others before requesting review. Reviewers might start reviewing from
|
||||||
different places and could miss other required PRs.
|
different places and could miss other required PRs.
|
||||||
* Avoid force pushing to a PR after the first round of review
|
- Avoid force pushing to a PR after the first round of review
|
||||||
* Use the GitHub default of merge commits when landing (avoid alternate options
|
- Use the GitHub default of merge commits when landing (avoid alternate options
|
||||||
like squash or rebase)
|
like squash or rebase)
|
||||||
* PR author merges after review (assuming they have write access)
|
- PR author merges after review (assuming they have write access)
|
||||||
* Assign issues only when in progress to indicate to others what can be picked
|
- Assign issues only when in progress to indicate to others what can be picked
|
||||||
up
|
up
|
||||||
|
|
||||||
## Code Quality
|
## Code Quality
|
||||||
|
|
||||||
|
@ -64,10 +64,10 @@ In the past, we have occasionally written different kinds of tests for
|
||||||
Element and the SDKs, but it hasn't been a consistent focus. Going forward, we'd
|
Element and the SDKs, but it hasn't been a consistent focus. Going forward, we'd
|
||||||
like to change that.
|
like to change that.
|
||||||
|
|
||||||
* For new features, code reviewers will expect some form of automated testing to
|
- For new features, code reviewers will expect some form of automated testing to
|
||||||
be included by default
|
be included by default
|
||||||
* For bug fixes, regression tests are of course great to have, but we don't want
|
- For bug fixes, regression tests are of course great to have, but we don't want
|
||||||
to block fixes on this, so we won't require them at this time
|
to block fixes on this, so we won't require them at this time
|
||||||
|
|
||||||
The above policy is not a strict rule, but instead it's meant to be a
|
The above policy is not a strict rule, but instead it's meant to be a
|
||||||
conversation between the author and reviewer. As an author, try to think about
|
conversation between the author and reviewer. As an author, try to think about
|
||||||
|
@ -104,10 +104,10 @@ perspective.
|
||||||
In more detail, our usual process for changes that affect the UI or alter user
|
In more detail, our usual process for changes that affect the UI or alter user
|
||||||
functionality is:
|
functionality is:
|
||||||
|
|
||||||
* For changes that will go live when merged, always flag Design and Product
|
- For changes that will go live when merged, always flag Design and Product
|
||||||
teams as appropriate
|
teams as appropriate
|
||||||
* For changes guarded by a feature flag, Design and Product review is not
|
- For changes guarded by a feature flag, Design and Product review is not
|
||||||
required (though may still be useful) since we can continue tweaking
|
required (though may still be useful) since we can continue tweaking
|
||||||
|
|
||||||
As it can be difficult to review design work from looking at just the changed
|
As it can be difficult to review design work from looking at just the changed
|
||||||
files in a PR, a [preview site](./pr-previews.md) that includes your changes
|
files in a PR, a [preview site](./pr-previews.md) that includes your changes
|
||||||
|
|
|
@ -1,31 +1,29 @@
|
||||||
Theming Element
|
# Theming Element
|
||||||
============
|
|
||||||
|
|
||||||
Themes are a very basic way of providing simple alternative look & feels to the
|
Themes are a very basic way of providing simple alternative look & feels to the
|
||||||
Element app via CSS & custom imagery.
|
Element app via CSS & custom imagery.
|
||||||
|
|
||||||
They are *NOT* co be confused with 'skins', which describe apps which sit on top
|
They are _NOT_ co be confused with 'skins', which describe apps which sit on top
|
||||||
of matrix-react-sdk - e.g. in theory Element itself is a react-sdk skin.
|
of matrix-react-sdk - e.g. in theory Element itself is a react-sdk skin.
|
||||||
As of March 2022, skins are not fully supported; Element is the only available skin.
|
As of March 2022, skins are not fully supported; Element is the only available skin.
|
||||||
|
|
||||||
To define a theme for Element:
|
To define a theme for Element:
|
||||||
|
|
||||||
1. Pick a name, e.g. `teal`. at time of writing we have `light` and `dark`.
|
1. Pick a name, e.g. `teal`. at time of writing we have `light` and `dark`.
|
||||||
2. Fork `src/skins/vector/css/themes/dark.pcss` to be `teal.pcss`
|
2. Fork `src/skins/vector/css/themes/dark.pcss` to be `teal.pcss`
|
||||||
3. Fork `src/skins/vector/css/themes/_base.pcss` to be `_teal.pcss`
|
3. Fork `src/skins/vector/css/themes/_base.pcss` to be `_teal.pcss`
|
||||||
4. Override variables in `_teal.pcss` as desired. You may wish to delete ones
|
4. Override variables in `_teal.pcss` as desired. You may wish to delete ones
|
||||||
which don't differ from `_base.pcss`, to make it clear which are being
|
which don't differ from `_base.pcss`, to make it clear which are being
|
||||||
overridden. If every single colour is being changed (as per `_dark.pcss`)
|
overridden. If every single colour is being changed (as per `_dark.pcss`)
|
||||||
then you might as well keep them all.
|
then you might as well keep them all.
|
||||||
5. Add the theme to the list of entrypoints in webpack.config.js
|
5. Add the theme to the list of entrypoints in webpack.config.js
|
||||||
6. Add the theme to the list of themes in matrix-react-sdk's UserSettings.js
|
6. Add the theme to the list of themes in matrix-react-sdk's UserSettings.js
|
||||||
7. Sit back and admire your handywork.
|
7. Sit back and admire your handywork.
|
||||||
|
|
||||||
In future, the assets for a theme will probably be gathered together into a
|
In future, the assets for a theme will probably be gathered together into a
|
||||||
single directory tree.
|
single directory tree.
|
||||||
|
|
||||||
Custom Themes
|
# Custom Themes
|
||||||
=============
|
|
||||||
|
|
||||||
Themes derived from the built in themes may also be defined in settings.
|
Themes derived from the built in themes may also be defined in settings.
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- A working [Development Setup](../README.md#setting-up-a-dev-environment)
|
- A working [Development Setup](../README.md#setting-up-a-dev-environment)
|
||||||
- Including up-to-date versions of matrix-react-sdk and matrix-js-sdk
|
- Including up-to-date versions of matrix-react-sdk and matrix-js-sdk
|
||||||
- Latest LTS version of Node.js installed
|
- Latest LTS version of Node.js installed
|
||||||
- Be able to understand English
|
- Be able to understand English
|
||||||
- Be able to understand the language you want to translate Element into
|
- Be able to understand the language you want to translate Element into
|
||||||
|
|
||||||
## Translating strings vs. marking strings for translation
|
## Translating strings vs. marking strings for translation
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ Translating strings are done with the `_t()` function found in matrix-react-sdk/
|
||||||
Basically, whenever a translatable string is introduced, you should call either `_t()` immediately OR `_td()` and later `_t()`.
|
Basically, whenever a translatable string is introduced, you should call either `_t()` immediately OR `_td()` and later `_t()`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
// Module-level constant
|
// Module-level constant
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
|
@ -30,10 +31,10 @@ function getColorName(hex) {
|
||||||
|
|
||||||
## Adding new strings
|
## Adding new strings
|
||||||
|
|
||||||
1. Check if the import ``import { _t } from 'matrix-react-sdk/src/languageHandler';`` is present. If not add it to the other import statements. Also import `_td` if needed.
|
1. Check if the import `import { _t } from 'matrix-react-sdk/src/languageHandler';` is present. If not add it to the other import statements. Also import `_td` if needed.
|
||||||
1. Add ``_t()`` to your string. (Don't forget curly braces when you assign an expression to JSX attributes in the render method). If the string is introduced at a point before the translation system has not yet been initialized, use `_td()` instead, and call `_t()` at the appropriate time.
|
1. Add `_t()` to your string. (Don't forget curly braces when you assign an expression to JSX attributes in the render method). If the string is introduced at a point before the translation system has not yet been initialized, use `_td()` instead, and call `_t()` at the appropriate time.
|
||||||
1. Run `yarn i18n` to update ``src/i18n/strings/en_EN.json``
|
1. Run `yarn i18n` to update `src/i18n/strings/en_EN.json`
|
||||||
1. If you added a string with a plural, you can add other English plural variants to ``src/i18n/strings/en_EN.json`` (remeber to edit the one in the same project as the source file containing your new translation).
|
1. If you added a string with a plural, you can add other English plural variants to `src/i18n/strings/en_EN.json` (remeber to edit the one in the same project as the source file containing your new translation).
|
||||||
|
|
||||||
## Editing existing strings
|
## Editing existing strings
|
||||||
|
|
||||||
|
@ -43,21 +44,21 @@ function getColorName(hex) {
|
||||||
|
|
||||||
## Adding variables inside a string.
|
## Adding variables inside a string.
|
||||||
|
|
||||||
1. Extend your ``_t()`` call. Instead of ``_t(STRING)`` use ``_t(STRING, {})``
|
1. Extend your `_t()` call. Instead of `_t(STRING)` use `_t(STRING, {})`
|
||||||
1. Decide how to name it. Please think about if the person who has to translate it can understand what it does. E.g. using the name 'recipient' is bad, because a translator does not know if it is the name of a person, an email address, a user ID, etc. Rather use e.g. recipientEmailAddress.
|
1. Decide how to name it. Please think about if the person who has to translate it can understand what it does. E.g. using the name 'recipient' is bad, because a translator does not know if it is the name of a person, an email address, a user ID, etc. Rather use e.g. recipientEmailAddress.
|
||||||
1. Add it to the array in ``_t`` for example ``_t(STRING, {variable: this.variable})``
|
1. Add it to the array in `_t` for example `_t(STRING, {variable: this.variable})`
|
||||||
1. Add the variable inside the string. The syntax for variables is ``%(variable)s``. Please note the _s_ at the end. The name of the variable has to match the previous used name.
|
1. Add the variable inside the string. The syntax for variables is `%(variable)s`. Please note the _s_ at the end. The name of the variable has to match the previous used name.
|
||||||
|
|
||||||
- You can use the special ``count`` variable to choose between multiple versions of the same string, in order to get the correct pluralization. E.g. ``_t('You have %(count)s new messages', { count: 2 })`` would show 'You have 2 new messages', while ``_t('You have %(count)s new messages', { count: 1 })`` would show 'You have one new message' (assuming a singular version of the string has been added to the translation file. See above). Passing in ``count`` is much prefered over having an if-statement choose the correct string to use, because some languages have much more complicated plural rules than english (e.g. they might need a completely different form if there are three things rather than two).
|
- You can use the special `count` variable to choose between multiple versions of the same string, in order to get the correct pluralization. E.g. `_t('You have %(count)s new messages', { count: 2 })` would show 'You have 2 new messages', while `_t('You have %(count)s new messages', { count: 1 })` would show 'You have one new message' (assuming a singular version of the string has been added to the translation file. See above). Passing in `count` is much prefered over having an if-statement choose the correct string to use, because some languages have much more complicated plural rules than english (e.g. they might need a completely different form if there are three things rather than two).
|
||||||
- If you want to translate text that includes e.g. hyperlinks or other HTML you have to also use tag substitution, e.g. ``_t('<a>Click here!</a>', {}, { 'a': (sub) => <a>{sub}</a> })``. If you don't do the tag substitution you will end up showing literally '<a>' rather than making a hyperlink.
|
- If you want to translate text that includes e.g. hyperlinks or other HTML you have to also use tag substitution, e.g. `_t('<a>Click here!</a>', {}, { 'a': (sub) => <a>{sub}</a> })`. If you don't do the tag substitution you will end up showing literally '<a>' rather than making a hyperlink.
|
||||||
- You can also use React components with normal variable substitution if you want to insert HTML markup, e.g. ``_t('Your email address is %(emailAddress)s', { emailAddress: <i>{userEmailAddress}</i> })``.
|
- You can also use React components with normal variable substitution if you want to insert HTML markup, e.g. `_t('Your email address is %(emailAddress)s', { emailAddress: <i>{userEmailAddress}</i> })`.
|
||||||
|
|
||||||
## Things to know/Style Guides
|
## Things to know/Style Guides
|
||||||
|
|
||||||
- Do not use `_t()` inside ``getDefaultProps``: the translations aren't loaded when `getDefaultProps` is called, leading to missing translations. Use `_td()` to indicate that `_t()` will be called on the string later.
|
- Do not use `_t()` inside `getDefaultProps`: the translations aren't loaded when `getDefaultProps` is called, leading to missing translations. Use `_td()` to indicate that `_t()` will be called on the string later.
|
||||||
- If using translated strings as constants, translated strings can't be in constants loaded at class-load time since the translations won't be loaded. Mark the strings using `_td()` instead and perform the actual translation later.
|
- If using translated strings as constants, translated strings can't be in constants loaded at class-load time since the translations won't be loaded. Mark the strings using `_td()` instead and perform the actual translation later.
|
||||||
- If a string is presented in the UI with punctuation like a full stop, include this in the translation strings, since punctuation varies between languages too.
|
- If a string is presented in the UI with punctuation like a full stop, include this in the translation strings, since punctuation varies between languages too.
|
||||||
- Avoid "translation in parts", i.e. concatenating translated strings or using translated strings in variable substitutions. Context is important for translations, and translating partial strings this way is simply not always possible.
|
- Avoid "translation in parts", i.e. concatenating translated strings or using translated strings in variable substitutions. Context is important for translations, and translating partial strings this way is simply not always possible.
|
||||||
- Concatenating strings often also introduces an implicit assumption about word order (e.g. that the subject of the sentence comes first), which is incorrect for many languages.
|
- Concatenating strings often also introduces an implicit assumption about word order (e.g. that the subject of the sentence comes first), which is incorrect for many languages.
|
||||||
- Translation 'smell test': If you have a string that does not begin with a capital letter (is not the start of a sentence) or it ends with e.g. ':' or a preposition (e.g. 'to') you should recheck that you are not trying to translate a partial sentence.
|
- Translation 'smell test': If you have a string that does not begin with a capital letter (is not the start of a sentence) or it ends with e.g. ':' or a preposition (e.g. 'to') you should recheck that you are not trying to translate a partial sentence.
|
||||||
- If you have multiple strings, that are almost identical, except some part (e.g. a word or two) it is still better to translate the full sentence multiple times. It may seem like inefficient repetion, but unlike programming where you try to minimize repetition, translation is much faster if you have many, full, clear, sentences to work with, rather than fewer, but incomplete sentence fragments.
|
- If you have multiple strings, that are almost identical, except some part (e.g. a word or two) it is still better to translate the full sentence multiple times. It may seem like inefficient repetion, but unlike programming where you try to minimize repetition, translation is much faster if you have many, full, clear, sentences to work with, rather than fewer, but incomplete sentence fragments.
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Web Browser
|
- Web Browser
|
||||||
- Be able to understand English
|
- Be able to understand English
|
||||||
- Be able to understand the language you want to translate Element into
|
- Be able to understand the language you want to translate Element into
|
||||||
|
|
||||||
## Step 0: Join #element-translations:matrix.org
|
## Step 0: Join #element-translations:matrix.org
|
||||||
|
|
||||||
1. Come and join https://matrix.to/#/#element-translations:matrix.org for general discussion
|
1. Come and join https://matrix.to/#/#element-translations:matrix.org for general discussion
|
||||||
2. Join https://matrix.to/#/#element-translators:matrix.org for language-specific rooms
|
2. Join https://matrix.to/#/#element-translators:matrix.org for language-specific rooms
|
||||||
3. Read scrollback and/or ask if anyone else is working on your language, and co-ordinate if needed. In general little-or-no coordination is needed though :)
|
3. Read scrollback and/or ask if anyone else is working on your language, and co-ordinate if needed. In general little-or-no coordination is needed though :)
|
||||||
|
|
||||||
## Step 1: Preparing your Weblate Profile
|
## Step 1: Preparing your Weblate Profile
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ If your language is listed go to Step 2a and if not go to Step 2b
|
||||||
## Step 2a: Helping on existing languages.
|
## Step 2a: Helping on existing languages.
|
||||||
|
|
||||||
1. Head to one of the projects listed https://translate.element.io/projects/element-web/
|
1. Head to one of the projects listed https://translate.element.io/projects/element-web/
|
||||||
2. Click on the ``translate`` button on the right side of your language
|
2. Click on the `translate` button on the right side of your language
|
||||||
3. Fill in the translations in the writeable field. You will see the original English string and the string of your second language above.
|
3. Fill in the translations in the writeable field. You will see the original English string and the string of your second language above.
|
||||||
|
|
||||||
Head to the explanations under Steb 2b
|
Head to the explanations under Steb 2b
|
||||||
|
@ -35,7 +35,7 @@ Head to the explanations under Steb 2b
|
||||||
## Step 2b: Adding a new language
|
## Step 2b: Adding a new language
|
||||||
|
|
||||||
1. Go to one of the projects listed https://translate.element.io/projects/element-web/
|
1. Go to one of the projects listed https://translate.element.io/projects/element-web/
|
||||||
2. Click the ``Start new translation`` button at the bottom
|
2. Click the `Start new translation` button at the bottom
|
||||||
3. Select a language
|
3. Select a language
|
||||||
4. Start translating like in 2a.3
|
4. Start translating like in 2a.3
|
||||||
5. Repeat these steps for the other projects which are listed at the link of step 2b.1
|
5. Repeat these steps for the other projects which are listed at the link of step 2b.1
|
||||||
|
@ -52,13 +52,12 @@ The yellow button has to be used if you are unsure about the translation but you
|
||||||
|
|
||||||
These things are variables that are expanded when displayed by Element. They can be room names, usernames or similar. If you find one, you can move to the right place for your language, but not delete it as the variable will be missing if you do.
|
These things are variables that are expanded when displayed by Element. They can be room names, usernames or similar. If you find one, you can move to the right place for your language, but not delete it as the variable will be missing if you do.
|
||||||
|
|
||||||
A special case is `%(urlStart)s` and `%(urlEnd)s` which are used to mark the beginning of a hyperlink (i.e. `<a href="/somewhere">` and `</a>`. You must keep these markers surrounding the equivalent string in your language that needs to be hyperlinked.
|
A special case is `%(urlStart)s` and `%(urlEnd)s` which are used to mark the beginning of a hyperlink (i.e. `<a href="/somewhere">` and `</a>`. You must keep these markers surrounding the equivalent string in your language that needs to be hyperlinked.
|
||||||
|
|
||||||
### "I want to come back to this string. How?"
|
### "I want to come back to this string. How?"
|
||||||
|
|
||||||
You can use inside the translation field "Review needed" checkbox. It will be shown as Strings that need to be reviewed.
|
You can use inside the translation field "Review needed" checkbox. It will be shown as Strings that need to be reviewed.
|
||||||
|
|
||||||
|
|
||||||
### Further reading
|
### Further reading
|
||||||
|
|
||||||
The official Weblate doc provides some more in-depth explanation on how to do translations and talks about do and don'ts. You can find it at: https://docs.weblate.org/en/latest/user/translating.html
|
The official Weblate doc provides some more in-depth explanation on how to do translations and talks about do and don'ts. You can find it at: https://docs.weblate.org/en/latest/user/translating.html
|
||||||
|
|
|
@ -15,11 +15,7 @@
|
||||||
"uisi_autorageshake_app": "element-auto-uisi",
|
"uisi_autorageshake_app": "element-auto-uisi",
|
||||||
"showLabsSettings": false,
|
"showLabsSettings": false,
|
||||||
"roomDirectory": {
|
"roomDirectory": {
|
||||||
"servers": [
|
"servers": ["matrix.org", "gitter.im", "libera.chat"]
|
||||||
"matrix.org",
|
|
||||||
"gitter.im",
|
|
||||||
"libera.chat"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"enable_presence_by_hs_url": {
|
"enable_presence_by_hs_url": {
|
||||||
"https://matrix.org": false,
|
"https://matrix.org": false,
|
||||||
|
@ -36,14 +32,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hostSignup": {
|
"hostSignup": {
|
||||||
"brand": "Element Home",
|
"brand": "Element Home",
|
||||||
"cookiePolicyUrl": "https://element.io/cookie-policy",
|
"cookiePolicyUrl": "https://element.io/cookie-policy",
|
||||||
"domains": [
|
"domains": ["matrix.org"],
|
||||||
"matrix.org"
|
"privacyPolicyUrl": "https://element.io/privacy",
|
||||||
],
|
"termsOfServiceUrl": "https://element.io/terms-of-service",
|
||||||
"privacyPolicyUrl": "https://element.io/privacy",
|
"url": "https://ems.element.io/element-home/in-app-loader"
|
||||||
"termsOfServiceUrl": "https://element.io/terms-of-service",
|
|
||||||
"url": "https://ems.element.io/element-home/in-app-loader"
|
|
||||||
},
|
},
|
||||||
"posthog": {
|
"posthog": {
|
||||||
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# download and unpack a element-web tarball.
|
|
||||||
#
|
|
||||||
# Allows `bundles` to be extracted to a common directory, and a link to
|
|
||||||
# config.json to be added.
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tarfile
|
|
||||||
import shutil
|
|
||||||
import glob
|
|
||||||
|
|
||||||
try:
|
|
||||||
# python3
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
except ImportError:
|
|
||||||
# python2
|
|
||||||
from urllib import urlretrieve
|
|
||||||
|
|
||||||
class DeployException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def create_relative_symlink(linkname, target):
|
|
||||||
relpath = os.path.relpath(target, os.path.dirname(linkname))
|
|
||||||
print ("Symlink %s -> %s" % (linkname, relpath))
|
|
||||||
os.symlink(relpath, linkname)
|
|
||||||
|
|
||||||
|
|
||||||
def move_bundles(source, dest):
|
|
||||||
"""Move the contents of the 'bundles' directory to a common dir
|
|
||||||
|
|
||||||
We check that we will not be overwriting anything before we proceed.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
source (str): path to 'bundles' within the extracted tarball
|
|
||||||
dest (str): target common directory
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not os.path.isdir(dest):
|
|
||||||
os.mkdir(dest)
|
|
||||||
|
|
||||||
# build a map from source to destination, checking for non-existence as we go.
|
|
||||||
renames = {}
|
|
||||||
for f in os.listdir(source):
|
|
||||||
dst = os.path.join(dest, f)
|
|
||||||
if os.path.exists(dst):
|
|
||||||
print (
|
|
||||||
"Skipping bundle. The bundle includes '%s' which we have previously deployed."
|
|
||||||
% f
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
renames[os.path.join(source, f)] = dst
|
|
||||||
|
|
||||||
for (src, dst) in renames.iteritems():
|
|
||||||
print ("Move %s -> %s" % (src, dst))
|
|
||||||
os.rename(src, dst)
|
|
||||||
|
|
||||||
class Deployer:
|
|
||||||
def __init__(self):
|
|
||||||
self.packages_path = "."
|
|
||||||
self.bundles_path = None
|
|
||||||
self.should_clean = False
|
|
||||||
# filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json'
|
|
||||||
self.symlink_paths = {}
|
|
||||||
self.verify_signature = True
|
|
||||||
|
|
||||||
def deploy(self, tarball, extract_path):
|
|
||||||
"""Download a tarball if necessary, and unpack it
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(str) the path to the unpacked deployment
|
|
||||||
"""
|
|
||||||
print("Deploying %s to %s" % (tarball, extract_path))
|
|
||||||
|
|
||||||
name_str = os.path.basename(tarball).replace(".tar.gz", "")
|
|
||||||
extracted_dir = os.path.join(extract_path, name_str)
|
|
||||||
if os.path.exists(extracted_dir):
|
|
||||||
raise DeployException('Cannot unpack %s: %s already exists' % (
|
|
||||||
tarball, extracted_dir))
|
|
||||||
|
|
||||||
downloaded = False
|
|
||||||
if tarball.startswith("http://") or tarball.startswith("https://"):
|
|
||||||
tarball = self.download_and_verify(tarball)
|
|
||||||
print("Downloaded file: %s" % tarball)
|
|
||||||
downloaded = True
|
|
||||||
|
|
||||||
try:
|
|
||||||
with tarfile.open(tarball) as tar:
|
|
||||||
tar.extractall(extract_path)
|
|
||||||
finally:
|
|
||||||
if self.should_clean and downloaded:
|
|
||||||
os.remove(tarball)
|
|
||||||
|
|
||||||
print ("Extracted into: %s" % extracted_dir)
|
|
||||||
|
|
||||||
if self.symlink_paths:
|
|
||||||
for link_path, file_path in self.symlink_paths.iteritems():
|
|
||||||
create_relative_symlink(
|
|
||||||
target=file_path,
|
|
||||||
linkname=os.path.join(extracted_dir, link_path)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.bundles_path:
|
|
||||||
extracted_bundles = os.path.join(extracted_dir, 'bundles')
|
|
||||||
move_bundles(source=extracted_bundles, dest=self.bundles_path)
|
|
||||||
|
|
||||||
# replace the extracted_bundles dir (which may not be empty if some
|
|
||||||
# bundles were skipped) with a symlink to the common dir.
|
|
||||||
shutil.rmtree(extracted_bundles)
|
|
||||||
create_relative_symlink(
|
|
||||||
target=self.bundles_path,
|
|
||||||
linkname=extracted_bundles,
|
|
||||||
)
|
|
||||||
return extracted_dir
|
|
||||||
|
|
||||||
def download_and_verify(self, url):
|
|
||||||
tarball = self.download_file(url)
|
|
||||||
|
|
||||||
if self.verify_signature:
|
|
||||||
sigfile = self.download_file(url + ".asc")
|
|
||||||
subprocess.check_call(["gpg", "--verify", sigfile, tarball])
|
|
||||||
|
|
||||||
return tarball
|
|
||||||
|
|
||||||
def download_file(self, url):
|
|
||||||
if not os.path.isdir(self.packages_path):
|
|
||||||
os.mkdir(self.packages_path)
|
|
||||||
local_filename = os.path.join(self.packages_path,
|
|
||||||
url.split('/')[-1])
|
|
||||||
sys.stdout.write("Downloading %s -> %s..." % (url, local_filename))
|
|
||||||
sys.stdout.flush()
|
|
||||||
urlretrieve(url, local_filename)
|
|
||||||
print ("Done")
|
|
||||||
return local_filename
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser("Deploy a Riot build on a web server.")
|
|
||||||
parser.add_argument(
|
|
||||||
"-p", "--packages-dir", default="./packages", help=(
|
|
||||||
"The directory to download the tarball into. (Default: '%(default)s')"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-e", "--extract-path", default="./deploys", help=(
|
|
||||||
"The location to extract .tar.gz files to. (Default: '%(default)s')"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-b", "--bundles-dir", nargs='?', default="./bundles", help=(
|
|
||||||
"A directory to move the contents of the 'bundles' directory to. A \
|
|
||||||
symlink to the bundles directory will also be written inside the \
|
|
||||||
extracted tarball. Example: './bundles'. \
|
|
||||||
(Default: '%(default)s')"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-c", "--clean", action="store_true", default=False, help=(
|
|
||||||
"Remove .tar.gz files after they have been downloaded and extracted. \
|
|
||||||
(Default: %(default)s)"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--include", nargs='*', default=['./config*.json'], help=(
|
|
||||||
"Symlink these files into the root of the deployed tarball. \
|
|
||||||
Useful for config files and home pages. Supports glob syntax. \
|
|
||||||
(Default: '%(default)s')"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"tarball", help=(
|
|
||||||
"filename of tarball, or URL to download."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
deployer = Deployer()
|
|
||||||
deployer.packages_path = args.packages_dir
|
|
||||||
deployer.bundles_path = args.bundles_dir
|
|
||||||
deployer.should_clean = args.clean
|
|
||||||
|
|
||||||
for include in args.include:
|
|
||||||
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
|
||||||
|
|
||||||
deployer.deploy(args.tarball, args.extract_path)
|
|
|
@ -15,11 +15,7 @@
|
||||||
"uisi_autorageshake_app": "element-auto-uisi",
|
"uisi_autorageshake_app": "element-auto-uisi",
|
||||||
"showLabsSettings": true,
|
"showLabsSettings": true,
|
||||||
"roomDirectory": {
|
"roomDirectory": {
|
||||||
"servers": [
|
"servers": ["matrix.org", "gitter.im", "libera.chat"]
|
||||||
"matrix.org",
|
|
||||||
"gitter.im",
|
|
||||||
"libera.chat"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"enable_presence_by_hs_url": {
|
"enable_presence_by_hs_url": {
|
||||||
"https://matrix.org": false,
|
"https://matrix.org": false,
|
||||||
|
@ -36,14 +32,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"hostSignup": {
|
"hostSignup": {
|
||||||
"brand": "Element Home",
|
"brand": "Element Home",
|
||||||
"cookiePolicyUrl": "https://element.io/cookie-policy",
|
"cookiePolicyUrl": "https://element.io/cookie-policy",
|
||||||
"domains": [
|
"domains": ["matrix.org"],
|
||||||
"matrix.org"
|
"privacyPolicyUrl": "https://element.io/privacy",
|
||||||
],
|
"termsOfServiceUrl": "https://element.io/terms-of-service",
|
||||||
"privacyPolicyUrl": "https://element.io/privacy",
|
"url": "https://ems.element.io/element-home/in-app-loader"
|
||||||
"termsOfServiceUrl": "https://element.io/terms-of-service",
|
|
||||||
"url": "https://ems.element.io/element-home/in-app-loader"
|
|
||||||
},
|
},
|
||||||
"sentry": {
|
"sentry": {
|
||||||
"dsn": "https://029a0eb289f942508ae0fb17935bd8c5@sentry.matrix.org/6",
|
"dsn": "https://029a0eb289f942508ae0fb17935bd8c5@sentry.matrix.org/6",
|
||||||
|
@ -58,5 +52,8 @@
|
||||||
"feature_spotlight": true,
|
"feature_spotlight": true,
|
||||||
"feature_video_rooms": 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"
|
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export function installer(config: BuildConfig): void {
|
||||||
// else must be a module, we assume.
|
// else must be a module, we assume.
|
||||||
const pkgJsonStr = fs.readFileSync("./package.json", "utf-8");
|
const pkgJsonStr = fs.readFileSync("./package.json", "utf-8");
|
||||||
const optionalDepNames = getOptionalDepNames(pkgJsonStr);
|
const optionalDepNames = getOptionalDepNames(pkgJsonStr);
|
||||||
const installedModules = optionalDepNames.filter(d => !currentOptDeps.includes(d));
|
const installedModules = optionalDepNames.filter((d) => !currentOptDeps.includes(d));
|
||||||
|
|
||||||
// Ensure all the modules are compatible. We check them all and report at the end to
|
// Ensure all the modules are compatible. We check them all and report at the end to
|
||||||
// try and save the user some time debugging this sort of failure.
|
// try and save the user some time debugging this sort of failure.
|
||||||
|
@ -80,7 +80,7 @@ export function installer(config: BuildConfig): void {
|
||||||
if (incompatibleNames.length > 0) {
|
if (incompatibleNames.length > 0) {
|
||||||
console.error(
|
console.error(
|
||||||
"The following modules are not compatible with this version of element-web. Please update the module " +
|
"The following modules are not compatible with this version of element-web. Please update the module " +
|
||||||
"references and try again.",
|
"references and try again.",
|
||||||
JSON.stringify(incompatibleNames, null, 4), // stringify to get prettier/complete output
|
JSON.stringify(incompatibleNames, null, 4), // stringify to get prettier/complete output
|
||||||
);
|
);
|
||||||
exitCode = 1;
|
exitCode = 1;
|
||||||
|
@ -123,39 +123,43 @@ function readCurrentPackageDetails(): RawDependencies {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function writePackageDetails(deps: RawDependencies) {
|
function writePackageDetails(deps: RawDependencies): void {
|
||||||
fs.writeFileSync("./yarn.lock", deps.lockfile, "utf-8");
|
fs.writeFileSync("./yarn.lock", deps.lockfile, "utf-8");
|
||||||
fs.writeFileSync("./package.json", deps.packageJson, "utf-8");
|
fs.writeFileSync("./package.json", deps.packageJson, "utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
function callYarnAdd(dep: string) {
|
function callYarnAdd(dep: string): void {
|
||||||
// Add the module to the optional dependencies section just in case something
|
// Add the module to the optional dependencies section just in case something
|
||||||
// goes wrong in restoring the original package details.
|
// goes wrong in restoring the original package details.
|
||||||
childProcess.execSync(`yarn add -O ${dep}`, {
|
childProcess.execSync(`yarn add -O ${dep}`, {
|
||||||
env: process.env,
|
env: process.env,
|
||||||
stdio: ['inherit', 'inherit', 'inherit'],
|
stdio: ["inherit", "inherit", "inherit"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOptionalDepNames(pkgJsonStr: string): string[] {
|
function getOptionalDepNames(pkgJsonStr: string): string[] {
|
||||||
return Object.keys(JSON.parse(pkgJsonStr)?.['optionalDependencies'] ?? {});
|
return Object.keys(JSON.parse(pkgJsonStr)?.["optionalDependencies"] ?? {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function findDepVersionInPackageJson(dep: string, pkgJsonStr: string): string {
|
function findDepVersionInPackageJson(dep: string, pkgJsonStr: string): string {
|
||||||
const pkgJson = JSON.parse(pkgJsonStr);
|
const pkgJson = JSON.parse(pkgJsonStr);
|
||||||
const packages = {
|
const packages = {
|
||||||
...(pkgJson['optionalDependencies'] ?? {}),
|
...(pkgJson["optionalDependencies"] ?? {}),
|
||||||
...(pkgJson['devDependencies'] ?? {}),
|
...(pkgJson["devDependencies"] ?? {}),
|
||||||
...(pkgJson['dependencies'] ?? {}),
|
...(pkgJson["dependencies"] ?? {}),
|
||||||
};
|
};
|
||||||
return packages[dep];
|
return packages[dep];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopLevelDependencyVersion(dep: string): string {
|
function getTopLevelDependencyVersion(dep: string): string {
|
||||||
const dependencyTree = JSON.parse(childProcess.execSync(`npm list ${dep} --depth=0 --json`, {
|
const dependencyTree = JSON.parse(
|
||||||
env: process.env,
|
childProcess
|
||||||
stdio: ['inherit', 'pipe', 'pipe'],
|
.execSync(`npm list ${dep} --depth=0 --json`, {
|
||||||
}).toString('utf-8'));
|
env: process.env,
|
||||||
|
stdio: ["inherit", "pipe", "pipe"],
|
||||||
|
})
|
||||||
|
.toString("utf-8"),
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
What a dependency tree looks like:
|
What a dependency tree looks like:
|
||||||
|
@ -186,6 +190,6 @@ function isModuleVersionCompatible(ourApiVersion: string, moduleApiVersion: stri
|
||||||
return semver.satisfies(ourApiVersion, moduleApiVersion);
|
return semver.satisfies(ourApiVersion, moduleApiVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeModulesTs(content: string) {
|
function writeModulesTs(content: string): void {
|
||||||
fs.writeFileSync("./src/modules.ts", content, "utf-8");
|
fs.writeFileSync("./src/modules.ts", content, "utf-8");
|
||||||
}
|
}
|
||||||
|
|
425
package.json
425
package.json
|
@ -1,215 +1,220 @@
|
||||||
{
|
{
|
||||||
"name": "element-web",
|
"name": "element-web",
|
||||||
"version": "1.11.2",
|
"version": "1.11.20",
|
||||||
"description": "A feature-rich client for Matrix.org",
|
"description": "A feature-rich client for Matrix.org",
|
||||||
"author": "New Vector Ltd.",
|
"author": "New Vector Ltd.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/vector-im/element-web"
|
"url": "https://github.com/vector-im/element-web"
|
||||||
},
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"files": [
|
|
||||||
"lib",
|
|
||||||
"res",
|
|
||||||
"src",
|
|
||||||
"webpack.config.js",
|
|
||||||
"scripts",
|
|
||||||
"docs",
|
|
||||||
"release.sh",
|
|
||||||
"deploy",
|
|
||||||
"CHANGELOG.md",
|
|
||||||
"CONTRIBUTING.rst",
|
|
||||||
"LICENSE",
|
|
||||||
"README.md",
|
|
||||||
"AUTHORS.rst",
|
|
||||||
"package.json",
|
|
||||||
"contribute.json"
|
|
||||||
],
|
|
||||||
"style": "bundle.css",
|
|
||||||
"scripts": {
|
|
||||||
"i18n": "matrix-gen-i18n",
|
|
||||||
"prunei18n": "matrix-prune-i18n",
|
|
||||||
"diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
|
|
||||||
"clean": "rimraf lib webapp",
|
|
||||||
"build": "yarn clean && yarn build:genfiles && yarn build:bundle",
|
|
||||||
"build-stats": "yarn clean && yarn build:genfiles && yarn build:bundle-stats",
|
|
||||||
"build:jitsi": "node scripts/build-jitsi.js",
|
|
||||||
"build:res": "node scripts/copy-res.js",
|
|
||||||
"build:genfiles": "yarn build:res && yarn build:jitsi && yarn build:module_system",
|
|
||||||
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
|
||||||
"build:bundle": "webpack --progress --bail --mode production",
|
|
||||||
"build:bundle-stats": "webpack --progress --bail --mode production --json > webpack-stats.json",
|
|
||||||
"build:module_system": "tsc --project ./tsconfig.module_system.json && node ./lib/module_system/scripts/install.js",
|
|
||||||
"dist": "scripts/package.sh",
|
|
||||||
"start": "yarn build:module_system && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js\"",
|
|
||||||
"start:https": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js --https\"",
|
|
||||||
"start:res": "yarn build:jitsi && node scripts/copy-res.js -w",
|
|
||||||
"start:js": "webpack-dev-server --host=0.0.0.0 --output-filename=bundles/_dev_/[name].js --output-chunk-filename=bundles/_dev_/[name].js -w --mode development --disable-host-check --hot",
|
|
||||||
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
|
|
||||||
"lint:js": "eslint --max-warnings 0 src module_system",
|
|
||||||
"lint:js-fix": "eslint --fix src module_system",
|
|
||||||
"lint:types": "tsc --noEmit --jsx react && tsc --noEmit --project ./tsconfig.module_system.json",
|
|
||||||
"lint:style": "stylelint \"res/css/**/*.pcss\"",
|
|
||||||
"test": "jest",
|
|
||||||
"coverage": "yarn test --coverage",
|
|
||||||
"analyse:unused-exports": "node ./scripts/analyse_unused_exports.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
|
|
||||||
"@matrix-org/react-sdk-module-api": "^0.0.3",
|
|
||||||
"browser-request": "^0.3.3",
|
|
||||||
"gfm.css": "^1.1.2",
|
|
||||||
"jsrsasign": "^10.5.25",
|
|
||||||
"katex": "^0.12.0",
|
|
||||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
|
||||||
"matrix-react-sdk": "github:matrix-org/matrix-react-sdk#develop",
|
|
||||||
"matrix-widget-api": "^0.1.0-beta.18",
|
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.12.10",
|
|
||||||
"@babel/eslint-parser": "^7.12.10",
|
|
||||||
"@babel/eslint-plugin": "^7.12.10",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
|
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
|
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
||||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
|
||||||
"@babel/preset-env": "^7.12.11",
|
|
||||||
"@babel/preset-react": "^7.12.10",
|
|
||||||
"@babel/preset-typescript": "^7.12.7",
|
|
||||||
"@babel/register": "^7.12.10",
|
|
||||||
"@babel/runtime": "^7.12.5",
|
|
||||||
"@principalstudio/html-webpack-inject-preload": "^1.2.7",
|
|
||||||
"@sentry/webpack-plugin": "^1.18.1",
|
|
||||||
"@svgr/webpack": "^5.5.0",
|
|
||||||
"@types/flux": "^3.1.9",
|
|
||||||
"@types/jest": "^28.0.0",
|
|
||||||
"@types/modernizr": "^3.5.3",
|
|
||||||
"@types/node": "^14.14.22",
|
|
||||||
"@types/react": "17.0.14",
|
|
||||||
"@types/react-dom": "17.0.9",
|
|
||||||
"@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",
|
|
||||||
"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",
|
|
||||||
"eslint-config-google": "^0.14.0",
|
|
||||||
"eslint-plugin-deprecate": "^0.7.0",
|
|
||||||
"eslint-plugin-import": "^2.25.4",
|
|
||||||
"eslint-plugin-matrix-org": "^0.6.1",
|
|
||||||
"eslint-plugin-react": "^7.28.0",
|
|
||||||
"eslint-plugin-react-hooks": "^4.3.0",
|
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
|
||||||
"fake-indexeddb": "^3.1.2",
|
|
||||||
"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-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-react-test-utils": "^0.2.3",
|
|
||||||
"matrix-web-i18n": "^1.3.0",
|
|
||||||
"mini-css-extract-plugin": "^0.12.0",
|
|
||||||
"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-easings": "^2.0.0",
|
|
||||||
"postcss-hexrgba": "2.0.1",
|
|
||||||
"postcss-import": "^12.0.1",
|
|
||||||
"postcss-loader": "^3.0.0",
|
|
||||||
"postcss-mixins": "^6.2.3",
|
|
||||||
"postcss-nested": "^4.2.3",
|
|
||||||
"postcss-preset-env": "^6.7.0",
|
|
||||||
"postcss-scss": "^2.1.1",
|
|
||||||
"postcss-simple-vars": "^5.0.2",
|
|
||||||
"raw-loader": "^4.0.2",
|
|
||||||
"rimraf": "^3.0.2",
|
|
||||||
"semver": "^7.3.7",
|
|
||||||
"shell-escape": "^0.2.0",
|
|
||||||
"simple-proxy-agent": "^1.1.0",
|
|
||||||
"string-replace-loader": "2",
|
|
||||||
"style-loader": "2",
|
|
||||||
"stylelint": "^14.9.1",
|
|
||||||
"stylelint-config-standard": "^26.0.0",
|
|
||||||
"stylelint-scss": "^4.2.0",
|
|
||||||
"terser-webpack-plugin": "^2.3.8",
|
|
||||||
"ts-prune": "^0.10.3",
|
|
||||||
"typescript": "^4.7.4",
|
|
||||||
"webpack": "^4.46.0",
|
|
||||||
"webpack-cli": "^3.3.12",
|
|
||||||
"webpack-dev-server": "^3.11.2",
|
|
||||||
"worker-loader": "^2.0.0",
|
|
||||||
"worklet-loader": "^2.0.0",
|
|
||||||
"yaml": "^2.0.1"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"@types/react": "17.0.14"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"testEnvironment": "jsdom",
|
|
||||||
"testEnvironmentOptions": {
|
|
||||||
"url": "http://localhost/"
|
|
||||||
},
|
},
|
||||||
"testMatch": [
|
"license": "Apache-2.0",
|
||||||
"<rootDir>/test/**/*-test.[tj]s?(x)"
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"res",
|
||||||
|
"src",
|
||||||
|
"webpack.config.js",
|
||||||
|
"scripts",
|
||||||
|
"docs",
|
||||||
|
"release.sh",
|
||||||
|
"deploy",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"CONTRIBUTING.rst",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md",
|
||||||
|
"AUTHORS.rst",
|
||||||
|
"package.json",
|
||||||
|
"contribute.json"
|
||||||
],
|
],
|
||||||
"setupFilesAfterEnv": [
|
"style": "bundle.css",
|
||||||
"<rootDir>/node_modules/matrix-react-sdk/test/setupTests.js"
|
"scripts": {
|
||||||
],
|
"i18n": "matrix-gen-i18n",
|
||||||
"moduleNameMapper": {
|
"prunei18n": "matrix-prune-i18n",
|
||||||
"\\.(css|scss|pcss)$": "<rootDir>/__mocks__/cssMock.js",
|
"diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
|
||||||
"\\.(gif|png|ttf|woff2)$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/imageMock.js",
|
"clean": "rimraf lib webapp",
|
||||||
"\\.svg$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/svg.js",
|
"build": "yarn clean && yarn build:genfiles && yarn build:bundle",
|
||||||
"\\$webapp/i18n/languages.json": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/languages.json",
|
"build-stats": "yarn clean && yarn build:genfiles && yarn build:bundle-stats",
|
||||||
"^browser-request$": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/browser-request.js",
|
"build:jitsi": "node scripts/build-jitsi.js",
|
||||||
"^react$": "<rootDir>/node_modules/react",
|
"build:res": "node scripts/copy-res.js",
|
||||||
"^react-dom$": "<rootDir>/node_modules/react-dom",
|
"build:genfiles": "yarn build:res && yarn build:jitsi && yarn build:module_system",
|
||||||
"^matrix-js-sdk$": "<rootDir>/node_modules/matrix-js-sdk/src",
|
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
|
||||||
"^matrix-react-sdk$": "<rootDir>/node_modules/matrix-react-sdk/src",
|
"build:bundle": "webpack --progress --bail --mode production",
|
||||||
"decoderWorker\\.min\\.js": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
"build:bundle-stats": "webpack --progress --bail --mode production --json > webpack-stats.json",
|
||||||
"decoderWorker\\.min\\.wasm": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
"build:module_system": "tsc --project ./tsconfig.module_system.json && node ./lib/module_system/scripts/install.js",
|
||||||
"waveWorker\\.min\\.js": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
"dist": "scripts/package.sh",
|
||||||
"context-filter-polyfill": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
"start": "yarn build:module_system && concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js\"",
|
||||||
"FontManager.ts": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/FontManager.js",
|
"start:https": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n res,element-js \"yarn start:res\" \"yarn start:js --https\"",
|
||||||
"workers/(.+)\\.worker\\.ts": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/workerMock.js",
|
"start:res": "yarn build:jitsi && node scripts/copy-res.js -w",
|
||||||
"^!!raw-loader!.*": "jest-raw-loader",
|
"start:js": "webpack-dev-server --host=0.0.0.0 --output-filename=bundles/_dev_/[name].js --output-chunk-filename=bundles/_dev_/[name].js -w --mode development --disable-host-check --hot",
|
||||||
"RecorderWorklet": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js"
|
"lint": "yarn lint:types && yarn lint:js && yarn lint:style",
|
||||||
|
"lint:js": "eslint --max-warnings 0 src module_system test && prettier --check .",
|
||||||
|
"lint:js-fix": "prettier --write . && eslint --fix src module_system test",
|
||||||
|
"lint:types": "tsc --noEmit --jsx react && tsc --noEmit --project ./tsconfig.module_system.json",
|
||||||
|
"lint:style": "stylelint \"res/css/**/*.pcss\"",
|
||||||
|
"test": "jest",
|
||||||
|
"coverage": "yarn test --coverage",
|
||||||
|
"analyse:unused-exports": "node ./scripts/analyse_unused_exports.js"
|
||||||
},
|
},
|
||||||
"transformIgnorePatterns": [
|
"dependencies": {
|
||||||
"/node_modules/(?!matrix-js-sdk).+$",
|
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
|
||||||
"/node_modules/(?!matrix-react-sdk).+$"
|
"@matrix-org/react-sdk-module-api": "^0.0.3",
|
||||||
],
|
"gfm.css": "^1.1.2",
|
||||||
"coverageReporters": [
|
"jsrsasign": "^10.5.25",
|
||||||
"text-summary",
|
"katex": "^0.16.0",
|
||||||
"lcov"
|
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop",
|
||||||
],
|
"matrix-react-sdk": "github:matrix-org/matrix-react-sdk#develop",
|
||||||
"testResultsProcessor": "jest-sonar-reporter"
|
"matrix-widget-api": "^1.1.1",
|
||||||
},
|
"react": "17.0.2",
|
||||||
"jestSonar": {
|
"react-dom": "17.0.2",
|
||||||
"reportPath": "coverage",
|
"sanitize-html": "^2.3.2",
|
||||||
"sonar56x": true
|
"ua-parser-js": "^1.0.0"
|
||||||
}
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.12.10",
|
||||||
|
"@babel/eslint-parser": "^7.12.10",
|
||||||
|
"@babel/eslint-plugin": "^7.12.10",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
|
"@babel/plugin-proposal-export-default-from": "^7.12.1",
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
|
||||||
|
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
|
||||||
|
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
|
||||||
|
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||||
|
"@babel/preset-env": "^7.12.11",
|
||||||
|
"@babel/preset-react": "^7.12.10",
|
||||||
|
"@babel/preset-typescript": "^7.12.7",
|
||||||
|
"@babel/register": "^7.12.10",
|
||||||
|
"@babel/runtime": "^7.12.5",
|
||||||
|
"@casualbot/jest-sonar-reporter": "^2.2.5",
|
||||||
|
"@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": "^29.0.0",
|
||||||
|
"@types/jsrsasign": "^10.5.4",
|
||||||
|
"@types/modernizr": "^3.5.3",
|
||||||
|
"@types/node": "^16",
|
||||||
|
"@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",
|
||||||
|
"babel-jest": "^29.0.0",
|
||||||
|
"babel-loader": "^8.2.2",
|
||||||
|
"chokidar": "^3.5.1",
|
||||||
|
"concurrently": "^7.0.0",
|
||||||
|
"cpx": "^1.5.0",
|
||||||
|
"css-loader": "^4",
|
||||||
|
"dotenv": "^16.0.2",
|
||||||
|
"eslint": "8.28.0",
|
||||||
|
"eslint-config-google": "^0.14.0",
|
||||||
|
"eslint-config-prettier": "^8.5.0",
|
||||||
|
"eslint-plugin-deprecate": "^0.7.0",
|
||||||
|
"eslint-plugin-import": "^2.25.4",
|
||||||
|
"eslint-plugin-matrix-org": "^0.9.0",
|
||||||
|
"eslint-plugin-react": "^7.28.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.3.0",
|
||||||
|
"eslint-plugin-unicorn": "^45.0.0",
|
||||||
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
|
"fake-indexeddb": "^4.0.0",
|
||||||
|
"fetch-mock-jest": "^1.5.1",
|
||||||
|
"file-loader": "^6.0.0",
|
||||||
|
"fs-extra": "^11.0.0",
|
||||||
|
"html-webpack-plugin": "^4.5.2",
|
||||||
|
"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",
|
||||||
|
"json-loader": "^0.5.7",
|
||||||
|
"loader-utils": "^3.0.0",
|
||||||
|
"matrix-mock-request": "^2.5.0",
|
||||||
|
"matrix-web-i18n": "^1.3.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": "^6.0.0",
|
||||||
|
"postcss": "^8.4.16",
|
||||||
|
"postcss-easings": "^2.0.0",
|
||||||
|
"postcss-hexrgba": "2.0.1",
|
||||||
|
"postcss-import": "^12.0.1",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"postcss-mixins": "^6.2.3",
|
||||||
|
"postcss-nested": "^4.2.3",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"postcss-scss": "^4.0.4",
|
||||||
|
"postcss-simple-vars": "^5.0.2",
|
||||||
|
"prettier": "2.8.0",
|
||||||
|
"raw-loader": "^4.0.2",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"semver": "^7.3.7",
|
||||||
|
"simple-proxy-agent": "^1.1.0",
|
||||||
|
"string-replace-loader": "3",
|
||||||
|
"style-loader": "2",
|
||||||
|
"stylelint": "^14.9.1",
|
||||||
|
"stylelint-config-prettier": "^9.0.4",
|
||||||
|
"stylelint-config-standard": "^29.0.0",
|
||||||
|
"stylelint-scss": "^4.2.0",
|
||||||
|
"terser-webpack-plugin": "^4.0.0",
|
||||||
|
"ts-prune": "^0.10.3",
|
||||||
|
"typescript": "4.9.3",
|
||||||
|
"webpack": "^4.46.0",
|
||||||
|
"webpack-cli": "^3.3.12",
|
||||||
|
"webpack-dev-server": "^3.11.2",
|
||||||
|
"worker-loader": "^3.0.0",
|
||||||
|
"worklet-loader": "^2.0.0",
|
||||||
|
"yaml": "^2.0.1"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"testEnvironment": "jsdom",
|
||||||
|
"testEnvironmentOptions": {
|
||||||
|
"url": "http://localhost/"
|
||||||
|
},
|
||||||
|
"testMatch": [
|
||||||
|
"<rootDir>/test/**/*-test.[tj]s?(x)"
|
||||||
|
],
|
||||||
|
"setupFiles": [
|
||||||
|
"jest-canvas-mock"
|
||||||
|
],
|
||||||
|
"setupFilesAfterEnv": [
|
||||||
|
"<rootDir>/node_modules/matrix-react-sdk/test/setupTests.js"
|
||||||
|
],
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"\\.(css|scss|pcss)$": "<rootDir>/__mocks__/cssMock.js",
|
||||||
|
"\\.(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",
|
||||||
|
"^react$": "<rootDir>/node_modules/react",
|
||||||
|
"^react-dom$": "<rootDir>/node_modules/react-dom",
|
||||||
|
"^matrix-js-sdk$": "<rootDir>/node_modules/matrix-js-sdk/src",
|
||||||
|
"^matrix-react-sdk$": "<rootDir>/node_modules/matrix-react-sdk/src",
|
||||||
|
"decoderWorker\\.min\\.js": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
||||||
|
"decoderWorker\\.min\\.wasm": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
||||||
|
"waveWorker\\.min\\.js": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
||||||
|
"context-filter-polyfill": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js",
|
||||||
|
"FontManager.ts": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/FontManager.js",
|
||||||
|
"workers/(.+)\\.worker\\.ts": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/workerMock.js",
|
||||||
|
"^!!raw-loader!.*": "jest-raw-loader",
|
||||||
|
"RecorderWorklet": "<rootDir>/node_modules/matrix-react-sdk/__mocks__/empty.js"
|
||||||
|
},
|
||||||
|
"transformIgnorePatterns": [
|
||||||
|
"/node_modules/(?!matrix-js-sdk).+$",
|
||||||
|
"/node_modules/(?!matrix-react-sdk).+$"
|
||||||
|
],
|
||||||
|
"coverageReporters": [
|
||||||
|
"text-summary",
|
||||||
|
"lcov"
|
||||||
|
],
|
||||||
|
"testResultsProcessor": "@casualbot/jest-sonar-reporter"
|
||||||
|
},
|
||||||
|
"@casualbot/jest-sonar-reporter": {
|
||||||
|
"outputDirectory": "coverage",
|
||||||
|
"outputName": "jest-sonar-report.xml",
|
||||||
|
"relativePaths": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
65
release.sh
65
release.sh
|
@ -1,68 +1,9 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Script to perform a release of element-web.
|
# 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
|
set -e
|
||||||
|
|
||||||
orig_args=$@
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
# chomp any args starting with '-' as these need to go
|
./node_modules/matrix-js-sdk/release.sh "$@"
|
||||||
# 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
|
|
||||||
|
|
|
@ -2,3 +2,5 @@ signing_id: releases@riot.im
|
||||||
subprojects:
|
subprojects:
|
||||||
matrix-react-sdk:
|
matrix-react-sdk:
|
||||||
includeByDefault: true
|
includeByDefault: true
|
||||||
|
matrix-js-sdk:
|
||||||
|
includeByDefault: false
|
||||||
|
|
18
res/apple-app-site-association
Normal file
18
res/apple-app-site-association
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"applinks": {
|
||||||
|
"apps": [],
|
||||||
|
"details": [
|
||||||
|
{
|
||||||
|
"appID": "7J4U792NQT.im.vector.app",
|
||||||
|
"paths": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"webcredentials": {
|
||||||
|
"apps": [
|
||||||
|
"7J4U792NQT.im.vector.app"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,21 +25,14 @@ limitations under the License.
|
||||||
background: linear-gradient(to bottom, #c5e0f7 0%, #ffffff 100%);
|
background: linear-gradient(to bottom, #c5e0f7 0%, #ffffff 100%);
|
||||||
/* stylelint-disable-next-line function-no-unknown */
|
/* stylelint-disable-next-line function-no-unknown */
|
||||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#c5e0f7', endColorstr='#ffffff', GradientType=0);
|
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#c5e0f7', endColorstr='#ffffff', GradientType=0);
|
||||||
font-family:
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
|
||||||
-apple-system,
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
BlinkMacSystemFont,
|
|
||||||
"Segoe UI",
|
|
||||||
Roboto,
|
|
||||||
Helvetica,
|
|
||||||
Arial,
|
|
||||||
sans-serif,
|
|
||||||
"Apple Color Emoji",
|
|
||||||
"Segoe UI Emoji",
|
|
||||||
"Segoe UI Symbol";
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
height: auto;
|
|
||||||
color: #000;
|
color: #000;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
.mx_ErrorView_container {
|
.mx_ErrorView_container {
|
||||||
max-width: 680px;
|
max-width: 680px;
|
||||||
|
@ -97,7 +90,8 @@ limitations under the License.
|
||||||
margin: auto 20px auto 0;
|
margin: auto 20px auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2 {
|
h1,
|
||||||
|
h2 {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
class Optional {
|
class Optional {
|
||||||
static from(value) {
|
static from(value) {
|
||||||
return value && Some.of(value) || None;
|
return (value && Some.of(value)) || None;
|
||||||
}
|
}
|
||||||
map(f) {
|
map(f) {
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -10,11 +10,11 @@ async function getBundleName(baseUrl) {
|
||||||
throw new StartupError(`Couldn't fetch index.html to prefill bundle; ${res.status} ${res.statusText}`);
|
throw new StartupError(`Couldn't fetch index.html to prefill bundle; ${res.status} ${res.statusText}`);
|
||||||
}
|
}
|
||||||
const index = await res.text();
|
const index = await res.text();
|
||||||
return index.split("\n").map((line) =>
|
return index
|
||||||
line.match(/<script src="bundles\/([^/]+)\/bundle.js"/),
|
.split("\n")
|
||||||
)
|
.map((line) => line.match(/<script src="bundles\/([^/]+)\/bundle.js"/))
|
||||||
.filter((result) => result)
|
.filter((result) => result)
|
||||||
.map((result) => result[1])[0];
|
.map((result) => result[1])[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateBundle(value) {
|
function validateBundle(value) {
|
||||||
|
@ -69,7 +69,7 @@ function observeReadableStream(readableStream, pendingContext = {}) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bytesReceived += value.length;
|
bytesReceived += value.length;
|
||||||
pendingSubject.next(Pending.of({...pendingContext, bytesReceived }));
|
pendingSubject.next(Pending.of({ ...pendingContext, bytesReceived }));
|
||||||
/* string concatenation is apparently the most performant way to do this */
|
/* string concatenation is apparently the most performant way to do this */
|
||||||
buffer += utf8Decoder.decode(value);
|
buffer += utf8Decoder.decode(value);
|
||||||
readNextChunk();
|
readNextChunk();
|
||||||
|
@ -120,25 +120,27 @@ const e = React.createElement;
|
||||||
* Provides user feedback given a FetchStatus object.
|
* Provides user feedback given a FetchStatus object.
|
||||||
*/
|
*/
|
||||||
function ProgressBar({ fetchStatus }) {
|
function ProgressBar({ fetchStatus }) {
|
||||||
return e('span', { className: "progress "},
|
return e(
|
||||||
|
"span",
|
||||||
|
{ className: "progress " },
|
||||||
fetchStatus.fold({
|
fetchStatus.fold({
|
||||||
pending: ({ bytesReceived, length }) => {
|
pending: ({ bytesReceived, length }) => {
|
||||||
if (!bytesReceived) {
|
if (!bytesReceived) {
|
||||||
return e('span', { className: "spinner" }, "\u29b5");
|
return e("span", { className: "spinner" }, "\u29b5");
|
||||||
}
|
}
|
||||||
const kB = Math.floor(10 * bytesReceived / 1024) / 10;
|
const kB = Math.floor((10 * bytesReceived) / 1024) / 10;
|
||||||
if (!length) {
|
if (!length) {
|
||||||
return e('span', null, `Fetching (${kB}kB)`);
|
return e("span", null, `Fetching (${kB}kB)`);
|
||||||
}
|
}
|
||||||
const percent = Math.floor(100 * bytesReceived / length);
|
const percent = Math.floor((100 * bytesReceived) / length);
|
||||||
return e('span', null, `Fetching (${kB}kB) ${percent}%`);
|
return e("span", null, `Fetching (${kB}kB) ${percent}%`);
|
||||||
},
|
},
|
||||||
success: () => e('span', null, "\u2713"),
|
success: () => e("span", null, "\u2713"),
|
||||||
error: (reason) => {
|
error: (reason) => {
|
||||||
return e('span', { className: 'error'}, `\u2717 ${reason}`);
|
return e("span", { className: "error" }, `\u2717 ${reason}`);
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -193,23 +195,24 @@ function BundlePicker() {
|
||||||
setColumn(value);
|
setColumn(value);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------ */
|
/* ------------------------------------------------ */
|
||||||
/* Plumb data-fetching observables through to React */
|
/* Plumb data-fetching observables through to React */
|
||||||
/* ------------------------------------------------ */
|
/* ------------------------------------------------ */
|
||||||
|
|
||||||
/* Whenever a valid bundle name is input, go see if it's a real bundle on the server */
|
/* Whenever a valid bundle name is input, go see if it's a real bundle on the server */
|
||||||
React.useEffect(() =>
|
React.useEffect(
|
||||||
validateBundle(bundle).fold({
|
() =>
|
||||||
some: (value) => {
|
validateBundle(bundle).fold({
|
||||||
const subscription = bundleSubject(baseUrl, value)
|
some: (value) => {
|
||||||
.pipe(rxjs.operators.map(Some.of))
|
const subscription = bundleSubject(baseUrl, value)
|
||||||
.subscribe(setBundleFetchStatus);
|
.pipe(rxjs.operators.map(Some.of))
|
||||||
return () => subscription.unsubscribe();
|
.subscribe(setBundleFetchStatus);
|
||||||
},
|
return () => subscription.unsubscribe();
|
||||||
none: () => setBundleFetchStatus(None),
|
},
|
||||||
}),
|
none: () => setBundleFetchStatus(None),
|
||||||
[baseUrl, bundle]);
|
}),
|
||||||
|
[baseUrl, bundle],
|
||||||
|
);
|
||||||
|
|
||||||
/* Whenever a valid javascript file is input, see if it corresponds to a sourcemap file and initiate a fetch
|
/* Whenever a valid javascript file is input, see if it corresponds to a sourcemap file and initiate a fetch
|
||||||
* if so. */
|
* if so. */
|
||||||
|
@ -218,17 +221,18 @@ function BundlePicker() {
|
||||||
setFileFetchStatus(None);
|
setFileFetchStatus(None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const observable = fetchAsSubject(new URL(`bundles/${bundle}/${file}.map`, baseUrl).toString())
|
const observable = fetchAsSubject(new URL(`bundles/${bundle}/${file}.map`, baseUrl).toString()).pipe(
|
||||||
.pipe(
|
rxjs.operators.map((fetchStatus) =>
|
||||||
rxjs.operators.map((fetchStatus) => fetchStatus.flatMap(value => {
|
fetchStatus.flatMap((value) => {
|
||||||
try {
|
try {
|
||||||
return Success.of(JSON.parse(value));
|
return Success.of(JSON.parse(value));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return FetchError.of(e);
|
return FetchError.of(e);
|
||||||
}
|
}
|
||||||
})),
|
}),
|
||||||
rxjs.operators.map(Some.of),
|
),
|
||||||
);
|
rxjs.operators.map(Some.of),
|
||||||
|
);
|
||||||
const subscription = observable.subscribe(setFileFetchStatus);
|
const subscription = observable.subscribe(setFileFetchStatus);
|
||||||
return () => subscription.unsubscribe();
|
return () => subscription.unsubscribe();
|
||||||
}, [baseUrl, bundle, file]);
|
}, [baseUrl, bundle, file]);
|
||||||
|
@ -256,26 +260,33 @@ function BundlePicker() {
|
||||||
});
|
});
|
||||||
}, [fileFetchStatus, line, column]);
|
}, [fileFetchStatus, line, column]);
|
||||||
|
|
||||||
|
|
||||||
/* ------ */
|
/* ------ */
|
||||||
/* Render */
|
/* Render */
|
||||||
/* ------ */
|
/* ------ */
|
||||||
return e('div', {},
|
return e(
|
||||||
e('div', { className: 'inputs' },
|
"div",
|
||||||
e('div', { className: 'baseUrl' },
|
{},
|
||||||
e('label', { htmlFor: 'baseUrl'}, 'Base URL'),
|
e(
|
||||||
e('input', {
|
"div",
|
||||||
name: 'baseUrl',
|
{ className: "inputs" },
|
||||||
|
e(
|
||||||
|
"div",
|
||||||
|
{ className: "baseUrl" },
|
||||||
|
e("label", { htmlFor: "baseUrl" }, "Base URL"),
|
||||||
|
e("input", {
|
||||||
|
name: "baseUrl",
|
||||||
required: true,
|
required: true,
|
||||||
pattern: ".+",
|
pattern: ".+",
|
||||||
onChange: onBaseUrlChange,
|
onChange: onBaseUrlChange,
|
||||||
value: baseUrl,
|
value: baseUrl,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
e('div', { className: 'bundle' },
|
e(
|
||||||
e('label', { htmlFor: 'bundle'}, 'Bundle'),
|
"div",
|
||||||
e('input', {
|
{ className: "bundle" },
|
||||||
name: 'bundle',
|
e("label", { htmlFor: "bundle" }, "Bundle"),
|
||||||
|
e("input", {
|
||||||
|
name: "bundle",
|
||||||
required: true,
|
required: true,
|
||||||
pattern: "[0-9a-f]{20}",
|
pattern: "[0-9a-f]{20}",
|
||||||
onChange: onBundleChange,
|
onChange: onBundleChange,
|
||||||
|
@ -286,10 +297,12 @@ function BundlePicker() {
|
||||||
none: () => null,
|
none: () => null,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
e('div', { className: 'file' },
|
e(
|
||||||
e('label', { htmlFor: 'file' }, 'File'),
|
"div",
|
||||||
e('input', {
|
{ className: "file" },
|
||||||
name: 'file',
|
e("label", { htmlFor: "file" }, "File"),
|
||||||
|
e("input", {
|
||||||
|
name: "file",
|
||||||
required: true,
|
required: true,
|
||||||
pattern: ".+\\.js",
|
pattern: ".+\\.js",
|
||||||
onChange: onFileChange,
|
onChange: onFileChange,
|
||||||
|
@ -300,20 +313,24 @@ function BundlePicker() {
|
||||||
none: () => null,
|
none: () => null,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
e('div', { className: 'line' },
|
e(
|
||||||
e('label', { htmlFor: 'line' }, 'Line'),
|
"div",
|
||||||
e('input', {
|
{ className: "line" },
|
||||||
name: 'line',
|
e("label", { htmlFor: "line" }, "Line"),
|
||||||
|
e("input", {
|
||||||
|
name: "line",
|
||||||
required: true,
|
required: true,
|
||||||
pattern: "[0-9]+",
|
pattern: "[0-9]+",
|
||||||
onChange: onLineChange,
|
onChange: onLineChange,
|
||||||
value: line,
|
value: line,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
e('div', { className: 'column' },
|
e(
|
||||||
e('label', { htmlFor: 'column' }, 'Column'),
|
"div",
|
||||||
e('input', {
|
{ className: "column" },
|
||||||
name: 'column',
|
e("label", { htmlFor: "column" }, "Column"),
|
||||||
|
e("input", {
|
||||||
|
name: "column",
|
||||||
required: true,
|
required: true,
|
||||||
pattern: "[0-9]+",
|
pattern: "[0-9]+",
|
||||||
onChange: onColumnChange,
|
onChange: onColumnChange,
|
||||||
|
@ -321,10 +338,12 @@ function BundlePicker() {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
e('div', null,
|
e(
|
||||||
|
"div",
|
||||||
|
null,
|
||||||
result.fold({
|
result.fold({
|
||||||
none: () => "Select a bundle, file and line",
|
none: () => "Select a bundle, file and line",
|
||||||
some: (value) => e('pre', null, value),
|
some: (value) => e("pre", null, value),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Rageshake decoder ring</title>
|
<title>Rageshake decoder ring</title>
|
||||||
<script crossorigin src="https://unpkg.com/source-map@0.7.3/dist/source-map.js"></script>
|
<script crossorigin src="https://unpkg.com/source-map@0.7.3/dist/source-map.js"></script>
|
||||||
<script>
|
<script>
|
||||||
sourceMap.SourceMapConsumer.initialize({
|
sourceMap.SourceMapConsumer.initialize({
|
||||||
"lib/mappings.wasm": "https://unpkg.com/source-map@0.7.3/lib/mappings.wasm"
|
"lib/mappings.wasm": "https://unpkg.com/source-map@0.7.3/lib/mappings.wasm",
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
|
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
|
||||||
|
@ -18,12 +18,16 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
from {transform:rotate(0deg);}
|
from {
|
||||||
to {transform:rotate(359deg);}
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
|
@ -44,7 +48,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.valid::after {
|
.valid::after {
|
||||||
content: "✓"
|
content: "✓";
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
@ -68,7 +72,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
try {
|
try {
|
||||||
ReactDOM.render(React.createElement(Decoder.BundlePicker), document.getElementById("main"))
|
ReactDOM.render(React.createElement(Decoder.BundlePicker), document.getElementById("main"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const n = document.createElement("div");
|
const n = document.createElement("div");
|
||||||
n.innerText = `Error starting: ${e.message}`;
|
n.innerText = `Error starting: ${e.message}`;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
self.addEventListener('fetch', () => {});
|
self.addEventListener("fetch", () => {});
|
||||||
|
|
278
res/welcome.html
278
res/welcome.html
|
@ -1,175 +1,173 @@
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
/* we deliberately inline style here to avoid flash-of-CSS problems, and to avoid
|
||||||
/* we deliberately inline style here to avoid flash-of-CSS problems, and to avoid
|
|
||||||
* voodoo where we have to set display: none by default
|
* voodoo where we have to set display: none by default
|
||||||
*/
|
*/
|
||||||
|
|
||||||
h1::after {
|
h1::after {
|
||||||
content: "!";
|
content: "!";
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Parent {
|
.mx_Parent {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-box-direction: normal;
|
-webkit-box-direction: normal;
|
||||||
-webkit-flex-direction: column;
|
-webkit-flex-direction: column;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
-webkit-box-pack: center;
|
-webkit-box-pack: center;
|
||||||
-webkit-justify-content: center;
|
-webkit-justify-content: center;
|
||||||
-ms-flex-pack: center;
|
-ms-flex-pack: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 25px 35px;
|
padding: 25px 35px;
|
||||||
color: #2e2f32;
|
color: #2e2f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Logo {
|
.mx_Logo {
|
||||||
height: 54px;
|
height: 54px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonGroup {
|
.mx_ButtonGroup {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonRow {
|
.mx_ButtonRow {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-justify-content: space-around;
|
-webkit-justify-content: space-around;
|
||||||
-ms-flex-pack: distribute;
|
-ms-flex-pack: distribute;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 12px 0 0;
|
margin: 12px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonRow > * {
|
.mx_ButtonRow > * {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonRow > *:first-child {
|
.mx_ButtonRow > *:first-child {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonRow > *:last-child {
|
.mx_ButtonRow > *:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonParent {
|
.mx_ButtonParent {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
display: -ms-flexbox;
|
display: -ms-flexbox;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
-webkit-box-orient: horizontal;
|
-webkit-box-orient: horizontal;
|
||||||
-webkit-box-direction: normal;
|
-webkit-box-direction: normal;
|
||||||
-webkit-flex-direction: row;
|
-webkit-flex-direction: row;
|
||||||
-ms-flex-direction: row;
|
-ms-flex-direction: row;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
-webkit-box-pack: center;
|
-webkit-box-pack: center;
|
||||||
-webkit-justify-content: center;
|
-webkit-justify-content: center;
|
||||||
-ms-flex-pack: center;
|
-ms-flex-pack: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
-webkit-box-align: center;
|
-webkit-box-align: center;
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
-ms-flex-align: center;
|
-ms-flex-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
width: 150px;
|
width: 150px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 10px center;
|
background-position: 10px center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #2e2f32 !important;
|
color: #2e2f32 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonLabel {
|
.mx_ButtonLabel {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Header_title {
|
.mx_Header_title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin: 20px 0 0;
|
margin: 20px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Header_subtitle {
|
.mx_Header_subtitle {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 8px 0 0;
|
margin: 8px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonSignIn {
|
.mx_ButtonSignIn {
|
||||||
background-color: #368BD6;
|
background-color: #368bd6;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonCreateAccount {
|
.mx_ButtonCreateAccount {
|
||||||
background-color: #0DBD8B;
|
background-color: #0dbd8b;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SecondaryButton {
|
.mx_SecondaryButton {
|
||||||
background-color: #FFFFFF;
|
background-color: #ffffff;
|
||||||
color: #2E2F32;
|
color: #2e2f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Button_iconSignIn {
|
.mx_Button_iconSignIn {
|
||||||
background-image: url('welcome/images/icon-sign-in.svg');
|
background-image: url("welcome/images/icon-sign-in.svg");
|
||||||
}
|
}
|
||||||
.mx_Button_iconCreateAccount {
|
.mx_Button_iconCreateAccount {
|
||||||
background-image: url('welcome/images/icon-create-account.svg');
|
background-image: url("welcome/images/icon-create-account.svg");
|
||||||
}
|
}
|
||||||
.mx_Button_iconHelp {
|
.mx_Button_iconHelp {
|
||||||
background-image: url('welcome/images/icon-help.svg');
|
background-image: url("welcome/images/icon-help.svg");
|
||||||
}
|
}
|
||||||
.mx_Button_iconRoomDirectory {
|
.mx_Button_iconRoomDirectory {
|
||||||
background-image: url('welcome/images/icon-room-directory.svg');
|
background-image: url("welcome/images/icon-room-directory.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
.mx_WelcomePage_loggedIn is applied by EmbeddedPage from the Welcome component
|
.mx_WelcomePage_loggedIn is applied by EmbeddedPage from the Welcome component
|
||||||
If it is set on the page, we should show the buttons. Otherwise, we have to assume
|
If it is set on the page, we should show the buttons. Otherwise, we have to assume
|
||||||
we don't have an account and should hide them. No account == no guest account either.
|
we don't have an account and should hide them. No account == no guest account either.
|
||||||
*/
|
*/
|
||||||
.mx_WelcomePage:not(.mx_WelcomePage_loggedIn) .mx_WelcomePage_guestFunctions {
|
.mx_WelcomePage:not(.mx_WelcomePage_loggedIn) .mx_WelcomePage_guestFunctions {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ButtonRow.mx_WelcomePage_guestFunctions {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
.mx_ButtonRow.mx_WelcomePage_guestFunctions > div {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 480px) {
|
|
||||||
.mx_ButtonRow {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ButtonRow > * {
|
.mx_ButtonRow.mx_WelcomePage_guestFunctions {
|
||||||
margin: 0 0 10px 0;
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.mx_ButtonRow.mx_WelcomePage_guestFunctions > div {
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@media only screen and (max-width: 480px) {
|
||||||
|
.mx_ButtonRow {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_ButtonRow > * {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="mx_Parent">
|
<div class="mx_Parent">
|
||||||
<a href="https://element.io" target="_blank" rel="noopener">
|
<a href="https://element.io" target="_blank" rel="noopener">
|
||||||
<img src="welcome/images/logo.svg" alt="" class="mx_Logo"/>
|
<img src="welcome/images/logo.svg" alt="" class="mx_Logo" />
|
||||||
</a>
|
</a>
|
||||||
<h1 class="mx_Header_title">_t("Welcome to Element")</h1>
|
<h1 class="mx_Header_title">_t("Welcome to Element")</h1>
|
||||||
<!-- XXX: Our translations system isn't smart enough to recognize variables in the HTML, so we manually do it -->
|
<!-- XXX: Our translations system isn't smart enough to recognize variables in the HTML, so we manually do it -->
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const { exec } = require("node:child_process");
|
const { exec } = require("node:child_process");
|
||||||
|
|
|
@ -21,11 +21,13 @@ if (process.env.HTTPS_PROXY) {
|
||||||
options.agent = new ProxyAgent(process.env.HTTPS_PROXY, { tunnel: true });
|
options.agent = new ProxyAgent(process.env.HTTPS_PROXY, { tunnel: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch("https://meet.element.io/libs/external_api.min.js", options).then(res => {
|
fetch("https://meet.element.io/libs/external_api.min.js", options)
|
||||||
const stream = fs.createWriteStream(fname);
|
.then((res) => {
|
||||||
return new Promise((resolve, reject) => {
|
const stream = fs.createWriteStream(fname);
|
||||||
res.body.pipe(stream);
|
return new Promise((resolve, reject) => {
|
||||||
res.body.on('error', err => reject(err));
|
res.body.pipe(stream);
|
||||||
res.body.on('finish', () => resolve());
|
res.body.on("error", (err) => reject(err));
|
||||||
});
|
res.body.on("finish", () => resolve());
|
||||||
}).then(() => console.log('Done with Jitsi download'));
|
});
|
||||||
|
})
|
||||||
|
.then(() => console.log("Done with Jitsi download"));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Runs package.sh, passing DIST_VERSION determined by git
|
# Runs package.sh, passing DIST_VERSION determined by git
|
||||||
|
|
||||||
|
|
|
@ -11,58 +11,59 @@ const loaderUtils = require("loader-utils");
|
||||||
// This could readily be automated, but it's nice to explicitly
|
// This could readily be automated, but it's nice to explicitly
|
||||||
// control when new languages are available.
|
// control when new languages are available.
|
||||||
const INCLUDE_LANGS = [
|
const INCLUDE_LANGS = [
|
||||||
{'value': 'bg', 'label': 'Български'},
|
{ value: "bg", label: "Български" },
|
||||||
{'value': 'ca', 'label': 'Català'},
|
{ value: "ca", label: "Català" },
|
||||||
{'value': 'cs', 'label': 'čeština'},
|
{ value: "cs", label: "čeština" },
|
||||||
{'value': 'da', 'label': 'Dansk'},
|
{ value: "da", label: "Dansk" },
|
||||||
{'value': 'de_DE', 'label': 'Deutsch'},
|
{ value: "de_DE", label: "Deutsch" },
|
||||||
{'value': 'el', 'label': 'Ελληνικά'},
|
{ value: "el", label: "Ελληνικά" },
|
||||||
{'value': 'en_EN', 'label': 'English'},
|
{ value: "en_EN", label: "English" },
|
||||||
{'value': 'en_US', 'label': 'English (US)'},
|
{ value: "en_US", label: "English (US)" },
|
||||||
{'value': 'eo', 'label': 'Esperanto'},
|
{ value: "eo", label: "Esperanto" },
|
||||||
{'value': 'es', 'label': 'Español'},
|
{ value: "es", label: "Español" },
|
||||||
{'value': 'et', 'label': 'Eesti'},
|
{ value: "et", label: "Eesti" },
|
||||||
{'value': 'eu', 'label': 'Euskara'},
|
{ value: "eu", label: "Euskara" },
|
||||||
{'value': 'fi', 'label': 'Suomi'},
|
{ value: "fi", label: "Suomi" },
|
||||||
{'value': 'fr', 'label': 'Français'},
|
{ value: "fr", label: "Français" },
|
||||||
{'value': 'gl', 'label': 'Galego'},
|
{ value: "gl", label: "Galego" },
|
||||||
{'value': 'he', 'label': 'עברית'},
|
{ value: "he", label: "עברית" },
|
||||||
{'value': 'hi', 'label': 'हिन्दी'},
|
{ value: "hi", label: "हिन्दी" },
|
||||||
{'value': 'hu', 'label': 'Magyar'},
|
{ value: "hu", label: "Magyar" },
|
||||||
{'value': 'id', 'label': 'Bahasa Indonesia'},
|
{ value: "id", label: "Bahasa Indonesia" },
|
||||||
{'value': 'is', 'label': 'íslenska'},
|
{ value: "is", label: "íslenska" },
|
||||||
{'value': 'it', 'label': 'Italiano'},
|
{ value: "it", label: "Italiano" },
|
||||||
{'value': 'ja', 'label': '日本語'},
|
{ value: "ja", label: "日本語" },
|
||||||
{'value': 'kab', 'label': 'Taqbaylit'},
|
{ value: "kab", label: "Taqbaylit" },
|
||||||
{'value': 'ko', 'label': '한국어'},
|
{ value: "ko", label: "한국어" },
|
||||||
{'value': 'lo', 'label': 'ລາວ'},
|
{ value: "lo", label: "ລາວ" },
|
||||||
{'value': 'lt', 'label': 'Lietuvių'},
|
{ value: "lt", label: "Lietuvių" },
|
||||||
{'value': 'lv', 'label': 'Latviešu'},
|
{ value: "lv", label: "Latviešu" },
|
||||||
{'value': 'nb_NO', 'label': 'Norwegian Bokmål'},
|
{ value: "nb_NO", label: "Norwegian Bokmål" },
|
||||||
{'value': 'nl', 'label': 'Nederlands'},
|
{ value: "nl", label: "Nederlands" },
|
||||||
{'value': 'nn', 'label': 'Norsk Nynorsk'},
|
{ value: "nn", label: "Norsk Nynorsk" },
|
||||||
{'value': 'pl', 'label': 'Polski'},
|
{ value: "pl", label: "Polski" },
|
||||||
{'value': 'pt', 'label': 'Português'},
|
{ value: "pt", label: "Português" },
|
||||||
{'value': 'pt_BR', 'label': 'Português do Brasil'},
|
{ value: "pt_BR", label: "Português do Brasil" },
|
||||||
{'value': 'ru', 'label': 'Русский'},
|
{ value: "ru", label: "Русский" },
|
||||||
{'value': 'sk', 'label': 'Slovenčina'},
|
{ value: "sk", label: "Slovenčina" },
|
||||||
{'value': 'sq', 'label': 'Shqip'},
|
{ value: "sq", label: "Shqip" },
|
||||||
{'value': 'sr', 'label': 'српски'},
|
{ value: "sr", label: "српски" },
|
||||||
{'value': 'sv', 'label': 'Svenska'},
|
{ value: "sv", label: "Svenska" },
|
||||||
{'value': 'te', 'label': 'తెలుగు'},
|
{ value: "te", label: "తెలుగు" },
|
||||||
{'value': 'th', 'label': 'ไทย'},
|
{ value: "th", label: "ไทย" },
|
||||||
{'value': 'tr', 'label': 'Türkçe'},
|
{ value: "tr", label: "Türkçe" },
|
||||||
{'value': 'uk', 'label': 'українська мова'},
|
{ value: "uk", label: "українська мова" },
|
||||||
{'value': 'vi', 'label': 'Tiếng Việt'},
|
{ value: "vi", label: "Tiếng Việt" },
|
||||||
{'value': 'vls', 'label': 'West-Vlaams'},
|
{ value: "vls", label: "West-Vlaams" },
|
||||||
{'value': 'zh_Hans', 'label': '简体中文'}, // simplified chinese
|
{ value: "zh_Hans", label: "简体中文" }, // simplified chinese
|
||||||
{'value': 'zh_Hant', 'label': '繁體中文'}, // traditional chinese
|
{ value: "zh_Hant", label: "繁體中文" }, // traditional chinese
|
||||||
];
|
];
|
||||||
|
|
||||||
// cpx includes globbed parts of the filename in the destination, but excludes
|
// cpx includes globbed parts of the filename in the destination, but excludes
|
||||||
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
||||||
// "dest/b/...".
|
// "dest/b/...".
|
||||||
const COPY_LIST = [
|
const COPY_LIST = [
|
||||||
|
["res/apple-app-site-association", "webapp"],
|
||||||
["res/manifest.json", "webapp"],
|
["res/manifest.json", "webapp"],
|
||||||
["res/sw.js", "webapp"],
|
["res/sw.js", "webapp"],
|
||||||
["res/welcome.html", "webapp"],
|
["res/welcome.html", "webapp"],
|
||||||
|
@ -76,15 +77,13 @@ const COPY_LIST = [
|
||||||
["contribute.json", "webapp"],
|
["contribute.json", "webapp"],
|
||||||
];
|
];
|
||||||
|
|
||||||
const parseArgs = require('minimist');
|
const parseArgs = require("minimist");
|
||||||
const Cpx = require('cpx');
|
const Cpx = require("cpx");
|
||||||
const chokidar = require('chokidar');
|
const chokidar = require("chokidar");
|
||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const rimraf = require('rimraf');
|
const rimraf = require("rimraf");
|
||||||
|
|
||||||
const argv = parseArgs(
|
const argv = parseArgs(process.argv.slice(2), {});
|
||||||
process.argv.slice(2), {}
|
|
||||||
);
|
|
||||||
|
|
||||||
const watch = argv.w;
|
const watch = argv.w;
|
||||||
const verbose = argv.v;
|
const verbose = argv.v;
|
||||||
|
@ -97,12 +96,12 @@ function errCheck(err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if webapp exists
|
// Check if webapp exists
|
||||||
if (!fs.existsSync('webapp')) {
|
if (!fs.existsSync("webapp")) {
|
||||||
fs.mkdirSync('webapp');
|
fs.mkdirSync("webapp");
|
||||||
}
|
}
|
||||||
// Check if i18n exists
|
// Check if i18n exists
|
||||||
if (!fs.existsSync('webapp/i18n/')) {
|
if (!fs.existsSync("webapp/i18n/")) {
|
||||||
fs.mkdirSync('webapp/i18n/');
|
fs.mkdirSync("webapp/i18n/");
|
||||||
}
|
}
|
||||||
|
|
||||||
function next(i, err) {
|
function next(i, err) {
|
||||||
|
@ -131,7 +130,9 @@ function next(i, err) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cb = (err) => { next(i + 1, err) };
|
const cb = (err) => {
|
||||||
|
next(i + 1, err);
|
||||||
|
};
|
||||||
|
|
||||||
if (watch) {
|
if (watch) {
|
||||||
if (opts.directwatch) {
|
if (opts.directwatch) {
|
||||||
|
@ -139,14 +140,12 @@ function next(i, err) {
|
||||||
// which in the case of config.json is '.', which inevitably takes
|
// which in the case of config.json is '.', which inevitably takes
|
||||||
// ages to crawl. So we create our own watcher on the files
|
// ages to crawl. So we create our own watcher on the files
|
||||||
// instead.
|
// instead.
|
||||||
const copy = () => { cpx.copy(errCheck) };
|
const copy = () => {
|
||||||
chokidar.watch(source)
|
cpx.copy(errCheck);
|
||||||
.on('add', copy)
|
};
|
||||||
.on('change', copy)
|
chokidar.watch(source).on("add", copy).on("change", copy).on("ready", cb).on("error", errCheck);
|
||||||
.on('ready', cb)
|
|
||||||
.on('error', errCheck);
|
|
||||||
} else {
|
} else {
|
||||||
cpx.on('watch-ready', cb);
|
cpx.on("watch-ready", cb);
|
||||||
cpx.on("watch-error", cb);
|
cpx.on("watch-error", cb);
|
||||||
cpx.watch();
|
cpx.watch();
|
||||||
}
|
}
|
||||||
|
@ -156,17 +155,14 @@ function next(i, err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function genLangFile(lang, dest) {
|
function genLangFile(lang, dest) {
|
||||||
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
|
const reactSdkFile = "node_modules/matrix-react-sdk/src/i18n/strings/" + lang + ".json";
|
||||||
const riotWebFile = 'src/i18n/strings/' + lang + '.json';
|
const riotWebFile = "src/i18n/strings/" + lang + ".json";
|
||||||
|
|
||||||
let translations = {};
|
let translations = {};
|
||||||
[reactSdkFile, riotWebFile].forEach(function(f) {
|
[reactSdkFile, riotWebFile].forEach(function (f) {
|
||||||
if (fs.existsSync(f)) {
|
if (fs.existsSync(f)) {
|
||||||
try {
|
try {
|
||||||
Object.assign(
|
Object.assign(translations, JSON.parse(fs.readFileSync(f).toString()));
|
||||||
translations,
|
|
||||||
JSON.parse(fs.readFileSync(f).toString())
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed: " + f, e);
|
console.error("Failed: " + f, e);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -191,16 +187,16 @@ function genLangFile(lang, dest) {
|
||||||
|
|
||||||
function genLangList(langFileMap) {
|
function genLangList(langFileMap) {
|
||||||
const languages = {};
|
const languages = {};
|
||||||
INCLUDE_LANGS.forEach(function(lang) {
|
INCLUDE_LANGS.forEach(function (lang) {
|
||||||
const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
|
const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
|
||||||
const languageParts = normalizedLanguage.split('-');
|
const languageParts = normalizedLanguage.split("-");
|
||||||
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
||||||
languages[languageParts[0]] = {'fileName': langFileMap[lang.value], 'label': lang.label};
|
languages[languageParts[0]] = { fileName: langFileMap[lang.value], label: lang.label };
|
||||||
} else {
|
} else {
|
||||||
languages[normalizedLanguage] = {'fileName': langFileMap[lang.value], 'label': lang.label};
|
languages[normalizedLanguage] = { fileName: langFileMap[lang.value], label: lang.label };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) {
|
fs.writeFile("webapp/i18n/languages.json", JSON.stringify(languages, null, 4), function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Copy Error occured: " + err);
|
console.error("Copy Error occured: " + err);
|
||||||
throw new Error("Failed to generate languages.json");
|
throw new Error("Failed to generate languages.json");
|
||||||
|
@ -229,7 +225,7 @@ function weblateToCounterpart(inTrs) {
|
||||||
const outTrs = {};
|
const outTrs = {};
|
||||||
|
|
||||||
for (const key of Object.keys(inTrs)) {
|
for (const key of Object.keys(inTrs)) {
|
||||||
const keyParts = key.split('|', 2);
|
const keyParts = key.split("|", 2);
|
||||||
if (keyParts.length === 2) {
|
if (keyParts.length === 2) {
|
||||||
let obj = outTrs[keyParts[0]];
|
let obj = outTrs[keyParts[0]];
|
||||||
if (obj === undefined) {
|
if (obj === undefined) {
|
||||||
|
@ -238,7 +234,7 @@ function weblateToCounterpart(inTrs) {
|
||||||
// This is a transitional edge case if a string went from singular to pluralised and both still remain
|
// This is a transitional edge case if a string went from singular to pluralised and both still remain
|
||||||
// in the translation json file. Use the singular translation as `other` and merge pluralisation atop.
|
// in the translation json file. Use the singular translation as `other` and merge pluralisation atop.
|
||||||
obj = outTrs[keyParts[0]] = {
|
obj = outTrs[keyParts[0]] = {
|
||||||
"other": inTrs[key],
|
other: inTrs[key],
|
||||||
};
|
};
|
||||||
console.warn("Found entry in i18n file in both singular and pluralised form", keyParts[0]);
|
console.warn("Found entry in i18n file in both singular and pluralised form", keyParts[0]);
|
||||||
}
|
}
|
||||||
|
@ -257,8 +253,8 @@ regenerate the file, adding its content-hashed filename to langFileMap
|
||||||
and regenerating languages.json with the new filename
|
and regenerating languages.json with the new filename
|
||||||
*/
|
*/
|
||||||
function watchLanguage(lang, dest, langFileMap) {
|
function watchLanguage(lang, dest, langFileMap) {
|
||||||
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
|
const reactSdkFile = "node_modules/matrix-react-sdk/src/i18n/strings/" + lang + ".json";
|
||||||
const riotWebFile = 'src/i18n/strings/' + lang + '.json';
|
const riotWebFile = "src/i18n/strings/" + lang + ".json";
|
||||||
|
|
||||||
// XXX: Use a debounce because for some reason if we read the language
|
// XXX: Use a debounce because for some reason if we read the language
|
||||||
// file immediately after the FS event is received, the file contents
|
// file immediately after the FS event is received, the file contents
|
||||||
|
@ -270,16 +266,13 @@ function watchLanguage(lang, dest, langFileMap) {
|
||||||
}
|
}
|
||||||
makeLangDebouncer = setTimeout(() => {
|
makeLangDebouncer = setTimeout(() => {
|
||||||
const filename = genLangFile(lang, dest);
|
const filename = genLangFile(lang, dest);
|
||||||
langFileMap[lang]=filename;
|
langFileMap[lang] = filename;
|
||||||
genLangList(langFileMap);
|
genLangList(langFileMap);
|
||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
[reactSdkFile, riotWebFile].forEach(function(f) {
|
[reactSdkFile, riotWebFile].forEach(function (f) {
|
||||||
chokidar.watch(f)
|
chokidar.watch(f).on("add", makeLang).on("change", makeLang).on("error", errCheck);
|
||||||
.on('add', makeLang)
|
|
||||||
.on('change', makeLang)
|
|
||||||
.on('error', errCheck);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +286,7 @@ const I18N_FILENAME_MAP = INCLUDE_LANGS.reduce((m, l) => {
|
||||||
genLangList(I18N_FILENAME_MAP);
|
genLangList(I18N_FILENAME_MAP);
|
||||||
|
|
||||||
if (watch) {
|
if (watch) {
|
||||||
INCLUDE_LANGS.forEach(l => watchLanguage(l.value, I18N_DEST, I18N_FILENAME_MAP));
|
INCLUDE_LANGS.forEach((l) => watchLanguage(l.value, I18N_DEST, I18N_FILENAME_MAP));
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-language resources
|
// non-language resources
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
#
|
#
|
||||||
# download and unpack a element-web tarball.
|
# download and unpack a element-web tarball.
|
||||||
#
|
#
|
||||||
# Allows `bundles` to be extracted to a common directory, and a link to
|
# Allows `bundles` to be extracted to a common directory, and a link to
|
||||||
# config.json to be added.
|
# config.json to be added.
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import errno
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -15,21 +14,26 @@ import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
import shutil
|
import shutil
|
||||||
import glob
|
import glob
|
||||||
|
from urllib.request import urlretrieve
|
||||||
|
|
||||||
try:
|
|
||||||
# python3
|
|
||||||
from urllib.request import urlretrieve
|
|
||||||
except ImportError:
|
|
||||||
# python2
|
|
||||||
from urllib import urlretrieve
|
|
||||||
|
|
||||||
class DeployException(Exception):
|
class DeployException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def create_relative_symlink(linkname, target):
|
def create_relative_symlink(linkname, target):
|
||||||
relpath = os.path.relpath(target, os.path.dirname(linkname))
|
relpath = os.path.relpath(target, os.path.dirname(linkname))
|
||||||
print ("Symlink %s -> %s" % (linkname, relpath))
|
print("Symlink %s -> %s" % (linkname, relpath))
|
||||||
os.symlink(relpath, linkname)
|
|
||||||
|
try:
|
||||||
|
os.symlink(relpath, linkname)
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == errno.EEXIST:
|
||||||
|
# atomic modification
|
||||||
|
os.symlink(relpath, linkname + ".tmp")
|
||||||
|
os.rename(linkname + ".tmp", linkname)
|
||||||
|
else:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def move_bundles(source, dest):
|
def move_bundles(source, dest):
|
||||||
|
@ -50,33 +54,35 @@ def move_bundles(source, dest):
|
||||||
for f in os.listdir(source):
|
for f in os.listdir(source):
|
||||||
dst = os.path.join(dest, f)
|
dst = os.path.join(dest, f)
|
||||||
if os.path.exists(dst):
|
if os.path.exists(dst):
|
||||||
print (
|
print(
|
||||||
"Skipping bundle. The bundle includes '%s' which we have previously deployed."
|
"Skipping bundle. The bundle includes '%s' which we have previously deployed."
|
||||||
% f
|
% f
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
renames[os.path.join(source, f)] = dst
|
renames[os.path.join(source, f)] = dst
|
||||||
|
|
||||||
for (src, dst) in renames.iteritems():
|
for (src, dst) in renames.items():
|
||||||
print ("Move %s -> %s" % (src, dst))
|
print("Move %s -> %s" % (src, dst))
|
||||||
os.rename(src, dst)
|
os.rename(src, dst)
|
||||||
|
|
||||||
|
|
||||||
class Deployer:
|
class Deployer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.packages_path = "."
|
self.packages_path = "."
|
||||||
self.bundles_path = None
|
self.bundles_path = None
|
||||||
self.should_clean = False
|
self.should_clean = False
|
||||||
|
self.symlink_latest = None
|
||||||
# filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json'
|
# filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json'
|
||||||
self.symlink_paths = {}
|
self.symlink_paths = {}
|
||||||
self.verify_signature = True
|
self.verify_signature = True
|
||||||
|
|
||||||
def deploy(self, tarball, extract_path):
|
def fetch(self, tarball, extract_path):
|
||||||
"""Download a tarball if necessary, and unpack it
|
"""Download a tarball, verifies it if needed, and unpacks it
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
(str) the path to the unpacked deployment
|
(str) the path to the unpacked directory
|
||||||
"""
|
"""
|
||||||
print("Deploying %s to %s" % (tarball, extract_path))
|
print("Fetching %s to %s" % (tarball, extract_path))
|
||||||
|
|
||||||
name_str = os.path.basename(tarball).replace(".tar.gz", "")
|
name_str = os.path.basename(tarball).replace(".tar.gz", "")
|
||||||
extracted_dir = os.path.join(extract_path, name_str)
|
extracted_dir = os.path.join(extract_path, name_str)
|
||||||
|
@ -92,15 +98,37 @@ class Deployer:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with tarfile.open(tarball) as tar:
|
with tarfile.open(tarball) as tar:
|
||||||
tar.extractall(extract_path)
|
def is_within_directory(directory, target):
|
||||||
|
abs_directory = os.path.abspath(directory)
|
||||||
|
abs_target = os.path.abspath(target)
|
||||||
|
|
||||||
|
prefix = os.path.commonprefix([abs_directory, abs_target])
|
||||||
|
|
||||||
|
return prefix == abs_directory
|
||||||
|
|
||||||
|
def safe_extract(tar, path=".", members=None, *, numeric_owner=False):
|
||||||
|
for member in tar.getmembers():
|
||||||
|
member_path = os.path.join(path, member.name)
|
||||||
|
if not is_within_directory(path, member_path):
|
||||||
|
raise Exception("Attempted Path Traversal in Tar File")
|
||||||
|
|
||||||
|
tar.extractall(path, members, numeric_owner=numeric_owner)
|
||||||
|
|
||||||
|
|
||||||
|
safe_extract(tar, extract_path)
|
||||||
finally:
|
finally:
|
||||||
if self.should_clean and downloaded:
|
if self.should_clean and downloaded:
|
||||||
os.remove(tarball)
|
os.remove(tarball)
|
||||||
|
|
||||||
print ("Extracted into: %s" % extracted_dir)
|
print("Extracted into: %s" % extracted_dir)
|
||||||
|
return extracted_dir
|
||||||
|
|
||||||
|
def deploy(self, extracted_dir):
|
||||||
|
"""Applies symlinks and handles the bundles directory on an extracted tarball"""
|
||||||
|
print("Deploying %s" % extracted_dir)
|
||||||
|
|
||||||
if self.symlink_paths:
|
if self.symlink_paths:
|
||||||
for link_path, file_path in self.symlink_paths.iteritems():
|
for link_path, file_path in self.symlink_paths.items():
|
||||||
create_relative_symlink(
|
create_relative_symlink(
|
||||||
target=file_path,
|
target=file_path,
|
||||||
linkname=os.path.join(extracted_dir, link_path)
|
linkname=os.path.join(extracted_dir, link_path)
|
||||||
|
@ -117,7 +145,12 @@ class Deployer:
|
||||||
target=self.bundles_path,
|
target=self.bundles_path,
|
||||||
linkname=extracted_bundles,
|
linkname=extracted_bundles,
|
||||||
)
|
)
|
||||||
return extracted_dir
|
|
||||||
|
if self.symlink_latest:
|
||||||
|
create_relative_symlink(
|
||||||
|
target=extracted_dir,
|
||||||
|
linkname=self.symlink_latest,
|
||||||
|
)
|
||||||
|
|
||||||
def download_and_verify(self, url):
|
def download_and_verify(self, url):
|
||||||
tarball = self.download_file(url)
|
tarball = self.download_file(url)
|
||||||
|
@ -139,6 +172,7 @@ class Deployer:
|
||||||
print ("Done")
|
print ("Done")
|
||||||
return local_filename
|
return local_filename
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser("Deploy a Riot build on a web server.")
|
parser = argparse.ArgumentParser("Deploy a Riot build on a web server.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -173,8 +207,15 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"tarball", help=(
|
"-s", "--symlink", dest="symlink", default="./latest", help=(
|
||||||
"filename of tarball, or URL to download."
|
"Write a symlink to this location pointing to the extracted tarball. \
|
||||||
|
New builds will keep overwriting this symlink. The symlink will point \
|
||||||
|
to the webapp directory INSIDE the tarball."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"target", help=(
|
||||||
|
"filename of extracted directory, tarball, or URL to download."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -184,8 +225,18 @@ if __name__ == "__main__":
|
||||||
deployer.packages_path = args.packages_dir
|
deployer.packages_path = args.packages_dir
|
||||||
deployer.bundles_path = args.bundles_dir
|
deployer.bundles_path = args.bundles_dir
|
||||||
deployer.should_clean = args.clean
|
deployer.should_clean = args.clean
|
||||||
|
deployer.symlink_latest = args.symlink
|
||||||
|
|
||||||
for include in args.include:
|
for include in args.include:
|
||||||
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
||||||
|
|
||||||
deployer.deploy(args.tarball, args.extract_path)
|
if os.path.isdir(args.target):
|
||||||
|
# If the given directory contains a single directory then use that instead, the ci package wraps in an extra dir
|
||||||
|
files = os.listdir(args.target)
|
||||||
|
if len(files) == 1 and os.path.isdir(os.path.join(args.target, files[0])):
|
||||||
|
extracted_dir = os.path.join(args.target, files[0])
|
||||||
|
else:
|
||||||
|
extracted_dir = args.target
|
||||||
|
else:
|
||||||
|
extracted_dir = deployer.fetch(args.target, args.extract_path)
|
||||||
|
deployer.deploy(extracted_dir)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
@ -7,8 +7,10 @@ DIST_VERSION=$(git describe --abbrev=0 --tags)
|
||||||
|
|
||||||
DIR=$(dirname "$0")
|
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 the branch comes out as HEAD then we're probably checked out to a tag, so if the thing is *not*
|
||||||
if [[ $USE_CUSTOM_SDKS == false ]] && [[ $BRANCH != 'master' ]]
|
# 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
|
then
|
||||||
DIST_VERSION=$("$DIR"/get-version-from-git.sh)
|
DIST_VERSION=$("$DIR"/get-version-from-git.sh)
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Fetches the js-sdk and matrix-react-sdk dependencies for development
|
# Fetches the js-sdk and matrix-react-sdk dependencies for development
|
||||||
# or testing purposes
|
# or testing purposes
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
# the branch the current checkout is on, use that branch. Otherwise,
|
# the branch the current checkout is on, use that branch. Otherwise,
|
||||||
# use develop.
|
# use develop.
|
||||||
|
|
||||||
set -ex
|
set -x
|
||||||
|
|
||||||
GIT_CLONE_ARGS=("$@")
|
GIT_CLONE_ARGS=("$@")
|
||||||
[ -z "$defbranch" ] && defbranch="develop"
|
[ -z "$defbranch" ] && defbranch="develop"
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
# all phonenumber.js-supported country flags (as SVGs) into
|
# all phonenumber.js-supported country flags (as SVGs) into
|
||||||
# PNGs that can be used by CountryDropdown.js.
|
# PNGs that can be used by CountryDropdown.js.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
# Allow CTRL+C to terminate the script
|
# Allow CTRL+C to terminate the script
|
||||||
trap "echo Exited!; exit;" SIGINT SIGTERM
|
trap "echo Exited!; exit;" SIGINT SIGTERM
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Echoes a version based on the git hashes of the element-web, react-sdk & js-sdk checkouts, for the case where
|
# 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.
|
# these dependencies are git checkouts.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
# Since the deps are fetched from git, we can rev-parse
|
# 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)
|
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)
|
JSSDK_SHA=$(git -C node_modules/matrix-js-sdk rev-parse --short=12 HEAD)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -x
|
set -ex
|
||||||
|
|
||||||
# Creates a layered environment with the full repo for the app and SDKs cloned
|
# 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
|
# and linked. This gives an element-web dev environment ready to build with
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# Converts an svg logo into the various image resources required by
|
# Converts an svg logo into the various image resources required by
|
||||||
# the various platforms deployments.
|
# the various platforms deployments.
|
||||||
|
@ -12,8 +12,7 @@ then
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -e
|
set -ex
|
||||||
set -x
|
|
||||||
|
|
||||||
tmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'icontmp'`
|
tmpdir=`mktemp -d 2>/dev/null || mktemp -d -t 'icontmp'`
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env 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 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
|
if [[ $1 =~ ^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+(-.+)?$ ]]; then
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
|
|
@ -1,308 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# auto-deploy script for https://develop.element.io
|
|
||||||
#
|
|
||||||
# Listens for buildkite webhook pokes (https://buildkite.com/docs/apis/webhooks)
|
|
||||||
# When it gets one, downloads the artifact from buildkite
|
|
||||||
# and deploys it as the new version.
|
|
||||||
#
|
|
||||||
# Requires the following python packages:
|
|
||||||
#
|
|
||||||
# - requests
|
|
||||||
# - flask
|
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
import json, requests, tarfile, argparse, os, errno
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
from urlparse import urljoin
|
|
||||||
import glob
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import threading
|
|
||||||
from Queue import Queue
|
|
||||||
|
|
||||||
from flask import Flask, jsonify, request, abort
|
|
||||||
|
|
||||||
from deploy import Deployer, DeployException
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
deployer = None
|
|
||||||
arg_extract_path = None
|
|
||||||
arg_symlink = None
|
|
||||||
arg_webhook_token = None
|
|
||||||
arg_api_token = None
|
|
||||||
|
|
||||||
workQueue = Queue()
|
|
||||||
|
|
||||||
def create_symlink(source, linkname):
|
|
||||||
try:
|
|
||||||
os.symlink(source, linkname)
|
|
||||||
except OSError, e:
|
|
||||||
if e.errno == errno.EEXIST:
|
|
||||||
# atomic modification
|
|
||||||
os.symlink(source, linkname + ".tmp")
|
|
||||||
os.rename(linkname + ".tmp", linkname)
|
|
||||||
else:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def req_headers():
|
|
||||||
return {
|
|
||||||
"Authorization": "Bearer %s" % (arg_api_token,),
|
|
||||||
}
|
|
||||||
|
|
||||||
# Buildkite considers a poke to have failed if it has to wait more than 10s for
|
|
||||||
# data (any data, not just the initial response) and it normally takes longer than
|
|
||||||
# that to download an artifact from buildkite. Apparently there is no way in flask
|
|
||||||
# to finish the response and then keep doing stuff, so instead this has to involve
|
|
||||||
# threading. Sigh.
|
|
||||||
def worker_thread():
|
|
||||||
while True:
|
|
||||||
toDeploy = workQueue.get()
|
|
||||||
deploy_buildkite_artifact(*toDeploy)
|
|
||||||
|
|
||||||
@app.route("/", methods=["POST"])
|
|
||||||
def on_receive_buildkite_poke():
|
|
||||||
got_webhook_token = request.headers.get('X-Buildkite-Token')
|
|
||||||
if got_webhook_token != arg_webbook_token:
|
|
||||||
print("Denying request with incorrect webhook token: %s" % (got_webhook_token,))
|
|
||||||
abort(400, "Incorrect webhook token")
|
|
||||||
return
|
|
||||||
|
|
||||||
required_api_prefix = None
|
|
||||||
if arg_buildkite_org is not None:
|
|
||||||
required_api_prefix = 'https://api.buildkite.com/v2/organizations/%s' % (arg_buildkite_org,)
|
|
||||||
|
|
||||||
incoming_json = request.get_json()
|
|
||||||
if not incoming_json:
|
|
||||||
abort(400, "No JSON provided!")
|
|
||||||
return
|
|
||||||
print("Incoming JSON: %s" % (incoming_json,))
|
|
||||||
|
|
||||||
event = incoming_json.get("event")
|
|
||||||
if event is None:
|
|
||||||
abort(400, "No 'event' specified")
|
|
||||||
return
|
|
||||||
|
|
||||||
if event == 'ping':
|
|
||||||
print("Got ping request - responding")
|
|
||||||
return jsonify({'response': 'pong!'})
|
|
||||||
|
|
||||||
if event != 'build.finished':
|
|
||||||
print("Rejecting '%s' event")
|
|
||||||
abort(400, "Unrecognised event")
|
|
||||||
return
|
|
||||||
|
|
||||||
build_obj = incoming_json.get("build")
|
|
||||||
if build_obj is None:
|
|
||||||
abort(400, "No 'build' object")
|
|
||||||
return
|
|
||||||
|
|
||||||
build_url = build_obj.get('url')
|
|
||||||
if build_url is None:
|
|
||||||
abort(400, "build has no url")
|
|
||||||
return
|
|
||||||
|
|
||||||
if required_api_prefix is not None and not build_url.startswith(required_api_prefix):
|
|
||||||
print("Denying poke for build url with incorrect prefix: %s" % (build_url,))
|
|
||||||
abort(400, "Invalid build url")
|
|
||||||
return
|
|
||||||
|
|
||||||
build_num = build_obj.get('number')
|
|
||||||
if build_num is None:
|
|
||||||
abort(400, "build has no number")
|
|
||||||
return
|
|
||||||
|
|
||||||
pipeline_obj = incoming_json.get("pipeline")
|
|
||||||
if pipeline_obj is None:
|
|
||||||
abort(400, "No 'pipeline' object")
|
|
||||||
return
|
|
||||||
|
|
||||||
pipeline_name = pipeline_obj.get('name')
|
|
||||||
if pipeline_name is None:
|
|
||||||
abort(400, "pipeline has no name")
|
|
||||||
return
|
|
||||||
|
|
||||||
artifacts_url = build_url + "/artifacts"
|
|
||||||
artifacts_resp = requests.get(artifacts_url, headers=req_headers())
|
|
||||||
artifacts_resp.raise_for_status()
|
|
||||||
artifacts_array = artifacts_resp.json()
|
|
||||||
|
|
||||||
artifact_to_deploy = None
|
|
||||||
for artifact in artifacts_array:
|
|
||||||
if re.match(r"dist/.*.tar.gz", artifact['path']):
|
|
||||||
artifact_to_deploy = artifact
|
|
||||||
if artifact_to_deploy is None:
|
|
||||||
print("No suitable artifacts found")
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
# double paranoia check: make sure the artifact is on the right org too
|
|
||||||
if required_api_prefix is not None and not artifact_to_deploy['url'].startswith(required_api_prefix):
|
|
||||||
print("Denying poke for build url with incorrect prefix: %s" % (artifact_to_deploy['url'],))
|
|
||||||
abort(400, "Refusing to deploy artifact from URL %s", artifact_to_deploy['url'])
|
|
||||||
return
|
|
||||||
|
|
||||||
# there's no point building up a queue of things to deploy, so if there are any pending jobs,
|
|
||||||
# remove them
|
|
||||||
while not workQueue.empty():
|
|
||||||
try:
|
|
||||||
workQueue.get(False)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
workQueue.put([artifact_to_deploy, pipeline_name, build_num])
|
|
||||||
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
def deploy_buildkite_artifact(artifact, pipeline_name, build_num):
|
|
||||||
artifact_response = requests.get(artifact['url'], headers=req_headers())
|
|
||||||
artifact_response.raise_for_status()
|
|
||||||
artifact_obj = artifact_response.json()
|
|
||||||
|
|
||||||
# we extract into a directory based on the build number. This avoids the
|
|
||||||
# problem of multiple builds building the same git version and thus having
|
|
||||||
# the same tarball name. That would lead to two potential problems:
|
|
||||||
# (a) sometimes jenkins serves corrupted artifacts; we would replace
|
|
||||||
# a good deploy with a bad one
|
|
||||||
# (b) we'll be overwriting the live deployment, which means people might
|
|
||||||
# see half-written files.
|
|
||||||
build_dir = os.path.join(arg_extract_path, "%s-#%s" % (pipeline_name, build_num))
|
|
||||||
try:
|
|
||||||
extracted_dir = deploy_tarball(artifact_obj, build_dir)
|
|
||||||
except DeployException as e:
|
|
||||||
traceback.print_exc()
|
|
||||||
abort(400, e.message)
|
|
||||||
|
|
||||||
create_symlink(source=extracted_dir, linkname=arg_symlink)
|
|
||||||
|
|
||||||
def deploy_tarball(artifact, build_dir):
|
|
||||||
"""Download a tarball from jenkins and unpack it
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(str) the path to the unpacked deployment
|
|
||||||
"""
|
|
||||||
if os.path.exists(build_dir):
|
|
||||||
raise DeployException(
|
|
||||||
"Not deploying. We have previously deployed this build."
|
|
||||||
)
|
|
||||||
os.mkdir(build_dir)
|
|
||||||
|
|
||||||
print("Fetching artifact %s -> %s..." % (artifact['download_url'], artifact['filename']))
|
|
||||||
|
|
||||||
# Download the tarball here as buildkite needs auth to do this
|
|
||||||
# we don't pgp-sign buildkite artifacts, relying on HTTPS and buildkite
|
|
||||||
# not being evil. If that's not good enough for you, don't use develop.element.io.
|
|
||||||
resp = requests.get(artifact['download_url'], stream=True, headers=req_headers())
|
|
||||||
resp.raise_for_status()
|
|
||||||
with open(artifact['filename'], 'wb') as ofp:
|
|
||||||
shutil.copyfileobj(resp.raw, ofp)
|
|
||||||
print("...download complete. Deploying...")
|
|
||||||
|
|
||||||
# we rely on the fact that flask only serves one request at a time to
|
|
||||||
# ensure that we do not overwrite a tarball from a concurrent request.
|
|
||||||
|
|
||||||
return deployer.deploy(artifact['filename'], build_dir)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser("Runs a Vector redeployment server.")
|
|
||||||
parser.add_argument(
|
|
||||||
"-p", "--port", dest="port", default=4000, type=int, help=(
|
|
||||||
"The port to listen on for requests from Jenkins."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-e", "--extract", dest="extract", default="./extracted", help=(
|
|
||||||
"The location to extract .tar.gz files to."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-b", "--bundles-dir", dest="bundles_dir", help=(
|
|
||||||
"A directory to move the contents of the 'bundles' directory to. A \
|
|
||||||
symlink to the bundles directory will also be written inside the \
|
|
||||||
extracted tarball. Example: './bundles'."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-c", "--clean", dest="clean", action="store_true", default=False, help=(
|
|
||||||
"Remove .tar.gz files after they have been downloaded and extracted."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-s", "--symlink", dest="symlink", default="./latest", help=(
|
|
||||||
"Write a symlink to this location pointing to the extracted tarball. \
|
|
||||||
New builds will keep overwriting this symlink. The symlink will point \
|
|
||||||
to the /vector directory INSIDE the tarball."
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# --include ../../config.json ./localhost.json homepages/*
|
|
||||||
parser.add_argument(
|
|
||||||
"--include", nargs='*', default='./config*.json', help=(
|
|
||||||
"Symlink these files into the root of the deployed tarball. \
|
|
||||||
Useful for config files and home pages. Supports glob syntax. \
|
|
||||||
(Default: '%(default)s')"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--test", dest="tarball_uri", help=(
|
|
||||||
"Don't start an HTTP listener. Instead download a build from Jenkins \
|
|
||||||
immediately."
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--webhook-token", dest="webhook_token", help=(
|
|
||||||
"Only accept pokes with this buildkite token."
|
|
||||||
), required=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
"--api-token", dest="api_token", help=(
|
|
||||||
"API access token for buildkite. Require read_artifacts scope."
|
|
||||||
), required=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# We require a matching webhook token, but because we take everything else
|
|
||||||
# about what to deploy from the poke body, we can be a little more paranoid
|
|
||||||
# and only accept builds / artifacts from a specific buildkite org
|
|
||||||
parser.add_argument(
|
|
||||||
"--org", dest="buildkite_org", help=(
|
|
||||||
"Lock down to this buildkite org"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
arg_extract_path = args.extract
|
|
||||||
arg_symlink = args.symlink
|
|
||||||
arg_webbook_token = args.webhook_token
|
|
||||||
arg_api_token = args.api_token
|
|
||||||
arg_buildkite_org = args.buildkite_org
|
|
||||||
|
|
||||||
if not os.path.isdir(arg_extract_path):
|
|
||||||
os.mkdir(arg_extract_path)
|
|
||||||
|
|
||||||
deployer = Deployer()
|
|
||||||
deployer.bundles_path = args.bundles_dir
|
|
||||||
deployer.should_clean = args.clean
|
|
||||||
|
|
||||||
for include in args.include:
|
|
||||||
deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) })
|
|
||||||
|
|
||||||
if args.tarball_uri is not None:
|
|
||||||
build_dir = os.path.join(arg_extract_path, "test-%i" % (time.time()))
|
|
||||||
deploy_tarball(args.tarball_uri, build_dir)
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
"Listening on port %s. Extracting to %s%s. Symlinking to %s. Include files: %s" %
|
|
||||||
(args.port,
|
|
||||||
arg_extract_path,
|
|
||||||
" (clean after)" if deployer.should_clean else "",
|
|
||||||
arg_symlink,
|
|
||||||
deployer.symlink_paths,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fred = threading.Thread(target=worker_thread)
|
|
||||||
fred.daemon = True
|
|
||||||
fred.start()
|
|
||||||
app.run(port=args.port, debug=False)
|
|
|
@ -11,4 +11,4 @@ sonar.exclusions=__mocks__,docs,element.io,nginx
|
||||||
sonar.typescript.tsconfigPath=./tsconfig.json
|
sonar.typescript.tsconfigPath=./tsconfig.json
|
||||||
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
||||||
sonar.coverage.exclusions=test/**/*,res/**/*
|
sonar.coverage.exclusions=test/**/*,res/**/*
|
||||||
sonar.testExecutionReportPaths=coverage/test-report.xml
|
sonar.testExecutionReportPaths=coverage/jest-sonar-report.xml
|
||||||
|
|
28
src/@types/global.d.ts
vendored
28
src/@types/global.d.ts
vendored
|
@ -19,20 +19,20 @@ import type { Renderer } from "react-dom";
|
||||||
import type { logger } from "matrix-js-sdk/src/logger";
|
import type { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
type ElectronChannel =
|
type ElectronChannel =
|
||||||
"app_onAction" |
|
| "app_onAction"
|
||||||
"before-quit" |
|
| "before-quit"
|
||||||
"check_updates" |
|
| "check_updates"
|
||||||
"install_update" |
|
| "install_update"
|
||||||
"ipcCall" |
|
| "ipcCall"
|
||||||
"ipcReply" |
|
| "ipcReply"
|
||||||
"loudNotification" |
|
| "loudNotification"
|
||||||
"preferences" |
|
| "preferences"
|
||||||
"seshat" |
|
| "seshat"
|
||||||
"seshatReply" |
|
| "seshatReply"
|
||||||
"setBadgeCount" |
|
| "setBadgeCount"
|
||||||
"update-downloaded" |
|
| "update-downloaded"
|
||||||
"userDownloadCompleted" |
|
| "userDownloadCompleted"
|
||||||
"userDownloadAction";
|
| "userDownloadAction";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
2
src/@types/raw-loader.d.ts
vendored
2
src/@types/raw-loader.d.ts
vendored
|
@ -1,4 +1,4 @@
|
||||||
declare module '!!raw-loader!*' {
|
declare module "!!raw-loader!*" {
|
||||||
const contents: string;
|
const contents: string;
|
||||||
export default contents;
|
export default contents;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { _t } from "matrix-react-sdk/src/languageHandler";
|
import { _t } from "matrix-react-sdk/src/languageHandler";
|
||||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||||
|
|
||||||
// directly import the style here as this layer does not support rethemedex at this time so no matrix-react-sdk
|
// directly import the style here as this layer does not support rethemedex at this time so no matrix-react-sdk
|
||||||
// PostCSS variables will be accessible.
|
// PostCSS variables will be accessible.
|
||||||
|
@ -32,115 +32,131 @@ const CompatibilityView: React.FC<IProps> = ({ onAccept }) => {
|
||||||
|
|
||||||
let ios = null;
|
let ios = null;
|
||||||
const iosCustomUrl = mobileBuilds?.ios;
|
const iosCustomUrl = mobileBuilds?.ios;
|
||||||
if (iosCustomUrl !== null) { // could be undefined or a string
|
if (iosCustomUrl !== null) {
|
||||||
ios = <>
|
// could be undefined or a string
|
||||||
<p><strong>iOS</strong> (iPhone or iPad)</p>
|
ios = (
|
||||||
<a
|
<>
|
||||||
href={iosCustomUrl || "https://apps.apple.com/app/vector/id1083446067"}
|
<p>
|
||||||
target="_blank"
|
<strong>iOS</strong> (iPhone or iPad)
|
||||||
className="mx_ClearDecoration"
|
</p>
|
||||||
>
|
<a
|
||||||
<img height="48" src="themes/element/img/download/apple.svg" alt="Apple App Store" />
|
href={iosCustomUrl || "https://apps.apple.com/app/vector/id1083446067"}
|
||||||
</a>
|
target="_blank"
|
||||||
</>;
|
className="mx_ClearDecoration"
|
||||||
|
>
|
||||||
|
<img height="48" src="themes/element/img/download/apple.svg" alt="Apple App Store" />
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let android = [<p className="mx_Spacer" key="header"><strong>Android</strong></p>];
|
let android = [
|
||||||
|
<p className="mx_Spacer" key="header">
|
||||||
|
<strong>Android</strong>
|
||||||
|
</p>,
|
||||||
|
];
|
||||||
const andCustomUrl = mobileBuilds?.android;
|
const andCustomUrl = mobileBuilds?.android;
|
||||||
const fdroidCustomUrl = mobileBuilds?.fdroid;
|
const fdroidCustomUrl = mobileBuilds?.fdroid;
|
||||||
if (andCustomUrl !== null) { // undefined or string
|
if (andCustomUrl !== null) {
|
||||||
android.push(<a
|
// undefined or string
|
||||||
href={andCustomUrl || "https://play.google.com/store/apps/details?id=im.vector.app"}
|
android.push(
|
||||||
target="_blank"
|
<a
|
||||||
className="mx_ClearDecoration"
|
href={andCustomUrl || "https://play.google.com/store/apps/details?id=im.vector.app"}
|
||||||
key="android"
|
target="_blank"
|
||||||
>
|
className="mx_ClearDecoration"
|
||||||
<img height="48" src="themes/element/img/download/google.svg" alt="Google Play Store" />
|
key="android"
|
||||||
</a>);
|
>
|
||||||
|
<img height="48" src="themes/element/img/download/google.svg" alt="Google Play Store" />
|
||||||
|
</a>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (fdroidCustomUrl !== null) { // undefined or string
|
if (fdroidCustomUrl !== null) {
|
||||||
android.push(<a
|
// undefined or string
|
||||||
href={fdroidCustomUrl || "https://f-droid.org/repository/browse/?fdid=im.vector.app"}
|
android.push(
|
||||||
target="_blank"
|
<a
|
||||||
className="mx_ClearDecoration"
|
href={fdroidCustomUrl || "https://f-droid.org/repository/browse/?fdid=im.vector.app"}
|
||||||
key="fdroid"
|
target="_blank"
|
||||||
>
|
className="mx_ClearDecoration"
|
||||||
<img height="48" src="themes/element/img/download/fdroid.svg" alt="F-Droid" />
|
key="fdroid"
|
||||||
</a>);
|
>
|
||||||
|
<img height="48" src="themes/element/img/download/fdroid.svg" alt="F-Droid" />
|
||||||
|
</a>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (android.length === 1) { // just a header, meaning no links
|
if (android.length === 1) {
|
||||||
|
// just a header, meaning no links
|
||||||
android = [];
|
android = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let mobileHeader = <h2 id="step2_heading">{ _t("Use %(brand)s on mobile", { brand }) }</h2>;
|
let mobileHeader = <h2 id="step2_heading">{_t("Use %(brand)s on mobile", { brand })}</h2>;
|
||||||
if (!android.length && !ios) {
|
if (!android.length && !ios) {
|
||||||
mobileHeader = null;
|
mobileHeader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mx_ErrorView">
|
return (
|
||||||
<div className="mx_ErrorView_container">
|
<div className="mx_ErrorView">
|
||||||
<div className="mx_HomePage_header">
|
<div className="mx_ErrorView_container">
|
||||||
<span className="mx_HomePage_logo">
|
<div className="mx_HomePage_header">
|
||||||
<img height="42" src="themes/element/img/logos/element-logo.svg" alt="Element" />
|
<span className="mx_HomePage_logo">
|
||||||
</span>
|
<img height="42" src="themes/element/img/logos/element-logo.svg" alt="Element" />
|
||||||
<h1>{ _t("Unsupported browser") }</h1>
|
</span>
|
||||||
</div>
|
<h1>{_t("Unsupported browser")}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mx_HomePage_col">
|
<div className="mx_HomePage_col">
|
||||||
<div className="mx_HomePage_row">
|
<div className="mx_HomePage_row">
|
||||||
<div>
|
<div>
|
||||||
<h2 id="step1_heading">{ _t("Your browser can't run %(brand)s", { brand }) }</h2>
|
<h2 id="step1_heading">{_t("Your browser can't run %(brand)s", { brand })}</h2>
|
||||||
<p>
|
<p>
|
||||||
{ _t(
|
{_t(
|
||||||
"%(brand)s uses advanced browser features which aren't " +
|
"%(brand)s uses advanced browser features which aren't " +
|
||||||
"supported by your current browser.",
|
"supported by your current browser.",
|
||||||
{ brand },
|
{ brand },
|
||||||
) }
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{ _t(
|
{_t(
|
||||||
'Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, ' +
|
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, " +
|
||||||
'or <safariLink>Safari</safariLink> for the best experience.',
|
"or <safariLink>Safari</safariLink> for the best experience.",
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
'chromeLink': (sub) => <a href="https://www.google.com/chrome">{ sub }</a>,
|
chromeLink: (sub) => <a href="https://www.google.com/chrome">{sub}</a>,
|
||||||
'firefoxLink': (sub) => <a href="https://firefox.com">{ sub }</a>,
|
firefoxLink: (sub) => <a href="https://firefox.com">{sub}</a>,
|
||||||
'safariLink': (sub) => <a href="https://apple.com/safari">{ sub }</a>,
|
safariLink: (sub) => <a href="https://apple.com/safari">{sub}</a>,
|
||||||
},
|
},
|
||||||
) }
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{ _t(
|
{_t(
|
||||||
"You can continue using your current browser, but some or all features may not work " +
|
"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.",
|
"and the look and feel of the application may be incorrect.",
|
||||||
) }
|
)}
|
||||||
</p>
|
</p>
|
||||||
<button onClick={onAccept}>
|
<button onClick={onAccept}>{_t("I understand the risks and wish to continue")}</button>
|
||||||
{ _t("I understand the risks and wish to continue") }
|
</div>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mx_HomePage_col">
|
<div className="mx_HomePage_col">
|
||||||
<div className="mx_HomePage_row">
|
<div className="mx_HomePage_row">
|
||||||
<div>
|
<div>
|
||||||
{ mobileHeader }
|
{mobileHeader}
|
||||||
{ ios }
|
{ios}
|
||||||
{ android }
|
{android}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mx_HomePage_row mx_Center mx_Spacer">
|
<div className="mx_HomePage_row mx_Center mx_Spacer">
|
||||||
<p className="mx_Spacer">
|
<p className="mx_Spacer">
|
||||||
<a href="https://element.io" target="_blank" className="mx_FooterLink">
|
<a href="https://element.io" target="_blank" className="mx_FooterLink">
|
||||||
{ _t("Go to element.io") }
|
{_t("Go to element.io")}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CompatibilityView;
|
export default CompatibilityView;
|
||||||
|
|
|
@ -28,34 +28,33 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorView: React.FC<IProps> = ({ title, messages }) => {
|
const ErrorView: React.FC<IProps> = ({ title, messages }) => {
|
||||||
return <div className="mx_ErrorView">
|
return (
|
||||||
<div className="mx_ErrorView_container">
|
<div className="mx_ErrorView">
|
||||||
<div className="mx_HomePage_header">
|
<div className="mx_ErrorView_container">
|
||||||
<span className="mx_HomePage_logo">
|
<div className="mx_HomePage_header">
|
||||||
<img height="42" src="themes/element/img/logos/element-logo.svg" alt="Element" />
|
<span className="mx_HomePage_logo">
|
||||||
</span>
|
<img height="42" src="themes/element/img/logos/element-logo.svg" alt="Element" />
|
||||||
<h1>{ _t("Failed to start") }</h1>
|
</span>
|
||||||
</div>
|
<h1>{_t("Failed to start")}</h1>
|
||||||
<div className="mx_HomePage_col">
|
</div>
|
||||||
<div className="mx_HomePage_row">
|
<div className="mx_HomePage_col">
|
||||||
<div>
|
<div className="mx_HomePage_row">
|
||||||
<h2 id="step1_heading">{ title }</h2>
|
<div>
|
||||||
{ messages && messages.map(msg => <p key={msg}>
|
<h2 id="step1_heading">{title}</h2>
|
||||||
{ msg }
|
{messages && messages.map((msg) => <p key={msg}>{msg}</p>)}
|
||||||
</p>) }
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="mx_HomePage_row mx_Center mx_Spacer">
|
||||||
<div className="mx_HomePage_row mx_Center mx_Spacer">
|
<p className="mx_Spacer">
|
||||||
<p className="mx_Spacer">
|
<a href="https://element.io" target="_blank" className="mx_FooterLink">
|
||||||
<a href="https://element.io" target="_blank" className="mx_FooterLink">
|
{_t("Go to element.io")}
|
||||||
{ _t("Go to element.io") }
|
</a>
|
||||||
</a>
|
</p>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ErrorView;
|
export default ErrorView;
|
||||||
|
|
||||||
|
|
|
@ -15,31 +15,33 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { ReactElement } from "react";
|
||||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||||
import { _t } from 'matrix-react-sdk/src/languageHandler';
|
import { _t } from "matrix-react-sdk/src/languageHandler";
|
||||||
|
|
||||||
const VectorAuthFooter = () => {
|
const VectorAuthFooter = (): ReactElement => {
|
||||||
const brandingConfig = SdkConfig.getObject("branding");
|
const brandingConfig = SdkConfig.getObject("branding");
|
||||||
const links = brandingConfig?.get("auth_footer_links") ?? [
|
const links = brandingConfig?.get("auth_footer_links") ?? [
|
||||||
{ "text": "Blog", "url": "https://element.io/blog" },
|
{ text: "Blog", url: "https://element.io/blog" },
|
||||||
{ "text": "Twitter", "url": "https://twitter.com/element_hq" },
|
{ text: "Twitter", url: "https://twitter.com/element_hq" },
|
||||||
{ "text": "GitHub", "url": "https://github.com/vector-im/element-web" },
|
{ text: "GitHub", url: "https://github.com/vector-im/element-web" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const authFooterLinks = [];
|
const authFooterLinks = [];
|
||||||
for (const linkEntry of links) {
|
for (const linkEntry of links) {
|
||||||
authFooterLinks.push(
|
authFooterLinks.push(
|
||||||
<a href={linkEntry.url} key={linkEntry.text} target="_blank" rel="noreferrer noopener">
|
<a href={linkEntry.url} key={linkEntry.text} target="_blank" rel="noreferrer noopener">
|
||||||
{ linkEntry.text }
|
{linkEntry.text}
|
||||||
</a>,
|
</a>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="mx_AuthFooter" role="contentinfo">
|
<footer className="mx_AuthFooter" role="contentinfo">
|
||||||
{ authFooterLinks }
|
{authFooterLinks}
|
||||||
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">{ _t('Powered by Matrix') }</a>
|
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
|
||||||
|
{_t("Powered by Matrix")}
|
||||||
|
</a>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,11 +15,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import * as React from "react";
|
||||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||||
|
|
||||||
export default class VectorAuthHeaderLogo extends React.PureComponent {
|
export default class VectorAuthHeaderLogo extends React.PureComponent {
|
||||||
public render() {
|
public render(): React.ReactElement {
|
||||||
const brandingConfig = SdkConfig.getObject("branding");
|
const brandingConfig = SdkConfig.getObject("branding");
|
||||||
const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg";
|
const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg";
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { CSSProperties } from 'react';
|
import * as React from "react";
|
||||||
import SdkConfig from 'matrix-react-sdk/src/SdkConfig';
|
import SdkConfig from "matrix-react-sdk/src/SdkConfig";
|
||||||
|
|
||||||
import VectorAuthFooter from "./VectorAuthFooter";
|
import VectorAuthFooter from "./VectorAuthFooter";
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ export default class VectorAuthPage extends React.PureComponent {
|
||||||
private static welcomeBackgroundUrl;
|
private static welcomeBackgroundUrl;
|
||||||
|
|
||||||
// cache the url as a static to prevent it changing without refreshing
|
// cache the url as a static to prevent it changing without refreshing
|
||||||
private static getWelcomeBackgroundUrl() {
|
private static getWelcomeBackgroundUrl(): string {
|
||||||
if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl;
|
if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl;
|
||||||
|
|
||||||
const brandingConfig = SdkConfig.getObject("branding");
|
const brandingConfig = SdkConfig.getObject("branding");
|
||||||
|
@ -42,31 +42,31 @@ export default class VectorAuthPage extends React.PureComponent {
|
||||||
return VectorAuthPage.welcomeBackgroundUrl;
|
return VectorAuthPage.welcomeBackgroundUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render(): React.ReactElement {
|
||||||
const pageStyle = {
|
const pageStyle = {
|
||||||
background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`,
|
background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalStyle: CSSProperties = {
|
const modalStyle: React.CSSProperties = {
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
background: 'initial',
|
background: "initial",
|
||||||
};
|
};
|
||||||
|
|
||||||
const blurStyle: CSSProperties = {
|
const blurStyle: React.CSSProperties = {
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
filter: 'blur(40px)',
|
filter: "blur(40px)",
|
||||||
background: pageStyle.background,
|
background: pageStyle.background,
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalContentStyle: CSSProperties = {
|
const modalContentStyle: React.CSSProperties = {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
background: 'rgba(255, 255, 255, 0.59)',
|
background: "rgba(255, 255, 255, 0.59)",
|
||||||
borderRadius: '8px',
|
borderRadius: "8px",
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -74,7 +74,7 @@ export default class VectorAuthPage extends React.PureComponent {
|
||||||
<div className="mx_AuthPage_modal" style={modalStyle}>
|
<div className="mx_AuthPage_modal" style={modalStyle}>
|
||||||
<div className="mx_AuthPage_modalBlur" style={blurStyle} />
|
<div className="mx_AuthPage_modalBlur" style={blurStyle} />
|
||||||
<div className="mx_AuthPage_modalContent" style={modalContentStyle}>
|
<div className="mx_AuthPage_modalContent" style={modalContentStyle}>
|
||||||
{ this.props.children }
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VectorAuthFooter />
|
<VectorAuthFooter />
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default class Favicon {
|
||||||
// callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown
|
// callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown
|
||||||
private readyCb?: () => void;
|
private readyCb?: () => void;
|
||||||
|
|
||||||
constructor(params: Partial<IParams> = {}) {
|
public constructor(params: Partial<IParams> = {}) {
|
||||||
this.params = { ...defaults, ...params };
|
this.params = { ...defaults, ...params };
|
||||||
|
|
||||||
this.icons = Favicon.getIcons();
|
this.icons = Favicon.getIcons();
|
||||||
|
@ -68,10 +68,10 @@ export default class Favicon {
|
||||||
const lastIcon = this.icons[this.icons.length - 1];
|
const lastIcon = this.icons[this.icons.length - 1];
|
||||||
if (lastIcon.hasAttribute("href")) {
|
if (lastIcon.hasAttribute("href")) {
|
||||||
this.baseImage.setAttribute("crossOrigin", "anonymous");
|
this.baseImage.setAttribute("crossOrigin", "anonymous");
|
||||||
this.baseImage.onload = () => {
|
this.baseImage.onload = (): void => {
|
||||||
// get height and width of the favicon
|
// get height and width of the favicon
|
||||||
this.canvas.height = (this.baseImage.height > 0) ? this.baseImage.height : 32;
|
this.canvas.height = this.baseImage.height > 0 ? this.baseImage.height : 32;
|
||||||
this.canvas.width = (this.baseImage.width > 0) ? this.baseImage.width : 32;
|
this.canvas.width = this.baseImage.width > 0 ? this.baseImage.width : 32;
|
||||||
this.context = this.canvas.getContext("2d");
|
this.context = this.canvas.getContext("2d");
|
||||||
this.ready();
|
this.ready();
|
||||||
};
|
};
|
||||||
|
@ -84,14 +84,24 @@ export default class Favicon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private reset() {
|
private reset(): void {
|
||||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
this.context.drawImage(this.baseImage, 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 = {
|
const opt = {
|
||||||
n: ((typeof n) === "number") ? Math.abs(n as number | 0) : n,
|
n: typeof n === "number" ? Math.abs(n as number | 0) : n,
|
||||||
len: ("" + n).length,
|
len: ("" + n).length,
|
||||||
// badge positioning constants as percentages
|
// badge positioning constants as percentages
|
||||||
x: 0.4,
|
x: 0.4,
|
||||||
|
@ -124,7 +134,7 @@ export default class Favicon {
|
||||||
return opt;
|
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 params = { ...this.params, ...opts };
|
||||||
const opt = this.options(n, params);
|
const opt = this.options(n, params);
|
||||||
|
|
||||||
|
@ -167,8 +177,8 @@ export default class Favicon {
|
||||||
this.context.stroke();
|
this.context.stroke();
|
||||||
this.context.fillStyle = params.textColor;
|
this.context.fillStyle = params.textColor;
|
||||||
|
|
||||||
if ((typeof opt.n) === "number" && opt.n > 999) {
|
if (typeof opt.n === "number" && opt.n > 999) {
|
||||||
const count = ((opt.n > 9999) ? 9 : Math.floor(opt.n as number / 1000)) + "k+";
|
const count = (opt.n > 9999 ? 9 : Math.floor((opt.n as number) / 1000)) + "k+";
|
||||||
this.context.fillText(count, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
|
this.context.fillText(count, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
|
||||||
} else {
|
} else {
|
||||||
this.context.fillText("" + opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
this.context.fillText("" + opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
||||||
|
@ -177,19 +187,19 @@ export default class Favicon {
|
||||||
this.context.closePath();
|
this.context.closePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ready() {
|
private ready(): void {
|
||||||
if (this.isReady) return;
|
if (this.isReady) return;
|
||||||
this.isReady = true;
|
this.isReady = true;
|
||||||
this.readyCb?.();
|
this.readyCb?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
private setIcon(canvas) {
|
private setIcon(canvas: HTMLCanvasElement): void {
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
this.setIconSrc(canvas.toDataURL("image/png"));
|
this.setIconSrc(canvas.toDataURL("image/png"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private setIconSrc(url) {
|
private setIconSrc(url: string): void {
|
||||||
// if is attached to fav icon
|
// if is attached to fav icon
|
||||||
if (this.browser.ff || this.browser.opera) {
|
if (this.browser.ff || this.browser.opera) {
|
||||||
// for FF we need to "recreate" element, attach to dom and remove old <link>
|
// for FF we need to "recreate" element, attach to dom and remove old <link>
|
||||||
|
@ -200,19 +210,17 @@ export default class Favicon {
|
||||||
newIcon.setAttribute("type", "image/png");
|
newIcon.setAttribute("type", "image/png");
|
||||||
window.document.getElementsByTagName("head")[0].appendChild(newIcon);
|
window.document.getElementsByTagName("head")[0].appendChild(newIcon);
|
||||||
newIcon.setAttribute("href", url);
|
newIcon.setAttribute("href", url);
|
||||||
if (old.parentNode) {
|
old.parentNode?.removeChild(old);
|
||||||
old.parentNode.removeChild(old);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.icons.forEach(icon => {
|
this.icons.forEach((icon) => {
|
||||||
icon.setAttribute("href", url);
|
icon.setAttribute("href", url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public badge(content: number | string, opts?: Partial<IParams>) {
|
public badge(content: number | string, opts?: Partial<IParams>): void {
|
||||||
if (!this.isReady) {
|
if (!this.isReady) {
|
||||||
this.readyCb = () => {
|
this.readyCb = (): void => {
|
||||||
this.badge(content, opts);
|
this.badge(content, opts);
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
|
@ -227,18 +235,18 @@ export default class Favicon {
|
||||||
this.setIcon(this.canvas);
|
this.setIcon(this.canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getLinks() {
|
private static getLinks(): HTMLLinkElement[] {
|
||||||
const icons: HTMLLinkElement[] = [];
|
const icons: HTMLLinkElement[] = [];
|
||||||
const links = window.document.getElementsByTagName("head")[0].getElementsByTagName("link");
|
const links = window.document.getElementsByTagName("head")[0].getElementsByTagName("link");
|
||||||
for (const link of links) {
|
for (const link of links) {
|
||||||
if ((/(^|\s)icon(\s|$)/i).test(link.getAttribute("rel"))) {
|
if (/(^|\s)icon(\s|$)/i.test(link.getAttribute("rel"))) {
|
||||||
icons.push(link);
|
icons.push(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return icons;
|
return icons;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getIcons() {
|
private static getIcons(): HTMLLinkElement[] {
|
||||||
// get favicon link elements
|
// get favicon link elements
|
||||||
let elms = Favicon.getLinks();
|
let elms = Favicon.getLinks();
|
||||||
if (elms.length === 0) {
|
if (elms.length === 0) {
|
||||||
|
@ -247,7 +255,7 @@ export default class Favicon {
|
||||||
window.document.getElementsByTagName("head")[0].appendChild(elms[0]);
|
window.document.getElementsByTagName("head")[0].appendChild(elms[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
elms.forEach(item => {
|
elms.forEach((item) => {
|
||||||
item.setAttribute("type", "image/png");
|
item.setAttribute("type", "image/png");
|
||||||
});
|
});
|
||||||
return elms;
|
return elms;
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
"Unexpected error preparing the app. See console for details.": "حدث عُطل غير متوقع أثناء تجهيز التطبيق. طالِع المِعراض للتفاصيل.",
|
"Unexpected error preparing the app. See console for details.": "حدث عُطل غير متوقع أثناء تجهيز التطبيق. طالِع المِعراض للتفاصيل.",
|
||||||
"Download Completed": "اكتمل التنزيل",
|
"Download Completed": "اكتمل التنزيل",
|
||||||
"Open": "افتح",
|
"Open": "افتح",
|
||||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s لسطح المكتب (%(platformName)s)",
|
|
||||||
"Go to your browser to complete Sign In": "افتح المتصفح لإكمال الولوج",
|
"Go to your browser to complete Sign In": "افتح المتصفح لإكمال الولوج",
|
||||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s، %(osName)s)",
|
|
||||||
"Unsupported browser": "متصفح غير مدعوم",
|
"Unsupported browser": "متصفح غير مدعوم",
|
||||||
"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 ميزات متقدمة في المتصفحات لا يدعمها متصفحك الحالي.",
|
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "يستعمل %(brand)s ميزات متقدمة في المتصفحات لا يدعمها متصفحك الحالي.",
|
||||||
|
@ -28,6 +26,5 @@
|
||||||
"Failed to start": "فشل البدء",
|
"Failed to start": "فشل البدء",
|
||||||
"Powered by Matrix": "تدعمه «ماترِكس»",
|
"Powered by Matrix": "تدعمه «ماترِكس»",
|
||||||
"Use %(brand)s on mobile": "استعمل %(brand)s على المحمول",
|
"Use %(brand)s on mobile": "استعمل %(brand)s على المحمول",
|
||||||
"Switch to space by number": "التبديل إلى المساحة بالرقم",
|
|
||||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "محادثة لامركزية، مشفرة & تعمل بواسطة $matrixLogo"
|
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "محادثة لامركزية، مشفرة & تعمل بواسطة $matrixLogo"
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
"The message from the parser is: %(message)s": "Sözügedən mesaj: %(message)s",
|
"The message from the parser is: %(message)s": "Sözügedən mesaj: %(message)s",
|
||||||
"Dismiss": "Nəzərə almayın",
|
"Dismiss": "Nəzərə almayın",
|
||||||
"Welcome to Element": "Element-ə xoş gəlmişsiniz",
|
"Welcome to Element": "Element-ə xoş gəlmişsiniz",
|
||||||
"Decentralised, encrypted chat & collaboration powered by [matrix]": "[matrix] tərəfindən təchiz edilmiş mərkəziləşdirilməmiş, şifrələnmiş çat və əməkdaşlıq platforması",
|
|
||||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "$matrixLogo tərəfindən dəstəklənən mərkəzləşdirilməmiş ,şifrələnmiş söhbət & əməkdaşlıq",
|
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "$matrixLogo tərəfindən dəstəklənən mərkəzləşdirilməmiş ,şifrələnmiş söhbət & əməkdaşlıq",
|
||||||
"Failed to start": "Başlatmaq alınmadı",
|
"Failed to start": "Başlatmaq alınmadı",
|
||||||
"Go to element.io": "element.io saytına keçin",
|
"Go to element.io": "element.io saytına keçin",
|
||||||
|
@ -22,9 +21,7 @@
|
||||||
"Unsupported browser": "Dəstəklənməyən brauzer",
|
"Unsupported browser": "Dəstəklənməyən brauzer",
|
||||||
"Use %(brand)s on mobile": "Mobil telefonda %(brand)s istifadə edin",
|
"Use %(brand)s on mobile": "Mobil telefonda %(brand)s istifadə edin",
|
||||||
"Powered by Matrix": "Gücünü Matrix'dən alır",
|
"Powered by Matrix": "Gücünü Matrix'dən alır",
|
||||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
|
||||||
"Go to your browser to complete Sign In": "Girişi tamamlamaq üçün brauzerinizə keçin",
|
"Go to your browser to complete Sign In": "Girişi tamamlamaq üçün brauzerinizə keçin",
|
||||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s Masaüstü (%(platformName)s)",
|
|
||||||
"Open": "Aç",
|
"Open": "Aç",
|
||||||
"Download Completed": "Yükləmə Tamamlandı",
|
"Download Completed": "Yükləmə Tamamlandı",
|
||||||
"Unable to load config file: please refresh the page to try again.": "Konfiqurasiya faylını yükləmək mümkün deyil: yenidən cəhd etmək üçün səhifəni yeniləyin.",
|
"Unable to load config file: please refresh the page to try again.": "Konfiqurasiya faylını yükləmək mümkün deyil: yenidən cəhd etmək üçün səhifəni yeniləyin.",
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
"Invalid JSON": "Невалиден JSON",
|
"Invalid JSON": "Невалиден JSON",
|
||||||
"Go to your browser to complete Sign In": "Отидете в браузъра за да завършите влизането",
|
"Go to your browser to complete Sign In": "Отидете в браузъра за да завършите влизането",
|
||||||
"Unable to load config file: please refresh the page to try again.": "Неуспешно зареждане на конфигурационния файл: презаредете страницата за да опитате пак.",
|
"Unable to load config file: please refresh the page to try again.": "Неуспешно зареждане на конфигурационния файл: презаредете страницата за да опитате пак.",
|
||||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)",
|
|
||||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
|
||||||
"Unsupported browser": "Неподдържан браузър",
|
"Unsupported browser": "Неподдържан браузър",
|
||||||
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Инсталирайте <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink> или <safariLink>Safari</safariLink> за най-добра работа.",
|
"Please install <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink>, or <safariLink>Safari</safariLink> for the best experience.": "Инсталирайте <chromeLink>Chrome</chromeLink>, <firefoxLink>Firefox</firefoxLink> или <safariLink>Safari</safariLink> за най-добра работа.",
|
||||||
"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.": "Може да продължите да използвате сегашния си браузър, но някои или всички функции може да се окажат неработещи, или пък външния вид на приложението да изглежда неправилен.",
|
"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.": "Може да продължите да използвате сегашния си браузър, но някои или всички функции може да се окажат неработещи, или пък външния вид на приложението да изглежда неправилен.",
|
||||||
|
@ -28,5 +26,7 @@
|
||||||
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s използва модерни функции на браузъра, които не се поддържат от Вашия.",
|
"%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s използва модерни функции на браузъра, които не се поддържат от Вашия.",
|
||||||
"Powered by Matrix": "Базирано на Matrix",
|
"Powered by Matrix": "Базирано на Matrix",
|
||||||
"Use %(brand)s on mobile": "Използвайте %(brand)s на мобилен телефон",
|
"Use %(brand)s on mobile": "Използвайте %(brand)s на мобилен телефон",
|
||||||
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Децентрализиран, криптиран чат & сътрудничество, захранено от $matrixlogo"
|
"Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Децентрализиран, криптиран чат & сътрудничество, захранено от $matrixlogo",
|
||||||
|
"%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s под %(osName)s",
|
||||||
|
"%(brand)s Desktop: %(platformName)s": "%(brand)s Desktop: %(platformName)s"
|
||||||
}
|
}
|
||||||
|
|
3
src/i18n/strings/br.json
Normal file
3
src/i18n/strings/br.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"Open": "Digeriñ"
|
||||||
|
}
|
|
@ -10,10 +10,8 @@
|
||||||
"Download Completed": "Preuzimanje završeno",
|
"Download Completed": "Preuzimanje završeno",
|
||||||
"Open": "Otvori",
|
"Open": "Otvori",
|
||||||
"Dismiss": "Odbaci",
|
"Dismiss": "Odbaci",
|
||||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s Radna povrsina (%(platformName)s)",
|
|
||||||
"Go to your browser to complete Sign In": "Idite na svoj pretraživač da biste dovršili prijavu",
|
"Go to your browser to complete Sign In": "Idite na svoj pretraživač da biste dovršili prijavu",
|
||||||
"Unknown device": "Nepoznat uređaj",
|
"Unknown device": "Nepoznat uređaj",
|
||||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
|
||||||
"Powered by Matrix": "Pokretano uz Matrix",
|
"Powered by Matrix": "Pokretano uz Matrix",
|
||||||
"Unsupported browser": "Nepodržani pretraživač",
|
"Unsupported browser": "Nepodržani pretraživač",
|
||||||
"Your browser can't run %(brand)s": "Vaš pretraživač ne može pokretati %(brand)s",
|
"Your browser can't run %(brand)s": "Vaš pretraživač ne može pokretati %(brand)s",
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
"Unexpected error preparing the app. See console for details.": "Error inesperat durant la preparació de l'aplicació. Consulta la consola pels a més detalls.",
|
"Unexpected error preparing the app. See console for details.": "Error inesperat durant la preparació de l'aplicació. Consulta la consola pels a més detalls.",
|
||||||
"Download Completed": "Baixada completada",
|
"Download Completed": "Baixada completada",
|
||||||
"Open": "Obre",
|
"Open": "Obre",
|
||||||
"%(brand)s Desktop (%(platformName)s)": "%(brand)s d'escriptori (%(platformName)s)",
|
|
||||||
"%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)",
|
|
||||||
"Powered by Matrix": "Amb tecnologia de Matrix",
|
"Powered by Matrix": "Amb tecnologia de Matrix",
|
||||||
"Unsupported browser": "Navegador no compatible",
|
"Unsupported browser": "Navegador no compatible",
|
||||||
"Your browser can't run %(brand)s": "El teu navegador no pot executar %(brand)s",
|
"Your browser can't run %(brand)s": "El teu navegador no pot executar %(brand)s",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue