Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f20fc78bd7 | ||
|
|
741233909d | ||
|
|
4e0f4a8dc7 | ||
|
|
0d151452ba | ||
|
|
4fd76f9599 | ||
|
|
d123793deb | ||
|
|
449c1c9d79 | ||
|
|
de5b58792e | ||
|
|
7769074410 | ||
|
|
881054e265 | ||
|
|
767f9cdc4a | ||
|
|
946f564f84 | ||
|
|
468e389324 | ||
|
|
62e98f6c47 | ||
|
|
de31c099e3 | ||
|
|
49cae76387 | ||
|
|
d45ea78ddb | ||
|
|
dcbc3ed865 | ||
|
|
ff19135d4e | ||
|
|
de7343d16a | ||
|
|
e5135a41ba | ||
|
|
67d1c29d6a | ||
|
|
7ee6b02aeb | ||
|
|
6b021b9f70 | ||
|
|
faa8f95f97 | ||
|
|
c09fec5f88 | ||
|
|
b711a67893 | ||
|
|
a30bded3ee | ||
|
|
0349f5306c | ||
|
|
6980652cbc | ||
|
|
eff56d7ce4 | ||
|
|
1a66c455f6 | ||
|
|
7163db357c | ||
|
|
e5572210d3 | ||
|
|
11a262b58f | ||
|
|
62e4e80ca3 | ||
|
|
f55cc21289 | ||
|
|
c34a1f7f65 | ||
|
|
70b693ef3c | ||
|
|
d2175b40a4 | ||
|
|
1830acbddf | ||
|
|
df9c1fed2a | ||
|
|
05be247946 | ||
|
|
1f5c22e325 | ||
|
|
b9ee9583e4 | ||
|
|
fef503c65d | ||
|
|
dc37c83aac | ||
|
|
398e238bfb | ||
|
|
10819ed044 | ||
|
|
6edcdd3890 | ||
|
|
5e47a439ca | ||
|
|
d1091eda17 | ||
|
|
0488cbdd8c | ||
|
|
5823cd41e8 | ||
|
|
de0f2e65a5 | ||
|
|
891ff86b49 | ||
|
|
d7d7bee685 | ||
|
|
2c2aded094 | ||
|
|
f35b50d89f | ||
|
|
0880faf312 | ||
|
|
51be754ad8 | ||
|
|
70522ed8da | ||
|
|
3581aceb5a | ||
|
|
16e8ea3420 | ||
|
|
29f48f25f4 | ||
|
|
089234ae09 | ||
|
|
4dd823eca4 | ||
|
|
6bc5b16b02 | ||
|
|
f67eb328bf | ||
|
|
1c824da32b | ||
|
|
1442e57a23 | ||
|
|
39e92b9e2e | ||
|
|
c879090a34 | ||
|
|
6303b357ab | ||
|
|
b3d97810a8 | ||
|
|
eaf14a0562 | ||
|
|
fd3c0d9fc6 | ||
|
|
7765cfe1c2 | ||
|
|
b94562d43b | ||
|
|
19e478f2a9 | ||
|
|
d6b8ecdfd1 | ||
|
|
47ade7ee3c | ||
|
|
23387ee75f | ||
|
|
c85d1c1d9c | ||
|
|
96de515e56 | ||
|
|
e4c25bcc69 | ||
|
|
824ed06f36 | ||
|
|
aa57cf039a | ||
|
|
850d6a40cc | ||
|
|
282a4853cf | ||
|
|
7c26bdbda3 | ||
|
|
4ad5ea49c2 | ||
|
|
e3aa810230 | ||
|
|
db2e0758de | ||
|
|
39467f434e | ||
|
|
fddf344923 | ||
|
|
f806538e2c | ||
|
|
c6ad2003f0 | ||
|
|
9aed344a80 | ||
|
|
d8b4fea6fc | ||
|
|
0c55efe4b6 | ||
|
|
c93df1fd06 | ||
|
|
c30eb19021 | ||
|
|
2d8c33d66d | ||
|
|
223793a445 | ||
|
|
b60a92112f | ||
|
|
b017faac36 | ||
|
|
1615b6e559 | ||
|
|
d71542a757 | ||
|
|
eb8a1cea45 | ||
|
|
a44a716100 | ||
|
|
34a4403135 | ||
|
|
cfe5ce977e | ||
|
|
102ce87bb0 | ||
|
|
f9845617b3 | ||
|
|
1ec598453b | ||
|
|
4659e58be8 | ||
|
|
9f6cacb3b6 | ||
|
|
32168fb467 | ||
|
|
90ef5505bb | ||
|
|
acc41c532e | ||
|
|
fb4fe0e928 | ||
|
|
e6e18dd3f9 | ||
|
|
357a3be90d | ||
|
|
be6f21c7e1 | ||
|
|
6d8ae91b6c | ||
|
|
5bd0429e98 | ||
|
|
0a38395bdc | ||
|
|
29d8f03a43 | ||
|
|
c3a9760f22 | ||
|
|
086bacc10e | ||
|
|
1b78461ee8 | ||
|
|
0464515f3e | ||
|
|
978c408ab3 | ||
|
|
d6a800166a | ||
|
|
70620d8294 | ||
|
|
18606d46fa | ||
|
|
0e3a2afb4e | ||
|
|
4de0edc359 | ||
|
|
3a752b8f12 | ||
|
|
f81ef3e134 | ||
|
|
593e7a788a | ||
|
|
09f4bdef8e | ||
|
|
88d358f976 | ||
|
|
a8394ebc56 | ||
|
|
fde1712809 | ||
|
|
a4b6e4ff54 | ||
|
|
d7dc76a93d | ||
|
|
6340fb7c13 | ||
|
|
21ffcd503b | ||
|
|
63dc5744f3 | ||
|
|
e363fe8367 | ||
|
|
d6d919bce9 | ||
|
|
7e4c04d54e | ||
|
|
3c1d86214a | ||
|
|
37654bce7c | ||
|
|
33f983d254 | ||
|
|
6a116a4413 | ||
|
|
c9a9aa399c | ||
|
|
f8795931c1 | ||
|
|
bba60189e9 | ||
|
|
44e22e2684 | ||
|
|
aa828fe9f5 | ||
|
|
aec034182b | ||
|
|
5ba7267164 | ||
|
|
5c735f0936 | ||
|
|
9c08a69226 | ||
|
|
40a0958e0d | ||
|
|
098be75415 | ||
|
|
13def24f7e | ||
|
|
46e429c37b | ||
|
|
eab8b1d095 | ||
|
|
b92acd4822 | ||
|
|
93aafb1415 | ||
|
|
734d330a10 | ||
|
|
432f7ef93a | ||
|
|
5623fa415f | ||
|
|
f2746ab994 | ||
|
|
80f07a5454 | ||
|
|
18139f78d2 | ||
|
|
a2bbe61292 | ||
|
|
6855e61c47 | ||
|
|
d09c3d8374 | ||
|
|
67b97e63ca | ||
|
|
4cd49dee4b | ||
|
|
0aadb7e60c | ||
|
|
c67e7ebc2c | ||
|
|
b30ef953b4 | ||
|
|
c9330debd4 | ||
|
|
456194312b | ||
|
|
cb85733426 | ||
|
|
6ef41b924d | ||
|
|
24299c09b1 | ||
|
|
ab860b8655 | ||
|
|
f69e032a52 | ||
|
|
bd08166a50 | ||
|
|
d8688413f5 | ||
|
|
556f975552 | ||
|
|
12079ded4f | ||
|
|
62988e6b46 | ||
|
|
0e478f4c20 | ||
|
|
9bf1b6f928 | ||
|
|
3f341de78f | ||
|
|
6498d2bd19 | ||
|
|
15bb710394 | ||
|
|
57bf934bc2 | ||
|
|
7553983655 | ||
|
|
ca6d75e384 | ||
|
|
85b02a3589 | ||
|
|
ba6c3fac7d | ||
|
|
b5f7b52a63 | ||
|
|
88ec0d7c2f | ||
|
|
5f84cb5790 | ||
|
|
fb75c1536b | ||
|
|
715bec5949 | ||
|
|
c91dfdfe9d | ||
|
|
667f902278 | ||
|
|
e133625405 | ||
|
|
01244c1873 | ||
|
|
70344fd40f | ||
|
|
0a5701b9fa | ||
|
|
85959046a5 | ||
|
|
7444763008 | ||
|
|
d5a5ce9860 | ||
|
|
e5feba8c26 | ||
|
|
3cac74df24 | ||
|
|
51572b5787 | ||
|
|
bcbc20b53d | ||
|
|
5c8562088d | ||
|
|
58e505cd38 | ||
|
|
509fd65156 | ||
|
|
cafac39733 | ||
|
|
123763afec | ||
|
|
72503d0335 | ||
|
|
d5326ed9ee | ||
|
|
6a619de67b | ||
|
|
a47bd13db6 | ||
|
|
0cd2ad6242 | ||
|
|
78a313c373 | ||
|
|
806a9032e1 | ||
|
|
02e1d602d9 | ||
|
|
1e02afe1c1 | ||
|
|
2d5f413a1f | ||
|
|
093bf7c1a1 |
@@ -1,19 +1,12 @@
|
||||
####
|
||||
# App Config
|
||||
# Build-time app config
|
||||
# Environment files are documented here:
|
||||
# https://vitejs.dev/guide/env-and-mode.html#env-files
|
||||
####
|
||||
|
||||
# Used for determining the homeserver to use for short urls etc.
|
||||
# VITE_DEFAULT_HOMESERVER=http://localhost:8008
|
||||
# VITE_FALLBACK_STUN_ALLOWED=false
|
||||
|
||||
# Used for submitting debug logs to an external rageshake server
|
||||
# VITE_RAGESHAKE_SUBMIT_URL=http://localhost:9110/api/submit
|
||||
|
||||
# The Sentry DSN to use for error reporting. Leave undefined to disable.
|
||||
# VITE_SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
|
||||
|
||||
# VITE_CUSTOM_THEME=true
|
||||
# VITE_THEME_ACCENT=#0dbd8b
|
||||
# VITE_THEME_ACCENT_20=#0dbd8b33
|
||||
|
||||
@@ -1,42 +1,34 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
"matrix-org",
|
||||
],
|
||||
extends: [
|
||||
plugins: ["matrix-org"],
|
||||
extends: ["plugin:matrix-org/react", "plugin:matrix-org/a11y", "prettier"],
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
rules: {
|
||||
"jsx-a11y/media-has-caption": ["off"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
extends: [
|
||||
"plugin:matrix-org/typescript",
|
||||
"plugin:matrix-org/react",
|
||||
"plugin:matrix-org/a11y",
|
||||
"prettier",
|
||||
],
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
],
|
||||
rules: {
|
||||
// We're aiming to convert this code to strict mode
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
parserOptions: {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
},
|
||||
rules: {
|
||||
"jsx-a11y/media-has-caption": ["off"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
"src/**/*.{ts,tsx}",
|
||||
],
|
||||
extends: [
|
||||
"plugin:matrix-org/typescript",
|
||||
"plugin:matrix-org/react",
|
||||
"prettier",
|
||||
],
|
||||
rules: {
|
||||
// We're aiming to convert this code to strict mode
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: "detect",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/bug.yml
vendored
8
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -42,7 +42,7 @@ body:
|
||||
id: browser
|
||||
attributes:
|
||||
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
|
||||
validations:
|
||||
required: false
|
||||
@@ -58,10 +58,10 @@ body:
|
||||
id: rageshake
|
||||
attributes:
|
||||
label: Will you send logs?
|
||||
description: |
|
||||
description: |
|
||||
To send them, press the 'Submit Feedback' button and check 'Include Debug Logs'. Please link to this issue in the description field.
|
||||
options:
|
||||
- 'Yes'
|
||||
- 'No'
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
13
.github/workflows/build.yaml
vendored
13
.github/workflows/build.yaml
vendored
@@ -1,12 +1,8 @@
|
||||
name: Build
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches: [main]
|
||||
env:
|
||||
VITE_DEFAULT_HOMESERVER: "https://call.ems.host"
|
||||
VITE_SENTRY_DSN: https://b1e328d49be3402ba96101338989fb35@sentry.matrix.org/41
|
||||
VITE_SENTRY_ENVIRONMENT: main-branch-cd
|
||||
VITE_RAGESHAKE_SUBMIT_URL: https://element.io/bugreports/submit
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
@@ -17,11 +13,16 @@ jobs:
|
||||
- name: Yarn cache
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
cache: "yarn"
|
||||
- name: Install dependencies
|
||||
run: "yarn install"
|
||||
- name: Build
|
||||
run: "yarn run build"
|
||||
env:
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Yarn cache
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: 'yarn'
|
||||
cache: "yarn"
|
||||
- name: Install dependencies
|
||||
run: "yarn install"
|
||||
- name: Prettier
|
||||
|
||||
13
.github/workflows/netlify-main.yaml
vendored
13
.github/workflows/netlify-main.yaml
vendored
@@ -4,13 +4,19 @@ on:
|
||||
workflows: ["Build"]
|
||||
types:
|
||||
- completed
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
deployments: write
|
||||
if: github.event.workflow_run.conclusion == 'success'
|
||||
# Important: the 'branches' filter above will match the 'main' branch on forks,
|
||||
# so we need to check the head repo too in order to not run on PRs from forks
|
||||
# We check the branch name again too just for completeness
|
||||
# (Is there a nicer way to see if a PR is from a fork?)
|
||||
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_repository.full_name == 'vector-im/element-call' && github.event.workflow_run.head_branch == 'main'
|
||||
steps:
|
||||
- name: Create Deployment
|
||||
uses: bobheadxi/deployments@v1
|
||||
@@ -21,7 +27,7 @@ jobs:
|
||||
env: main-branch-cd
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
|
||||
- name: 'Download artifact'
|
||||
- name: "Download artifact"
|
||||
uses: actions/github-script@v3.1.0
|
||||
with:
|
||||
script: |
|
||||
@@ -49,6 +55,9 @@ jobs:
|
||||
# We fetch from github directly as we don't bother checking out the repo
|
||||
run: curl -s https://raw.githubusercontent.com/vector-im/element-call/main/config/netlify_redirects > dist/_redirects
|
||||
|
||||
- name: Add config file
|
||||
run: curl -s https://raw.githubusercontent.com/vector-im/element-call/main/config/element_io_develop.json > dist/config.json
|
||||
|
||||
- name: Deploy to Netlify
|
||||
id: netlify
|
||||
uses: nwtgck/actions-netlify@v1.2.3
|
||||
|
||||
81
.github/workflows/netlify-pr.yaml
vendored
Normal file
81
.github/workflows/netlify-pr.yaml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Netlify PR Preview
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Build"]
|
||||
types:
|
||||
- completed
|
||||
branches-ignore:
|
||||
- "main"
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
deployments: write
|
||||
environment: Netlify
|
||||
steps:
|
||||
- name: 📝 Create Deployment
|
||||
uses: bobheadxi/deployments@v1
|
||||
id: deployment
|
||||
with:
|
||||
step: start
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
env: Netlify
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
desc: |
|
||||
Do you trust the author of this PR? Maybe this build will steal your keys or give you malware.
|
||||
Exercise caution. Use test accounts.
|
||||
|
||||
- id: prdetails
|
||||
uses: matrix-org/pr-details-action@v1.2
|
||||
with:
|
||||
owner: ${{ github.event.workflow_run.head_repository.owner.login }}
|
||||
branch: ${{ github.event.workflow_run.head_branch }}
|
||||
|
||||
# There's a 'download artifact' action, but it hasn't been updated for the workflow_run action
|
||||
# (https://github.com/actions/download-artifact/issues/60) so instead we get this mess:
|
||||
- name: 📥 Download artifact
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
name: build
|
||||
path: webapp
|
||||
|
||||
- name: Add redirects file
|
||||
# We fetch from github directly as we don't bother checking out the repo
|
||||
run: curl -s https://raw.githubusercontent.com/vector-im/element-call/main/config/netlify_redirects > webapp/_redirects
|
||||
|
||||
- name: Add config file
|
||||
env:
|
||||
HEADBRACH: ${{ github.event.workflow_run.head_branch }}
|
||||
run: curl -s "https://raw.githubusercontent.com/vector-im/element-call/${HEADBRACH}/config/element_io_preview.json" > webapp/config.json
|
||||
|
||||
- name: ☁️ Deploy to Netlify
|
||||
id: netlify
|
||||
uses: nwtgck/actions-netlify@v1.2
|
||||
with:
|
||||
publish-dir: webapp
|
||||
deploy-message: "Deploy from GitHub Actions"
|
||||
# These don't work because we're in workflow_run
|
||||
enable-pull-request-comment: false
|
||||
enable-commit-comment: false
|
||||
alias: pr${{ steps.prdetails.outputs.pr_id }}
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
timeout-minutes: 1
|
||||
|
||||
- name: 🚦 Update deployment status
|
||||
uses: bobheadxi/deployments@v1
|
||||
if: always()
|
||||
with:
|
||||
step: finish
|
||||
override: false
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
status: ${{ job.status }}
|
||||
env: ${{ steps.deployment.outputs.env }}
|
||||
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
|
||||
env_url: ${{ steps.netlify.outputs.deploy-url }}
|
||||
desc: |
|
||||
Do you trust the author of this PR? Maybe this build will steal your keys or give you malware.
|
||||
Exercise caution. Use test accounts.
|
||||
29
.github/workflows/publish.yaml
vendored
29
.github/workflows/publish.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Build & publish
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write # required to upload release asset
|
||||
packages: write
|
||||
steps:
|
||||
- name: Check it out
|
||||
@@ -26,6 +26,33 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Yarn cache
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
- name: Install dependencies
|
||||
run: "yarn install"
|
||||
- name: Build
|
||||
run: "yarn run build"
|
||||
env:
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
SENTRY_URL: ${{ secrets.SENTRY_URL }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
VITE_APP_VERSION: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Create Tarball
|
||||
env:
|
||||
GITHUB_TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
tar --numeric-owner --transform "s/dist/element-call-${GITHUB_TAG_NAME}/" -cvzf element-call-${GITHUB_TAG_NAME}.tar.gz dist
|
||||
- name: Upload
|
||||
uses: alexellis/upload-assets@0.4.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
asset_paths: '["element-call-${{ github.event.release.tag_name }}.tar.gz"]'
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
|
||||
12
.github/workflows/triage-incoming.yaml
vendored
12
.github/workflows/triage-incoming.yaml
vendored
@@ -2,7 +2,7 @@ name: Move new issues into triage board
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [ opened ]
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
@@ -13,13 +13,13 @@ jobs:
|
||||
with:
|
||||
headers: '{"GraphQL-Features": "projects_next_graphql"}'
|
||||
query: |
|
||||
mutation add_to_project($projectid:ID!,$contentid:ID!) {
|
||||
addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) {
|
||||
item {
|
||||
id
|
||||
}
|
||||
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:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.idea/
|
||||
public/config.json
|
||||
|
||||
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -5,18 +5,18 @@
|
||||
"editor.tabSize": 2,
|
||||
"[typescriptreact]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
Contributing code to Element
|
||||
============================
|
||||
# Contributing code to Element
|
||||
|
||||
Element follows the same pattern as the [matrix-js-sdk](https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md).
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -1,15 +1,7 @@
|
||||
FROM --platform=$BUILDPLATFORM node:16-buster as builder
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY . /src/element-call
|
||||
RUN element-call/scripts/dockerbuild.sh
|
||||
|
||||
# App
|
||||
FROM nginxinc/nginx-unprivileged:alpine
|
||||
|
||||
COPY --from=builder /src/element-call/dist /app
|
||||
COPY config/default.conf /etc/nginx/conf.d/
|
||||
COPY ./dist /app
|
||||
COPY config/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
26
README.md
26
README.md
@@ -15,19 +15,19 @@ Until prebuilt tarballs are available, you'll need to build Element Call from so
|
||||
git clone https://github.com/vector-im/element-call.git
|
||||
cd element-call
|
||||
yarn
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
You can now edit the configuration in `.env` to your liking. The most important thing is to set `VITE_DEFAULT_HOMESERVER` to the homeserver that the app should use, such as `https://call.ems.host`.
|
||||
|
||||
Next, build the project:
|
||||
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
If all went well, you can now find the build output under `dist` as a series of static files. These can be hosted using any web server of your choice.
|
||||
|
||||
You may also wish to add a configuration file (Element Call uses the domain it's hosted on as a Homeserver URL by default,
|
||||
but you can change this in the config file). This goes in `public/config.json` - you can use the sample as a starting point:
|
||||
|
||||
```
|
||||
cp config/config.sample.json public/config.json
|
||||
# edit public/config.json
|
||||
```
|
||||
|
||||
Because Element Call uses client-side routing, your server must be able to route any requests to non-existing paths back to `/index.html`. For example, in Nginx you can achieve this with the `try_files` directive:
|
||||
|
||||
```
|
||||
@@ -42,12 +42,11 @@ server {
|
||||
|
||||
## Development
|
||||
|
||||
Element Call is built against the `robertlong/group-call` branch of [matrix-js-sdk](https://github.com/matrix-org/matrix-js-sdk/pull/2553). To get started, clone, install, and link the package:
|
||||
Element Call is built against [matrix-js-sdk](https://github.com/matrix-org/matrix-js-sdk/pull/2553). To get started, clone, install, and link the package:
|
||||
|
||||
```
|
||||
git clone https://github.com/matrix-org/matrix-js-sdk.git
|
||||
cd matrix-js-sdk
|
||||
git switch robertlong/group-call
|
||||
yarn
|
||||
yarn link
|
||||
```
|
||||
@@ -59,10 +58,9 @@ git clone https://github.com/vector-im/element-call.git
|
||||
cd element-call
|
||||
yarn
|
||||
yarn link matrix-js-sdk
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
By default, the app expects you to have [Synapse](https://matrix-org.github.io/synapse/latest/setup/installation.html) installed locally and running on port 8008. If you wish to use another homeserver, you can set it in your `.env` file.
|
||||
By default, the app expects you to have [Synapse](https://matrix-org.github.io/synapse/latest/setup/installation.html) installed locally and running on port 8008. If you wish to use another homeserver, you can add a config file as above.
|
||||
|
||||
You're now ready to launch the development server:
|
||||
|
||||
@@ -70,9 +68,9 @@ You're now ready to launch the development server:
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Config
|
||||
## Configuration
|
||||
|
||||
Configuration options are documented in the `.env` file.
|
||||
There are currently two different config files. `.env` holds variables that are used at build time, while `public/config.json` holds variables that are used at runtime. Documentation and default values for `public/config.json` can be found in [ConfigOptions.ts](src/config/ConfigOptions.ts).
|
||||
|
||||
## Translation
|
||||
|
||||
|
||||
8
config/config.sample.json
Normal file
8
config/config.sample.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://call.ems.host",
|
||||
"server_name": "call.ems.host"
|
||||
}
|
||||
}
|
||||
}
|
||||
19
config/element_io_develop.json
Normal file
19
config/element_io_develop.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://call.ems.host",
|
||||
"server_name": "call.ems.host"
|
||||
}
|
||||
},
|
||||
"posthog": {
|
||||
"api_key": "phc_rXGHx9vDmyEvyRxPziYtdVIv0ahEv8A9uLWFcCi1WcU",
|
||||
"api_host": "https://posthog-element-call.element.io"
|
||||
},
|
||||
"sentry": {
|
||||
"environment": "main-branch-cd",
|
||||
"DSN": "https://b1e328d49be3402ba96101338989fb35@sentry.matrix.org/41"
|
||||
},
|
||||
"rageshake": {
|
||||
"submit_url": "https://element.io/bugreports/submit"
|
||||
}
|
||||
}
|
||||
11
config/element_io_preview.json
Normal file
11
config/element_io_preview.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://call.ems.host",
|
||||
"server_name": "call.ems.host"
|
||||
}
|
||||
},
|
||||
"rageshake": {
|
||||
"submit_url": "https://element.io/bugreports/submit"
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,13 @@ export default {
|
||||
createOldCatalogs: false,
|
||||
defaultNamespace: "app",
|
||||
lexers: {
|
||||
ts: [{
|
||||
lexer: "JavascriptLexer",
|
||||
functions: ["t", "translatedError"],
|
||||
functionsNamespace: ["useTranslation", "withTranslation"],
|
||||
}],
|
||||
ts: [
|
||||
{
|
||||
lexer: "JavascriptLexer",
|
||||
functions: ["t", "translatedError"],
|
||||
functionsNamespace: ["useTranslation", "withTranslation"],
|
||||
},
|
||||
],
|
||||
},
|
||||
locales: ["en-GB"],
|
||||
output: "public/locales/$LOCALE/$NAMESPACE.json",
|
||||
|
||||
13
package.json
13
package.json
@@ -7,8 +7,8 @@
|
||||
"serve": "vite preview",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"build-storybook": "build-storybook",
|
||||
"prettier:check": "prettier -c src",
|
||||
"prettier:format": "prettier -w src",
|
||||
"prettier:check": "prettier -c .",
|
||||
"prettier:format": "prettier -w .",
|
||||
"lint": "yarn lint:types && yarn lint:js",
|
||||
"lint:js": "eslint --max-warnings 0 src",
|
||||
"lint:types": "tsc",
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@juggle/resize-observer": "^3.3.1",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz",
|
||||
"@react-aria/button": "^3.3.4",
|
||||
"@react-aria/dialog": "^3.1.4",
|
||||
"@react-aria/focus": "^3.5.0",
|
||||
@@ -45,12 +45,13 @@
|
||||
"i18next": "^21.10.0",
|
||||
"i18next-browser-languagedetector": "^6.1.8",
|
||||
"i18next-http-backend": "^1.4.4",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#7ec726e10be835588d4b188fcd3d137b4690d79a",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#79575ef3760bb6085b7b770f241b3d32756d5b96",
|
||||
"matrix-widget-api": "^1.0.0",
|
||||
"mermaid": "^8.13.8",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pako": "^2.0.4",
|
||||
"postcss-preset-env": "^7",
|
||||
"posthog-js": "^1.29.0",
|
||||
"re-resizable": "^6.9.0",
|
||||
"react": "18",
|
||||
"react-dom": "18",
|
||||
@@ -65,7 +66,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz",
|
||||
"@sentry/vite-plugin": "^0.3.0",
|
||||
"@storybook/react": "^6.5.0-alpha.5",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
@@ -85,7 +86,7 @@
|
||||
"i18next-parser": "^6.6.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"prettier": "^2.6.2",
|
||||
"sass": "^1.42.1",
|
||||
"storybook-builder-vite": "^0.1.12",
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.png" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
|
||||
/>
|
||||
<title><%- title %></title>
|
||||
<script>
|
||||
window.global = window;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
<title>
|
||||
<%- title %>
|
||||
</title>
|
||||
<script>
|
||||
window.global = window;
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Вече имате акаунт?</0><1><0>Влезте с него</0> или <2>Влезте като гост</2></1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Създайте акаунт</0> или <2>Влезте като гост</2>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Възникна грешка.</0><1>Изпращнето на debug логове ще ни помогне да открием проблема.</1>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Защо не настройте парола за да запазите акаунта си?</0><1>Ще можете да запазите името и аватара си за бъдещи разговори</1>",
|
||||
"Accept camera/microphone permissions to join the call.": "Приемете разрешенията за камера/микрофон за да се присъедините в разговора.",
|
||||
"Accept microphone permissions to join the call.": "Приемете разрешението за микрофона за да се присъедините в разговора.",
|
||||
@@ -29,7 +28,6 @@
|
||||
"Developer": "Разработчик",
|
||||
"Display name": "Име/псевдоним",
|
||||
"Download debug logs": "Изтеглете debug логове",
|
||||
"Entering room…": "Влизане в стаята…",
|
||||
"Exit full screen": "Излез от цял екран",
|
||||
"Fetching group call timed out.": "Изтече времето за взимане на груповия разговор.",
|
||||
"Freedom": "Свобода",
|
||||
|
||||
@@ -79,5 +79,62 @@
|
||||
"Invite": "Pozvat",
|
||||
"Inspector": "Insepktor",
|
||||
"Incompatible versions!": "Nekompatibilní verze!",
|
||||
"Incompatible versions": "Nekompatibilní verze"
|
||||
"Incompatible versions": "Nekompatibilní verze",
|
||||
"{{name}} is talking…": "{{name}} mluví…",
|
||||
"{{name}} is presenting": "{{name}} prezentuje",
|
||||
"{{name}} (Connecting...)": "{{name}} (Připojení...)",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}, váš hovor je nyní ukončen",
|
||||
"{{count}} people connected|other": "{{count}} lidí připojeno",
|
||||
"{{count}} people connected|one": "{{count}} lidí připojeno",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "Tato možnost způsobí, že zvuk účastníků hovoru se bude tvářit jako by přicházel z místa, kde jsou umístěni na obrazovce.(Experimentální možnost: může způsobit nestabilitu audia.)",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "Tato stárnka je chráněna pomocí ReCAPTCHA a Google <2>zásad ochrany osobních údajů</2> a <6>podmínky služby</6> platí.<9></9>Kliknutím na \"Registrovat\", souhlasíte s <12>Pravidly a podmínkami</12>",
|
||||
"Walkie-talkie call name": "Jméno vysílačkového hovoru",
|
||||
"Walkie-talkie call": "Vysílačkový hovor",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - Vysílačkový hovor",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Zapnout jedno-klávesové zkratky, např. 'm' pro vypnutí/zapnutí mikrofonu.",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Toto bude odesílat anonymizovaná data (jako délku a počet účastníků hovoru) týmu Element Call, aby nám pomohly zlepšovat aplikaci podle toho, jak je používaná.",
|
||||
"Talking…": "Mluvení…",
|
||||
"Talk over speaker": "Mluvit přes mluvčího",
|
||||
"Spotlight": "Soustředěný mód",
|
||||
"Single-key keyboard shortcuts": "Jedno-klávesová klávesnice",
|
||||
"Release to stop": "Pusťte pro ukončení",
|
||||
"Release spacebar key to stop": "Pusťte mezerník pro ukončení",
|
||||
"Recaptcha not loaded": "Recaptcha se nenačetla",
|
||||
"Recaptcha dismissed": "Recaptcha byla zamítnuta",
|
||||
"Press and hold to talk over {{name}}": "Zmáčkněte a držte, abyste mluvili přes {{name}}",
|
||||
"Press and hold spacebar to talk over {{name}}": "Zmáčkněte a držte mezerník, abyste mluvili přes {{name}}",
|
||||
"Other users are trying to join this call from incompatible versions. These users should ensure that they have refreshed their browsers:<1>{userLis}</1>": "Ostatní uživatelé se pokoušejí připojit k tomuto hovoru s nekompatibilních verzí. Tito uživatelé by se měli ujistit, že stránku načetli znovu:<1>{userLis}</1>",
|
||||
"Not registered yet? <2>Create an account</2>": "Nejste registrovaní? <2>Vytvořit účet</2>",
|
||||
"More menu": "Další možnosti",
|
||||
"Join existing call?": "Připojit se k existujícimu hovoru?",
|
||||
"Include debug logs": "Zahrnout ladící záznamy",
|
||||
"Home": "Domov",
|
||||
"Having trouble? Help us fix it.": "Máte problémy? Pomozte nám je spravit.",
|
||||
"Grid layout menu": "Menu rozložení",
|
||||
"Go": "Pokračovat",
|
||||
"Full screen": "Zvětšit na celou obrazovku",
|
||||
"Freedom": "Volný",
|
||||
"Fetching group call timed out.": "Vypršel časový limit načítání skupinového hovoru.",
|
||||
"Exit full screen": "Ukončit režim celé obrazovky",
|
||||
"Element Call Home": "Domov Element Call",
|
||||
"Download debug logs": "Stáhnout ladící záznamy",
|
||||
"Display name": "Zobrazované jméno",
|
||||
"Developer": "Vývojář",
|
||||
"Details": "Detaily",
|
||||
"Description (optional)": "Popis (nepovinný)",
|
||||
"Debug log request": "Žádost o protokoly ladění",
|
||||
"Debug log": "Protokoly ladění",
|
||||
"Create account": "Vytvořit účet",
|
||||
"Copy": "Kopírovat",
|
||||
"Call type menu": "Menu typu hovoru",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "Kliknutím na \"Připojit se do hovoru\", odsouhlasíte naše <2>Terms and conditions</2>",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Kliknutím na \"Pokračovat\", odsouhlasíte naše <2>Terms and conditions</2>",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Jiný uživatel v tomto hovoru má problémy. Abychom mohli diagnostikovat problém, rádi bychom shromáždili protokoly ladění.",
|
||||
"Allow analytics": "Povolit analytiku",
|
||||
"Advanced": "Pokročilé",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Proč neskončit nastavením hesla, abyste mohli účet použít znovu?</0><1>Budete si moci nechat své jméno a nastavit si avatar pro budoucí hovory </1>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Připojit se</0><1>Or</1><2>Zkopírovat odkaz a připojit se později</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Už máte účet?</0><1><0>Přihlásit se</0> Or <2>Jako host</2></1>",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Čekání na video...)"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Du hast bereits ein Konto?</0><1><0>Anmelden</0> Oder <2>Als Gast betreten</2></1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Konto erstellen</0> Oder <2>Als Gast betreten</2>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Hoppla, da ist etwas schief gelaufen.</0><1>Die Übermittlung von Debug-Protokollen wird uns helfen, das Problem zu finden.</1>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Warum vergibst du nicht abschließend ein Passwort, um dein Konto zu erhalten?</0><1>Du kannst deinen Namen behalten und ein Profilbild für zukünftige Anrufe festlegen.</1>",
|
||||
"Accept camera/microphone permissions to join the call.": "Erlaube Zugriff auf Kamera/Mikrofon um dem Anruf beizutreten.",
|
||||
"Accept microphone permissions to join the call.": "Erlaube Zugriff auf das Mikrofon um dem Anruf beizutreten.",
|
||||
@@ -14,7 +13,7 @@
|
||||
"Call type menu": "Anruftyp Menü",
|
||||
"Camera": "Kamera",
|
||||
"Camera {{n}}": "Kamera {{n}}",
|
||||
"Camera/microphone permissions needed to join the call.": "Kamera-/Mikrofonberechtigung für die Teilnahme am Anruf erforderlich.",
|
||||
"Camera/microphone permissions needed to join the call.": "Für die Teilnahme am Anruf sind Kamera- und Mikrofonberechtigungen erforderlich.",
|
||||
"Change layout": "Layout ändern",
|
||||
"Close": "Schließen",
|
||||
"Confirm password": "Passwort bestätigen",
|
||||
@@ -29,7 +28,6 @@
|
||||
"Developer": "Entwickler",
|
||||
"Display name": "Anzeigename",
|
||||
"Download debug logs": "Debug-Protokolle herunterladen",
|
||||
"Entering room…": "Betrete Raum …",
|
||||
"Exit full screen": "Vollbildmodus verlassen",
|
||||
"Freedom": "Freiraum",
|
||||
"Full screen": "Vollbild",
|
||||
@@ -130,5 +128,16 @@
|
||||
"Walkie-talkie call name": "Name des Walkie-Talkie-Anrufs",
|
||||
"Sending debug logs…": "Sende Debug-Protokolle …",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Anruf beitreten</0><1>Oder</1><2>Anruflink kopieren und später beitreten</2>",
|
||||
"{{name}} (Connecting...)": "{{name}} (verbindet sich …)"
|
||||
"{{name}} (Connecting...)": "{{name}} (verbindet sich …)",
|
||||
"Allow analytics": "Analysedaten senden",
|
||||
"Advanced": "Erweitert",
|
||||
"Copy": "Kopieren",
|
||||
"Element Call Home": "Element Call-Startseite",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Dies wird anonymisierte Daten (wie z. B. die Dauer eines Anrufs und die Zahl der Teilnehmenden) dem Element Call-Team senden, um uns bei der Optimierung der Anwendung basierend auf dem Nutzungsverhalten zu helfen.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Ob Tastenkürzel mit nur einer Taste aktiviert sein sollen, z. B. „m“ um das Mikrofon stumm/aktiv zu schalten.",
|
||||
"Single-key keyboard shortcuts": "Ein-Tasten-Tastenkürzel",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Warte auf Video …)",
|
||||
"This feature is only supported on Firefox.": "Diese Funktion wird nur in Firefox unterstützt.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Übermittelte Problemberichte helfen uns, Fehler zu beheben.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Hoppla, etwas ist schiefgelaufen.</0>"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"{{count}} people connected|other": "{{count}} people connected",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}, your call is now ended",
|
||||
"{{name}} (Connecting...)": "{{name}} (Connecting...)",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Waiting for video...)",
|
||||
"{{name}} is presenting": "{{name}} is presenting",
|
||||
"{{name}} is talking…": "{{name}} is talking…",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
@@ -10,10 +11,13 @@
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Create an account</0> Or <2>Access as a guest</2>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Oops, something's gone wrong.</0>",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Submitting debug logs will help us track down the problem.</0>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>",
|
||||
"Accept camera/microphone permissions to join the call.": "Accept camera/microphone permissions to join the call.",
|
||||
"Accept microphone permissions to join the call.": "Accept microphone permissions to join the call.",
|
||||
"Advanced": "Advanced",
|
||||
"Allow analytics": "Allow analytics",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.",
|
||||
"Audio": "Audio",
|
||||
"Avatar": "Avatar",
|
||||
@@ -29,6 +33,7 @@
|
||||
"Confirm password": "Confirm password",
|
||||
"Connection lost": "Connection lost",
|
||||
"Copied!": "Copied!",
|
||||
"Copy": "Copy",
|
||||
"Copy and share this call link": "Copy and share this call link",
|
||||
"Create account": "Create account",
|
||||
"Debug log": "Debug log",
|
||||
@@ -38,7 +43,7 @@
|
||||
"Developer": "Developer",
|
||||
"Display name": "Display name",
|
||||
"Download debug logs": "Download debug logs",
|
||||
"Entering room…": "Entering room…",
|
||||
"Element Call Home": "Element Call Home",
|
||||
"Exit full screen": "Exit full screen",
|
||||
"Fetching group call timed out.": "Fetching group call timed out.",
|
||||
"Freedom": "Freedom",
|
||||
@@ -99,6 +104,7 @@
|
||||
"Show call inspector": "Show call inspector",
|
||||
"Sign in": "Sign in",
|
||||
"Sign out": "Sign out",
|
||||
"Single-key keyboard shortcuts": "Single-key keyboard shortcuts",
|
||||
"Spatial audio": "Spatial audio",
|
||||
"Speaker": "Speaker",
|
||||
"Speaker {{n}}": "Speaker {{n}}",
|
||||
@@ -111,8 +117,10 @@
|
||||
"Talking…": "Talking…",
|
||||
"Thanks! We'll get right on it.": "Thanks! We'll get right on it.",
|
||||
"This call already exists, would you like to join?": "This call already exists, would you like to join?",
|
||||
"This feature is only supported on Firefox.": "This feature is only supported on Firefox.",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.",
|
||||
"Turn off camera": "Turn off camera",
|
||||
"Turn on camera": "Turn on camera",
|
||||
"Unmute microphone": "Unmute microphone",
|
||||
@@ -128,6 +136,7 @@
|
||||
"Walkie-talkie call": "Walkie-talkie call",
|
||||
"Walkie-talkie call name": "Walkie-talkie call name",
|
||||
"WebRTC is not supported or is being blocked in this browser.": "WebRTC is not supported or is being blocked in this browser.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.",
|
||||
"Yes, join call": "Yes, join call",
|
||||
"You can't talk at the same time": "You can't talk at the same time",
|
||||
"Your recent calls": "Your recent calls"
|
||||
|
||||
@@ -91,12 +91,11 @@
|
||||
"Home": "Inicio",
|
||||
"Having trouble? Help us fix it.": "¿Tienes problemas? Ayúdanos a resolverlos.",
|
||||
"Grid layout menu": "Menú de distribución de cuadrícula",
|
||||
"Go": "Empezar",
|
||||
"Go": "Comenzar",
|
||||
"Full screen": "Pantalla completa",
|
||||
"Freedom": "Libre",
|
||||
"Fetching group call timed out.": "Se ha agotado el tiempo de espera para obtener la llamada grupal.",
|
||||
"Exit full screen": "Salir de pantalla completa",
|
||||
"Entering room…": "Entrando a la sala…",
|
||||
"Download debug logs": "Descargar registros de depuración",
|
||||
"Display name": "Nombre a mostrar",
|
||||
"Developer": "Desarrollador",
|
||||
@@ -120,7 +119,6 @@
|
||||
"Audio": "Audio",
|
||||
"Avatar": "Avatar",
|
||||
"Accept camera/microphone permissions to join the call.": "Acepta los permisos de cámara/micrófono para unirte a la llamada.",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Ups, algo ha salido mal.</0><1>Enviar los registros de depuración nos ayudará a localizar el problema.</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Crear una cuenta</0> o <2>Acceder como invitado</2>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Unirse ahora</0><1>Or</1><2>Copiar el enlace y unirse más tarde</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>¿Ya tienes una cuenta?</0><1><0>Iniciar sesión</0> o <2>Acceder como invitado</2></1>",
|
||||
@@ -130,5 +128,13 @@
|
||||
"{{name}} (Connecting...)": "{{name}} (Conectando...)",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}, tu llamada ha finalizado",
|
||||
"{{count}} people connected|other": "{{count}} personas conectadas",
|
||||
"{{count}} people connected|one": "{{count}} persona conectada"
|
||||
"{{count}} people connected|one": "{{count}} persona conectada",
|
||||
"Allow analytics": "Permitir analíticas",
|
||||
"Advanced": "Avanzado",
|
||||
"Element Call Home": "Inicio de Element Call",
|
||||
"Copy": "Copiar",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Esto enviará datos anónimos (como la duración de la llamada y el número de participantes) al equipo de Element Call para ayudarnos a optimizar la aplicación dependiendo de cómo se use.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Habilita los atajos de teclado de una sola tecla, por ejemplo 'm' para silenciar/desilenciar el micrófono.",
|
||||
"Single-key keyboard shortcuts": "Atajos de teclado de una sola tecla",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Esperando al video...)"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"Accept camera/microphone permissions to join the call.": "Kõnega anna õigused kaamera/mikrofoni kasutamiseks.",
|
||||
"Accept camera/microphone permissions to join the call.": "Kõnega liitumiseks anna õigused kaamera/mikrofoni kasutamiseks.",
|
||||
"Accept microphone permissions to join the call.": "Kõnega liitumiseks anna õigused mikrofoni kasutamiseks.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Kas hoopis tahad salasõna seadistada ja sellega oma kasutajakonto alles jätta?</0><1>Siis saad säilitada oma nime ja määrata tunnuspildi, mida saad kasutada tulevastes kõnedes</1>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Ups, midagi läks valesti.</0><1>Logide saatmine meile aitab meil probleemi lahendada.</1>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Kas soovid salasõna seadistada ja sellega oma kasutajakonto alles jätta?</0><1>Nii saad säilitada oma nime ja määrata profiilipildi, mida saad kasutada tulevastes kõnedes</1>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Liitu kõnega kohe</0><1> Või</1><2>Kopeeri kõne link ja liitu hiljem</2>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Loo konto</0> Või <2>Sisene külalisena</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>On sul juba konto?</0><1><0>Logi sisse</0> Või <2>Logi sisse külalisena</2></1>",
|
||||
@@ -28,7 +27,6 @@
|
||||
"Freedom": "Vaba",
|
||||
"Fetching group call timed out.": "Grupikõne kättesaamine aegus.",
|
||||
"Exit full screen": "Välju täisekraanivaatest",
|
||||
"Entering room…": "Ruumi sisenemine…",
|
||||
"Download debug logs": "Lae alla veatuvastuslogid",
|
||||
"Display name": "Kuvatav nimi",
|
||||
"Developer": "Arendaja",
|
||||
@@ -130,5 +128,16 @@
|
||||
"Walkie-talkie call name": "Walkie-talkie stiilis kõne nimi",
|
||||
"WebRTC is not supported or is being blocked in this browser.": "WebRTC pole kas selles brauseris toetatud või on keelatud.",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "Muudab kõneleja heli nii, nagu tuleks see sealt, kus on tema pilt ekraanil. (See on katseline funktsionaalsus ja võib mõjutada heli stabiilsust.)",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "Siin saidis on kasutusel ReCAPTCHA ning kehtivad Google <2>privaatsuspoliitika</2> ja <6>teenusetingimused</6>.<9></9>Klikkides „Registreeru“, nõustud meie <12>kasutustingimustega</12>"
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "Siin saidis on kasutusel ReCAPTCHA ning kehtivad Google <2>privaatsuspoliitika</2> ja <6>teenusetingimused</6>.<9></9>Klikkides „Registreeru“, nõustud meie <12>kasutustingimustega</12>",
|
||||
"Allow analytics": "Luba analüütika",
|
||||
"Advanced": "Lisaseadistused",
|
||||
"Element Call Home": "Element Call Home",
|
||||
"Copy": "Kopeeri",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Me saadame kõne anonüümsed andmed (nagu kõne kestus ja osalejate arv) meie arendustiimile ja see võimaldab levinud kasutusmustrite alusel arendust optimeerida.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Kas kasutame üheklahvilisi kiirklahve, näiteks „m“ mikrofoni sisse/välja lülitamiseks.",
|
||||
"Single-key keyboard shortcuts": "Üheklahvilised kiirklahvid",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Ootame videovoo algust...)",
|
||||
"This feature is only supported on Firefox.": "See funktsionaalsus on toetatud vaid Firefoxis.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Kui saadad meile vealogid, siis on lihtsam vea põhjust otsida.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Ohoo, midagi on nüüd katki.</0>"
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
"Full screen": "تمام صحفه",
|
||||
"Freedom": "آزادی",
|
||||
"Exit full screen": "خروج از حالت تمام صفحه",
|
||||
"Entering room…": "درحال وارد شدن به اتاق…",
|
||||
"Download debug logs": "دانلود لاگ عیبیابی",
|
||||
"Display name": "نام نمایشی",
|
||||
"Developer": "توسعه دهنده",
|
||||
@@ -62,7 +61,6 @@
|
||||
"Accept microphone permissions to join the call.": "پذیرفتن دسترسی به میکروفون برای پیوستن به تماس.",
|
||||
"Accept camera/microphone permissions to join the call.": "پذیرفتن دسترسی دوربین/ میکروفون برای پیوستن به تماس.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>چرا یک رمز عبور برای حساب کاربری خود تنظیم نمیکنید؟</0><1>شما میتوانید نام خود را حفظ کنید و یک آواتار برای تماسهای آینده بسازید</1>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>اوه، مشکلی پیش آمده.</0><1>ثبت کردن لاگ رفع اشکال به پیدا کردن مشکل توسط ما کمک میکند</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>ساخت حساب کاربری</0> Or <2>دسترسی به عنوان میهمان</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>از قبل حساب کاربری دارید؟</0><1><0>ورود</0> Or <2>به عنوان یک میهمان وارد شوید</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - تماس واکی-تاکی",
|
||||
@@ -91,7 +89,7 @@
|
||||
"Registering…": "ثبتنام…",
|
||||
"Register": "ثبتنام",
|
||||
"Recaptcha not loaded": "کپچا بارگیری نشد",
|
||||
"Recaptcha dismissed": "بازکپچا رد شد",
|
||||
"Recaptcha dismissed": "ریکپچا رد شد",
|
||||
"Press and hold to talk over {{name}}": "برای صحبت فشار دهید و نگهدارید {{name}}",
|
||||
"Press and hold to talk": "برای صحبت فشار دهید و نگهدارید",
|
||||
"Press and hold spacebar to talk over {{name}}": "برای صحبت کردن دکمه اسپیس بار را فشار دهید و نگه دارید {{name}}",
|
||||
@@ -108,7 +106,7 @@
|
||||
"Having trouble? Help us fix it.": "با مشکلی رو به رو شدید؟ به ما کمک کنید رفعش کنیم.",
|
||||
"Grid layout menu": "منوی طرحبندی شبکهای",
|
||||
"Fetching group call timed out.": "زمان اتصال به مکالمه گروهی تمام شد.",
|
||||
"You can't talk at the same time": "شما نمی توانید همزمان تماس بگیرید",
|
||||
"You can't talk at the same time": "نمی توانید همزمان صحبت کنید",
|
||||
"Yes, join call": "بله، به تماس بپیوندید",
|
||||
"WebRTC is not supported or is being blocked in this browser.": "WebRTC (ارتباطات رسانهای بلادرنگ مانند انتقال صدا، ویدئو و داده) در این مرورگر پشتیبانی نمیشود یا در حال مسدود شدن است.",
|
||||
"Walkie-talkie call name": "نامِ تماسِ واکی-تاکی",
|
||||
@@ -118,8 +116,8 @@
|
||||
"Video call name": "نامِ تماسِ تصویری",
|
||||
"Version: {{version}}": "نسخه: {{نسخه}}",
|
||||
"User menu": "فهرست کاربر",
|
||||
"Unmute microphone": "میکروفون را باصدا کنید",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "این کار باعث میشود صدای بلندگو از جایی که کاشیهای آن روی صفحه قرار گرفته است به نظر برسد. (ویژگی آزمایشی: این ممکن است بر پایداری صدا تأثیر بگذارد.)",
|
||||
"Unmute microphone": "ناخموشی میکروفون",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "این کار باعث میشود به نظر برسد صدای بلندگو از جایی که کاشیاش روی صفحه قرار گرفته میآید (ویژگی آزمایشی: ممکن است بر پایداری صدا تأثیر بگذارد.)",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "این سایت توسط ReCAPTCHA محافظت می شود و <2>خط مشی رازداری</2> و <6>شرایط خدمات</6> Google اعمال می شود.<9></9>با کلیک کردن بر روی \"ثبت نام\"، شما با <12 >شرایط و ضوابط </12> ما موافقت می کنید",
|
||||
"This call already exists, would you like to join?": "این تماس از قبل وجود دارد، میخواهید بپیوندید؟",
|
||||
"Thanks! We'll get right on it.": "با تشکر! ما به درستی آن را انجام خواهیم داد.",
|
||||
@@ -128,5 +126,15 @@
|
||||
"Submitting feedback…": "در حال ارسال بازخورد…",
|
||||
"Submit feedback": "بازخورد ارائه دهید",
|
||||
"Stop sharing screen": "توقف اشتراکگذاری صفحه نمایش",
|
||||
"Spatial audio": "صدای فضایی"
|
||||
"Spatial audio": "صدای جهتدار",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "این که میانبرهای صفحهکلید تککلیده مثل m برای خموشی و ناخموشی میکروفون به کار بیفتند یا نه.",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "دادههای ناشناس شده (از اطَلاعاتی مثل طول تماس و شمارهٔ طرفها) را به گروه تماس المنت فرستاده تا در بهینهسازی برنامه بر پایهٔ چگونگی استفادهاش یاریمان کنند.",
|
||||
"Single-key keyboard shortcuts": "میانبرهای صفحهکلید تککلیده",
|
||||
"Element Call Home": "خانهٔ تماس المنت",
|
||||
"Copy": "رونوشت",
|
||||
"Allow analytics": "نمایش تجزیهها",
|
||||
"Advanced": "پیش رفته",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>اکنون به تماس پیوسته</0><1>یا</1><2>پیوند تماس را رونوشت کرده و بعداً بپیوندید</2>",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (منتظر تصویر…)",
|
||||
"{{name}} (Connecting...)": "{{name}} (وصل شدن…)"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Créer un compte</0> Or <2>Accès invité</2>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Mince, une erreur est survenue.</0><1>Envoyer les journaux de débogage nous aidera à résoudre le problème.</1>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Pourquoi ne pas créer un mot de passe pour conserver votre compte ?</0><1>Vous pourrez garder votre nom et définir un avatar pour vos futurs appels</1>",
|
||||
"Accept camera/microphone permissions to join the call.": "Autorisez l’accès à votre caméra et microphone pour rejoindre l’appel.",
|
||||
"Accept microphone permissions to join the call.": "Autorisez l’accès au microphone pour rejoindre l’appel.",
|
||||
@@ -28,7 +27,6 @@
|
||||
"Developer": "Développeur",
|
||||
"Display name": "Nom d’affichage",
|
||||
"Download debug logs": "Télécharger les journaux de débogage",
|
||||
"Entering room…": "Entrée dans le salon…",
|
||||
"Exit full screen": "Quitter le plein écran",
|
||||
"Freedom": "Libre",
|
||||
"Full screen": "Plein écran",
|
||||
@@ -130,5 +128,16 @@
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Vous avez déjà un compte ?</0><1><0>Se connecter</0> Ou <2>Accès invité</2></1>",
|
||||
"Sending debug logs…": "Envoi des journaux de débogage…",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Rejoindre l’appel maintenant</0><1>Ou</1><2>Copier le lien de l’appel et rejoindre plus tard</2>",
|
||||
"{{name}} (Connecting...)": "{{name}} (Connexion…)"
|
||||
"{{name}} (Connecting...)": "{{name}} (Connexion…)",
|
||||
"Allow analytics": "Autoriser les statistiques",
|
||||
"Advanced": "Avancé",
|
||||
"Element Call Home": "Accueil Element Call",
|
||||
"Copy": "Copier",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Cela enverra des données anonymisées (telles que la durée d’un appel et le nombre de participants) à l’équipe de Element Call pour aider à optimiser l’application en fonction de l’utilisation.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Bascule sur les raccourcis clavier à touche unique, par exemple « m » pour désactiver / activer le micro.",
|
||||
"Single-key keyboard shortcuts": "Raccourcis clavier en une touche",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (En attente de vidéo…)",
|
||||
"This feature is only supported on Firefox.": "Cette fonctionnalité est prise en charge dans Firefox uniquement.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Soumettre les journaux de débogage nous aidera à déterminer le problème.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Oups, quelque chose s’est mal passé.</0>"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Sudah punya akun?</0><1><0>Masuk</0> Atau <2>Akses sebagai tamu</2></1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Buat akun</0> Atau <2>Akses sebagai tamu</2>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Aduh, ada yang salah.</0><1>Mengirimkan catatan pengawakutuan akan membantu kami melacak masalahnya.</1>",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Kenapa tidak selesaikan dengan mengatur sebuah kata sandi untuk menjaga akun Anda?</0><1>Anda akan dapat tetap menggunakan nama Anda dan atur sebuah avatar untuk digunakan dalam panggilan di masa mendatang</1>",
|
||||
"Accept camera/microphone permissions to join the call.": "Terima izin kamera/mikrofon untuk bergabung ke panggilan.",
|
||||
"Accept microphone permissions to join the call.": "Terima izin mikrofon untuk bergabung ke panggilan.",
|
||||
@@ -29,7 +28,6 @@
|
||||
"Developer": "Pengembang",
|
||||
"Display name": "Nama tampilan",
|
||||
"Download debug logs": "Unduh catatan pengawakutuan",
|
||||
"Entering room…": "Memasuki ruangan…",
|
||||
"Exit full screen": "Keluar dari layar penuh",
|
||||
"Fetching group call timed out.": "Waktu pendapatan panggilan grup habis.",
|
||||
"Freedom": "Bebas",
|
||||
@@ -130,5 +128,16 @@
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - Panggilan protofon",
|
||||
"Sending debug logs…": "Mengirimkan catatan pengawakutuan…",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Bergabung panggilan sekarang</0><1>Atau</1><2>Salin tautan dan bergabung nanti</2>",
|
||||
"{{name}} (Connecting...)": "{{name}} (Menghubungkan...)"
|
||||
"{{name}} (Connecting...)": "{{name}} (Menghubungkan...)",
|
||||
"Allow analytics": "Perbolehkan analitik",
|
||||
"Advanced": "Tingkat lanjut",
|
||||
"Element Call Home": "Beranda Element Call",
|
||||
"Copy": "Salin",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Ini akan mengirimkan data anonim (seperti durasi dan jumlah peserta panggilan) ke tim Element Call untuk membantu kami mengoptimalkan aplikasi berdasarkan bagaimana penggunaannya.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Apakah pintasan papan ketik seharusnya diaktifkan, mis. 'm' untuk membisukan/menyuarakan mikrofon.",
|
||||
"Single-key keyboard shortcuts": "Pintasan papan ketik satu tombol",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Menunggu video...)",
|
||||
"This feature is only supported on Firefox.": "Fitur ini hanya didukung di Firefox.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Mengirim catatan pengawakutuan akan membantu kami melacak masalahnya.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Aduh, ada yang salah.</0>"
|
||||
}
|
||||
|
||||
1
public/locales/ja/app.json
Normal file
1
public/locales/ja/app.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "",
|
||||
"{{count}} people connected|one": "{{count}}명 연결됨",
|
||||
"{{count}} people connected|other": "{{count}}명 연결됨",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}님, 전화가 종료되었습니다",
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
"Freedom": "Wolność",
|
||||
"Fetching group call timed out.": "Przekroczono limit czasu na uzyskanie połączenia grupowego.",
|
||||
"Exit full screen": "Zamknij pełny ekran",
|
||||
"Entering room…": "Wchodzenie do pokoju…",
|
||||
"Download debug logs": "Pobierz dzienniki debugowania",
|
||||
"Display name": "Wyświetlana nazwa",
|
||||
"Developer": "Deweloper",
|
||||
@@ -118,7 +117,6 @@
|
||||
"Accept microphone permissions to join the call.": "Przyznaj uprawnienia do mikrofonu aby dołączyć do połączenia.",
|
||||
"Accept camera/microphone permissions to join the call.": "Przyznaj uprawnienia do kamery/mikrofonu aby dołączyć do połączenia.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Może zechcesz ustawić hasło, aby zachować swoje konto?</0><1>Będziesz w stanie utrzymać swoją nazwę i ustawić awatar do wyświetlania podczas połączeń w przyszłości</1>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Ups, coś poszło nie tak.</0><1>Przesłanie dzienników debugowania pomoże nam odnaleźć ten błąd.</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Utwórz konto</0> Albo <2>Dołącz jako gość</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Masz już konto?</0><1><0>Zaloguj się</0> Albo <2>Dołącz jako gość</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - połączenie walkie-talkie",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"Saving…": "Сохранение…",
|
||||
"Registering…": "Регистрация…",
|
||||
"Logging in…": "Вход…",
|
||||
"Entering room…": "Вход в комнату…",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"Waiting for other participants…": "Ожидание других участников…",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "Эта функция балансирует звук к расположению плитки на экране. (Экспериментальная функция: может повлиять на стабильность аудио.)",
|
||||
@@ -65,7 +64,6 @@
|
||||
"Debug log request": "Запрос журнала отладки",
|
||||
"Debug log": "Журнал отладки",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "У одного из участников звонка есть неполадки. Чтобы лучше диагностировать похожие проблемы, нам нужен журнал отладки.",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Ой, что-то пошло не так.</0><1>Отправив журнал отладки, вы поможете нам найти проблемный участок.</1>",
|
||||
"Send debug logs": "Отправить журнал отладки",
|
||||
"Save": "Сохранить",
|
||||
"Return to home screen": "Вернуться в Начало",
|
||||
@@ -128,5 +126,12 @@
|
||||
"{{name}} is presenting": "{{name}} показывает",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}, ваш звонок завершён",
|
||||
"{{count}} people connected|other": "{{count}} подключилось",
|
||||
"{{count}} people connected|one": "{{count}} подключился"
|
||||
"{{count}} people connected|one": "{{count}} подключился",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Это даст разрешение на отправку анонимизированных данных (таких, как продолжительность звонка и количество участников) команде Element Call, чтобы помочь нам оптимизировать работу приложения на основании того как оно используется.",
|
||||
"Element Call Home": "Главная Element Call",
|
||||
"Copy": "Копировать",
|
||||
"Allow analytics": "Разрешить аналитику",
|
||||
"Advanced": "Расширенные",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Присоединиться сейчас</0><1>или<1><2>Скопировать ссылку на звонок и присоединиться позже</2>",
|
||||
"{{name}} (Connecting...)": "{{name}} (Соединение...)"
|
||||
}
|
||||
|
||||
143
public/locales/sk/app.json
Normal file
143
public/locales/sk/app.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"Spotlight": "Stredobod",
|
||||
"Local volume": "Lokálna hlasitosť",
|
||||
"Include debug logs": "Zahrnúť záznamy o ladení",
|
||||
"Fetching group call timed out.": "Vypršal čas načítania skupinového volania.",
|
||||
"Element Call Home": "Domov Element Call",
|
||||
"You can't talk at the same time": "Nemôžete hovoriť naraz",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Či chcete povoliť jednotlačidlové klávesové skratky, napr. \"m\" na stlmenie/zapnutie mikrofónu.",
|
||||
"Waiting for other participants…": "Čaká sa na ďalších účastníkov…",
|
||||
"Waiting for network": "Čakanie na sieť",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Týmto spôsobom sa budú posielať anonymizované údaje (napríklad trvanie hovoru a počet účastníkov) tímu Element Call, aby nám pomohli optimalizovať aplikáciu na základe toho, ako sa používa.",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "Zvuk reproduktora tak bude vyzerať, akoby vychádzal z miesta, kde je na obrazovke umiestnená jeho ikona. (Experimentálna funkcia: môže to mať vplyv na stabilitu zvuku.)",
|
||||
"Thanks! We'll get right on it.": "Vďaka! Hneď sa do toho pustíme.",
|
||||
"Talking…": "Rozprávanie…",
|
||||
"Talk over speaker": "Hovor cez reproduktor",
|
||||
"Take me Home": "Zober ma domov",
|
||||
"Submitting feedback…": "Odosielanie spätnej väzby…",
|
||||
"Submit feedback": "Odoslať spätnú väzbu",
|
||||
"Stop sharing screen": "Zastaviť zdieľanie obrazovky",
|
||||
"Single-key keyboard shortcuts": "Jednotlačidlové klávesové skratky",
|
||||
"Show call inspector": "Zobraziť inšpektora hovorov",
|
||||
"Share screen": "Zdieľať obrazovku",
|
||||
"Sending…": "Odosielanie…",
|
||||
"Sending debug logs…": "Odosielanie záznamov o ladení…",
|
||||
"Send debug logs": "Odoslať záznamy o ladení",
|
||||
"Select an option": "Vyberte možnosť",
|
||||
"Saving…": "Ukladanie…",
|
||||
"Save": "Uložiť",
|
||||
"Return to home screen": "Návrat na domovskú obrazovku",
|
||||
"Remove": "Odstrániť",
|
||||
"Release spacebar key to stop": "Pustite medzerník pre ukončenie",
|
||||
"Release to stop": "Pustite pre ukončenie",
|
||||
"Registering…": "Registrácia…",
|
||||
"Register": "Registrovať sa",
|
||||
"Recaptcha not loaded": "Recaptcha sa nenačítala",
|
||||
"Recaptcha dismissed": "Recaptcha zamietnutá",
|
||||
"Profile": "Profil",
|
||||
"Press and hold to talk over {{name}}": "Stlačte a podržte pre hovor cez {{name}}",
|
||||
"Press and hold to talk": "Stlačte a podržte pre hovor",
|
||||
"Press and hold spacebar to talk over {{name}}": "Stlačte a podržte medzerník, ak chcete hovoriť cez {{name}}",
|
||||
"Press and hold spacebar to talk": "Stlačte a podržte medzerník, ak chcete hovoriť",
|
||||
"Passwords must match": "Heslá sa musia zhodovať",
|
||||
"Password": "Heslo",
|
||||
"Other users are trying to join this call from incompatible versions. These users should ensure that they have refreshed their browsers:<1>{userLis}</1>": "Ostatní používatelia sa pokúšajú pripojiť k tomuto hovoru z nekompatibilných verzií. Títo používatelia by sa mali uistiť, že si obnovili svoje prehliadače:<1>{userLis}</1>",
|
||||
"Not registered yet? <2>Create an account</2>": "Ešte nie ste zaregistrovaný? <2>Vytvorte si účet</2>",
|
||||
"Not now, return to home screen": "Teraz nie, vrátiť sa na domovskú obrazovku",
|
||||
"No": "Nie",
|
||||
"Mute microphone": "Stlmiť mikrofón",
|
||||
"More menu": "Ponuka viac",
|
||||
"More": "Viac",
|
||||
"Microphone permissions needed to join the call.": "Povolenie mikrofónu je potrebné na pripojenie k hovoru.",
|
||||
"Microphone {{n}}": "Mikrofón {{n}}",
|
||||
"Microphone": "Mikrofón",
|
||||
"Login to your account": "Prihláste sa do svojho konta",
|
||||
"Login": "Prihlásiť sa",
|
||||
"Logging in…": "Prihlasovanie…",
|
||||
"Loading…": "Načítanie…",
|
||||
"Loading room…": "Načítanie miestnosti…",
|
||||
"Leave": "Opustiť",
|
||||
"Join existing call?": "Pripojiť sa k existujúcemu hovoru?",
|
||||
"Join call now": "Pripojiť sa k hovoru teraz",
|
||||
"Join call": "Pripojiť sa k hovoru",
|
||||
"Invite people": "Pozvať ľudí",
|
||||
"Invite": "Pozvať",
|
||||
"Inspector": "Inšpektor",
|
||||
"Incompatible versions!": "Nekompatibilné verzie!",
|
||||
"Incompatible versions": "Nekompatibilné verzie",
|
||||
"Home": "Domov",
|
||||
"Having trouble? Help us fix it.": "Máte problém? Pomôžte nám ho opraviť.",
|
||||
"Grid layout menu": "Ponuka rozloženia mriežky",
|
||||
"Go": "Prejsť",
|
||||
"Full screen": "Zobrazenie na celú obrazovku",
|
||||
"Freedom": "Sloboda",
|
||||
"Exit full screen": "Ukončiť zobrazenie na celú obrazovku",
|
||||
"Download debug logs": "Stiahnuť záznamy ladenia",
|
||||
"Your recent calls": "Vaše nedávne hovory",
|
||||
"Yes, join call": "Áno, pripojiť sa k hovoru",
|
||||
"WebRTC is not supported or is being blocked in this browser.": "WebRTC nie je podporované alebo je v tomto prehliadači blokované.",
|
||||
"Walkie-talkie call name": "Názov vysielačkového hovoru",
|
||||
"Walkie-talkie call": "Vysielačkový hovor",
|
||||
"Video call name": "Názov video hovoru",
|
||||
"Video call": "Video hovor",
|
||||
"Video": "Video",
|
||||
"Version: {{version}}": "Verzia: {{version}}",
|
||||
"Username": "Meno používateľa",
|
||||
"User menu": "Používateľské menu",
|
||||
"User ID": "ID používateľa",
|
||||
"Unmute microphone": "Zrušiť stlmenie mikrofónu",
|
||||
"Turn on camera": "Zapnúť kameru",
|
||||
"Turn off camera": "Vypnúť kameru",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "Táto stránka je chránená systémom ReCAPTCHA a platia na ňu <2>Pravidlá ochrany osobných údajov</2> a <6>Podmienky poskytovania služieb</6> spoločnosti Google.<9></9>Kliknutím na tlačidlo \"Registrovať sa\" vyjadrujete súhlas s našimi <12>Podmienkami poskytovania služieb</12>",
|
||||
"This call already exists, would you like to join?": "Tento hovor už existuje, chceli by ste sa k nemu pripojiť?",
|
||||
"Speaker {{n}}": "Reproduktor {{n}}",
|
||||
"Speaker": "Reproduktor",
|
||||
"Spatial audio": "Priestorový zvuk",
|
||||
"Sign out": "Odhlásiť sa",
|
||||
"Sign in": "Prihlásiť sa",
|
||||
"Settings": "Nastavenia",
|
||||
"Display name": "Zobrazované meno",
|
||||
"Developer": "Vývojár",
|
||||
"Details": "Podrobnosti",
|
||||
"Description (optional)": "Popis (voliteľné)",
|
||||
"Debug log request": "Žiadosť o záznam ladenia",
|
||||
"Debug log": "Záznam o ladení",
|
||||
"Create account": "Vytvoriť účet",
|
||||
"Copy and share this call link": "Skopírovať a zdieľať tento odkaz na hovor",
|
||||
"Copy": "Kopírovať",
|
||||
"Copied!": "Skopírované!",
|
||||
"Connection lost": "Strata spojenia",
|
||||
"Confirm password": "Potvrdiť heslo",
|
||||
"Close": "Zatvoriť",
|
||||
"Change layout": "Zmeniť rozloženie",
|
||||
"Camera/microphone permissions needed to join the call.": "Povolenie kamery/mikrofónu je potrebné na pripojenie k hovoru.",
|
||||
"Camera {{n}}": "Kamera {{n}}",
|
||||
"Camera": "Kamera",
|
||||
"Call type menu": "Ponuka typu hovoru",
|
||||
"Call link copied": "Odkaz na hovor skopírovaný",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "Kliknutím na \"Pripojiť sa k hovoru\" súhlasíte s našimi <2>Podmienkami</2>",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "Kliknutím na tlačidlo \"Prejsť\" súhlasíte s našimi <2>Podmienkami</2>",
|
||||
"Avatar": "Obrázok",
|
||||
"Audio": "Audio",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "Ďalší používateľ v tomto hovore má problém. Aby sme mohli lepšie diagnostikovať tieto problémy, chceli by sme získať záznam o ladení.",
|
||||
"Allow analytics": "Povoliť analytiku",
|
||||
"Advanced": "Pokročilé",
|
||||
"Accept camera/microphone permissions to join the call.": "Prijmite povolenia kamery/mikrofónu, aby ste sa mohli pripojiť k hovoru.",
|
||||
"Accept microphone permissions to join the call.": "Prijmite povolenia mikrofónu, aby ste sa mohli pripojiť k hovoru.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Prečo neskončiť nastavením hesla, aby ste si zachovali svoj účet? </0><1>Budete si môcť ponechať svoje meno a nastaviť obrázok, ktorý sa bude používať pri budúcich hovoroch</1>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Pripojiť sa k hovoru teraz</0><1>alebo</1><2>Kopírovať odkaz na hovor a pripojiť sa neskôr</2>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Vytvoriť konto</0> Alebo <2>Prihlásiť sa ako hosť</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Už máte konto?</0><1><0>Prihláste sa</0> Alebo <2>Prihlásiť sa ako hosť</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - Vysielačkový hovor",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"{{name}} is talking…": "{{name}} rozpráva…",
|
||||
"{{name}} is presenting": "{{name}} prezentuje",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Čaká sa na video...)",
|
||||
"{{name}} (Connecting...)": "{{name}} (Pripájanie...)",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}}, váš hovor je teraz ukončený",
|
||||
"{{count}} people connected|other": "{{count}} osôb pripojených",
|
||||
"{{count}} people connected|one": "{{count}} osoba pripojená",
|
||||
"This feature is only supported on Firefox.": "Táto funkcia je podporovaná len v prehliadači Firefox.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Odoslanie záznamov ladenia nám pomôže nájsť problém.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Hups, niečo sa pokazilo.</0>"
|
||||
}
|
||||
@@ -26,7 +26,6 @@
|
||||
"Developer": "Geliştirici",
|
||||
"Display name": "Ekran adı",
|
||||
"Download debug logs": "Hata ayıklama kütüğünü indir",
|
||||
"Entering room…": "Odaya giriliyor…",
|
||||
"Exit full screen": "Tam ekranı terk et",
|
||||
"Fetching group call timed out.": "Grup çağrısı zaman aşımına uğradı.",
|
||||
"Freedom": "Özgürlük",
|
||||
@@ -96,7 +95,6 @@
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"{{name}} is presenting": "{{name}} sunuyor",
|
||||
"{{name}} is talking…": "{{name}} konuşuyor…",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Hoop, bir şeyler yanlış.</0><1>Hata ayıklama kütüğünü göndermek sorunu incelememize yardımcı olur.</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Hesap oluştur</0> yahut <2>Konuk olarak gir</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Mevcut hesabınız mı var?</0><1><0>Gir</0> yahut <2>Konuk girişi</2></1>"
|
||||
}
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
"Freedom": "Свобода",
|
||||
"Fetching group call timed out.": "Вичерпано час очікування групового виклику.",
|
||||
"Exit full screen": "Вийти з повноекранного режиму",
|
||||
"Entering room…": "Вхід у кімнату…",
|
||||
"Download debug logs": "Завантажити журнали зневадження",
|
||||
"Display name": "Показуване ім'я",
|
||||
"Developer": "Розробнику",
|
||||
@@ -119,7 +118,6 @@
|
||||
"Accept microphone permissions to join the call.": "Надайте дозволи на використання мікрофонів для приєднання до виклику.",
|
||||
"Accept camera/microphone permissions to join the call.": "Надайте дозвіл на використання камери/мікрофона для приєднання до виклику.",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>Чому б не завершити, налаштувавши пароль для збереження свого облікового запису?</0><1>Ви зможете зберегти своє ім'я та встановити аватарку для подальшого користування під час майбутніх викликів</1>",
|
||||
"<0>Oops, something's gone wrong.</0><1>Submitting debug logs will help us track down the problem.</1>": "<0>Халепа, щось пішло не так.</0><1>Надсилання журналів зневадження допоможе нам виявити проблему.</1>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>Створити обліковий запис</0> або <2>Отримати доступ як гість</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>Уже маєте обліковий запис?</0><1><0>Увійти</0> Or <2>Отримати доступ як гість</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - Виклик-рація",
|
||||
@@ -130,5 +128,16 @@
|
||||
"{{count}} people connected|other": "{{count}} під'єдналися",
|
||||
"{{count}} people connected|one": "{{count}} під'єднується",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>Приєднатися до виклику зараз</0><1>Or</1><2>Скопіювати посилання на виклик і приєднатися пізніше</2>",
|
||||
"{{name}} (Connecting...)": "{{name}} (З'єднання...)"
|
||||
"{{name}} (Connecting...)": "{{name}} (З'єднання...)",
|
||||
"Allow analytics": "Дозволити аналітику",
|
||||
"Advanced": "Розширені",
|
||||
"Element Call Home": "Домівка Element Call",
|
||||
"Copy": "Копіювати",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "Це дозволить надсилати анонімні дані (такі як тривалість виклику та кількість учасників) команді Element Call, щоб допомогти нам оптимізувати роботу застосунку на основі того, як він використовується.",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "Чи вмикати/вимикати мікрофон однією клавішею, наприклад, «m» для ввімкнення/вимкнення мікрофона.",
|
||||
"Single-key keyboard shortcuts": "Одноклавішні комбінації клавіш",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (Очікування на відео...)",
|
||||
"This feature is only supported on Firefox.": "Ця функція підтримується лише в браузері Firefox.",
|
||||
"<0>Submitting debug logs will help us track down the problem.</0>": "<0>Надсилання журналів зневадження допоможе нам виявити проблему.</0>",
|
||||
"<0>Oops, something's gone wrong.</0>": "<0>Йой, щось пішло не за планом.</0>"
|
||||
}
|
||||
|
||||
140
public/locales/zh-Hans/app.json
Normal file
140
public/locales/zh-Hans/app.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"Your recent calls": "最近通话",
|
||||
"You can't talk at the same time": "你不能在同一时间发言",
|
||||
"Yes, join call": "是,加入通话",
|
||||
"Whether to enable single-key keyboard shortcuts, e.g. 'm' to mute/unmute the mic.": "是否启用单键键盘快捷键,例如,'m'可使麦克风静音/取消静音。",
|
||||
"WebRTC is not supported or is being blocked in this browser.": "此浏览器不支持WebRTC或WebRTC被浏览器阻止。",
|
||||
"Walkie-talkie call name": "对讲机通话名称",
|
||||
"Walkie-talkie call": "对讲机通话",
|
||||
"Waiting for other participants…": "等待其他参与者……",
|
||||
"Waiting for network": "正在等待网络",
|
||||
"Video call name": "视频通话名称",
|
||||
"Video call": "视频通话",
|
||||
"Video": "视频",
|
||||
"Version: {{version}}": "版本:{{version}}",
|
||||
"Username": "用户名",
|
||||
"User menu": "用户菜单",
|
||||
"User ID": "用户ID",
|
||||
"Unmute microphone": "取消麦克风静音",
|
||||
"Turn on camera": "开启摄像头",
|
||||
"Turn off camera": "关闭摄像头",
|
||||
"This will send anonymised data (such as the duration of a call and the number of participants) to the Element Call team to help us optimise the application based on how it is used.": "这将向Element Call团队发送匿名数据(如通话的持续时间和参与者的数量),以帮助我们根据使用方式优化应用程序。",
|
||||
"This will make a speaker's audio seem as if it is coming from where their tile is positioned on screen. (Experimental feature: this may impact the stability of audio.)": "这将使发言人的音频看起来像是来自他们在屏幕上的位置。(实验性功能:这可能影响音频的稳定性)",
|
||||
"This site is protected by ReCAPTCHA and the Google <2>Privacy Policy</2> and <6>Terms of Service</6> apply.<9></9>By clicking \"Register\", you agree to our <12>Terms and conditions</12>": "本网站受reCaptcha保护,并适用Google<2>隐私政策</2>和<6>服务条款</6>。<9></9>点击\"注册\"则表明您同意我们的<12>条款和条件</12>",
|
||||
"This call already exists, would you like to join?": "该通话已存在,你想加入吗?",
|
||||
"Thanks! We'll get right on it.": "谢谢!我们会马上去做的。",
|
||||
"Talking…": "正在发言……",
|
||||
"Talk over speaker": "通过扬声器发言",
|
||||
"Take me Home": "返回主页",
|
||||
"Submitting feedback…": "正在提交反馈……",
|
||||
"Submit feedback": "提交反馈",
|
||||
"Stop sharing screen": "停止屏幕共享",
|
||||
"Spotlight": "聚焦模式",
|
||||
"Speaker {{n}}": "发言人 {{n}}",
|
||||
"Speaker": "发言人",
|
||||
"Spatial audio": "空间音频",
|
||||
"Single-key keyboard shortcuts": "单键键盘快捷方式",
|
||||
"Sign out": "注销登录",
|
||||
"Sign in": "登录",
|
||||
"Audio": "音频",
|
||||
"Another user on this call is having an issue. In order to better diagnose these issues we'd like to collect a debug log.": "这个通话中的另一个用户出现了问题。为了更好地诊断这些问题,我们想收集调试日志。",
|
||||
"Allow analytics": "允许进行分析",
|
||||
"Advanced": "偏好",
|
||||
"Accept microphone permissions to join the call.": "授予麦克风权限以加入通话。",
|
||||
"Accept camera/microphone permissions to join the call.": "授予摄像头/麦克风权限以加入通话。",
|
||||
"<0>Why not finish by setting up a password to keep your account?</0><1>You'll be able to keep your name and set an avatar for use on future calls</1>": "<0>为什么不设置一个密码来保留你的账户?</0><1>你将可以保留你的名字并设置一个头像,以便在未来的通话中使用。</1>",
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>现在加入通话</0><1>或</1><2>复制通话链接并稍后加入</2>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>创建账户</0> Or <2>以访客身份继续</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>已有账户?</0><1><0>登录</0> Or <2>以访客身份继续</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - 对讲机通话",
|
||||
"{{names}}, {{name}}": "{{names}}, {{name}}",
|
||||
"{{name}} is talking…": "{{name}}正在发言……",
|
||||
"{{name}} is presenting": "{{name}}正在展示",
|
||||
"{{name}} (Waiting for video...)": "{{name}}(等待视频……)",
|
||||
"{{name}} (Connecting...)": "{{name}} (正在连接……)",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}},您的通话已结束",
|
||||
"{{count}} people connected|other": "{{count}}人已连接",
|
||||
"{{count}} people connected|one": "{{count}}人已连接",
|
||||
"Inspector": "检查器",
|
||||
"Show call inspector": "显示通话检查器",
|
||||
"Share screen": "屏幕共享",
|
||||
"Settings": "设置",
|
||||
"Sending…": "正在发送……",
|
||||
"Sending debug logs…": "正在发送调试日志……",
|
||||
"Send debug logs": "发送调试日志",
|
||||
"Select an option": "选择一个选项",
|
||||
"Saving…": "正在保存……",
|
||||
"Save": "保存",
|
||||
"Return to home screen": "返回主页",
|
||||
"Remove": "移除",
|
||||
"Release to stop": "松开后停止",
|
||||
"Release spacebar key to stop": "松开空格键停止",
|
||||
"Registering…": "正在注册……",
|
||||
"Register": "注册",
|
||||
"Recaptcha not loaded": "reCaptcha未加载",
|
||||
"Recaptcha dismissed": "reCaptcha验证失败",
|
||||
"Profile": "个人信息",
|
||||
"Press and hold to talk over {{name}}": "按住不放即可与 {{name}} 通话",
|
||||
"Press and hold to talk": "按住不放即可通话",
|
||||
"Press and hold spacebar to talk over {{name}}": "按住空格键,与 {{name}} 对话",
|
||||
"Press and hold spacebar to talk": "按住空格键发言",
|
||||
"Passwords must match": "密码必须匹配",
|
||||
"Password": "密码",
|
||||
"Other users are trying to join this call from incompatible versions. These users should ensure that they have refreshed their browsers:<1>{userLis}</1>": "其他用户正试图从不兼容的版本加入这一呼叫。这些用户应该确保已经刷新了浏览器:<1>{userLis}</1>",
|
||||
"Not registered yet? <2>Create an account</2>": "还没有注册? <2>创建账户<2>",
|
||||
"Not now, return to home screen": "暂不,先返回主页",
|
||||
"No": "否",
|
||||
"Mute microphone": "麦克风静音",
|
||||
"More menu": "更多",
|
||||
"More": "更多",
|
||||
"Microphone permissions needed to join the call.": "加入通话需要麦克风权限。",
|
||||
"Microphone {{n}}": "麦克风 {{n}}",
|
||||
"Microphone": "麦克风",
|
||||
"Login to your account": "登录你的账户",
|
||||
"Login": "登录",
|
||||
"Logging in…": "登录中……",
|
||||
"Local volume": "本地音量",
|
||||
"Loading…": "加载中……",
|
||||
"Loading room…": "加载房间中……",
|
||||
"Leave": "离开",
|
||||
"Join existing call?": "加入现有的通话?",
|
||||
"Join call now": "现在加入通话",
|
||||
"Join call": "加入通话",
|
||||
"Invite people": "邀请他人",
|
||||
"Invite": "邀请",
|
||||
"Incompatible versions!": "版本不兼容!",
|
||||
"Incompatible versions": "不兼容版本",
|
||||
"Include debug logs": "包含调试日志",
|
||||
"Home": "主页",
|
||||
"Having trouble? Help us fix it.": "遇到麻烦?帮助我们解决问题。",
|
||||
"Grid layout menu": "网格布局菜单",
|
||||
"Go": "开始",
|
||||
"Full screen": "全屏",
|
||||
"Freedom": "自由模式",
|
||||
"Fetching group call timed out.": "获取群组通话超时。",
|
||||
"Exit full screen": "退出全屏",
|
||||
"Element Call Home": "Element Call 主页",
|
||||
"Download debug logs": "下载调试日志",
|
||||
"Display name": "显示名称",
|
||||
"Developer": "开发者",
|
||||
"Details": "详情",
|
||||
"Description (optional)": "描述(可选)",
|
||||
"Debug log request": "调试日志请求",
|
||||
"Debug log": "调试日志",
|
||||
"Create account": "创建账户",
|
||||
"Copy and share this call link": "复制并分享该链接",
|
||||
"Copy": "复制",
|
||||
"Copied!": "已复制!",
|
||||
"Connection lost": "连接丢失",
|
||||
"Confirm password": "确认密码",
|
||||
"Close": "关闭",
|
||||
"By clicking \"Go\", you agree to our <2>Terms and conditions</2>": "点击开始则代表同意我们的<2>条款和条件<2>",
|
||||
"Change layout": "更改布局",
|
||||
"Camera/microphone permissions needed to join the call.": "加入通话需要摄像头/麦克风权限。",
|
||||
"Camera {{n}}": "摄像头 {{n}}",
|
||||
"Camera": "摄像头",
|
||||
"Call type menu": "通话类型菜单",
|
||||
"Call link copied": "链接已复制",
|
||||
"By clicking \"Join call now\", you agree to our <2>Terms and conditions</2>": "点击“现在加入”则表示同意我们的<2>条款与条件<2>",
|
||||
"Avatar": "头像"
|
||||
}
|
||||
14
public/locales/zh-Hant/app.json
Normal file
14
public/locales/zh-Hant/app.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"<0>Join call now</0><1>Or</1><2>Copy call link and join later</2>": "<0>加入通話</0><1>或</1><2>複製通話連結並稍候加入</2>",
|
||||
"<0>Create an account</0> Or <2>Access as a guest</2>": "<0>建立帳號</0> 或 <2>訪客模式</2>",
|
||||
"<0>Already have an account?</0><1><0>Log in</0> Or <2>Access as a guest</2></1>": "<0>已經有帳號了?</0><1><0>登入</0> Or <2>訪客模式登入</2></1>",
|
||||
"{{roomName}} - Walkie-talkie call": "{{roomName}} - 無線電通話",
|
||||
"{{names}}, {{name}}": "{{names}},{{name}}",
|
||||
"{{name}} is talking…": "{{name}} 正在交談中…",
|
||||
"{{name}} is presenting": "{{name}} 正在報告",
|
||||
"{{name}} (Waiting for video...)": "{{name}} (等待視訊畫面 ...)",
|
||||
"{{name}} (Connecting...)": "{{name}} (連線中 ...)",
|
||||
"{{displayName}}, your call is now ended": "{{displayName}},您的通話現在已結束",
|
||||
"{{count}} people connected|other": "{{count}} 人已連線",
|
||||
"{{count}} people connected|one": "{{count}} 人已連線"
|
||||
}
|
||||
@@ -2,22 +2,7 @@
|
||||
|
||||
set -ex
|
||||
|
||||
export VITE_DEFAULT_HOMESERVER=https://call.ems.host
|
||||
export VITE_SENTRY_DSN=https://b1e328d49be3402ba96101338989fb35@sentry.matrix.org/41
|
||||
export VITE_RAGESHAKE_SUBMIT_URL=https://element.io/bugreports/submit
|
||||
export VITE_PRODUCT_NAME="Element Call"
|
||||
|
||||
git clone https://github.com/matrix-org/matrix-js-sdk.git
|
||||
cd matrix-js-sdk
|
||||
git checkout robertlong/group-call
|
||||
yarn install
|
||||
yarn run build
|
||||
yarn link
|
||||
|
||||
cd ../element-call
|
||||
|
||||
export VITE_APP_VERSION=$(git describe --tags --abbrev=0)
|
||||
|
||||
yarn link matrix-js-sdk
|
||||
yarn install
|
||||
yarn run build
|
||||
|
||||
13
src/@types/global.d.ts
vendored
13
src/@types/global.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,12 @@ limitations under the License.
|
||||
import "matrix-js-sdk/src/@types/global";
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
// Safari only supports this prefixed, so tell the type system about it
|
||||
webkitExitFullscreen: () => void;
|
||||
webkitFullscreenElement: HTMLElement | null;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
// TODO: https://gitlab.matrix.org/matrix-org/olm/-/issues/10
|
||||
OLM_OPTIONS: Record<string, string>;
|
||||
@@ -27,4 +33,9 @@ declare global {
|
||||
interface MediaElement extends HTMLVideoElement {
|
||||
setSinkId: (id: string) => void;
|
||||
}
|
||||
|
||||
interface HTMLElement {
|
||||
// Safari only supports this prefixed, so tell the type system about it
|
||||
webkitRequestFullscreen: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
16
src/@types/modules.d.ts
vendored
16
src/@types/modules.d.ts
vendored
@@ -1,2 +1,18 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-plugin-svgr/client" />
|
||||
|
||||
77
src/App.tsx
77
src/App.tsx
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Suspense } from "react";
|
||||
import React, { Suspense, useEffect, useState } from "react";
|
||||
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { OverlayProvider } from "@react-aria/overlays";
|
||||
@@ -28,7 +28,8 @@ import { ClientProvider } from "./ClientContext";
|
||||
import { usePageFocusStyle } from "./usePageFocusStyle";
|
||||
import { SequenceDiagramViewerPage } from "./SequenceDiagramViewerPage";
|
||||
import { InspectorContextProvider } from "./room/GroupCallInspector";
|
||||
import { CrashView } from "./FullScreenView";
|
||||
import { CrashView, LoadingView } from "./FullScreenView";
|
||||
import { Initializer } from "./initializer";
|
||||
|
||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||
|
||||
@@ -37,42 +38,54 @@ interface AppProps {
|
||||
}
|
||||
|
||||
export default function App({ history }: AppProps) {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
Initializer.init()?.then(() => {
|
||||
setLoaded(true);
|
||||
});
|
||||
});
|
||||
|
||||
usePageFocusStyle();
|
||||
|
||||
const errorPage = <CrashView />;
|
||||
|
||||
return (
|
||||
<Router history={history}>
|
||||
<Suspense fallback={null}>
|
||||
<ClientProvider>
|
||||
<InspectorContextProvider>
|
||||
<Sentry.ErrorBoundary fallback={errorPage}>
|
||||
<OverlayProvider>
|
||||
<Switch>
|
||||
<SentryRoute exact path="/">
|
||||
<HomePage />
|
||||
</SentryRoute>
|
||||
<SentryRoute exact path="/login">
|
||||
<LoginPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute exact path="/register">
|
||||
<RegisterPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="/room/:roomId?">
|
||||
<RoomPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="/inspector">
|
||||
<SequenceDiagramViewerPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="*">
|
||||
<RoomRedirect />
|
||||
</SentryRoute>
|
||||
</Switch>
|
||||
</OverlayProvider>
|
||||
</Sentry.ErrorBoundary>
|
||||
</InspectorContextProvider>
|
||||
</ClientProvider>
|
||||
</Suspense>
|
||||
{loaded ? (
|
||||
<Suspense fallback={null}>
|
||||
<ClientProvider>
|
||||
<InspectorContextProvider>
|
||||
<Sentry.ErrorBoundary fallback={errorPage}>
|
||||
<OverlayProvider>
|
||||
<Switch>
|
||||
<SentryRoute exact path="/">
|
||||
<HomePage />
|
||||
</SentryRoute>
|
||||
<SentryRoute exact path="/login">
|
||||
<LoginPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute exact path="/register">
|
||||
<RegisterPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="/room/:roomId?">
|
||||
<RoomPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="/inspector">
|
||||
<SequenceDiagramViewerPage />
|
||||
</SentryRoute>
|
||||
<SentryRoute path="*">
|
||||
<RoomRedirect />
|
||||
</SentryRoute>
|
||||
</Switch>
|
||||
</OverlayProvider>
|
||||
</Sentry.ErrorBoundary>
|
||||
</InspectorContextProvider>
|
||||
</ClientProvider>
|
||||
</Suspense>
|
||||
) : (
|
||||
<LoadingView />
|
||||
)}
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
color: var(--primary-content);
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useMemo, CSSProperties } from "react";
|
||||
import classNames from "classnames";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
|
||||
@@ -25,24 +25,26 @@ import React, {
|
||||
useRef,
|
||||
} from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { ErrorView } from "./FullScreenView";
|
||||
import {
|
||||
initClient,
|
||||
defaultHomeserver,
|
||||
CryptoStoreIntegrityError,
|
||||
fallbackICEServerAllowed,
|
||||
} from "./matrix-utils";
|
||||
import { widget } from "./widget";
|
||||
import { PosthogAnalytics, RegistrationType } from "./PosthogAnalytics";
|
||||
import { translatedError } from "./TranslatedError";
|
||||
import { useEventTarget } from "./useEvents";
|
||||
import { Config } from "./config/Config";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
matrixclient: MatrixClient;
|
||||
isPasswordlessUser: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +56,9 @@ export interface Session {
|
||||
tempPassword?: string;
|
||||
}
|
||||
|
||||
const loadChannel =
|
||||
"BroadcastChannel" in window ? new BroadcastChannel("load") : null;
|
||||
|
||||
const loadSession = (): Session => {
|
||||
const data = localStorage.getItem("matrix-auth-store");
|
||||
if (data) return JSON.parse(data);
|
||||
@@ -114,7 +119,6 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
if (widget) {
|
||||
// We're inside a widget, so let's engage *matryoshka mode*
|
||||
logger.log("Using a matryoshka client");
|
||||
|
||||
return {
|
||||
client: await widget.client,
|
||||
isPasswordlessUser: false,
|
||||
@@ -135,7 +139,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
return {
|
||||
client: await initClient(
|
||||
{
|
||||
baseUrl: defaultHomeserver,
|
||||
baseUrl: Config.defaultHomeserverUrl(),
|
||||
accessToken: access_token,
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
@@ -151,7 +155,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
try {
|
||||
const client = await initClient(
|
||||
{
|
||||
baseUrl: defaultHomeserver,
|
||||
baseUrl: Config.defaultHomeserverUrl(),
|
||||
accessToken: access_token,
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
@@ -279,51 +283,34 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
error: undefined,
|
||||
});
|
||||
history.push("/");
|
||||
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Guest);
|
||||
}, [history, client]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
// To protect against multiple sessions writing to the same storage
|
||||
// simultaneously, we send a broadcast message that shuts down all other
|
||||
// running instances of the app. This isn't necessary if the app is running in
|
||||
// a widget though, since then it'll be mostly stateless.
|
||||
useEffect(() => {
|
||||
// To protect against multiple sessions writing to the same storage
|
||||
// simultaneously, we send a to-device message that shuts down all other
|
||||
// running instances of the app. This isn't necessary if the app is running
|
||||
// in a widget though, since then it'll be mostly stateless.
|
||||
if (!widget && client) {
|
||||
const loadTime = Date.now();
|
||||
if (!widget) loadChannel?.postMessage({});
|
||||
}, []);
|
||||
|
||||
const onToDeviceEvent = (event: MatrixEvent) => {
|
||||
if (event.getType() !== "org.matrix.call_duplicate_session") return;
|
||||
useEventTarget(
|
||||
loadChannel,
|
||||
"message",
|
||||
useCallback(() => {
|
||||
client?.stopClient();
|
||||
|
||||
const content = event.getContent();
|
||||
|
||||
if (content.session_id === client.getSessionId()) return;
|
||||
|
||||
if (content.timestamp > loadTime) {
|
||||
client?.stopClient();
|
||||
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error: translatedError(
|
||||
"This application has been opened in another tab.",
|
||||
t
|
||||
),
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
client.on(ClientEvent.ToDeviceEvent, onToDeviceEvent);
|
||||
|
||||
client.sendToDevice("org.matrix.call_duplicate_session", {
|
||||
[client.getUserId()]: {
|
||||
"*": { session_id: client.getSessionId(), timestamp: loadTime },
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
client?.removeListener(ClientEvent.ToDeviceEvent, onToDeviceEvent);
|
||||
};
|
||||
}
|
||||
}, [client, t]);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error: translatedError(
|
||||
"This application has been opened in another tab.",
|
||||
t
|
||||
),
|
||||
}));
|
||||
}, [client, setState, t])
|
||||
);
|
||||
|
||||
const context = useMemo<ClientState>(
|
||||
() => ({
|
||||
@@ -351,7 +338,8 @@ export const ClientProvider: FC<Props> = ({ children }) => {
|
||||
|
||||
useEffect(() => {
|
||||
window.matrixclient = client;
|
||||
}, [client]);
|
||||
window.isPasswordlessUser = isPasswordlessUser;
|
||||
}, [client, isPasswordlessUser]);
|
||||
|
||||
if (error) {
|
||||
return <ErrorView error={error} />;
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.facepile {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
@@ -32,7 +32,7 @@ const overlapMap: Partial<Record<Size, number>> = {
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
className: string;
|
||||
client: MatrixClient;
|
||||
participants: RoomMember[];
|
||||
members: RoomMember[];
|
||||
max?: number;
|
||||
size?: Size;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
export function Facepile({
|
||||
className,
|
||||
client,
|
||||
participants,
|
||||
members,
|
||||
max = 3,
|
||||
size = Size.XS,
|
||||
...rest
|
||||
@@ -51,14 +51,14 @@ export function Facepile({
|
||||
const _overlap = overlapMap[size];
|
||||
|
||||
const title = useMemo(() => {
|
||||
return participants.reduce<string | null>(
|
||||
return members.reduce<string | null>(
|
||||
(prev, curr) =>
|
||||
prev === null
|
||||
? curr.name
|
||||
: t("{{names}}, {{name}}", { names: prev, name: curr.name }),
|
||||
null
|
||||
) as string;
|
||||
}, [participants, t]);
|
||||
}, [members, t]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -66,12 +66,11 @@ export function Facepile({
|
||||
title={title}
|
||||
style={{
|
||||
width:
|
||||
Math.min(participants.length, max + 1) * (_size - _overlap) +
|
||||
_overlap,
|
||||
Math.min(members.length, max + 1) * (_size - _overlap) + _overlap,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{participants.slice(0, max).map((member, i) => {
|
||||
{members.slice(0, max).map((member, i) => {
|
||||
const avatarUrl = member.getMxcAvatarUrl();
|
||||
return (
|
||||
<Avatar
|
||||
@@ -84,11 +83,11 @@ export function Facepile({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{participants.length > max && (
|
||||
{members.length > max && (
|
||||
<Avatar
|
||||
key="additional"
|
||||
size={size}
|
||||
fallback={`+${participants.length - max}`}
|
||||
fallback={`+${members.length - max}`}
|
||||
className={styles.avatar}
|
||||
style={{ left: max * (_size - _overlap) }}
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ReactNode, useCallback, useEffect } from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import classNames from "classnames";
|
||||
@@ -9,6 +25,7 @@ import { useSubmitRageshake } from "./settings/submit-rageshake";
|
||||
import { ErrorMessage } from "./input/Input";
|
||||
import styles from "./FullScreenView.module.css";
|
||||
import { translatedError, TranslatedError } from "./TranslatedError";
|
||||
import { Config } from "./config/Config";
|
||||
|
||||
interface FullScreenViewProps {
|
||||
className?: string;
|
||||
@@ -98,7 +115,7 @@ export function CrashView() {
|
||||
logsComponent = <div>{t("Thanks! We'll get right on it.")}</div>;
|
||||
} else if (sending) {
|
||||
logsComponent = <div>{t("Sending…")}</div>;
|
||||
} else {
|
||||
} else if (Config.get().rageshake?.submit_url) {
|
||||
logsComponent = (
|
||||
<Button
|
||||
size="lg"
|
||||
@@ -115,8 +132,13 @@ export function CrashView() {
|
||||
<FullScreenView>
|
||||
<Trans>
|
||||
<h1>Oops, something's gone wrong.</h1>
|
||||
<p>Submitting debug logs will help us track down the problem.</p>
|
||||
</Trans>
|
||||
{Config.get().rageshake?.submit_url && (
|
||||
<Trans>
|
||||
<p>Submitting debug logs will help us track down the problem.</p>
|
||||
</Trans>
|
||||
)}
|
||||
|
||||
<div className={styles.sendLogsSection}>{logsComponent}</div>
|
||||
{error && (
|
||||
<ErrorMessage error={translatedError("Couldn't send debug logs!", t)} />
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -131,7 +147,7 @@
|
||||
}
|
||||
|
||||
.leftNav h3 {
|
||||
font-size: 18px;
|
||||
font-size: var(--font-size-subtitle);
|
||||
}
|
||||
|
||||
.nav {
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import classNames from "classnames";
|
||||
import React, { HTMLAttributes, ReactNode, useCallback, useRef } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -88,8 +104,14 @@ interface HeaderLogoProps {
|
||||
}
|
||||
|
||||
export function HeaderLogo({ className }: HeaderLogoProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Link className={classNames(styles.headerLogo, className)} to="/">
|
||||
<Link
|
||||
className={classNames(styles.headerLogo, className)}
|
||||
to="/"
|
||||
aria-label={t("Element Call Home")}
|
||||
>
|
||||
<Logo />
|
||||
</Link>
|
||||
);
|
||||
|
||||
@@ -24,11 +24,13 @@ import { Body } from "./typography/Typography";
|
||||
interface Props {
|
||||
userIds: Set<string>;
|
||||
room: Room;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const IncompatibleVersionModal: React.FC<Props> = ({
|
||||
userIds,
|
||||
room,
|
||||
onClose,
|
||||
...rest
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -38,7 +40,12 @@ export const IncompatibleVersionModal: React.FC<Props> = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal title={t("Incompatible versions")} isDismissable {...rest}>
|
||||
<Modal
|
||||
title={t("Incompatible versions")}
|
||||
isDismissable
|
||||
onClose={onClose}
|
||||
{...rest}
|
||||
>
|
||||
<ModalContent>
|
||||
<Body>
|
||||
<Trans>
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { IndexedDBStoreWorker } from "matrix-js-sdk/src/indexeddb-worker";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.listBox {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -19,7 +35,7 @@
|
||||
padding: 8px 16px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useRef } from "react";
|
||||
import React, { useCallback, useRef } from "react";
|
||||
import { useListBox, useOption, AriaListBoxOptions } from "@react-aria/listbox";
|
||||
import { ListState } from "@react-stately/list";
|
||||
import { Node } from "@react-types/shared";
|
||||
@@ -73,6 +73,22 @@ function Option<T>({ item, state, className }: OptionProps<T>) {
|
||||
ref
|
||||
);
|
||||
|
||||
// Hack: remove the onPointerUp event handler and re-wire it to
|
||||
// onClick. Chrome Android triggers a click event after the onpointerup
|
||||
// event which leaks through to elements underneath the z-indexed select
|
||||
// popover. preventDefault / stopPropagation don't have any effect, even
|
||||
// adding just a dummy onClick handler still doesn't work, but it's fine
|
||||
// if we handle just onClick.
|
||||
// https://github.com/vector-im/element-call/issues/762
|
||||
const origPointerUp = optionProps.onPointerUp;
|
||||
delete optionProps.onPointerUp;
|
||||
optionProps.onClick = useCallback(
|
||||
(e) => {
|
||||
origPointerUp(e as unknown as React.PointerEvent<HTMLElement>);
|
||||
},
|
||||
[origPointerUp]
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
{...optionProps}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.menu {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
@@ -12,7 +28,10 @@
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
color: var(--primary-content);
|
||||
font-size: 14px;
|
||||
font-size: var(--font-size-body);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.menuItem > * {
|
||||
|
||||
16
src/Menu.tsx
16
src/Menu.tsx
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Key, useRef, useState } from "react";
|
||||
import { AriaMenuOptions, useMenu, useMenuItem } from "@react-aria/menu";
|
||||
import { TreeState, useTreeState } from "@react-stately/tree";
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.modalOverlay {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
@@ -29,7 +45,7 @@
|
||||
|
||||
.modalHeader h3 {
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
font-size: var(--font-size-title);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface ModalProps extends OverlayProps, AriaDialogProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
mobileFullScreen?: boolean;
|
||||
onClose?: () => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function Modal({
|
||||
|
||||
418
src/PosthogAnalytics.ts
Normal file
418
src/PosthogAnalytics.ts
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
Copyright 2022 The New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import posthog, { CaptureOptions, PostHog, Properties } from "posthog-js";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { MatrixClient } from "matrix-js-sdk";
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
import { widget } from "./widget";
|
||||
import { getSetting, setSetting, settingsBus } from "./settings/useSetting";
|
||||
import {
|
||||
CallEndedTracker,
|
||||
CallStartedTracker,
|
||||
LoginTracker,
|
||||
SignupTracker,
|
||||
MuteCameraTracker,
|
||||
MuteMicrophoneTracker,
|
||||
} from "./PosthogEvents";
|
||||
import { Config } from "./config/Config";
|
||||
import { getUrlParams } from "./UrlParams";
|
||||
|
||||
/* Posthog analytics tracking.
|
||||
*
|
||||
* Anonymity behaviour is as follows:
|
||||
*
|
||||
* - If Posthog isn't configured in `config.json`, events are not sent.
|
||||
* - If [Do Not Track](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/doNotTrack) is
|
||||
* enabled, events are not sent (this detection is built into posthog and turned on via the
|
||||
* `respect_dnt` flag being passed to `posthog.init`).
|
||||
* - If the posthog analytics are explicitly activated by the user in the element call settings,
|
||||
* a randomised analytics ID is created and stored in account_data for that user (shared between devices)
|
||||
* so that the user can be identified in posthog.
|
||||
*/
|
||||
|
||||
export interface IPosthogEvent {
|
||||
// The event name that will be used by PostHog. Event names should use camelCase.
|
||||
eventName: string;
|
||||
|
||||
// do not allow these to be sent manually, we enqueue them all for caching purposes
|
||||
$set?: void;
|
||||
$set_once?: void;
|
||||
}
|
||||
|
||||
export enum Anonymity {
|
||||
Disabled,
|
||||
Anonymous,
|
||||
Pseudonymous,
|
||||
}
|
||||
|
||||
export enum RegistrationType {
|
||||
Guest,
|
||||
Registered,
|
||||
}
|
||||
|
||||
interface PlatformProperties {
|
||||
appVersion: string;
|
||||
matrixBackend: "embedded" | "jssdk";
|
||||
}
|
||||
|
||||
interface PosthogSettings {
|
||||
project_api_key?: string;
|
||||
api_host?: string;
|
||||
}
|
||||
|
||||
export class PosthogAnalytics {
|
||||
/* Wrapper for Posthog analytics.
|
||||
* 3 modes of anonymity are supported, governed by this.anonymity
|
||||
* - Anonymity.Disabled means *no data* is passed to posthog
|
||||
* - Anonymity.Anonymous means no identifier is passed to posthog
|
||||
* - Anonymity.Pseudonymous means an analytics ID stored in account_data and shared between devices
|
||||
* is passed to posthog.
|
||||
*
|
||||
* To update anonymity, call updateAnonymityFromSettings() or you can set it directly via setAnonymity().
|
||||
*
|
||||
* To pass an event to Posthog:
|
||||
*
|
||||
* 1. Declare a type for the event, extending IPosthogEvent.
|
||||
*/
|
||||
|
||||
private static ANALYTICS_EVENT_TYPE = "im.vector.analytics";
|
||||
|
||||
// set true during the constructor if posthog config is present, otherwise false
|
||||
private static internalInstance = null;
|
||||
|
||||
private identificationPromise: Promise<void>;
|
||||
private readonly enabled: boolean = false;
|
||||
private anonymity = Anonymity.Disabled;
|
||||
private platformSuperProperties = {};
|
||||
private registrationType: RegistrationType = RegistrationType.Guest;
|
||||
|
||||
public static get instance(): PosthogAnalytics {
|
||||
if (!this.internalInstance) {
|
||||
this.internalInstance = new PosthogAnalytics(posthog);
|
||||
}
|
||||
return this.internalInstance;
|
||||
}
|
||||
|
||||
constructor(private readonly posthog: PostHog) {
|
||||
const posthogConfig: PosthogSettings = {
|
||||
project_api_key: Config.get().posthog?.api_key,
|
||||
api_host: Config.get().posthog?.api_host,
|
||||
};
|
||||
|
||||
if (posthogConfig.project_api_key && posthogConfig.api_host) {
|
||||
if (
|
||||
PosthogAnalytics.getPlatformProperties().matrixBackend === "embedded"
|
||||
) {
|
||||
const { analyticsID } = getUrlParams();
|
||||
// if the embedding platform (element web) already got approval to communicating with posthog
|
||||
// element call can also send events to posthog
|
||||
setSetting("opt-in-analytics", Boolean(analyticsID));
|
||||
}
|
||||
|
||||
this.posthog.init(posthogConfig.project_api_key, {
|
||||
api_host: posthogConfig.api_host,
|
||||
autocapture: false,
|
||||
mask_all_text: true,
|
||||
mask_all_element_attributes: true,
|
||||
capture_pageview: false,
|
||||
sanitize_properties: this.sanitizeProperties,
|
||||
respect_dnt: true,
|
||||
advanced_disable_decide: true,
|
||||
});
|
||||
this.enabled = true;
|
||||
} else {
|
||||
this.enabled = false;
|
||||
}
|
||||
this.startListeningToSettingsChanges();
|
||||
const optInAnalytics = getSetting("opt-in-analytics", false);
|
||||
this.updateAnonymityAndIdentifyUser(optInAnalytics);
|
||||
}
|
||||
|
||||
private sanitizeProperties = (
|
||||
properties: Properties,
|
||||
_eventName: string
|
||||
): Properties => {
|
||||
// Callback from posthog to sanitize properties before sending them to the server.
|
||||
// Here we sanitize posthog's built in properties which leak PII e.g. url reporting.
|
||||
// See utils.js _.info.properties in posthog-js.
|
||||
|
||||
if (this.anonymity == Anonymity.Anonymous) {
|
||||
// drop referrer information for anonymous users
|
||||
properties["$referrer"] = null;
|
||||
properties["$referring_domain"] = null;
|
||||
properties["$initial_referrer"] = null;
|
||||
properties["$initial_referring_domain"] = null;
|
||||
|
||||
// drop device ID, which is a UUID persisted in local storage
|
||||
properties["$device_id"] = null;
|
||||
}
|
||||
// the url leaks a lot of private data like the call name or the user.
|
||||
// Its stripped down to the bare minimum to only give insights about the host (develop, main or sfu)
|
||||
properties["$current_url"] = (properties["$current_url"] as string)
|
||||
.split("/")
|
||||
.slice(0, 3)
|
||||
.join("");
|
||||
|
||||
return properties;
|
||||
};
|
||||
|
||||
private registerSuperProperties(properties: Properties) {
|
||||
if (this.enabled) {
|
||||
this.posthog.register(properties);
|
||||
}
|
||||
}
|
||||
|
||||
private static getPlatformProperties(): PlatformProperties {
|
||||
const appVersion = import.meta.env.VITE_APP_VERSION || "dev";
|
||||
return {
|
||||
appVersion,
|
||||
matrixBackend: widget ? "embedded" : "jssdk",
|
||||
};
|
||||
}
|
||||
|
||||
private capture(
|
||||
eventName: string,
|
||||
properties: Properties,
|
||||
options?: CaptureOptions
|
||||
) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.posthog.capture(eventName, { ...properties }, options);
|
||||
}
|
||||
|
||||
public isEnabled(): boolean {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
setAnonymity(anonymity: Anonymity): void {
|
||||
// Update this.anonymity.
|
||||
// To update the anonymity typically you want to call updateAnonymityFromSettings
|
||||
// to ensure this value is in step with the user's settings.
|
||||
if (
|
||||
this.enabled &&
|
||||
(anonymity == Anonymity.Disabled || anonymity == Anonymity.Anonymous)
|
||||
) {
|
||||
// when transitioning to Disabled or Anonymous ensure we clear out any prior state
|
||||
// set in posthog e.g. distinct ID
|
||||
this.posthog.reset();
|
||||
// Restore any previously set platform super properties
|
||||
this.updateSuperProperties();
|
||||
}
|
||||
this.anonymity = anonymity;
|
||||
}
|
||||
|
||||
private static getRandomAnalyticsId(): string {
|
||||
return [...crypto.getRandomValues(new Uint8Array(16))]
|
||||
.map((c) => c.toString(16))
|
||||
.join("");
|
||||
}
|
||||
|
||||
public async identifyUser(analyticsIdGenerator: () => string) {
|
||||
// There might be a better way to get the client here.
|
||||
|
||||
if (this.anonymity == Anonymity.Pseudonymous) {
|
||||
// Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows
|
||||
// different devices to send the same ID.
|
||||
let analyticsID = await this.getAnalyticsId();
|
||||
try {
|
||||
if (!analyticsID && !widget) {
|
||||
// only try setting up a new analytics ID in the standalone app.
|
||||
|
||||
// Couldn't retrieve an analytics ID from user settings, so create one and set it on the server.
|
||||
// Note there's a race condition here - if two devices do these steps at the same time, last write
|
||||
// wins, and the first writer will send tracking with an ID that doesn't match the one on the server
|
||||
// until the next time account data is refreshed and this function is called (most likely on next
|
||||
// page load). This will happen pretty infrequently, so we can tolerate the possibility.
|
||||
const accountDataAnalyticsId = analyticsIdGenerator();
|
||||
await this.setAccountAnalyticsId(accountDataAnalyticsId);
|
||||
analyticsID = await this.hashedEcAnalyticsId(accountDataAnalyticsId);
|
||||
}
|
||||
} catch (e) {
|
||||
// The above could fail due to network requests, but not essential to starting the application,
|
||||
// so swallow it.
|
||||
logger.log("Unable to identify user for tracking" + e.toString());
|
||||
}
|
||||
if (analyticsID) {
|
||||
this.posthog.identify(analyticsID);
|
||||
} else {
|
||||
logger.info(
|
||||
"No analyticsID is availble. Should not try to setup posthog"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getAnalyticsId() {
|
||||
const client: MatrixClient = window.matrixclient;
|
||||
let accountAnalyticsId;
|
||||
if (widget) {
|
||||
accountAnalyticsId = getUrlParams().analyticsID;
|
||||
} else {
|
||||
const accountData = await client.getAccountDataFromServer(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE
|
||||
);
|
||||
accountAnalyticsId = accountData?.id;
|
||||
}
|
||||
if (accountAnalyticsId) {
|
||||
// we dont just use the element web analytics ID because that would allow to associate
|
||||
// users between the two posthog instances. By using a hash from the username and the element web analytics id
|
||||
// it is not possible to conclude the element web posthog user id from the element call user id and vice versa.
|
||||
return await this.hashedEcAnalyticsId(accountAnalyticsId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async hashedEcAnalyticsId(accountAnalyticsId: string): Promise<string> {
|
||||
const client: MatrixClient = window.matrixclient;
|
||||
const posthogIdMaterial = "ec" + accountAnalyticsId + client.getUserId();
|
||||
const bufferForPosthogId = await crypto.subtle.digest(
|
||||
"sha-256",
|
||||
Buffer.from(posthogIdMaterial, "utf-8")
|
||||
);
|
||||
const view = new Int32Array(bufferForPosthogId);
|
||||
return Array.from(view)
|
||||
.map((b) => Math.abs(b).toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
async setAccountAnalyticsId(analyticsID: string) {
|
||||
if (!widget) {
|
||||
const client = window.matrixclient;
|
||||
|
||||
// the analytics ID only needs to be set in the standalone version.
|
||||
const accountData = await client.getAccountDataFromServer(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE
|
||||
);
|
||||
await client.setAccountData(
|
||||
PosthogAnalytics.ANALYTICS_EVENT_TYPE,
|
||||
Object.assign({ id: analyticsID }, accountData)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getAnonymity(): Anonymity {
|
||||
return this.anonymity;
|
||||
}
|
||||
|
||||
public logout(): void {
|
||||
if (this.enabled) {
|
||||
this.posthog.reset();
|
||||
}
|
||||
this.setAnonymity(Anonymity.Disabled);
|
||||
}
|
||||
|
||||
public updateSuperProperties() {
|
||||
// Update super properties in posthog with our platform (app version, platform).
|
||||
// These properties will be subsequently passed in every event.
|
||||
//
|
||||
// This only needs to be done once per page lifetime. Note that getPlatformProperties
|
||||
this.platformSuperProperties = PosthogAnalytics.getPlatformProperties();
|
||||
this.registerSuperProperties({
|
||||
...this.platformSuperProperties,
|
||||
registrationType:
|
||||
this.registrationType == RegistrationType.Guest
|
||||
? "Guest"
|
||||
: "Registered",
|
||||
});
|
||||
}
|
||||
|
||||
private userRegisteredInThisSession(): boolean {
|
||||
// only if the signup end got tracked the end time is set. Otherwise its default value is Date(0).
|
||||
return this.eventSignup.getSignupEndTime() > new Date(0);
|
||||
}
|
||||
|
||||
public async updateAnonymityAndIdentifyUser(
|
||||
pseudonymousOptIn: boolean
|
||||
): Promise<void> {
|
||||
// Update this.anonymity based on the user's analytics opt-in settings
|
||||
const anonymity = pseudonymousOptIn
|
||||
? Anonymity.Pseudonymous
|
||||
: Anonymity.Disabled;
|
||||
this.setAnonymity(anonymity);
|
||||
|
||||
if (anonymity === Anonymity.Pseudonymous) {
|
||||
this.setRegistrationType(
|
||||
window.matrixclient.isGuest() || window.isPasswordlessUser
|
||||
? RegistrationType.Guest
|
||||
: RegistrationType.Registered
|
||||
);
|
||||
// store the promise to await posthog-tracking-events until the identification is done.
|
||||
this.identificationPromise = this.identifyUser(
|
||||
PosthogAnalytics.getRandomAnalyticsId
|
||||
);
|
||||
await this.identificationPromise;
|
||||
if (this.userRegisteredInThisSession()) {
|
||||
this.eventSignup.track();
|
||||
}
|
||||
}
|
||||
|
||||
if (anonymity !== Anonymity.Disabled) {
|
||||
this.updateSuperProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public async trackEvent<E extends IPosthogEvent>(
|
||||
{ eventName, ...properties }: E,
|
||||
options?: CaptureOptions
|
||||
): Promise<void> {
|
||||
if (this.identificationPromise) {
|
||||
// only make calls to posthog after the identificaion is done
|
||||
await this.identificationPromise;
|
||||
}
|
||||
if (
|
||||
this.anonymity == Anonymity.Disabled ||
|
||||
this.anonymity == Anonymity.Anonymous
|
||||
)
|
||||
return;
|
||||
this.capture(eventName, properties, options);
|
||||
}
|
||||
|
||||
public startListeningToSettingsChanges(): void {
|
||||
// Listen to account data changes from sync so we can observe changes to relevant flags and update.
|
||||
// This is called -
|
||||
// * On page load, when the account data is first received by sync
|
||||
// * On login
|
||||
// * When another device changes account data
|
||||
// * When the user changes their preferences on this device
|
||||
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
|
||||
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
|
||||
settingsBus.on("opt-in-analytics", (optInAnalytics) => {
|
||||
this.updateAnonymityAndIdentifyUser(optInAnalytics);
|
||||
});
|
||||
}
|
||||
|
||||
public setRegistrationType(registrationType: RegistrationType): void {
|
||||
this.registrationType = registrationType;
|
||||
if (
|
||||
this.anonymity == Anonymity.Disabled ||
|
||||
this.anonymity == Anonymity.Anonymous
|
||||
)
|
||||
return;
|
||||
this.updateSuperProperties();
|
||||
}
|
||||
|
||||
// ----- Events
|
||||
|
||||
public eventCallEnded = new CallEndedTracker();
|
||||
public eventSignup = new SignupTracker();
|
||||
public eventCallStarted = new CallStartedTracker();
|
||||
public eventLogin = new LoginTracker();
|
||||
public eventMuteMicrophone = new MuteMicrophoneTracker();
|
||||
public eventMuteCamera = new MuteCameraTracker();
|
||||
}
|
||||
151
src/PosthogEvents.ts
Normal file
151
src/PosthogEvents.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Copyright 2022 The New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
IPosthogEvent,
|
||||
PosthogAnalytics,
|
||||
RegistrationType,
|
||||
} from "./PosthogAnalytics";
|
||||
|
||||
interface CallEnded extends IPosthogEvent {
|
||||
eventName: "CallEnded";
|
||||
callId: string;
|
||||
callParticipantsOnLeave: number;
|
||||
callParticipantsMax: number;
|
||||
callDuration: number;
|
||||
}
|
||||
|
||||
export class CallEndedTracker {
|
||||
private cache: { startTime: Date; maxParticipantsCount: number } = {
|
||||
startTime: new Date(0),
|
||||
maxParticipantsCount: 0,
|
||||
};
|
||||
|
||||
cacheStartCall(time: Date) {
|
||||
this.cache.startTime = time;
|
||||
}
|
||||
|
||||
cacheParticipantCountChanged(count: number) {
|
||||
this.cache.maxParticipantsCount = Math.max(
|
||||
count,
|
||||
this.cache.maxParticipantsCount
|
||||
);
|
||||
}
|
||||
|
||||
track(callId: string, callParticipantsNow: number, sendInstantly: boolean) {
|
||||
PosthogAnalytics.instance.trackEvent<CallEnded>(
|
||||
{
|
||||
eventName: "CallEnded",
|
||||
callId: callId,
|
||||
callParticipantsMax: this.cache.maxParticipantsCount,
|
||||
callParticipantsOnLeave: callParticipantsNow,
|
||||
callDuration: (Date.now() - this.cache.startTime.getTime()) / 1000,
|
||||
},
|
||||
{ send_instantly: sendInstantly }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface CallStarted extends IPosthogEvent {
|
||||
eventName: "CallStarted";
|
||||
callId: string;
|
||||
}
|
||||
|
||||
export class CallStartedTracker {
|
||||
track(callId: string) {
|
||||
PosthogAnalytics.instance.trackEvent<CallStarted>({
|
||||
eventName: "CallStarted",
|
||||
callId: callId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface Signup extends IPosthogEvent {
|
||||
eventName: "Signup";
|
||||
signupDuration: number;
|
||||
}
|
||||
|
||||
export class SignupTracker {
|
||||
private cache: { signupStart: Date; signupEnd: Date } = {
|
||||
signupStart: new Date(0),
|
||||
signupEnd: new Date(0),
|
||||
};
|
||||
|
||||
cacheSignupStart(time: Date) {
|
||||
this.cache.signupStart = time;
|
||||
}
|
||||
|
||||
getSignupEndTime() {
|
||||
return this.cache.signupEnd;
|
||||
}
|
||||
|
||||
cacheSignupEnd(time: Date) {
|
||||
this.cache.signupEnd = time;
|
||||
}
|
||||
|
||||
track() {
|
||||
PosthogAnalytics.instance.trackEvent<Signup>({
|
||||
eventName: "Signup",
|
||||
signupDuration: Date.now() - this.cache.signupStart.getTime(),
|
||||
});
|
||||
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Registered);
|
||||
}
|
||||
}
|
||||
|
||||
interface Login extends IPosthogEvent {
|
||||
eventName: "Login";
|
||||
}
|
||||
|
||||
export class LoginTracker {
|
||||
track() {
|
||||
PosthogAnalytics.instance.trackEvent<Login>({
|
||||
eventName: "Login",
|
||||
});
|
||||
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Registered);
|
||||
}
|
||||
}
|
||||
|
||||
interface MuteMicrophone {
|
||||
eventName: "MuteMicrophone";
|
||||
targetMuteState: "mute" | "unmute";
|
||||
callId: string;
|
||||
}
|
||||
|
||||
export class MuteMicrophoneTracker {
|
||||
track(targetIsMute: boolean, callId: string) {
|
||||
PosthogAnalytics.instance.trackEvent<MuteMicrophone>({
|
||||
eventName: "MuteMicrophone",
|
||||
targetMuteState: targetIsMute ? "mute" : "unmute",
|
||||
callId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface MuteCamera {
|
||||
eventName: "MuteCamera";
|
||||
targetMuteState: "mute" | "unmute";
|
||||
callId: string;
|
||||
}
|
||||
|
||||
export class MuteCameraTracker {
|
||||
track(targetIsMute: boolean, callId: string) {
|
||||
PosthogAnalytics.instance.trackEvent<MuteCamera>({
|
||||
eventName: "MuteCamera",
|
||||
targetMuteState: targetIsMute ? "mute" : "unmute",
|
||||
callId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.tooltip {
|
||||
background-color: var(--system);
|
||||
flex-direction: row;
|
||||
@@ -8,7 +24,7 @@
|
||||
border-radius: 8px;
|
||||
max-width: 135px;
|
||||
width: max-content;
|
||||
font-size: 12px;
|
||||
font-size: var(--font-size-caption);
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -21,30 +21,64 @@ export interface UrlParams {
|
||||
roomAlias: string | null;
|
||||
roomId: string | null;
|
||||
viaServers: string[];
|
||||
// Whether the app is running in embedded mode, and should keep the user
|
||||
// confined to the current room
|
||||
/**
|
||||
* Whether the app is running in embedded mode, and should keep the user
|
||||
* confined to the current room.
|
||||
*/
|
||||
isEmbedded: boolean;
|
||||
// Whether the app should pause before joining the call until it sees an
|
||||
// io.element.join widget action, allowing it to be preloaded
|
||||
/**
|
||||
* Whether the app should pause before joining the call until it sees an
|
||||
* io.element.join widget action, allowing it to be preloaded.
|
||||
*/
|
||||
preload: boolean;
|
||||
// Whether to hide the room header when in a call
|
||||
/**
|
||||
* Whether to hide the room header when in a call.
|
||||
*/
|
||||
hideHeader: boolean;
|
||||
// Whether to hide the screen-sharing button
|
||||
/**
|
||||
* Whether to hide the screen-sharing button.
|
||||
*/
|
||||
hideScreensharing: boolean;
|
||||
// Whether to start a walkie-talkie call instead of a video call
|
||||
/**
|
||||
* Whether to start a walkie-talkie call instead of a video call.
|
||||
*/
|
||||
isPtt: boolean;
|
||||
// Whether to use end-to-end encryption
|
||||
/**
|
||||
* Whether to use end-to-end encryption.
|
||||
*/
|
||||
e2eEnabled: boolean;
|
||||
// The user's ID (only used in matryoshka mode)
|
||||
/**
|
||||
* The user's ID (only used in matryoshka mode).
|
||||
*/
|
||||
userId: string | null;
|
||||
// The display name to use for auto-registration
|
||||
/**
|
||||
* The display name to use for auto-registration.
|
||||
*/
|
||||
displayName: string | null;
|
||||
// The device's ID (only used in matryoshka mode)
|
||||
/**
|
||||
* The device's ID (only used in matryoshka mode).
|
||||
*/
|
||||
deviceId: string | null;
|
||||
// The base URL of the homeserver to use for media lookups in matryoshka mode
|
||||
/**
|
||||
* The base URL of the homeserver to use for media lookups in matryoshka mode.
|
||||
*/
|
||||
baseUrl: string | null;
|
||||
// The BCP 47 code of the language the app should use
|
||||
/**
|
||||
* The BCP 47 code of the language the app should use.
|
||||
*/
|
||||
lang: string | null;
|
||||
/**
|
||||
* The fonts which the interface should use, if not empty.
|
||||
*/
|
||||
fonts: string[];
|
||||
/**
|
||||
* The factor by which to scale the interface's font size.
|
||||
*/
|
||||
fontScale: number | null;
|
||||
/**
|
||||
* The Posthog analytics ID. It is only available if the user has given consent for sharing telemetry in element web.
|
||||
*/
|
||||
analyticsID: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,6 +115,8 @@ export const getUrlParams = (
|
||||
? fragment
|
||||
: fragment.substring(0, fragmentQueryStart);
|
||||
|
||||
const fontScale = parseFloat(getParam("fontScale") ?? "");
|
||||
|
||||
return {
|
||||
roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null,
|
||||
roomId: getParam("roomId"),
|
||||
@@ -96,6 +132,9 @@ export const getUrlParams = (
|
||||
deviceId: getParam("deviceId"),
|
||||
baseUrl: getParam("baseUrl"),
|
||||
lang: getParam("lang"),
|
||||
fonts: getAllParams("font"),
|
||||
fontScale: Number.isNaN(fontScale) ? null : fontScale,
|
||||
analyticsID: getParam("analyticsID"),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.menuIcon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
@@ -10,13 +26,13 @@
|
||||
.avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 12px;
|
||||
font-size: var(--font-size-caption);
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { Item } from "@react-stately/collections";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useCallback } from "react";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.logo {
|
||||
max-width: 300px;
|
||||
margin: 80px 0;
|
||||
@@ -36,7 +52,7 @@
|
||||
|
||||
.formContainer h4 {
|
||||
font-weight: normal;
|
||||
font-size: 18px;
|
||||
font-size: var(--font-size-subtitle);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -48,7 +64,7 @@
|
||||
.formContainer button {
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -61,7 +77,7 @@
|
||||
|
||||
.authLinks {
|
||||
margin-bottom: 100px;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
.authLinks a {
|
||||
|
||||
@@ -14,14 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
FC,
|
||||
FormEvent,
|
||||
useCallback,
|
||||
useRef,
|
||||
useState,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import React, { FC, FormEvent, useCallback, useRef, useState } from "react";
|
||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
|
||||
@@ -29,10 +22,11 @@ import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
|
||||
import { useClient } from "../ClientContext";
|
||||
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
|
||||
import { Button } from "../button";
|
||||
import { defaultHomeserver, defaultHomeserverHost } from "../matrix-utils";
|
||||
import styles from "./LoginPage.module.css";
|
||||
import { useInteractiveLogin } from "./useInteractiveLogin";
|
||||
import { usePageTitle } from "../usePageTitle";
|
||||
import { PosthogAnalytics } from "../PosthogAnalytics";
|
||||
import { Config } from "../config/Config";
|
||||
|
||||
export const LoginPage: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -40,7 +34,7 @@ export const LoginPage: FC = () => {
|
||||
|
||||
const { setClient } = useClient();
|
||||
const login = useInteractiveLogin();
|
||||
const homeserver = defaultHomeserver; // TODO: Make this configurable
|
||||
const homeserver = Config.defaultHomeserverUrl(); // TODO: Make this configurable
|
||||
const usernameRef = useRef<HTMLInputElement>();
|
||||
const passwordRef = useRef<HTMLInputElement>();
|
||||
const history = useHistory();
|
||||
@@ -64,6 +58,7 @@ export const LoginPage: FC = () => {
|
||||
} else {
|
||||
history.push("/");
|
||||
}
|
||||
PosthogAnalytics.instance.eventLogin.track();
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error);
|
||||
@@ -73,14 +68,6 @@ export const LoginPage: FC = () => {
|
||||
[login, location, history, homeserver, setClient]
|
||||
);
|
||||
|
||||
const homeserverHost = useMemo(() => {
|
||||
try {
|
||||
return new URL(homeserver).host;
|
||||
} catch (error) {
|
||||
return defaultHomeserverHost;
|
||||
}
|
||||
}, [homeserver]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.container}>
|
||||
@@ -100,7 +87,7 @@ export const LoginPage: FC = () => {
|
||||
autoCorrect="off"
|
||||
autoCapitalize="none"
|
||||
prefix="@"
|
||||
suffix={`:${homeserverHost}`}
|
||||
suffix={`:${Config.defaultServerName()}`}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
|
||||
@@ -31,7 +31,6 @@ import { Trans, useTranslation } from "react-i18next";
|
||||
import { FieldRow, InputField, ErrorMessage } from "../input/Input";
|
||||
import { Button } from "../button";
|
||||
import { useClient } from "../ClientContext";
|
||||
import { defaultHomeserverHost } from "../matrix-utils";
|
||||
import { useInteractiveRegistration } from "./useInteractiveRegistration";
|
||||
import styles from "./LoginPage.module.css";
|
||||
import { ReactComponent as Logo } from "../icons/LogoLarge.svg";
|
||||
@@ -39,6 +38,8 @@ import { LoadingView } from "../FullScreenView";
|
||||
import { useRecaptcha } from "./useRecaptcha";
|
||||
import { Caption, Link } from "../typography/Typography";
|
||||
import { usePageTitle } from "../usePageTitle";
|
||||
import { PosthogAnalytics } from "../PosthogAnalytics";
|
||||
import { Config } from "../config/Config";
|
||||
|
||||
export const RegisterPage: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -98,6 +99,7 @@ export const RegisterPage: FC = () => {
|
||||
}
|
||||
|
||||
setClient(newClient, session);
|
||||
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
|
||||
};
|
||||
|
||||
submit()
|
||||
@@ -142,6 +144,8 @@ export const RegisterPage: FC = () => {
|
||||
|
||||
if (loading) {
|
||||
return <LoadingView />;
|
||||
} else {
|
||||
PosthogAnalytics.instance.eventSignup.cacheSignupStart(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -161,7 +165,7 @@ export const RegisterPage: FC = () => {
|
||||
autoCorrect="off"
|
||||
autoCapitalize="none"
|
||||
prefix="@"
|
||||
suffix={`:${defaultHomeserverHost}`}
|
||||
suffix={`:${Config.defaultServerName()}`}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldRow>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,7 +18,7 @@ import { useCallback } from "react";
|
||||
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
|
||||
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { initClient, defaultHomeserver } from "../matrix-utils";
|
||||
import { initClient } from "../matrix-utils";
|
||||
import { Session } from "../ClientContext";
|
||||
|
||||
export const useInteractiveLogin = () =>
|
||||
@@ -59,7 +59,7 @@ export const useInteractiveLogin = () =>
|
||||
|
||||
const client = await initClient(
|
||||
{
|
||||
baseUrl: defaultHomeserver,
|
||||
baseUrl: homeserver,
|
||||
accessToken: access_token,
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,9 @@ import { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth";
|
||||
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { initClient, defaultHomeserver } from "../matrix-utils";
|
||||
import { initClient } from "../matrix-utils";
|
||||
import { Session } from "../ClientContext";
|
||||
import { Config } from "../config/Config";
|
||||
|
||||
export const useInteractiveRegistration = (): [
|
||||
string,
|
||||
@@ -37,7 +38,9 @@ export const useInteractiveRegistration = (): [
|
||||
|
||||
const authClient = useRef<MatrixClient>();
|
||||
if (!authClient.current) {
|
||||
authClient.current = createClient({ baseUrl: defaultHomeserver });
|
||||
authClient.current = createClient({
|
||||
baseUrl: Config.defaultHomeserverUrl(),
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -92,7 +95,7 @@ export const useInteractiveRegistration = (): [
|
||||
|
||||
const client = await initClient(
|
||||
{
|
||||
baseUrl: defaultHomeserver,
|
||||
baseUrl: Config.defaultHomeserverUrl(),
|
||||
accessToken: access_token,
|
||||
userId: user_id,
|
||||
deviceId: device_id,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -41,7 +41,7 @@ limitations under the License.
|
||||
.copyButton {
|
||||
padding: 7px 15px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-size: var(--font-size-body);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ limitations under the License.
|
||||
|
||||
.copyButton span {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -48,6 +48,7 @@ export function CopyButton({
|
||||
className={className}
|
||||
onPress={setCopied}
|
||||
iconStyle={isCopied ? "stroke" : "fill"}
|
||||
aria-label={t("Copy")}
|
||||
>
|
||||
{isCopied ? (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
77
src/config/Config.ts
Normal file
77
src/config/Config.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2021-2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEFAULT_CONFIG,
|
||||
ConfigOptions,
|
||||
ResolvedConfigOptions,
|
||||
} from "./ConfigOptions";
|
||||
|
||||
export class Config {
|
||||
private static internalInstance: Config;
|
||||
|
||||
public static get(): ConfigOptions {
|
||||
if (!this.internalInstance?.config)
|
||||
throw new Error("Config instance read before config got initialized");
|
||||
return this.internalInstance.config;
|
||||
}
|
||||
|
||||
public static init(): Promise<void> {
|
||||
if (Config.internalInstance?.initPromise) {
|
||||
return Config.internalInstance.initPromise;
|
||||
}
|
||||
Config.internalInstance = new Config();
|
||||
Config.internalInstance.initPromise = new Promise<void>((resolve) => {
|
||||
downloadConfig("../config.json").then((config) => {
|
||||
Config.internalInstance.config = { ...DEFAULT_CONFIG, ...config };
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
return Config.internalInstance.initPromise;
|
||||
}
|
||||
|
||||
// Convenience accessors
|
||||
public static defaultHomeserverUrl(): string | undefined {
|
||||
return Config.get().default_server_config["m.homeserver"].base_url;
|
||||
}
|
||||
|
||||
public static defaultServerName(): string | undefined {
|
||||
return Config.get().default_server_config["m.homeserver"].server_name;
|
||||
}
|
||||
|
||||
public config?: ResolvedConfigOptions;
|
||||
private initPromise?: Promise<void>;
|
||||
}
|
||||
|
||||
async function downloadConfig(
|
||||
configJsonFilename: string
|
||||
): Promise<ConfigOptions> {
|
||||
const url = new URL(configJsonFilename, window.location.href);
|
||||
url.searchParams.set("cachebuster", Date.now().toString());
|
||||
const res = await fetch(url, {
|
||||
cache: "no-cache",
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (!res.ok || res.status === 404 || res.status === 0) {
|
||||
// Lack of a config isn't an error, we should just use the defaults.
|
||||
// Also treat a blank config as no config, assuming the status code is 0, because we don't get 404s from file:
|
||||
// URIs so this is the only way we can not fail if the file doesn't exist when loading from a file:// URI.
|
||||
return DEFAULT_CONFIG;
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
67
src/config/ConfigOptions.ts
Normal file
67
src/config/ConfigOptions.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export interface ConfigOptions {
|
||||
/**
|
||||
* The Posthog endpoint to which analytics data will be sent.
|
||||
*/
|
||||
posthog?: {
|
||||
api_key: string;
|
||||
api_host: string;
|
||||
};
|
||||
/**
|
||||
* The Sentry endpoint to which crash data will be sent.
|
||||
*/
|
||||
sentry?: {
|
||||
DSN: string;
|
||||
environment: string;
|
||||
};
|
||||
/**
|
||||
* The rageshake server to which feedback and debug logs will be sent.
|
||||
*/
|
||||
rageshake?: {
|
||||
submit_url: string;
|
||||
};
|
||||
|
||||
// Describes the default homeserver to use. The same format as Element Web
|
||||
// (without identity servers as we don't use them).
|
||||
default_server_config?: {
|
||||
["m.homeserver"]: {
|
||||
base_url: string;
|
||||
server_name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Overrides members from ConfigOptions that are always provided by the
|
||||
// default config and are therefore non-optional.
|
||||
export interface ResolvedConfigOptions extends ConfigOptions {
|
||||
default_server_config: {
|
||||
["m.homeserver"]: {
|
||||
base_url: string;
|
||||
server_name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG: ResolvedConfigOptions = {
|
||||
default_server_config: {
|
||||
["m.homeserver"]: {
|
||||
base_url: "http://localhost:8008",
|
||||
server_name: "localhost",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.callTileSpacer,
|
||||
.callTile {
|
||||
width: 329px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -92,7 +92,7 @@ function CallTile({
|
||||
<Facepile
|
||||
className={styles.facePile}
|
||||
client={client}
|
||||
participants={participants}
|
||||
members={participants}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.buttons {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,7 @@ import styles from "./JoinExistingCallModal.module.css";
|
||||
|
||||
interface Props {
|
||||
onJoin: (e: PressEvent) => void;
|
||||
onClose: (e: PressEvent) => void;
|
||||
onClose: () => void;
|
||||
// TODO: add used parameters for <Modal>
|
||||
[index: string]: unknown;
|
||||
}
|
||||
@@ -33,7 +33,12 @@ export function JoinExistingCallModal({ onJoin, onClose, ...rest }: Props) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Modal title={t("Join existing call?")} isDismissable {...rest}>
|
||||
<Modal
|
||||
title={t("Join existing call?")}
|
||||
isDismissable
|
||||
{...rest}
|
||||
onClose={onClose}
|
||||
>
|
||||
<ModalContent>
|
||||
<p>{t("This call already exists, would you like to join?")}</p>
|
||||
<FieldRow rightAlign className={styles.buttons}>
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.form {
|
||||
padding: 0 24px;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: calc(100% - 64px);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 Matrix.org Foundation C.I.C.
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.007 6.46375C8.60094 6.4097 5.70947 6.77458 5.00651 6.95945C4.96493 6.97038 4.91704 6.98261 4.86347 6.99628C3.78418 7.27174 0.402266 8.13487 0.0368686 10.8697C-0.246222 12.9885 1.17146 13.6298 1.88015 13.5322C2.37066 13.4707 3.77508 13.2486 5.0727 13.0158C6.34691 12.7872 6.34626 11.9466 6.34582 11.3782C6.34581 11.3677 6.34581 11.3574 6.34581 11.3471L6.34581 10.2044C6.34581 9.91339 6.61929 9.74516 6.9965 9.69969C8.33185 9.51831 9.44662 9.5178 10.0046 9.51779L10.0093 9.51779C10.5672 9.51779 11.6682 9.51832 13.0035 9.6997C13.3807 9.74517 13.6542 9.9134 13.6542 10.2044L13.6542 11.3471C13.6542 11.3574 13.6542 11.3677 13.6542 11.3782C13.6537 11.9466 13.6531 12.7872 14.9273 13.0158C16.2249 13.2486 17.6293 13.4707 18.1198 13.5322C18.8285 13.6298 20.2462 12.9885 19.9631 10.8697C19.5977 8.13487 16.2158 7.27174 15.1365 6.99629C15.083 6.98262 15.0351 6.97039 14.9935 6.95946C14.2905 6.77459 11.413 6.4097 10.007 6.46375Z" fill="white"/>
|
||||
<path d="M6.68883 13.3012C7.63969 14.3278 9.92871 16.1054 10.5526 16.4702C10.5895 16.4917 10.6317 16.5168 10.679 16.5449C11.631 17.1109 14.6141 18.8842 16.7875 17.2246C18.4714 15.9389 17.9239 14.4926 17.3571 14.0626C16.9691 13.7608 15.8258 12.9288 14.7502 12.1795C13.694 11.4436 13.1053 12.0332 12.7073 12.4318C12.7 12.4391 12.6927 12.4464 12.6856 12.4536L11.8848 13.2544C11.6808 13.4583 11.3706 13.3839 11.0735 13.1505C10.0074 12.3385 9.22308 11.555 8.8307 11.1626L8.82739 11.1593C8.43506 10.767 7.66123 9.99241 6.84932 8.92627C6.61592 8.62914 6.54149 8.31893 6.74542 8.11501L7.54622 7.31421C7.55341 7.30702 7.56067 7.29977 7.568 7.29245C7.96663 6.89444 8.55618 6.30581 7.82033 5.24958C7.07097 4.17394 6.239 3.03068 5.93717 2.64265C5.50723 2.07588 4.06088 1.52836 2.77514 3.21225C1.11556 5.38572 2.88891 8.36878 3.45484 9.32078C3.48293 9.36803 3.50805 9.41028 3.52962 9.44717C3.8944 10.0711 5.66224 12.3503 6.68883 13.3012Z" fill="white"/>
|
||||
<path d="M17.2473 2.56504C17.4497 2.3595 17.4497 2.02626 17.2473 1.82072C17.0448 1.61518 16.7166 1.61518 16.5142 1.82072L14.1663 4.20452L11.8185 1.82072C11.6161 1.61518 11.2878 1.61518 11.0854 1.82072C10.883 2.02626 10.883 2.3595 11.0854 2.56504L13.4332 4.94884L10.9848 7.43475C10.7824 7.64029 10.7824 7.97354 10.9848 8.17908C11.1873 8.38462 11.5155 8.38462 11.7179 8.17908L14.1663 5.69316L16.6148 8.17907C16.8172 8.38461 17.1454 8.38461 17.3478 8.17907C17.5503 7.97354 17.5503 7.64029 17.3478 7.43475L14.8994 4.94884L17.2473 2.56504Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -23,8 +23,20 @@ limitations under the License.
|
||||
@import "normalize.css/normalize.css";
|
||||
|
||||
:root {
|
||||
--font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
"Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
|
||||
"Helvetica Neue", sans-serif;
|
||||
--inter-unicode-range: U+0000-20e2, U+20e4-23ce, U+23d0-24c1, U+24c3-259f,
|
||||
U+25c2-2664, U+2666-2763, U+2765-2b05, U+2b07-2b1b, U+2b1d-10FFFF;
|
||||
|
||||
--font-scale: 1;
|
||||
--font-size-micro: calc(10px * var(--font-scale));
|
||||
--font-size-caption: calc(12px * var(--font-scale));
|
||||
--font-size-body: calc(15px * var(--font-scale));
|
||||
--font-size-subtitle: calc(18px * var(--font-scale));
|
||||
--font-size-title: calc(24px * var(--font-scale));
|
||||
--font-size-headline: calc(32px * var(--font-scale));
|
||||
|
||||
--accent: #0dbd8b;
|
||||
--accent-20: #0dbd8b33;
|
||||
--alert: #ff5b55;
|
||||
@@ -127,9 +139,7 @@ body {
|
||||
color: var(--primary-content);
|
||||
color-scheme: dark;
|
||||
margin: 0;
|
||||
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
font-family: var(--font-family);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -159,28 +169,31 @@ a {
|
||||
/* Headline Semi Bold */
|
||||
h1 {
|
||||
font-weight: 600;
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
font-size: var(--font-size-headline);
|
||||
}
|
||||
|
||||
/* Title */
|
||||
h2 {
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
line-height: 29px;
|
||||
font-size: var(--font-size-title);
|
||||
}
|
||||
|
||||
/* Subtitle */
|
||||
h3 {
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
font-size: var(--font-size-subtitle);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
p {
|
||||
font-size: 15px;
|
||||
line-height: 24px;
|
||||
font-size: var(--font-size-body);
|
||||
line-height: var(--font-size-title);
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -202,21 +215,21 @@ hr {
|
||||
text-align: center;
|
||||
height: 5px;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
font-size: var(--font-size-body);
|
||||
line-height: 24px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
summary {
|
||||
font-size: 14px;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
details > :not(summary) {
|
||||
margin-left: 16px;
|
||||
margin-left: var(--font-size-body);
|
||||
}
|
||||
|
||||
details[open] > summary {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: var(--font-size-body);
|
||||
}
|
||||
|
||||
#root > [data-overlay-container] {
|
||||
|
||||
218
src/initializer.tsx
Normal file
218
src/initializer.tsx
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import Backend from "i18next-http-backend";
|
||||
import * as Sentry from "@sentry/react";
|
||||
|
||||
import { getUrlParams } from "./UrlParams";
|
||||
import { Config } from "./config/Config";
|
||||
|
||||
enum LoadState {
|
||||
None,
|
||||
Loading,
|
||||
Loaded,
|
||||
}
|
||||
|
||||
class DependencyLoadStates {
|
||||
// TODO: decide where olm should be initialized (see TODO comment below)
|
||||
// olm: LoadState = LoadState.None;
|
||||
config: LoadState = LoadState.None;
|
||||
sentry: LoadState = LoadState.None;
|
||||
|
||||
allDepsAreLoaded() {
|
||||
return !Object.values(this).some((s) => s !== LoadState.Loaded);
|
||||
}
|
||||
}
|
||||
|
||||
export class Initializer {
|
||||
private static internalInstance: Initializer;
|
||||
public static initBeforeReact() {
|
||||
// this maybe also needs to return a promise in the future,
|
||||
// if we have to do async inits before showing the loading screen
|
||||
// but this should be avioded if possible
|
||||
|
||||
//i18n
|
||||
const languageDetector = new LanguageDetector();
|
||||
languageDetector.addDetector({
|
||||
name: "urlFragment",
|
||||
// Look for a language code in the URL's fragment
|
||||
lookup: () => getUrlParams().lang ?? undefined,
|
||||
});
|
||||
|
||||
i18n
|
||||
.use(Backend)
|
||||
.use(languageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: "en-GB",
|
||||
defaultNS: "app",
|
||||
keySeparator: false,
|
||||
nsSeparator: false,
|
||||
pluralSeparator: "|",
|
||||
contextSeparator: "|",
|
||||
interpolation: {
|
||||
escapeValue: false, // React has built-in XSS protections
|
||||
},
|
||||
detection: {
|
||||
// No localStorage detectors or caching here, since we don't have any way
|
||||
// of letting the user manually select a language
|
||||
order: ["urlFragment", "navigator"],
|
||||
caches: [],
|
||||
},
|
||||
});
|
||||
|
||||
// Custom Themeing
|
||||
if (import.meta.env.VITE_CUSTOM_THEME) {
|
||||
const style = document.documentElement.style;
|
||||
style.setProperty(
|
||||
"--accent",
|
||||
import.meta.env.VITE_THEME_ACCENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--accent-20",
|
||||
import.meta.env.VITE_THEME_ACCENT_20 as string
|
||||
);
|
||||
style.setProperty("--alert", import.meta.env.VITE_THEME_ALERT as string);
|
||||
style.setProperty(
|
||||
"--alert-20",
|
||||
import.meta.env.VITE_THEME_ALERT_20 as string
|
||||
);
|
||||
style.setProperty("--links", import.meta.env.VITE_THEME_LINKS as string);
|
||||
style.setProperty(
|
||||
"--primary-content",
|
||||
import.meta.env.VITE_THEME_PRIMARY_CONTENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--secondary-content",
|
||||
import.meta.env.VITE_THEME_SECONDARY_CONTENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--tertiary-content",
|
||||
import.meta.env.VITE_THEME_TERTIARY_CONTENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--tertiary-content-20",
|
||||
import.meta.env.VITE_THEME_TERTIARY_CONTENT_20 as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--quaternary-content",
|
||||
import.meta.env.VITE_THEME_QUATERNARY_CONTENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--quinary-content",
|
||||
import.meta.env.VITE_THEME_QUINARY_CONTENT as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--system",
|
||||
import.meta.env.VITE_THEME_SYSTEM as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--background",
|
||||
import.meta.env.VITE_THEME_BACKGROUND as string
|
||||
);
|
||||
style.setProperty(
|
||||
"--background-85",
|
||||
import.meta.env.VITE_THEME_BACKGROUND_85 as string
|
||||
);
|
||||
}
|
||||
|
||||
// Custom fonts
|
||||
const { fonts, fontScale } = getUrlParams();
|
||||
if (fontScale !== null) {
|
||||
document.documentElement.style.setProperty(
|
||||
"--font-scale",
|
||||
fontScale.toString()
|
||||
);
|
||||
}
|
||||
if (fonts.length > 0) {
|
||||
document.documentElement.style.setProperty(
|
||||
"--font-family",
|
||||
fonts.map((f) => `"${f}"`).join(", ")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static init(): Promise<void> | null {
|
||||
if (Initializer?.internalInstance?.initPromise) {
|
||||
return null;
|
||||
}
|
||||
Initializer.internalInstance = new Initializer();
|
||||
Initializer.internalInstance.initPromise = new Promise<void>((resolve) => {
|
||||
// initStep calls itself recursivly until everything is initialized in the correct order.
|
||||
// Then the promise gets resolved.
|
||||
Initializer.internalInstance.initStep(resolve);
|
||||
});
|
||||
return Initializer.internalInstance.initPromise;
|
||||
}
|
||||
|
||||
loadStates = new DependencyLoadStates();
|
||||
|
||||
initStep(resolve: (value: void | PromiseLike<void>) => void) {
|
||||
// TODO: Olm is initialized with the client currently (see `initClient()` and `olm.ts`)
|
||||
// we need to decide if we want to init it here or keep it in initClient
|
||||
// if (this.loadStates.olm === LoadState.None) {
|
||||
// this.loadStates.olm = LoadState.Loading;
|
||||
// // TODO: https://gitlab.matrix.org/matrix-org/olm/-/issues/10
|
||||
// window.OLM_OPTIONS = {};
|
||||
// Olm.init({ locateFile: () => olmWasmPath }).then(() => {
|
||||
// this.loadStates.olm = LoadState.Loaded;
|
||||
// this.initStep(resolve);
|
||||
// });
|
||||
// }
|
||||
|
||||
// config
|
||||
if (this.loadStates.config === LoadState.None) {
|
||||
this.loadStates.config = LoadState.Loading;
|
||||
Config.init().then(() => {
|
||||
this.loadStates.config = LoadState.Loaded;
|
||||
this.initStep(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
//sentry (only initialize after the config is ready)
|
||||
if (
|
||||
this.loadStates.sentry === LoadState.None &&
|
||||
this.loadStates.config === LoadState.Loaded
|
||||
) {
|
||||
if (Config.get().sentry?.DSN && Config.get().sentry?.environment) {
|
||||
Sentry.init({
|
||||
dsn: Config.get().sentry?.DSN,
|
||||
environment: Config.get().sentry?.environment,
|
||||
integrations: [
|
||||
new Integrations.BrowserTracing({
|
||||
routingInstrumentation:
|
||||
Sentry.reactRouterV5Instrumentation(history),
|
||||
}),
|
||||
],
|
||||
tracesSampleRate: 1.0,
|
||||
});
|
||||
}
|
||||
// Sentry is now 'loadeed' (even if we actually skipped starting
|
||||
// it due to to not being configured)
|
||||
this.loadStates.sentry = LoadState.Loaded;
|
||||
}
|
||||
|
||||
if (this.loadStates.allDepsAreLoaded()) {
|
||||
// resolve if there is no dependency that is not loaded
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
private initPromise: Promise<void>;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user