diff --git a/.eslintrc.js b/.eslintrc.js index 272b8b31f5..8124c143c8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,82 +1,102 @@ module.exports = { plugins: ["matrix-org"], - extends: [ - "plugin:matrix-org/babel", - "plugin:matrix-org/react", - ], + extends: ["plugin:matrix-org/babel", "plugin:matrix-org/react"], env: { browser: true, node: true, }, rules: { // Things we do that break the ideal style - "quotes": "off", + quotes: "off", }, settings: { react: { - version: 'detect', + version: "detect", }, }, - overrides: [{ - files: [ - "src/**/*.{ts,tsx}", - "test/**/*.{ts,tsx}", - "module_system/**/*.{ts,tsx}", - // :TCHAP: Lint our cypress files, copied from react-sdk. React-sdk lints them too, so we keep up ! - "cypress/**/*.ts", - "test/**/*.{ts,tsx,js}", - ], - extends: [ - "plugin:matrix-org/typescript", - "plugin:matrix-org/react", - ], - // NOTE: These rules are frozen and new rules should not be added here. - // New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/ - rules: { - // Things we do that break the ideal style - "prefer-promise-reject-errors": "off", - "quotes": "off", - - // We disable this while we're transitioning - "@typescript-eslint/no-explicit-any": "off", - // We're okay with assertion errors when we ask for them - "@typescript-eslint/no-non-null-assertion": "off", + overrides: [ + { + files: [ + "src/**/*.{ts,tsx}", + "test/**/*.{ts,tsx}", + "module_system/**/*.{ts,tsx}", + // :TCHAP: Lint our cypress files, copied from react-sdk. React-sdk lints them too, so we keep up ! + "cypress/**/*.ts", + "test/**/*.{ts,tsx,js}", + ], + extends: [ + "plugin:matrix-org/typescript", + "plugin:matrix-org/react", + ], + // NOTE: These rules are frozen and new rules should not be added here. + // New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/ + rules: { + // Things we do that break the ideal style + "prefer-promise-reject-errors": "off", + "quotes": "off", - // TCHAP: for cypress only - "@typescript-eslint/no-empty-interface": "off", + // We disable this while we're transitioning + "@typescript-eslint/no-explicit-any": "off", + // We're okay with assertion errors when we ask for them + "@typescript-eslint/no-non-null-assertion": "off", - // Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell. - "no-restricted-imports": ["error", { - "paths": [{ - "name": "matrix-js-sdk", - "message": "Please use matrix-js-sdk/src/matrix instead", - }, { - "name": "matrix-js-sdk/", - "message": "Please use matrix-js-sdk/src/matrix instead", - }, { - "name": "matrix-js-sdk/src", - "message": "Please use matrix-js-sdk/src/matrix instead", - }, { - "name": "matrix-js-sdk/src/", - "message": "Please use matrix-js-sdk/src/matrix instead", - }, { - "name": "matrix-js-sdk/src/index", - "message": "Please use matrix-js-sdk/src/matrix instead", - }, { - "name": "matrix-react-sdk", - "message": "Please use matrix-react-sdk/src/index instead", - }, { - "name": "matrix-react-sdk/", - "message": "Please use matrix-react-sdk/src/index instead", - }], - "patterns": [{ - "group": ["matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**"], - "message": "Please use matrix-js-sdk/src/* instead", - }, { - "group": ["matrix-react-sdk/lib", "matrix-react-sdk/lib/", "matrix-react-sdk/lib/**"], - "message": "Please use matrix-react-sdk/src/* instead", + // TCHAP: for cypress only + "@typescript-eslint/no-empty-interface": "off", + // Ban matrix-js-sdk/src imports in favour of matrix-js-sdk/src/matrix imports to prevent unleashing hell. + "no-restricted-imports": ["error", { + "paths": [{ + "name": "matrix-js-sdk", + "message": "Please use matrix-js-sdk/src/matrix instead", + }, { + "name": "matrix-js-sdk/", + "message": "Please use matrix-js-sdk/src/matrix instead", + }, { + "name": "matrix-js-sdk/src", + "message": "Please use matrix-js-sdk/src/matrix instead", + }, { + "name": "matrix-js-sdk/src/", + "message": "Please use matrix-js-sdk/src/matrix instead", + }, { + "name": "matrix-js-sdk/src/index", + "message": "Please use matrix-js-sdk/src/matrix instead", + }, { + "name": "matrix-react-sdk", + "message": "Please use matrix-react-sdk/src/index instead", + }, { + "name": "matrix-react-sdk/", + "message": "Please use matrix-react-sdk/src/index instead", + }], + "patterns": [{ + "group": ["matrix-js-sdk/lib", "matrix-js-sdk/lib/", "matrix-js-sdk/lib/**"], + "message": "Please use matrix-js-sdk/src/* instead", + }, { + "group": ["matrix-react-sdk/lib", "matrix-react-sdk/lib/", "matrix-react-sdk/lib/**"], + "message": "Please use matrix-react-sdk/src/* instead", + }], }], - }], + }, }, - }], + { + files: ["test/**/*.{ts,tsx}"], + rules: { + // We don't need super strict typing in test utilities + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-member-accessibility": "off", + }, + }, + { + files: [ + "src/**/*Tchap*.{ts,tsx}", + "src/**/*ContentScan*.{ts,tsx}", + "src/lib/ExpiredAccountHandler.ts", + "src/lib/IncomingKeyRequestHandler.ts", + "src/components/views/dialogs/ExpiredAccountDialog.tsx", + ], + rules: { + // Tchap files are not up to date yet in proper typescript style. Use warnings instead of errors to unbreak the CI. + "@typescript-eslint/explicit-function-return-type": "warn", + "@typescript-eslint/explicit-member-accessibility": "warn", + }, + }, + ], }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 558f9e0059..6d7619dfd8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,4 @@ -* @vector-im/element-web +* @vector-im/element-web +/.github/workflows/** @vector-im/element-web-app-team +/package.json @vector-im/element-web-app-team +/yarn.lock @vector-im/element-web-app-team diff --git a/.github/ISSUE_TEMPLATE/bug-web.yml b/.github/ISSUE_TEMPLATE/bug-web.yml index 342315369f..744c119b6f 100644 --- a/.github/ISSUE_TEMPLATE/bug-web.yml +++ b/.github/ISSUE_TEMPLATE/bug-web.yml @@ -2,31 +2,31 @@ name: Bug report for Tchap Web (in browser) description: File a bug report if you are using Element in a web browser like Firefox, Chrome, Edge, and so on. labels: [web, v4, bug] body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! - Please report security issues by email to security@matrix.org - - type: textarea - id: reproduction-steps - attributes: - label: Steps to reproduce - description: Please attach screenshots, videos or logs if you can. - placeholder: Tell us what you see! - value: | - 1. Where are you starting? What can you see? - 2. What do you click? - 3. More steps… - validations: - required: true - - type: textarea - id: result - attributes: - label: Outcome - placeholder: Tell us what went wrong - value: | - #### What did you expect? + Please report security issues by email to security@matrix.org + - type: textarea + id: reproduction-steps + attributes: + label: Steps to reproduce + description: Please attach screenshots, videos or logs if you can. + placeholder: Tell us what you see! + value: | + 1. Where are you starting? What can you see? + 2. What do you click? + 3. More steps… + validations: + required: true + - type: textarea + id: result + attributes: + label: Outcome + placeholder: Tell us what went wrong + value: | + #### What did you expect? #### What happened instead? validations: @@ -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 @@ -78,7 +78,7 @@ body: description: | Did you know that you can send a /rageshake command from the web application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers. options: - - 'Yes' - - 'No' + - "Yes" + - "No" validations: required: true diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml index 4e86f6e8ff..bca2efad2e 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yml +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -15,22 +15,22 @@ body: value: | #### What would you like to do? - #### Why would you like to do it? + #### Why would you like to do it? - #### How would you like to achieve it? - validations: - required: true - - type: textarea - id: alternative - attributes: - label: Have you considered any alternatives? - placeholder: A clear and concise description of any alternative solutions or features you've considered. - validations: - required: false - - type: textarea - id: additional-context - attributes: - label: Additional context - placeholder: Is there anything else you'd like to add? - validations: - required: false + #### How would you like to achieve it? + validations: + required: true + - type: textarea + id: alternative + attributes: + label: Have you considered any alternatives? + placeholder: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + - type: textarea + id: additional-context + attributes: + label: Additional context + placeholder: Is there anything else you'd like to add? + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4bace80f3f..c343afc442 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,9 +2,9 @@ ## Checklist -* [ ] Tests written for new code (and old code if feasible) -* [ ] Linter and other CI checks pass -* [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md)) +- [ ] Tests written for new code (and old code if feasible) +- [ ] Linter and other CI checks pass +- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md)) diff --git a/scripts/analyse_unused_exports.js b/scripts/analyse_unused_exports.js index 36014b1dc8..bf21a7ea61 100755 --- a/scripts/analyse_unused_exports.js +++ b/scripts/analyse_unused_exports.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -'use strict'; +"use strict"; const fs = require("fs"); const { exec } = require("node:child_process"); diff --git a/scripts/build-jitsi.js b/scripts/build-jitsi.js index e5ce21468d..f7ea841b01 100644 --- a/scripts/build-jitsi.js +++ b/scripts/build-jitsi.js @@ -21,11 +21,13 @@ if (process.env.HTTPS_PROXY) { options.agent = new ProxyAgent(process.env.HTTPS_PROXY, { tunnel: true }); } -fetch("https://meet.element.io/libs/external_api.min.js", options).then(res => { - const stream = fs.createWriteStream(fname); - return new Promise((resolve, reject) => { - res.body.pipe(stream); - res.body.on('error', err => reject(err)); - res.body.on('finish', () => resolve()); - }); -}).then(() => console.log('Done with Jitsi download')); +fetch("https://meet.element.io/libs/external_api.min.js", options) + .then((res) => { + const stream = fs.createWriteStream(fname); + return new Promise((resolve, reject) => { + res.body.pipe(stream); + res.body.on("error", (err) => reject(err)); + res.body.on("finish", () => resolve()); + }); + }) + .then(() => console.log("Done with Jitsi download")); diff --git a/scripts/ci_package.sh b/scripts/ci_package.sh index 72ae5f3a4e..d5736420c3 100755 --- a/scripts/ci_package.sh +++ b/scripts/ci_package.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Runs package.sh, passing DIST_VERSION determined by git diff --git a/scripts/copy-res.js b/scripts/copy-res.js index 7a2f2d9877..dd01082f72 100755 --- a/scripts/copy-res.js +++ b/scripts/copy-res.js @@ -11,15 +11,16 @@ const loaderUtils = require("loader-utils"); // This could readily be automated, but it's nice to explicitly // control when new languages are available. const INCLUDE_LANGS = [ - {'value': 'en_EN', 'label': 'English'}, - {'value': 'en_US', 'label': 'English (US)'}, - {'value': 'fr', 'label': 'Français'} + { value: "en_EN", label: "English" }, + { value: "en_US", label: "English (US)" }, + { value: "fr", label: "Français" }, ]; // cpx includes globbed parts of the filename in the destination, but excludes // common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and // "dest/b/...". const COPY_LIST = [ + ["res/apple-app-site-association", "webapp"], ["res/manifest.json", "webapp"], ["res/sw.js", "webapp"], ["res/welcome.html", "webapp"], @@ -35,15 +36,13 @@ const COPY_LIST = [ ["src/i18n/strings/tchap_translations.json", "webapp/i18n"], ]; -const parseArgs = require('minimist'); -const Cpx = require('cpx'); -const chokidar = require('chokidar'); -const fs = require('fs'); -const rimraf = require('rimraf'); +const parseArgs = require("minimist"); +const Cpx = require("cpx"); +const chokidar = require("chokidar"); +const fs = require("fs"); +const rimraf = require("rimraf"); -const argv = parseArgs( - process.argv.slice(2), {} -); +const argv = parseArgs(process.argv.slice(2), {}); const watch = argv.w; const verbose = argv.v; @@ -56,12 +55,12 @@ function errCheck(err) { } // Check if webapp exists -if (!fs.existsSync('webapp')) { - fs.mkdirSync('webapp'); +if (!fs.existsSync("webapp")) { + fs.mkdirSync("webapp"); } // Check if i18n exists -if (!fs.existsSync('webapp/i18n/')) { - fs.mkdirSync('webapp/i18n/'); +if (!fs.existsSync("webapp/i18n/")) { + fs.mkdirSync("webapp/i18n/"); } function next(i, err) { @@ -90,7 +89,9 @@ function next(i, err) { }); } - const cb = (err) => { next(i + 1, err) }; + const cb = (err) => { + next(i + 1, err); + }; if (watch) { if (opts.directwatch) { @@ -98,14 +99,12 @@ function next(i, err) { // which in the case of config.json is '.', which inevitably takes // ages to crawl. So we create our own watcher on the files // instead. - const copy = () => { cpx.copy(errCheck) }; - chokidar.watch(source) - .on('add', copy) - .on('change', copy) - .on('ready', cb) - .on('error', errCheck); + const copy = () => { + cpx.copy(errCheck); + }; + chokidar.watch(source).on("add", copy).on("change", copy).on("ready", cb).on("error", errCheck); } else { - cpx.on('watch-ready', cb); + cpx.on("watch-ready", cb); cpx.on("watch-error", cb); cpx.watch(); } @@ -115,17 +114,14 @@ function next(i, err) { } function genLangFile(lang, dest) { - const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json'; - const riotWebFile = 'src/i18n/strings/' + lang + '.json'; + const reactSdkFile = "node_modules/matrix-react-sdk/src/i18n/strings/" + lang + ".json"; + const riotWebFile = "src/i18n/strings/" + lang + ".json"; let translations = {}; - [reactSdkFile, riotWebFile].forEach(function(f) { + [reactSdkFile, riotWebFile].forEach(function (f) { if (fs.existsSync(f)) { try { - Object.assign( - translations, - JSON.parse(fs.readFileSync(f).toString()) - ); + Object.assign(translations, JSON.parse(fs.readFileSync(f).toString())); } catch (e) { console.error("Failed: " + f, e); throw e; @@ -150,16 +146,16 @@ function genLangFile(lang, dest) { function genLangList(langFileMap) { const languages = {}; - INCLUDE_LANGS.forEach(function(lang) { + INCLUDE_LANGS.forEach(function (lang) { const normalizedLanguage = lang.value.toLowerCase().replace("_", "-"); - const languageParts = normalizedLanguage.split('-'); + const languageParts = normalizedLanguage.split("-"); if (languageParts.length == 2 && languageParts[0] == languageParts[1]) { - languages[languageParts[0]] = {'fileName': langFileMap[lang.value], 'label': lang.label}; + languages[languageParts[0]] = { fileName: langFileMap[lang.value], label: lang.label }; } else { - languages[normalizedLanguage] = {'fileName': langFileMap[lang.value], 'label': lang.label}; + languages[normalizedLanguage] = { fileName: langFileMap[lang.value], label: lang.label }; } }); - fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) { + fs.writeFile("webapp/i18n/languages.json", JSON.stringify(languages, null, 4), function (err) { if (err) { console.error("Copy Error occured: " + err); throw new Error("Failed to generate languages.json"); @@ -188,7 +184,7 @@ function weblateToCounterpart(inTrs) { const outTrs = {}; for (const key of Object.keys(inTrs)) { - const keyParts = key.split('|', 2); + const keyParts = key.split("|", 2); if (keyParts.length === 2) { let obj = outTrs[keyParts[0]]; if (obj === undefined) { @@ -197,7 +193,7 @@ function weblateToCounterpart(inTrs) { // This is a transitional edge case if a string went from singular to pluralised and both still remain // in the translation json file. Use the singular translation as `other` and merge pluralisation atop. obj = outTrs[keyParts[0]] = { - "other": inTrs[key], + other: inTrs[key], }; console.warn("Found entry in i18n file in both singular and pluralised form", keyParts[0]); } @@ -216,8 +212,8 @@ regenerate the file, adding its content-hashed filename to langFileMap and regenerating languages.json with the new filename */ function watchLanguage(lang, dest, langFileMap) { - const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json'; - const riotWebFile = 'src/i18n/strings/' + lang + '.json'; + const reactSdkFile = "node_modules/matrix-react-sdk/src/i18n/strings/" + lang + ".json"; + const riotWebFile = "src/i18n/strings/" + lang + ".json"; // XXX: Use a debounce because for some reason if we read the language // file immediately after the FS event is received, the file contents @@ -229,16 +225,13 @@ function watchLanguage(lang, dest, langFileMap) { } makeLangDebouncer = setTimeout(() => { const filename = genLangFile(lang, dest); - langFileMap[lang]=filename; + langFileMap[lang] = filename; genLangList(langFileMap); }, 500); }; - [reactSdkFile, riotWebFile].forEach(function(f) { - chokidar.watch(f) - .on('add', makeLang) - .on('change', makeLang) - .on('error', errCheck); + [reactSdkFile, riotWebFile].forEach(function (f) { + chokidar.watch(f).on("add", makeLang).on("change", makeLang).on("error", errCheck); }); } @@ -252,7 +245,7 @@ const I18N_FILENAME_MAP = INCLUDE_LANGS.reduce((m, l) => { genLangList(I18N_FILENAME_MAP); if (watch) { - INCLUDE_LANGS.forEach(l => watchLanguage(l.value, I18N_DEST, I18N_FILENAME_MAP)); + INCLUDE_LANGS.forEach((l) => watchLanguage(l.value, I18N_DEST, I18N_FILENAME_MAP)); } // non-language resources diff --git a/scripts/deploy.py b/scripts/deploy.py index a56bb332d2..fa805a587e 100755 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -98,7 +98,24 @@ def fetch(self, tarball, extract_path): try: with tarfile.open(tarball) as tar: - tar.extractall(extract_path) + def is_within_directory(directory, target): + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + + safe_extract(tar, extract_path) finally: if self.should_clean and downloaded: os.remove(tarball) diff --git a/scripts/docker-link-repos.sh b/scripts/docker-link-repos.sh index 0c45137caf..499f6e6828 100644 --- a/scripts/docker-link-repos.sh +++ b/scripts/docker-link-repos.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -ex diff --git a/scripts/docker-package.sh b/scripts/docker-package.sh index 90875366c2..12f207d4b0 100755 --- a/scripts/docker-package.sh +++ b/scripts/docker-package.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -ex diff --git a/scripts/fetch-develop.deps.sh b/scripts/fetch-develop.deps.sh index 158cf85708..96464e789c 100755 --- a/scripts/fetch-develop.deps.sh +++ b/scripts/fetch-develop.deps.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Fetches the js-sdk and matrix-react-sdk dependencies for development # or testing purposes diff --git a/scripts/get-version-from-git.sh b/scripts/get-version-from-git.sh index bc08dd6774..cdec2e5e66 100755 --- a/scripts/get-version-from-git.sh +++ b/scripts/get-version-from-git.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Echoes a version based on the git hashes of the element-web, react-sdk & js-sdk checkouts, for the case where # these dependencies are git checkouts. diff --git a/scripts/layered.sh b/scripts/layered.sh index 406022e88d..a63803bba6 100755 --- a/scripts/layered.sh +++ b/scripts/layered.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -ex diff --git a/scripts/make-icons.sh b/scripts/make-icons.sh index 4fad8d7310..c5f6c81386 100755 --- a/scripts/make-icons.sh +++ b/scripts/make-icons.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Converts an svg logo into the various image resources required by # the various platforms deployments. diff --git a/scripts/normalize-version.sh b/scripts/normalize-version.sh index b090179aad..5337d116f6 100755 --- a/scripts/normalize-version.sh +++ b/scripts/normalize-version.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e diff --git a/scripts/package.sh b/scripts/package.sh index 9f95e87f1a..fb5aec9576 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e diff --git a/scripts/redeploy.py b/scripts/redeploy.py deleted file mode 100755 index 87e50e909a..0000000000 --- a/scripts/redeploy.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -# -# auto-deploy script for https://develop.element.io -# -# Listens for buildkite webhook pokes (https://buildkite.com/docs/apis/webhooks) -# When it gets one, downloads the artifact from buildkite -# and deploys it as the new version. -# -# Requires the following python packages: -# -# - requests -# - flask -# -from __future__ import print_function -import requests, argparse, os, errno -import time -import traceback -import glob -import re -import shutil -import threading -from Queue import Queue - -from flask import Flask, jsonify, request, abort - -from deploy import Deployer, DeployException - -app = Flask(__name__) - -deployer = None -arg_extract_path = None -arg_webhook_token = None -arg_api_token = None - -workQueue = Queue() - - -def req_headers(): - return { - "Authorization": "Bearer %s" % (arg_api_token,), - } - -# Buildkite considers a poke to have failed if it has to wait more than 10s for -# data (any data, not just the initial response) and it normally takes longer than -# that to download an artifact from buildkite. Apparently there is no way in flask -# to finish the response and then keep doing stuff, so instead this has to involve -# threading. Sigh. -def worker_thread(): - while True: - toDeploy = workQueue.get() - deploy_buildkite_artifact(*toDeploy) - -@app.route("/", methods=["POST"]) -def on_receive_buildkite_poke(): - got_webhook_token = request.headers.get('X-Buildkite-Token') - if got_webhook_token != arg_webbook_token: - print("Denying request with incorrect webhook token: %s" % (got_webhook_token,)) - abort(400, "Incorrect webhook token") - return - - required_api_prefix = None - if arg_buildkite_org is not None: - required_api_prefix = 'https://api.buildkite.com/v2/organizations/%s' % (arg_buildkite_org,) - - incoming_json = request.get_json() - if not incoming_json: - abort(400, "No JSON provided!") - return - print("Incoming JSON: %s" % (incoming_json,)) - - event = incoming_json.get("event") - if event is None: - abort(400, "No 'event' specified") - return - - if event == 'ping': - print("Got ping request - responding") - return jsonify({'response': 'pong!'}) - - if event != 'build.finished': - print("Rejecting '%s' event") - abort(400, "Unrecognised event") - return - - build_obj = incoming_json.get("build") - if build_obj is None: - abort(400, "No 'build' object") - return - - build_url = build_obj.get('url') - if build_url is None: - abort(400, "build has no url") - return - - if required_api_prefix is not None and not build_url.startswith(required_api_prefix): - print("Denying poke for build url with incorrect prefix: %s" % (build_url,)) - abort(400, "Invalid build url") - return - - build_num = build_obj.get('number') - if build_num is None: - abort(400, "build has no number") - return - - pipeline_obj = incoming_json.get("pipeline") - if pipeline_obj is None: - abort(400, "No 'pipeline' object") - return - - pipeline_name = pipeline_obj.get('name') - if pipeline_name is None: - abort(400, "pipeline has no name") - return - - artifacts_url = build_url + "/artifacts" - artifacts_resp = requests.get(artifacts_url, headers=req_headers()) - artifacts_resp.raise_for_status() - artifacts_array = artifacts_resp.json() - - artifact_to_deploy = None - for artifact in artifacts_array: - if re.match(r"dist/.*.tar.gz", artifact['path']): - artifact_to_deploy = artifact - if artifact_to_deploy is None: - print("No suitable artifacts found") - return jsonify({}) - - # double paranoia check: make sure the artifact is on the right org too - if required_api_prefix is not None and not artifact_to_deploy['url'].startswith(required_api_prefix): - print("Denying poke for build url with incorrect prefix: %s" % (artifact_to_deploy['url'],)) - abort(400, "Refusing to deploy artifact from URL %s", artifact_to_deploy['url']) - return - - # there's no point building up a queue of things to deploy, so if there are any pending jobs, - # remove them - while not workQueue.empty(): - try: - workQueue.get(False) - except: - pass - workQueue.put([artifact_to_deploy, pipeline_name, build_num]) - - return jsonify({}) - -def deploy_buildkite_artifact(artifact, pipeline_name, build_num): - artifact_response = requests.get(artifact['url'], headers=req_headers()) - artifact_response.raise_for_status() - artifact_obj = artifact_response.json() - - # we extract into a directory based on the build number. This avoids the - # problem of multiple builds building the same git version and thus having - # the same tarball name. That would lead to two potential problems: - # (a) sometimes jenkins serves corrupted artifacts; we would replace - # a good deploy with a bad one - # (b) we'll be overwriting the live deployment, which means people might - # see half-written files. - build_dir = os.path.join(arg_extract_path, "%s-#%s" % (pipeline_name, build_num)) - try: - extracted_dir = deploy_tarball(artifact_obj, build_dir) - except DeployException as e: - traceback.print_exc() - abort(400, e.message) - - -def deploy_tarball(artifact, build_dir): - """Download a tarball from jenkins and unpack it - - Returns: - (str) the path to the unpacked deployment - """ - if os.path.exists(build_dir): - raise DeployException( - "Not deploying. We have previously deployed this build." - ) - os.mkdir(build_dir) - - print("Fetching artifact %s -> %s..." % (artifact['download_url'], artifact['filename'])) - - # Download the tarball here as buildkite needs auth to do this - # we don't pgp-sign buildkite artifacts, relying on HTTPS and buildkite - # not being evil. If that's not good enough for you, don't use develop.element.io. - resp = requests.get(artifact['download_url'], stream=True, headers=req_headers()) - resp.raise_for_status() - with open(artifact['filename'], 'wb') as ofp: - shutil.copyfileobj(resp.raw, ofp) - print("...download complete. Deploying...") - - # we rely on the fact that flask only serves one request at a time to - # ensure that we do not overwrite a tarball from a concurrent request. - - return deployer.deploy(artifact['filename'], build_dir) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser("Runs a Vector redeployment server.") - parser.add_argument( - "-p", "--port", dest="port", default=4000, type=int, help=( - "The port to listen on for requests from Jenkins." - ) - ) - parser.add_argument( - "-e", "--extract", dest="extract", default="./extracted", help=( - "The location to extract .tar.gz files to." - ) - ) - parser.add_argument( - "-b", "--bundles-dir", dest="bundles_dir", help=( - "A directory to move the contents of the 'bundles' directory to. A \ - symlink to the bundles directory will also be written inside the \ - extracted tarball. Example: './bundles'." - ) - ) - parser.add_argument( - "-c", "--clean", dest="clean", action="store_true", default=False, help=( - "Remove .tar.gz files after they have been downloaded and extracted." - ) - ) - parser.add_argument( - "-s", "--symlink", dest="symlink", default="./latest", help=( - "Write a symlink to this location pointing to the extracted tarball. \ - New builds will keep overwriting this symlink. The symlink will point \ - to the /vector directory INSIDE the tarball." - ) - ) - - # --include ../../config.json ./localhost.json homepages/* - parser.add_argument( - "--include", nargs='*', default='./config*.json', help=( - "Symlink these files into the root of the deployed tarball. \ - Useful for config files and home pages. Supports glob syntax. \ - (Default: '%(default)s')" - ) - ) - parser.add_argument( - "--test", dest="tarball_uri", help=( - "Don't start an HTTP listener. Instead download a build from Jenkins \ - immediately." - ), - ) - - parser.add_argument( - "--webhook-token", dest="webhook_token", help=( - "Only accept pokes with this buildkite token." - ), required=True, - ) - - parser.add_argument( - "--api-token", dest="api_token", help=( - "API access token for buildkite. Require read_artifacts scope." - ), required=True, - ) - - # We require a matching webhook token, but because we take everything else - # about what to deploy from the poke body, we can be a little more paranoid - # and only accept builds / artifacts from a specific buildkite org - parser.add_argument( - "--org", dest="buildkite_org", help=( - "Lock down to this buildkite org" - ) - ) - - args = parser.parse_args() - arg_extract_path = args.extract - arg_webbook_token = args.webhook_token - arg_api_token = args.api_token - arg_buildkite_org = args.buildkite_org - - if not os.path.isdir(arg_extract_path): - os.mkdir(arg_extract_path) - - deployer = Deployer() - deployer.bundles_path = args.bundles_dir - deployer.should_clean = args.clean - deployer.symlink_latest = args.symlink - - for include in args.include: - deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) }) - - if args.tarball_uri is not None: - build_dir = os.path.join(arg_extract_path, "test-%i" % (time.time())) - deploy_tarball(args.tarball_uri, build_dir) - else: - print( - "Listening on port %s. Extracting to %s%s. Symlinking to %s. Include files: %s" % - (args.port, - arg_extract_path, - " (clean after)" if deployer.should_clean else "", - args.symlink, - deployer.symlink_paths, - ) - ) - fred = threading.Thread(target=worker_thread) - fred.daemon = True - fred.start() - app.run(port=args.port, debug=False) diff --git a/sonar-project.properties b/sonar-project.properties index 669f26bab2..3416e610f2 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,4 +11,4 @@ sonar.exclusions=__mocks__,docs,element.io,nginx sonar.typescript.tsconfigPath=./tsconfig.json sonar.javascript.lcov.reportPaths=coverage/lcov.info sonar.coverage.exclusions=test/**/*,res/**/* -sonar.testExecutionReportPaths=coverage/test-report.xml +sonar.testExecutionReportPaths=coverage/jest-sonar-report.xml diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 74a65af14f..5047aeeed5 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -19,20 +19,20 @@ import type { Renderer } from "react-dom"; import type { logger } from "matrix-js-sdk/src/logger"; type ElectronChannel = - "app_onAction" | - "before-quit" | - "check_updates" | - "install_update" | - "ipcCall" | - "ipcReply" | - "loudNotification" | - "preferences" | - "seshat" | - "seshatReply" | - "setBadgeCount" | - "update-downloaded" | - "userDownloadCompleted" | - "userDownloadAction"; + | "app_onAction" + | "before-quit" + | "check_updates" + | "install_update" + | "ipcCall" + | "ipcReply" + | "loudNotification" + | "preferences" + | "seshat" + | "seshatReply" + | "setBadgeCount" + | "update-downloaded" + | "userDownloadCompleted" + | "userDownloadAction"; declare global { interface Window { diff --git a/src/@types/raw-loader.d.ts b/src/@types/raw-loader.d.ts index ea3df880f6..c35dd356a8 100644 --- a/src/@types/raw-loader.d.ts +++ b/src/@types/raw-loader.d.ts @@ -1,4 +1,4 @@ -declare module '!!raw-loader!*' { +declare module "!!raw-loader!*" { const contents: string; export default contents; } diff --git a/src/async-components/structures/CompatibilityView.tsx b/src/async-components/structures/CompatibilityView.tsx index be96a083c3..193d3e85b0 100644 --- a/src/async-components/structures/CompatibilityView.tsx +++ b/src/async-components/structures/CompatibilityView.tsx @@ -16,7 +16,7 @@ limitations under the License. import * as React from "react"; import { _t } from "matrix-react-sdk/src/languageHandler"; -import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; +import SdkConfig from "matrix-react-sdk/src/SdkConfig"; // directly import the style here as this layer does not support rethemedex at this time so no matrix-react-sdk // PostCSS variables will be accessible. @@ -32,115 +32,131 @@ const CompatibilityView: React.FC = ({ onAccept }) => { let ios = null; const iosCustomUrl = mobileBuilds?.ios; - if (iosCustomUrl !== null) { // could be undefined or a string - ios = <> -

iOS (iPhone or iPad)

- - Apple App Store - - ; + if (iosCustomUrl !== null) { + // could be undefined or a string + ios = ( + <> +

+ iOS (iPhone or iPad) +

+ + Apple App Store + + + ); } - let android = [

Android

]; + let android = [ +

+ Android +

, + ]; const andCustomUrl = mobileBuilds?.android; const fdroidCustomUrl = mobileBuilds?.fdroid; - if (andCustomUrl !== null) { // undefined or string - android.push( - Google Play Store - ); + if (andCustomUrl !== null) { + // undefined or string + android.push( + + Google Play Store + , + ); } - if (fdroidCustomUrl !== null) { // undefined or string - android.push( - F-Droid - ); + if (fdroidCustomUrl !== null) { + // undefined or string + android.push( + + F-Droid + , + ); } - if (android.length === 1) { // just a header, meaning no links + if (android.length === 1) { + // just a header, meaning no links android = []; } - let mobileHeader =

{ _t("Use %(brand)s on mobile", { brand }) }

; + let mobileHeader =

{_t("Use %(brand)s on mobile", { brand })}

; if (!android.length && !ios) { mobileHeader = null; } - return
-
-
- - Element - -

{ _t("Unsupported browser") }

-
+ return ( +
+
+
+ + Element + +

{_t("Unsupported browser")}

+
-
-
-
-

{ _t("Your browser can't run %(brand)s", { brand }) }

-

- { _t( - "%(brand)s uses advanced browser features which aren't " + - "supported by your current browser.", - { brand }, - ) } -

-

- { _t( - 'Please install Chrome, Firefox, ' + - 'or Safari for the best experience.', - {}, - { - 'chromeLink': (sub) => { sub }, - 'firefoxLink': (sub) => { sub }, - 'safariLink': (sub) => { sub }, - }, - ) } -

-

- { _t( - "You can continue using your current browser, but some or all features may not work " + - "and the look and feel of the application may be incorrect.", - ) } -

- +
+
+
+

{_t("Your browser can't run %(brand)s", { brand })}

+

+ {_t( + "%(brand)s uses advanced browser features which aren't " + + "supported by your current browser.", + { brand }, + )} +

+

+ {_t( + "Please install Chrome, Firefox, " + + "or Safari for the best experience.", + {}, + { + chromeLink: (sub) => {sub}, + firefoxLink: (sub) => {sub}, + safariLink: (sub) => {sub}, + }, + )} +

+

+ {_t( + "You can continue using your current browser, but some or all features may not work " + + "and the look and feel of the application may be incorrect.", + )} +

+ +
-
-
-
-
- { mobileHeader } - { ios } - { android } +
+
+
+ {mobileHeader} + {ios} + {android} +
-
-
-
; + ); }; export default CompatibilityView; diff --git a/src/async-components/structures/ErrorView.tsx b/src/async-components/structures/ErrorView.tsx index 3c3bfc3c3e..b34226f3b4 100644 --- a/src/async-components/structures/ErrorView.tsx +++ b/src/async-components/structures/ErrorView.tsx @@ -28,34 +28,33 @@ interface IProps { } const ErrorView: React.FC = ({ title, messages }) => { - return
-
-
- - Element - -

{ _t("Failed to start") }

-
-
-
-
-

{ title }

- { messages && messages.map(msg =>

- { msg } -

) } + return ( +
+
+
+ + Element + +

{_t("Failed to start")}

+
+
+
+
+

{title}

+ {messages && messages.map((msg) =>

{msg}

)} +
-
-
-
; + ); }; export default ErrorView; - diff --git a/src/components/views/auth/VectorAuthFooter.tsx b/src/components/views/auth/VectorAuthFooter.tsx index c97718bda4..26ad2c64ac 100644 --- a/src/components/views/auth/VectorAuthFooter.tsx +++ b/src/components/views/auth/VectorAuthFooter.tsx @@ -15,31 +15,33 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; -import { _t } from 'matrix-react-sdk/src/languageHandler'; +import React, { ReactElement } from "react"; +import SdkConfig from "matrix-react-sdk/src/SdkConfig"; +import { _t } from "matrix-react-sdk/src/languageHandler"; -const VectorAuthFooter = () => { +const VectorAuthFooter = (): ReactElement => { const brandingConfig = SdkConfig.getObject("branding"); const links = brandingConfig?.get("auth_footer_links") ?? [ - { "text": "Blog", "url": "https://element.io/blog" }, - { "text": "Twitter", "url": "https://twitter.com/element_hq" }, - { "text": "GitHub", "url": "https://github.com/vector-im/element-web" }, + { text: "Blog", url: "https://element.io/blog" }, + { text: "Twitter", url: "https://twitter.com/element_hq" }, + { text: "GitHub", url: "https://github.com/vector-im/element-web" }, ]; const authFooterLinks = []; for (const linkEntry of links) { authFooterLinks.push( - { linkEntry.text } + {linkEntry.text} , ); } return ( ); }; diff --git a/src/components/views/auth/VectorAuthHeaderLogo.tsx b/src/components/views/auth/VectorAuthHeaderLogo.tsx index eaa60cf7ee..688a929d11 100644 --- a/src/components/views/auth/VectorAuthHeaderLogo.tsx +++ b/src/components/views/auth/VectorAuthHeaderLogo.tsx @@ -15,11 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as React from 'react'; -import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; +import * as React from "react"; +import SdkConfig from "matrix-react-sdk/src/SdkConfig"; export default class VectorAuthHeaderLogo extends React.PureComponent { - public render() { + public render(): React.ReactElement { const brandingConfig = SdkConfig.getObject("branding"); const logoUrl = brandingConfig?.get("auth_header_logo_url") ?? "themes/element/img/logos/element-logo.svg"; diff --git a/src/components/views/auth/VectorAuthPage.tsx b/src/components/views/auth/VectorAuthPage.tsx index 6b0004cf1b..560fe424aa 100644 --- a/src/components/views/auth/VectorAuthPage.tsx +++ b/src/components/views/auth/VectorAuthPage.tsx @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as React from 'react'; -import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; +import * as React from "react"; +import SdkConfig from "matrix-react-sdk/src/SdkConfig"; import VectorAuthFooter from "./VectorAuthFooter"; @@ -23,7 +23,7 @@ export default class VectorAuthPage extends React.PureComponent { private static welcomeBackgroundUrl; // cache the url as a static to prevent it changing without refreshing - private static getWelcomeBackgroundUrl() { + private static getWelcomeBackgroundUrl(): string { if (VectorAuthPage.welcomeBackgroundUrl) return VectorAuthPage.welcomeBackgroundUrl; const brandingConfig = SdkConfig.getObject("branding"); @@ -42,31 +42,31 @@ export default class VectorAuthPage extends React.PureComponent { return VectorAuthPage.welcomeBackgroundUrl; } - public render() { + public render(): React.ReactElement { const pageStyle = { background: `center/cover fixed url(${VectorAuthPage.getWelcomeBackgroundUrl()})`, }; const modalStyle: React.CSSProperties = { - position: 'relative', - background: 'initial', + position: "relative", + background: "initial", }; const blurStyle: React.CSSProperties = { - position: 'absolute', + position: "absolute", top: 0, right: 0, bottom: 0, left: 0, - filter: 'blur(40px)', + filter: "blur(40px)", background: pageStyle.background, }; const modalContentStyle: React.CSSProperties = { - display: 'flex', + display: "flex", zIndex: 1, - background: 'rgba(255, 255, 255, 0.59)', - borderRadius: '8px', + background: "rgba(255, 255, 255, 0.59)", + borderRadius: "8px", }; return ( @@ -74,7 +74,7 @@ export default class VectorAuthPage extends React.PureComponent {
- { this.props.children } + {this.props.children}
diff --git a/src/favicon.ts b/src/favicon.ts index 7488cac299..1ae1e5bd9e 100644 --- a/src/favicon.ts +++ b/src/favicon.ts @@ -56,7 +56,7 @@ export default class Favicon { // callback to run once isReady is asserted, allows for a badge to be queued for when it can be shown private readyCb?: () => void; - constructor(params: Partial = {}) { + public constructor(params: Partial = {}) { this.params = { ...defaults, ...params }; this.icons = Favicon.getIcons(); @@ -68,10 +68,10 @@ export default class Favicon { const lastIcon = this.icons[this.icons.length - 1]; if (lastIcon.hasAttribute("href")) { this.baseImage.setAttribute("crossOrigin", "anonymous"); - this.baseImage.onload = () => { + this.baseImage.onload = (): void => { // get height and width of the favicon - this.canvas.height = (this.baseImage.height > 0) ? this.baseImage.height : 32; - this.canvas.width = (this.baseImage.width > 0) ? this.baseImage.width : 32; + this.canvas.height = this.baseImage.height > 0 ? this.baseImage.height : 32; + this.canvas.width = this.baseImage.width > 0 ? this.baseImage.width : 32; this.context = this.canvas.getContext("2d"); this.ready(); }; @@ -89,7 +89,10 @@ export default class Favicon { this.context.drawImage(this.baseImage, 0, 0, this.canvas.width, this.canvas.height); } - private options(n: number | string, params: IParams): { + private options( + n: number | string, + params: IParams, + ): { n: string | number; len: number; x: number; @@ -98,7 +101,7 @@ export default class Favicon { h: number; } { const opt = { - n: ((typeof n) === "number") ? Math.abs(n as number | 0) : n, + n: typeof n === "number" ? Math.abs(n as number | 0) : n, len: ("" + n).length, // badge positioning constants as percentages x: 0.4, @@ -174,8 +177,8 @@ export default class Favicon { this.context.stroke(); this.context.fillStyle = params.textColor; - if ((typeof opt.n) === "number" && opt.n > 999) { - const count = ((opt.n > 9999) ? 9 : Math.floor(opt.n as number / 1000)) + "k+"; + if (typeof opt.n === "number" && opt.n > 999) { + const count = (opt.n > 9999 ? 9 : Math.floor((opt.n as number) / 1000)) + "k+"; this.context.fillText(count, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2)); } else { this.context.fillText("" + opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15)); @@ -209,7 +212,7 @@ export default class Favicon { newIcon.setAttribute("href", url); old.parentNode?.removeChild(old); } else { - this.icons.forEach(icon => { + this.icons.forEach((icon) => { icon.setAttribute("href", url); }); } @@ -217,7 +220,7 @@ export default class Favicon { public badge(content: number | string, opts?: Partial): void { if (!this.isReady) { - this.readyCb = () => { + this.readyCb = (): void => { this.badge(content, opts); }; return; @@ -236,7 +239,7 @@ export default class Favicon { const icons: HTMLLinkElement[] = []; const links = window.document.getElementsByTagName("head")[0].getElementsByTagName("link"); for (const link of links) { - if ((/(^|\s)icon(\s|$)/i).test(link.getAttribute("rel"))) { + if (/(^|\s)icon(\s|$)/i.test(link.getAttribute("rel"))) { icons.push(link); } } @@ -252,7 +255,7 @@ export default class Favicon { window.document.getElementsByTagName("head")[0].appendChild(elms[0]); } - elms.forEach(item => { + elms.forEach((item) => { item.setAttribute("type", "image/png"); }); return elms; diff --git a/src/i18n/strings/ar.json b/src/i18n/strings/ar.json index d85021a728..697db4c165 100644 --- a/src/i18n/strings/ar.json +++ b/src/i18n/strings/ar.json @@ -15,9 +15,7 @@ "Unexpected error preparing the app. See console for details.": "حدث عُطل غير متوقع أثناء تجهيز التطبيق. طالِع المِعراض للتفاصيل.", "Download Completed": "اكتمل التنزيل", "Open": "افتح", - "%(brand)s Desktop (%(platformName)s)": "‏‏%(brand)s لسطح المكتب (%(platformName)s)", "Go to your browser to complete Sign In": "افتح المتصفح لإكمال الولوج", - "%(appName)s (%(browserName)s, %(osName)s)": "‏‏%(appName)s (‏‏%(browserName)s، ‏‏%(osName)s)", "Unsupported browser": "متصفح غير مدعوم", "Your browser can't run %(brand)s": "لا يمكن لمتصفحك تشغيل %(brand)s", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "يستعمل %(brand)s ميزات متقدمة في المتصفحات لا يدعمها متصفحك الحالي.", @@ -28,6 +26,5 @@ "Failed to start": "فشل البدء", "Powered by Matrix": "تدعمه «ماترِكس»", "Use %(brand)s on mobile": "استعمل %(brand)s على المحمول", - "Switch to space by number": "التبديل إلى المساحة بالرقم", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "محادثة لامركزية، مشفرة & تعمل بواسطة $matrixLogo" } diff --git a/src/i18n/strings/az.json b/src/i18n/strings/az.json index 49ab8753cc..7a1016ecd7 100644 --- a/src/i18n/strings/az.json +++ b/src/i18n/strings/az.json @@ -10,7 +10,6 @@ "The message from the parser is: %(message)s": "Sözügedən mesaj: %(message)s", "Dismiss": "Nəzərə almayın", "Welcome to Element": "Element-ə xoş gəlmişsiniz", - "Decentralised, encrypted chat & collaboration powered by [matrix]": "[matrix] tərəfindən təchiz edilmiş mərkəziləşdirilməmiş, şifrələnmiş çat və əməkdaşlıq platforması", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "$matrixLogo tərəfindən dəstəklənən mərkəzləşdirilməmiş ,şifrələnmiş söhbət & əməkdaşlıq", "Failed to start": "Başlatmaq alınmadı", "Go to element.io": "element.io saytına keçin", @@ -22,9 +21,7 @@ "Unsupported browser": "Dəstəklənməyən brauzer", "Use %(brand)s on mobile": "Mobil telefonda %(brand)s istifadə edin", "Powered by Matrix": "Gücünü Matrix'dən alır", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Go to your browser to complete Sign In": "Girişi tamamlamaq üçün brauzerinizə keçin", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Masaüstü (%(platformName)s)", "Open": "Aç", "Download Completed": "Yükləmə Tamamlandı", "Unable to load config file: please refresh the page to try again.": "Konfiqurasiya faylını yükləmək mümkün deyil: yenidən cəhd etmək üçün səhifəni yeniləyin.", diff --git a/src/i18n/strings/bg.json b/src/i18n/strings/bg.json index 554d595e9a..16fbcf3478 100644 --- a/src/i18n/strings/bg.json +++ b/src/i18n/strings/bg.json @@ -12,8 +12,6 @@ "Invalid JSON": "Невалиден JSON", "Go to your browser to complete Sign In": "Отидете в браузъра за да завършите влизането", "Unable to load config file: please refresh the page to try again.": "Неуспешно зареждане на конфигурационния файл: презаредете страницата за да опитате пак.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Неподдържан браузър", "Please install Chrome, Firefox, or Safari for the best experience.": "Инсталирайте Chrome, Firefox или Safari за най-добра работа.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Може да продължите да използвате сегашния си браузър, но някои или всички функции може да се окажат неработещи, или пък външния вид на приложението да изглежда неправилен.", diff --git a/src/i18n/strings/bs.json b/src/i18n/strings/bs.json index e768351bac..e2385a702b 100644 --- a/src/i18n/strings/bs.json +++ b/src/i18n/strings/bs.json @@ -10,10 +10,8 @@ "Download Completed": "Preuzimanje završeno", "Open": "Otvori", "Dismiss": "Odbaci", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Radna povrsina (%(platformName)s)", "Go to your browser to complete Sign In": "Idite na svoj pretraživač da biste dovršili prijavu", "Unknown device": "Nepoznat uređaj", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Powered by Matrix": "Pokretano uz Matrix", "Unsupported browser": "Nepodržani pretraživač", "Your browser can't run %(brand)s": "Vaš pretraživač ne može pokretati %(brand)s", diff --git a/src/i18n/strings/ca.json b/src/i18n/strings/ca.json index 23827a2ed2..7f89cb117e 100644 --- a/src/i18n/strings/ca.json +++ b/src/i18n/strings/ca.json @@ -16,8 +16,6 @@ "Unexpected error preparing the app. See console for details.": "Error inesperat durant la preparació de l'aplicació. Consulta la consola pels a més detalls.", "Download Completed": "Baixada completada", "Open": "Obre", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s d'escriptori (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Powered by Matrix": "Amb tecnologia de Matrix", "Unsupported browser": "Navegador no compatible", "Your browser can't run %(brand)s": "El teu navegador no pot executar %(brand)s", diff --git a/src/i18n/strings/cs.json b/src/i18n/strings/cs.json index d42069980d..19c6477e44 100644 --- a/src/i18n/strings/cs.json +++ b/src/i18n/strings/cs.json @@ -16,7 +16,6 @@ "Unable to load config file: please refresh the page to try again.": "Nepodařilo se načíst konfigurační soubor: abyste to zkusili znovu, načtěte prosím znovu stránku.", "Download Completed": "Stahování dokončeno", "Open": "Otevřít", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Nepodporovaný prohlížeč", "Your browser can't run %(brand)s": "Váš prohlížeč nedokáže spustit %(brand)s", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s využívá pokročilých funkcí prohlížeče, které ten váš nepodporuje.", @@ -26,7 +25,6 @@ "Go to element.io": "Přejít na element.io", "Failed to start": "Nepovedlo se nastartovat", "Powered by Matrix": "Běží na Matrixu", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s pro desktopový počítač (%(platformName)s)", "Use %(brand)s on mobile": "Používání %(brand)s v mobilních zařízeních", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizovaný, šifrovaný chat a spolupráce na platformě $matrixLogo", "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s na %(osName)s", diff --git a/src/i18n/strings/da.json b/src/i18n/strings/da.json index e2268d3d70..698a66272b 100644 --- a/src/i18n/strings/da.json +++ b/src/i18n/strings/da.json @@ -1,6 +1,5 @@ { "Dismiss": "Afvis", - "powered by Matrix": "Drevet af Matrix", "Unknown device": "Ukendt enhed", "Welcome to Element": "Velkommen til Element", "The message from the parser is: %(message)s": "Beskeden fra parseren er: %(message)s", @@ -19,14 +18,15 @@ "Open": "Åbn", "Download Completed": "Hentning færdig", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Din Element konfiguration indeholder ugyldig JSON. Løs venligst problemet og genindlæs siden.", - "Your Element is misconfigured": "Din Element er konfigureret forkert", + "Your Element is misconfigured": "Dit Element er konfigureret forkert", "Your browser can't run %(brand)s": "Din browser kan ikke køre %(brand)s", "Powered by Matrix": "Drevet af Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Failed to start": "Opstart mislykkedes", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop %(platformName)s", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Du kan fortsætte med at bruge din nuværende browser, men du kan opleve at visse eller alle funktioner ikke vil fungere korrekt.", "Please install Chrome, Firefox, or Safari for the best experience.": "Venligst installer Chrome,Firefox eller Safari for den bedste oplevelse.", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s bruger avanceret browser funktioner som ikke er understøttet af din nuværende browser.", - "Use %(brand)s on mobile": "Brug %(brand)s på mobil" + "Use %(brand)s on mobile": "Brug %(brand)s på mobil", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentraliseret, krypteret chat & samarbejde drevet af $matrixLogo", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s på %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s Desktop: %(platformName)s" } diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index f170484404..cc4708ded8 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -15,8 +15,6 @@ "Unsupported browser": "Nicht unterstützter Browser", "Go to element.io": "Gehe zu element.io", "Failed to start": "Start fehlgeschlagen", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Please install Chrome, Firefox, or Safari for the best experience.": "Bitte installiere Chrome, Firefox oder Safari für das beste Erlebnis.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Du kannst deinen aktuellen Browser weiterhin verwenden. Es ist aber möglich, dass nicht alles richtig funktioniert oder das Aussehen der App inkorrekt ist.", "I understand the risks and wish to continue": "Ich verstehe die Risiken und möchte fortfahren", diff --git a/src/i18n/strings/el.json b/src/i18n/strings/el.json index 733f3ccd38..77fa06edf3 100644 --- a/src/i18n/strings/el.json +++ b/src/i18n/strings/el.json @@ -25,9 +25,6 @@ "I understand the risks and wish to continue": "Κατανοώ τους κινδύνους και επιθυμώ να συνεχίσω", "Go to element.io": "Πήγαινε στο element.io", "Failed to start": "Αποτυχία έναρξης", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Use %(brand)s on mobile": "Χρήση %(brand)s σε κινητό", - "Switch to space by number": "Εναλλαγή σε space με αριθμό", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Αποκεντρωμένη, κρυπτογραφημένη συνομιλία και συνεργασία χρησιμοποιώντας το $matrixLogo" } diff --git a/src/i18n/strings/en_US.json b/src/i18n/strings/en_US.json index ce1ec9f033..6926ff4b84 100644 --- a/src/i18n/strings/en_US.json +++ b/src/i18n/strings/en_US.json @@ -19,9 +19,7 @@ "Your browser can't run %(brand)s": "Your browser can't run %(brand)s", "Unsupported browser": "Unsupported browser", "Powered by Matrix": "Powered by Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Go to your browser to complete Sign In": "Go to your browser to complete Sign In", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Open": "Open", "Download Completed": "Download Completed", "Unable to load config file: please refresh the page to try again.": "Unable to load config file: please refresh the page to try again.", diff --git a/src/i18n/strings/eo.json b/src/i18n/strings/eo.json index 9b72a47eb2..73db1c4165 100644 --- a/src/i18n/strings/eo.json +++ b/src/i18n/strings/eo.json @@ -12,8 +12,6 @@ "Invalid JSON": "Nevalida JSON", "Go to your browser to complete Sign In": "Iru al via retumilo por finpretigi la ensaluton", "Unable to load config file: please refresh the page to try again.": "Ne povas enlegi agordan dosieron: bonvolu reprovi per aktualigo de la paĝo.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s labortabla (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Nesubtenata retumilo", "Please install Chrome, Firefox, or Safari for the best experience.": "Bonvolu instali retumilon Chrome, Firefox, aŭ Safari, por la plej bona sperto.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Vi povas daŭre uzi vian nunan foliumilon, sed iuj (eĉ ĉiuj) funkcioj eble ne funkciu, kaj la aspekto de la aplikaĵo eble ne estu ĝusta.", diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json index 28c41bbb98..e54ccd35f1 100644 --- a/src/i18n/strings/es.json +++ b/src/i18n/strings/es.json @@ -12,8 +12,6 @@ "Invalid JSON": "JSON inválido", "Go to your browser to complete Sign In": "Abre tu navegador web para completar el registro", "Unable to load config file: please refresh the page to try again.": "No se ha podido cargar el archivo de configuración. Recarga la página para intentarlo otra vez.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s de escritorio (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Navegador no compatible", "Please install Chrome, Firefox, or Safari for the best experience.": "Por favor, instale Chrome, Firefox, o Safari para la mejor experiencia.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Puedes seguir utilizando tu navegador actual, pero puede que algunas funcionalidades no estén disponibles o que algunas partes de la aplicación se muestren de forma incorrecta.", diff --git a/src/i18n/strings/et.json b/src/i18n/strings/et.json index 1f461acd6c..0ea8e9e2c9 100644 --- a/src/i18n/strings/et.json +++ b/src/i18n/strings/et.json @@ -12,8 +12,6 @@ "Welcome to Element": "Tere tulemast kasutama suhtlusrakendust Element", "Sign In": "Logi sisse", "Create Account": "Loo konto", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s'i töölauaversioon (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Sellele brauserile puudub tugi", "Please install Chrome, Firefox, or Safari for the best experience.": "Parima kasutuskogemuse jaoks palun paigalda Chrome, Firefox või Safari.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Sa võid jätkata praeguse brauseri kasutamist, kuid mõned või kõik funktsionaalsused ei pruugi toimida ning rakenduse välimus võib vigane olla.", diff --git a/src/i18n/strings/eu.json b/src/i18n/strings/eu.json index d374c0e13c..0fb124e8f6 100644 --- a/src/i18n/strings/eu.json +++ b/src/i18n/strings/eu.json @@ -12,8 +12,6 @@ "Invalid JSON": "JSON baliogabea", "Go to your browser to complete Sign In": "Joan zure nabigatzailera izena ematen bukatzeko", "Unable to load config file: please refresh the page to try again.": "Ezin izan da konfigurazio fitxategia kargatu: Saiatu orria birkargatzen.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Onartu gabeko nabigatzailea", "Please install Chrome, Firefox, or Safari for the best experience.": "Instalatu Chrome, Firefox, edo Safari esperientzia hobe baterako.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Zure oraingo nabigatzailea erabiltzen jarraitu dezakezu, baina ezaugarri batzuk agian ez dute funtzionatuko eta itxura desegokia izan daiteke.", diff --git a/src/i18n/strings/fa.json b/src/i18n/strings/fa.json index 6f58d6866f..484958b45d 100644 --- a/src/i18n/strings/fa.json +++ b/src/i18n/strings/fa.json @@ -16,8 +16,6 @@ "Unexpected error preparing the app. See console for details.": "خطای غیر منتظره در آماده سازی برنامه. کنسول را برای جزئیات مشاهده کنید.", "Download Completed": "بارگیری کامل شد", "Open": "باز", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s میزکار %(platformName)s", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "مرورگر پش‬تبانی نمی شود", "Your browser can't run %(brand)s": "مرورگر شما نمی تواند %(brand)s را اجرا کند", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s از ویژگی های پیشرفته مرورگر استفاده می کند که در مرورگر فعلی شما پشتیبانی نمی شوند.", diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json index 7ecab5c515..e47549c828 100644 --- a/src/i18n/strings/fi.json +++ b/src/i18n/strings/fi.json @@ -11,9 +11,7 @@ "The message from the parser is: %(message)s": "Viesti jäsentimeltä: %(message)s", "Invalid JSON": "Virheellinen JSON", "Unable to load config file: please refresh the page to try again.": "Asetustiedostoa ei voi ladata. Yritä uudelleen lataamalla sivu uudelleen.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)sin työpöytäversio (%(platformName)s)", "Go to your browser to complete Sign In": "Tee kirjautuminen loppuun selaimessasi", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Selainta ei tueta", "Please install Chrome, Firefox, or Safari for the best experience.": "Asenna Chrome, Firefox tai Safari, jotta kaikki toimii parhaiten.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Voit käyttää edelleen nykyistä selaintasi, mutta jotkut tai kaikki ominaisuudet eivät ehkä toimi ja sovelluksen ulkoasu voi olla virheellinen.", @@ -27,5 +25,8 @@ "Powered by Matrix": "Moottorina Matrix", "Your browser can't run %(brand)s": "%(brand)s ei toimi selaimessasi", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s käyttää edistyneitä selaimen ominaisuuksia, joita nykyinen selaimesi ei tue.", - "Use %(brand)s on mobile": "Käytä %(brand)sia mobiilisti" + "Use %(brand)s on mobile": "Käytä %(brand)sia mobiilisti", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Hajautettu, salattu keskustelu & yhteistyö, taustavoimana $matrixLogo", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s käyttöjärjestelmällä %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)sin työpöytäversio: %(platformName)s" } diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index e9a47205d1..c5d5d9f22c 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -12,14 +12,12 @@ "Invalid JSON": "JSON non valide", "Go to your browser to complete Sign In": "Utilisez votre navigateur pour terminer la connexion", "Unable to load config file: please refresh the page to try again.": "Impossible de charger le fichier de configuration : rechargez la page pour réessayer.", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Navigateur non pris en charge", "Please install Chrome, Firefox, or Safari for the best experience.": "Veuillez installer Chrome, Firefox ou Safari pour une expérience optimale.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Vous pouvez continuer à utiliser votre navigateur actuel, mais vous risquez de trouver que certaines fonctionnalités et/ou l’apparence de l’application sont incorrectes.", "I understand the risks and wish to continue": "Je comprends les risques et souhaite continuer", "Go to element.io": "Aller vers element.io", "Failed to start": "Échec au démarrage", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s pour bureau (%(platformName)s)", "Download Completed": "Téléchargement terminé", "Open": "Ouvrir", "Your Element is misconfigured": "Votre Element est mal configuré", diff --git a/src/i18n/strings/fy.json b/src/i18n/strings/fy.json index 8701abd29d..66d3ad84f5 100644 --- a/src/i18n/strings/fy.json +++ b/src/i18n/strings/fy.json @@ -5,12 +5,10 @@ "Please install Chrome, Firefox, or Safari for the best experience.": "Graach Chrome, Firefox, ofSafari ynstallearje foar de beste ûnderfining.", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s brûkt avansearre browserfunksjes dy’t net stipe wurde troch de browser dy’t jo no brûke.", "Powered by Matrix": "Mooglik makke troch Matrix", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Unexpected error preparing the app. See console for details.": "Unferwachte flater by it klearmeitsjen fan de applikaasje. Sjoch yn de console foar details.", "The message from the parser is: %(message)s": "It berjocht fan de ferwurker is: %(message)s", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Jo Element-konfiguraasje hat ûnjildige JSON. Nei dat jo dit oplost ha, kin dizze side ferfarske wurde.", "Use %(brand)s on mobile": "Brûk %(brand)s op mobyl", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Go to your browser to complete Sign In": "Gean nei jo browser om it ynskriuwen te foltôgjen", "Download Completed": "Download foltôge", "Unable to load config file: please refresh the page to try again.": "Kin konfiguraasjebestân net lade: ferfarskje de side en probearje it nochris.", diff --git a/src/i18n/strings/ga.json b/src/i18n/strings/ga.json index 8fb7c7c321..88189d897e 100644 --- a/src/i18n/strings/ga.json +++ b/src/i18n/strings/ga.json @@ -15,8 +15,6 @@ "Please install Chrome, Firefox, or Safari for the best experience.": "Suiteáil Chrome, Firefox, or Safari chun an taithí is fearr a fháil.", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "Úsáideann %(brand)s gnéithe ardforbartha nach bhfuil ar fáil faoi do bhrabhsálaí reatha.", "Unsupported browser": "Brabhsálaí gan tacaíocht", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s deisce (%(platformName)s)", "Unexpected error preparing the app. See console for details.": "Earráid nuair an feidhmchlár a hullmhú. Feic sa consól le haghaidh eolas.", "Unable to load config file: please refresh the page to try again.": "Ní féidir an comhad cumraíochta a lódáil. Athnuaigh an leathanach chun déanamh iarracht arís le do thoil.", "Download Completed": "Íoslódáil críochnaithe", diff --git a/src/i18n/strings/gl.json b/src/i18n/strings/gl.json index c1660e9d58..c492b68f5d 100644 --- a/src/i18n/strings/gl.json +++ b/src/i18n/strings/gl.json @@ -11,9 +11,7 @@ "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configuración non válida: só se pode indicar un de default_server_config, default_server_name, ou default_hs_url.", "Invalid configuration: no default server specified.": "Configuración non válida: non se indicou servidor por defecto.", "Unable to load config file: please refresh the page to try again.": "Non se cargou o ficheiro de configuración: actualiza a páxina para reintentalo.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Go to your browser to complete Sign In": "Abre o navegador para realizar a Conexión", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Navegador non soportado", "Please install Chrome, Firefox, or Safari for the best experience.": "Instala Chrome, Firefox, ou Safari para ter unha mellor experiencia.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Podes continuar co teu navegador, pero algunhas características poderían non funcionar e o aspecto da aplicación podería non ser o correcto.", @@ -28,5 +26,7 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s utiliza características avanzadas do navegador que non están dispoñibles no teu navegador.", "Powered by Matrix": "Funciona grazas a Matrix", "Use %(brand)s on mobile": "Utiliza %(brand)s no móbil", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Conversas & colaboración descentralizadas e cifradas grazas a $matrixLogo" + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Conversas & colaboración descentralizadas e cifradas grazas a $matrixLogo", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s en %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s para Escritorio: %(platformName)s" } diff --git a/src/i18n/strings/he.json b/src/i18n/strings/he.json index b7597ac098..f255b2bbc6 100644 --- a/src/i18n/strings/he.json +++ b/src/i18n/strings/he.json @@ -24,11 +24,7 @@ "Your browser can't run %(brand)s": "הדפדפן שלך לא יכול להריץ %(brand)s", "Unsupported browser": "דפדפן לא נתמך", "Powered by Matrix": "מופעל על ידי מטריקס", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s שולחן עבודה %(platformName)s", "The message from the parser is: %(message)s": "ההודעה מהמנתח היא: %(message)s", - "Missing indexeddb worker script!": "סקריפט indexeddb worker חסר!", - "Switch to space by number": "עבור 'למרחב' על פי המספר שלו", "Use %(brand)s on mobile": "השתמש ב-%(brand)s במכשיר הנייד", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "צ'אט מבוזר ומוצפן & מופעל בשיתוף פעולה ע\"י $matrixLogo" } diff --git a/src/i18n/strings/hi.json b/src/i18n/strings/hi.json index 2bb79d9af5..93b16b8417 100644 --- a/src/i18n/strings/hi.json +++ b/src/i18n/strings/hi.json @@ -5,8 +5,6 @@ "Sign In": "साइन करना", "Create Account": "खाता बनाएं", "Explore rooms": "रूम का अन्वेषण करें", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s का डेस्कटॉप (%(platformName)s)", "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "अमान्य कॉन्फ़िगरेशन: केवल default_server_config, default_server_name, या default_hs_url में से कोई एक निर्दिष्ट कर सकता है।", "Failed to start": "प्रारंभ करने में विफल", "Go to element.io": "element.io पर जाएं", diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json index f8a505638b..861c2ecec1 100644 --- a/src/i18n/strings/hu.json +++ b/src/i18n/strings/hu.json @@ -12,8 +12,6 @@ "Invalid JSON": "Érvénytelen JSON", "Go to your browser to complete Sign In": "A böngészőben fejezze be a bejelentkezést", "Unable to load config file: please refresh the page to try again.": "A konfigurációs fájlt nem sikerült betölteni: frissítse az oldalt és próbálja meg újra.", - "%(brand)s Desktop (%(platformName)s)": "Asztali %(brand)s (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Nem támogatott böngésző", "Please install Chrome, Firefox, or Safari for the best experience.": "A legjobb élmény érdékében telepítsen Chrome-ot, Firefoxot vagy Safarit.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Folytathatja a jelenlegi böngészőjével, de néhány vagy az összes funkció használhatatlan lehet, vagy hibák lehetnek az alkalmazás kinézetében és viselkedésében.", diff --git a/src/i18n/strings/hy.json b/src/i18n/strings/hy.json index 8cfe9aa3a4..20e4f92a79 100644 --- a/src/i18n/strings/hy.json +++ b/src/i18n/strings/hy.json @@ -2,7 +2,6 @@ "Explore rooms": "Փնտրել սենյակներ", "Failed to start": "Չի ստացվում սկսել", "Use %(brand)s on mobile": "Օգտագործում է %(brand)s հեռախոսի վրա", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s%(browserName)s%(osName)s", "Unknown device": "Անծանոթ սարք", "Welcome to Element": "Բարի գալուստ Element", "Your browser can't run %(brand)s": "Ձեր բրաուզերը չի թողարկում %(brand)s", diff --git a/src/i18n/strings/id.json b/src/i18n/strings/id.json index 09c26763cb..496a4d0ae4 100644 --- a/src/i18n/strings/id.json +++ b/src/i18n/strings/id.json @@ -18,8 +18,6 @@ "Unsupported browser": "Peramban tidak didukung", "Use %(brand)s on mobile": "Gunakan %(brand)s di ponsel", "Powered by Matrix": "Diberdayakan oleh Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Open": "Buka", "Download Completed": "Unduhan Selesai", "Unexpected error preparing the app. See console for details.": "Kesalahan tak terduga saat menyiapkan aplikasi. Lihat konsol untuk detail.", diff --git a/src/i18n/strings/is.json b/src/i18n/strings/is.json index 5e5f3b746e..afb854c038 100644 --- a/src/i18n/strings/is.json +++ b/src/i18n/strings/is.json @@ -11,7 +11,6 @@ "The message from the parser is: %(message)s": "Skilaboðið frá þáttaranum er %(message)s", "Invalid JSON": "Ógilt JSON", "Download Completed": "Niðurhali lokið", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Please install Chrome, Firefox, or Safari for the best experience.": "Þú ættir að setja upp Chrome, Firefox, eða Safari til að fá sem besta útkomu.", "I understand the risks and wish to continue": "Ég skil áhættuna og óska að halda áfram", "Go to element.io": "Fara á element.io", @@ -21,7 +20,6 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s notar háþróaða vafraeiginleika sem eru ekki studdir af vafranum þínum.", "Powered by Matrix": "Keyrt með Matrix", "Go to your browser to complete Sign In": "Farðu í vafrann þinn til að ljúka innskráningu", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop fyrir vinnutölvur (%(platformName)s)", "Unable to load config file: please refresh the page to try again.": "Ekki er hægt að hlaða stillingaskrána: endurnýjaðu síðuna til að reyna aftur.", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Element-stillingar þínar innihalda ógilt JSON. Leiðréttu vandamálið og endurlestu síðuna.", "Your Element is misconfigured": "Element-tilvikið þitt er rangt stillt", diff --git a/src/i18n/strings/it.json b/src/i18n/strings/it.json index b5d5bf35e8..2cf7d68ff2 100644 --- a/src/i18n/strings/it.json +++ b/src/i18n/strings/it.json @@ -12,8 +12,6 @@ "Invalid JSON": "JSON non valido", "Go to your browser to complete Sign In": "Vai nel tuo browser per completare l'accesso", "Unable to load config file: please refresh the page to try again.": "Impossibile caricare il file di configurazione: ricarica la pagina per riprovare.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Browser non supportato", "Please install Chrome, Firefox, or Safari for the best experience.": "Installa Chrome, Firefox, o Safari per una migliore esperienza.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Puoi comunque usare il browser attuale, ma alcune o tutte le caratteristiche potrebbero non funzionare e l'aspetto dell'applicazione potrebbe essere sbagliato.", diff --git a/src/i18n/strings/ja.json b/src/i18n/strings/ja.json index 08899a6d3b..f544c8b1cd 100644 --- a/src/i18n/strings/ja.json +++ b/src/i18n/strings/ja.json @@ -16,9 +16,7 @@ "Unable to load config file: please refresh the page to try again.": "設定ファイルの読み込みに失敗しました:ページを再読み込みして、もう一度やり直してください。", "Download Completed": "ダウンロードが完了しました", "Open": "開く", - "%(brand)s Desktop (%(platformName)s)": "%(brand)sデスクトップ版(%(platformName)s)", "Go to your browser to complete Sign In": "ブラウザーに移動してサインインを完了してください", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s(%(browserName)s、%(osName)s)", "Unsupported browser": "サポートされていないブラウザー", "Go to element.io": "element.ioへ移動", "Failed to start": "起動に失敗しました", @@ -27,5 +25,8 @@ "Your browser can't run %(brand)s": "このブラウザーでは%(brand)sが動きません", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)sはブラウザーの高度な機能を使う必要がありますが、このブラウザーではその機能がサポートされていないようです。", "Powered by Matrix": "Powered by Matrix", - "Use %(brand)s on mobile": "携帯端末で%(brand)sを使用できます" + "Use %(brand)s on mobile": "携帯端末で%(brand)sを使用できます", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "$matrixLogo による、分散型で暗号化された会話とコラボレーション", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(osName)sの%(browserName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)sデスクトップ:%(platformName)s" } diff --git a/src/i18n/strings/jbo.json b/src/i18n/strings/jbo.json index 9d86787a0a..c1733e86b6 100644 --- a/src/i18n/strings/jbo.json +++ b/src/i18n/strings/jbo.json @@ -4,9 +4,7 @@ "Invalid JSON": ".i le veirdjeisano na drani", "Download Completed": ".i mo'u kibycpa", "Open": "nu viska", - "%(brand)s Desktop (%(platformName)s)": ".i la'o zoi. %(brand)s .zoi samtci .i le vanbi na kibrbrauzero .i la'o zoi. %(platformName)s .zoi samcmu", "Go to your browser to complete Sign In": ".i do ka'e pilno pa kibrbrauzero lo nu mo'u co'a jaspu", - "%(appName)s (%(browserName)s, %(osName)s)": ".i la'o zoi. %(appName)s .zoi samtci .i la'o zoi. %(browserName)s .zoi kibrbrauzero .i la'o zoi. %(osName)s .zoi samcmu", "Unsupported browser": ".i le kibrbrauzero na kakne", "Your browser can't run %(brand)s": ".i na ka'e pilno le kibrbrauzero lo nu pilno la'o zoi. %(brand)s .zoi", "%(brand)s uses advanced browser features which aren't supported by your current browser.": ".i la'o zoi. %(brand)s .zoi pilno pa na jai se kakne be le kibrbrauzero", diff --git a/src/i18n/strings/ka.json b/src/i18n/strings/ka.json index 8ed37d4154..02c152b7b0 100644 --- a/src/i18n/strings/ka.json +++ b/src/i18n/strings/ka.json @@ -5,7 +5,6 @@ "Explore rooms": "ოთახების დათავლიერება", "Failed to start": "ჩართვა ვერ მოხერხდა", "Use %(brand)s on mobile": "გამოიყენე %(brand)s-ი მობილურზე", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s დესკტოპი (%(platformName)s)", "Unexpected error preparing the app. See console for details.": "მოულოდნელი ერორი აპლიკაციის შემზადებისას. იხილეთ კონსოლი დეტალებისთვის.", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "თქვენი Element-ის კონფიგურაცია შეიცავს მიუღებელ JSON-ს. გთხოვთ გადაჭრათ პრობლემა და დაარაფრეშოთ გვერდი.", "Sign In": "შესვლა", @@ -20,7 +19,6 @@ "Your Element is misconfigured": "შენი Element-ი არასწორადაა კონფიგურირებული", "Please install Chrome, Firefox, or Safari for the best experience.": "გთხოვთ დააინსტალოთ Chrome-ი, Firefox-ი, ან Safari საუკეთესო გამოცდილებისთვის.", "Powered by Matrix": "მუშაობს Matrix-ის მეშვეობით", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Go to your browser to complete Sign In": "გახსენი ბრაუზერი Sign In-ის დასასრულებლად", "Open": "გახსნა", "Download Completed": "გადმოწერა დასრულებულია" diff --git a/src/i18n/strings/kab.json b/src/i18n/strings/kab.json index 456478211e..1ab3b7d7ac 100644 --- a/src/i18n/strings/kab.json +++ b/src/i18n/strings/kab.json @@ -1,9 +1,7 @@ { "Invalid JSON": "JSON armeɣtu", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s n tnarit (%(platformName)s)", "Go to your browser to complete Sign In": "Ddu ɣer iminig akken ad tkemleḍ ajerred", "Unknown device": "Ibenk arussin", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Create Account": "Rnu amiḍan", "Dismiss": "Agwi", "Sign In": "Kcem", diff --git a/src/i18n/strings/ko.json b/src/i18n/strings/ko.json index a5492f7775..79f4db1d04 100644 --- a/src/i18n/strings/ko.json +++ b/src/i18n/strings/ko.json @@ -11,9 +11,7 @@ "Create Account": "계정 만들기", "Explore rooms": "방 검색", "Unable to load config file: please refresh the page to try again.": "설정 파일을 불러오는 데 실패: 페이지를 새로고침한 후에 다시 시도해 주십시오.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s 데스크탑 (%(platformName)s)", "Go to your browser to complete Sign In": "로그인을 완료하려면 브라우저로 이동해주세요", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "지원되지 않는 브라우저", "Please install Chrome, Firefox, or Safari for the best experience.": "최상의 경험을 위해 Chrome, Firefox, 또는 Safari를 설치해주세요.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "현재 사용 중인 브라우저를 계속 사용할 수 있지만, 일부 기능들이 작동하지 않거나 애플리케이션이 올바르게 보여지지 않을 수 있습니다.", diff --git a/src/i18n/strings/lo.json b/src/i18n/strings/lo.json index 17d98ae967..0cc81e864f 100644 --- a/src/i18n/strings/lo.json +++ b/src/i18n/strings/lo.json @@ -15,10 +15,8 @@ "Unsupported browser": "ບໍ່ຮັບຮອງເວັບບຣາວເຊີນີ້", "Use %(brand)s on mobile": "ໃຊ້ມືຖື %(brand)s", "Powered by Matrix": "ສະໜັບສະໜູນໂດຍ Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unknown device": "ທີ່ບໍ່ຮູ້ຈັກອຸປະກອນນີ້", "Go to your browser to complete Sign In": "ໄປທີ່ໜ້າເວັບຂອງທ່ານເພື່ອເຂົ້າສູ່ລະບົບ", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s ຕັ້ງໂຕະ (%(platformName)s)", "Dismiss": "ຍົກເລີກ", "Download Completed": "ດາວໂຫຼດສຳເລັດແລ້ວ", "Unexpected error preparing the app. See console for details.": "ເກີດຄວາມຜິດພາດທີ່ບໍ່ຄາດຄິດໃນການກະກຽມແອັບຯ. ເບິ່ງ console ສໍາລັບລາຍລະອຽດ.", diff --git a/src/i18n/strings/lt.json b/src/i18n/strings/lt.json index 9b0dcaf13c..79384fc541 100644 --- a/src/i18n/strings/lt.json +++ b/src/i18n/strings/lt.json @@ -12,8 +12,6 @@ "Invalid configuration: no default server specified.": "Klaidinga konfigūracija: nenurodytas numatytasis serveris.", "Go to your browser to complete Sign In": "Norėdami užbaigti prisijungimą, eikite į naršyklę", "Unable to load config file: please refresh the page to try again.": "Nepavyko įkelti konfigūracijos failo: atnaujinkite puslapį, kad pabandytumėte dar kartą.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Kompiuteryje (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Nepalaikoma naršyklė", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Jūs galite toliau naudotis savo dabartine naršykle, bet kai kurios arba visos funkcijos gali neveikti ir programos išvaizda bei sąsaja gali būti neteisingai rodoma.", "I understand the risks and wish to continue": "Suprantu šią riziką ir noriu tęsti", @@ -28,5 +26,6 @@ "Please install Chrome, Firefox, or Safari for the best experience.": "Geriausiam veikimui suinstaliuokite Chrome, Firefox, arba Safari.", "Powered by Matrix": "Veikia su Matrix", "Use %(brand)s on mobile": "Naudoti %(brand)s mobiliajame telefone", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizuotas, užšifruotų pokalbių & bendradarbiavimas, paremtas $matrixLogo" + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizuotas, užšifruotų pokalbių & bendradarbiavimas, paremtas $matrixLogo", + "%(brand)s Desktop: %(platformName)s": "%(brand)s Kompiuteryje: %(platformName)s" } diff --git a/src/i18n/strings/lv.json b/src/i18n/strings/lv.json index 81131bb4ca..9d0abbc6cf 100644 --- a/src/i18n/strings/lv.json +++ b/src/i18n/strings/lv.json @@ -25,8 +25,6 @@ "Download Completed": "Lejuplāde pabeigta", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Jūsu Element konfigurācija satur kļūdainu JSON. Lūdzu, izlabojiet un pārlādējiet lapu.", "Your Element is misconfigured": "Jūsu Element ir nokonfigurēts kļūdaini", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Galdvirsmas (%(platformName)s)", "Use %(brand)s on mobile": "Mobilajā tālrunī izmanojiet %(brand)s", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentralizēta, šifrēta saziņa & sadarbība, ko nodrošina $matrixLogo" } diff --git a/src/i18n/strings/ml.json b/src/i18n/strings/ml.json index 2e004badf5..1b3c584589 100644 --- a/src/i18n/strings/ml.json +++ b/src/i18n/strings/ml.json @@ -1,7 +1,6 @@ { "Dismiss": "ഒഴിവാക്കുക", "Unknown device": "അപരിചിത ഡിവൈസ്", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s%(browserName)s%(osName)s", "Please install Chrome, Firefox, or Safari for the best experience.": "ദയവായി Chrome, Firefox, അല്ലെങ്കിൽ Safari ഇൻസ്റ്റാൾ ചെയ്യുക.", "Your Element is misconfigured": "നിങ്ങളുടെ Element തെറ്റായിട്ടാണ് കോൺഫിഗർ ചെയ്തിരിക്കുന്നത്", "Invalid configuration: no default server specified.": "അസാധുവായ കോൺഫിഗറേഷൻ: സ്ഥിര സെർവർ ഒന്നും വ്യക്തമാക്കിയില്ല.", diff --git a/src/i18n/strings/nb_NO.json b/src/i18n/strings/nb_NO.json index 9e5026486d..9564162841 100644 --- a/src/i18n/strings/nb_NO.json +++ b/src/i18n/strings/nb_NO.json @@ -24,8 +24,6 @@ "Your Element is misconfigured": "Ditt Element er feilkonfigurert", "Please install Chrome, Firefox, or Safari for the best experience.": "Vennligst installer Chrome, Firefox, eller Safari for den beste opplevelsen.", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s bruker avanserte nettleserfunksjoner som ikke støttes av din nåværende nettleser.", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Skrivebord (%(platformName)s)", "Open": "Åpne", "Use %(brand)s on mobile": "Bruk %(brand)s på mobil" } diff --git a/src/i18n/strings/ne.json b/src/i18n/strings/ne.json index a069595e58..b19a309e64 100644 --- a/src/i18n/strings/ne.json +++ b/src/i18n/strings/ne.json @@ -1,8 +1,6 @@ { "Please install Chrome, Firefox, or Safari for the best experience.": "सर्वोत्तम अनुभव के लिए कृपया Chrome, Firefox, या Safari इंस्टॉल करें।", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s उन्नत ब्राउज़र सुविधाओं का उपयोग करते हैं जो आपके वर्तमान ब्राउज़र द्वारा समर्थित नहीं हैं।", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s का डेस्कटॉप (%(platformName)s)", "Sign In": "साइन करना", "Explore rooms": "रूम का अन्वेषण करें", "Create Account": "खाता बनाएं", diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json index 56f8a3d15c..1705f746bf 100644 --- a/src/i18n/strings/nl.json +++ b/src/i18n/strings/nl.json @@ -10,23 +10,23 @@ "Invalid configuration: no default server specified.": "Configuratie ongeldig: geen standaardserver opgegeven.", "The message from the parser is: %(message)s": "De ontleder meldt: %(message)s", "Invalid JSON": "Ongeldige JSON", - "Go to your browser to complete Sign In": "Ga naar uw browser om de aanmelding te voltooien", - "Unable to load config file: please refresh the page to try again.": "Kan het configuratiebestand niet laden. Herlaad de pagina alstublieft.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", + "Go to your browser to complete Sign In": "Ga naar je browser om de aanmelding te voltooien", + "Unable to load config file: please refresh the page to try again.": "Kan het configuratiebestand niet laden. Herlaad de pagina.", "Unsupported browser": "Niet-ondersteunde browser", "Please install Chrome, Firefox, or Safari for the best experience.": "Installeer Chrome, Firefox, of Safari voor de beste gebruikservaring.", - "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "U kunt uw huidige browser blijven gebruiken, maar sommige of alle functies zouden niet kunnen werken en de weergave van het programma kan verkeerd zijn.", + "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Je kan je huidige browser blijven gebruiken, maar sommige of alle functies zouden niet kunnen werken en de weergave van het programma kan verkeerd zijn.", "I understand the risks and wish to continue": "Ik begrijp de risico's en wil verder gaan", "Go to element.io": "Ga naar element.io", "Failed to start": "Opstarten mislukt", "Open": "Openen", - "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Uw Element configuratie bevat ongeldige JSON. Gelieve het probleem te corrigeren daarna de pagina te herladen.", + "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Jouw Element configuratie bevat ongeldige JSON. Corrigeer het probleem en herlaad de pagina.", "Download Completed": "Download voltooid", - "Your Element is misconfigured": "Uw Element is verkeerd geconfigureerd", - "Your browser can't run %(brand)s": "Uw browser kan %(brand)s niet starten", - "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s gebruikt geavanceerde functies die niet ondersteund worden in uw huidige browser.", + "Your Element is misconfigured": "Jouw Element is verkeerd geconfigureerd", + "Your browser can't run %(brand)s": "Jouw browser kan %(brand)s niet starten", + "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s gebruikt geavanceerde functies die niet ondersteund worden in je huidige browser.", "Powered by Matrix": "Mogelijk gemaakt door Matrix", - "Use %(brand)s on mobile": "Gebruik %(brand)s op uw mobiel", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Gedecentraliseerde, versleutelde chat & samenwerking mogelijk gemaakt door $matrixLogo" + "Use %(brand)s on mobile": "Gebruik %(brand)s op je mobiel", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Gedecentraliseerde, versleutelde chat & samenwerking mogelijk gemaakt door $matrixLogo", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s op %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s Desktop: %(platformName)s" } diff --git a/src/i18n/strings/nn.json b/src/i18n/strings/nn.json index cc99ddef40..cf3b36c4eb 100644 --- a/src/i18n/strings/nn.json +++ b/src/i18n/strings/nn.json @@ -16,14 +16,12 @@ "Unsupported browser": "Nettlesaren er ikkje støtta", "Your browser can't run %(brand)s": "Din nettlesar kan ikkje køyra %(brand)s", "Go to element.io": "Gå til element.io", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Du kan fortsetja å bruka gjeldande nettlesar, men nokre eller alle funksjonane fungerer kanskje ikkje, og utsjånaden og kjensla av applikasjonen kan vera feil.", "Please install Chrome, Firefox, or Safari for the best experience.": "Installer Chrome, Firefox, eller Safari for den beste opplevinga.", "I understand the risks and wish to continue": "Eg forstår risikoen og ynskjer å fortsetja", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s brukar avanserte nettlesarfunksjonar som ikkje er støtta av den gjeldande nettlesaren din.", "Use %(brand)s on mobile": "Bruk %(brand)s på mobil", "Powered by Matrix": "Driven av Matrix", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Skrivebord (%(platformName)s)", "Your Element is misconfigured": "Element er feilkonfigurert", "Failed to start": "Klarte ikkje å starta", "Open": "Opna", diff --git a/src/i18n/strings/oc.json b/src/i18n/strings/oc.json index 7fac35a6c2..5cdb14857d 100644 --- a/src/i18n/strings/oc.json +++ b/src/i18n/strings/oc.json @@ -20,8 +20,6 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s utiliza de foncions avançadas que lo vòstre navigator non suporta pas.", "Unsupported browser": "Navigator incompatible", "Powered by Matrix": "Fonciona ambé Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s de burèu (%(platformName)s)", "Open": "Dobrir", "Download Completed": "Descargament acabat", "Unable to load config file: please refresh the page to try again.": "Se pòt pas cargar lo fichièr de configuracion : si vos plai actualizatz la pagina per tornar ensajar.", diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json index bf3bd140fd..a22430ebed 100644 --- a/src/i18n/strings/pl.json +++ b/src/i18n/strings/pl.json @@ -12,8 +12,6 @@ "Invalid configuration: no default server specified.": "Błędna konfiguracja: nie wybrano domyślnego serwera.", "Go to your browser to complete Sign In": "Aby dokończyć proces rejestracji, przejdź do swojej przeglądarki", "Unable to load config file: please refresh the page to try again.": "Nie udało się załadować pliku konfiguracyjnego: odśwież stronę aby spróbować ponownie.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Niewspierana przeglądarka", "Please install Chrome, Firefox, or Safari for the best experience.": "Zainstaluj Chrome, Firefox, lub Safari w celu zapewnienia najlepszego działania.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Możesz kontynuować używając obecnej przeglądarki, lecz niektóre lub wszystkie funkcje mogą nie działać oraz wygląd aplikacji może być niepoprawny.", @@ -28,8 +26,5 @@ "Your Element is misconfigured": "Twój Element jest nieprawidłowo skonfigurowany", "Powered by Matrix": "Zasilane przez Matrix", "Use %(brand)s on mobile": "Użyj %(brand)s w telefonie", - "Switch to space by number": "Przełącz na przestrzeń według numeru", - "Next recently visited room or community": "Następne ostatnio odwiedzone pokoje i społeczności", - "Previous recently visited room or community": "Ostatnio odwiedzone pokoje i społeczności", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Zdecentralizowany, szyfrowany czat i współpraca oparte na $matrixLogo" } diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json index f17c9fb67b..b9ad18258d 100644 --- a/src/i18n/strings/pt.json +++ b/src/i18n/strings/pt.json @@ -17,7 +17,6 @@ "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "A configuração do Element contém um JSON inválido. Corrija o problema e recarregue a página.", "Your Element is misconfigured": "O Element está configurado incorretamente", "Powered by Matrix": "Desenvolvido por Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (2%(browserName)s, 3%(osName)s)", "Go to element.io": "Visite element.io", "I understand the risks and wish to continue": "Compreendo os riscos e pretendo continuar", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Podes continuar a utilizar teu browser atual, mas algumas funcionalidades podem não funcionar ou aparecerem de forma incorrecta.", diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 7ee1f3fa60..298a316440 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -12,7 +12,6 @@ "Invalid configuration: no default server specified.": "Configuração inválida: nenhum servidor default especificado.", "Unable to load config file: please refresh the page to try again.": "Incapaz de carregar arquivo de config: por favor atualize a página para tentar de novo.", "Download Completed": "Download Completado", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Browser insuportado", "Please install Chrome, Firefox, or Safari for the best experience.": "Por favor instale Chrome, Firefox, ou Safari para a melhor experiência.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Você pode continuar usando seu browser atual, mas alguma ou toda funcionalidade pode não funcionar e a aparência e sensação do aplicativo pode estar incorretas.", @@ -20,7 +19,6 @@ "Go to element.io": "Ir para element.io", "Failed to start": "Falha para iniciar", "Open": "Abrir", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Go to your browser to complete Sign In": "Vá para seu browser para completar Sign In", "Your Element is misconfigured": "Seu Element está malconfigurado", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Sua configuração de Element contém JSON inválido. Por favor corrija o problema e recarregue a página.", diff --git a/src/i18n/strings/ro.json b/src/i18n/strings/ro.json index 408624d327..2c6f360c8d 100644 --- a/src/i18n/strings/ro.json +++ b/src/i18n/strings/ro.json @@ -1,31 +1,32 @@ { - "Unknown device": "Device necunoscut", + "Unknown device": "Dispozitiv necunoscut", "Dismiss": "Închide", - "Welcome to Element": "Bun venit pe Element", - "Sign In": "Autentificare", - "Create Account": "Crează un cont", + "Welcome to Element": "Bine ai venit pe Element", + "Sign In": "Autentifică-te", + "Create Account": "Creează-ți Cont", "Explore rooms": "Explorează camerele", - "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configuratie invalida: se poate specifica doar una dintre default_server_config, default_server_name, or default_hs_url.", + "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Configurație invalidă: se poate specifica doar una dintre default_server_config, default_server_name, sau default_hs_url.", "Invalid JSON": "JSON invalid", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Acest browser nu este suportat", - "Please install Chrome, Firefox, or Safari for the best experience.": "Instalati va rog Chrome, Firefox, or Safari pentru o experienta mai buna.", - "I understand the risks and wish to continue": "Inteleg riscul si doresc sa continui", - "Go to element.io": "Acceseaza element.io", - "Failed to start": "Nu reuseste sa porneasca", + "Please install Chrome, Firefox, or Safari for the best experience.": "Instalați vă rog Chrome, Firefox, sau Safari pentru cea mai bună experiență.", + "I understand the risks and wish to continue": "Ințeleg riscurile și doresc să continui", + "Go to element.io": "Accesează element.io", + "Failed to start": "Inițializare eșuată", "Your Element is misconfigured": "Element-ul tău este configurat necorespunzător", - "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Poți continua să folosești browser-ul curent, însă aspectul și experiența câtorva sau tuturor funcțiilor poate fi incorectă.", + "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Poți continua să folosești browser-ul curent, însă unele sau toate funcționalitățile pot să nu meargă, iar aspectul și experiența în aplicație pot fi incorecte.", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s folosește funcții avansate de browser ce nu sunt suportate de browser-ul dumneavoastră.", - "Your browser can't run %(brand)s": "Browserul tău nu poate rula %(brand)s", + "Your browser can't run %(brand)s": "Browser-ul tău nu poate rula %(brand)s", "Use %(brand)s on mobile": "Folosește %(brand)s pe mobil", - "Powered by Matrix": "Bazat pe Matrix", - "Go to your browser to complete Sign In": "Du-te la browser pentru a finaliza Autentificarea", + "Powered by Matrix": "Cu ajutorul Matrix", + "Go to your browser to complete Sign In": "Deschide în browser pentru a finaliza Autentificarea", "Open": "Deschide", "Download Completed": "Descărcare Completă", "Unexpected error preparing the app. See console for details.": "Eroare neașteptată în aplicație. Vezi consola pentru detalii.", - "Unable to load config file: please refresh the page to try again.": "Nu se poate încărca fișierul de configurație: vă rugăm sa reîncărcați pagina și să încercați din nou.", + "Unable to load config file: please refresh the page to try again.": "Nu se poate încărca fișierul de configurație: vă rugăm să reîncărcați pagina și să încercați din nou.", "The message from the parser is: %(message)s": "Mesajul de la parser este: %(message)s", - "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Configurația ta Element conține JSON invalid. Vă rugăm sa corectați problema și să reîncărcați pagina.", - "Invalid configuration: no default server specified.": "Configurație invalidă: niciun server implicit specificat." + "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Configurația ta Element conține JSON invalid. Vă rugăm să corectați problema și să reîncărcați pagina.", + "Invalid configuration: no default server specified.": "Configurație invalidă: niciun server implicit nu este specificat.", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s pe %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s Desktop: %(platformName)s", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Chat & colaborare descentralizate și criptate cu ajutorul $matrixLogo" } diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index daca759c69..5b7b8c4115 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -12,8 +12,6 @@ "Invalid JSON": "Неверный JSON", "Go to your browser to complete Sign In": "Перейдите в браузер для завершения входа", "Unable to load config file: please refresh the page to try again.": "Не удалось загрузить файл конфигурации. Попробуйте обновить страницу.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s десктоп (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Неподдерживаемый браузер", "Please install Chrome, Firefox, or Safari for the best experience.": "Пожалуйста поставьте Chrome, Firefox, или Safari для лучшей совместимости.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Вы можете продолжать пользоваться этим браузером, но некоторые возможности будут недоступны и интерфейс может быть отрисован неправильно.", diff --git a/src/i18n/strings/si.json b/src/i18n/strings/si.json index bbcea6a5fd..cbb9c872e3 100644 --- a/src/i18n/strings/si.json +++ b/src/i18n/strings/si.json @@ -1,6 +1,5 @@ { "Unknown device": "නොදන්නා උපාංගයකි", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Welcome to Element": "ඉලමන්ට් වෙත සාදරයෙන් පිළිගනිමු", "Open": "විවෘත කරන්න", "Powered by Matrix": "මැට්‍රික්ස් මඟින් බලගන්වා ඇත", @@ -27,6 +26,5 @@ "I understand the risks and wish to continue": "අවදානම වැටහේ, ඉදිරියට යාමට කැමැත්තෙමි", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "විමධ්‍යගත, සංකේතිත කතාබහ සහ amp; $matrixLogo මගින් බලගැන්වූ සහයෝගිත්වය", "Use %(brand)s on mobile": "දුරකථනය සඳහා %(brand)s", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s වැඩතලය (%(platformName)s)", "Invalid JSON": "JSON වලංගු නොවේ" } diff --git a/src/i18n/strings/sk.json b/src/i18n/strings/sk.json index 135479e0f4..6bcf13747c 100644 --- a/src/i18n/strings/sk.json +++ b/src/i18n/strings/sk.json @@ -12,8 +12,6 @@ "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "Neplatná konfigurácia: je možné špecifikovať len jednu možnosť z default_server_config, default_server_name, alebo default_hs_url.", "Unable to load config file: please refresh the page to try again.": "Nemožno načítať konfiguračný súbor: prosím obnovte stránku a skúste to znova.", "Go to your browser to complete Sign In": "Prejdite do prehliadača a dokončite prihlásenie", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Nepodporovaný prehliadač", "Please install Chrome, Firefox, or Safari for the best experience.": "Prosím, nainštalujte si Chrome, Firefox alebo Safari pre najlepší zážitok.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Môžete naďalej používať váš súčasný prehliadač, ale niektoré alebo všetky funkcie nemusia fungovať a zážitok z aplikácie nemusí byť optimálny.", diff --git a/src/i18n/strings/sl.json b/src/i18n/strings/sl.json index 809eeb780a..c3b7677005 100644 --- a/src/i18n/strings/sl.json +++ b/src/i18n/strings/sl.json @@ -15,9 +15,7 @@ "Unexpected error preparing the app. See console for details.": "Nepričakovana napaka pri pripravi aplikacije: Za več poglejte konzolo.", "Download Completed": "Prenos zaključen", "Open": "Odpri", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s namizje za (%(platformName)s)", "Go to your browser to complete Sign In": "Nadaljujte s prijavo v spletnem brskalniku", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Powered by Matrix": "Poganja Matrix", "Unsupported browser": "Nepodprt brskalnik", "Your browser can't run %(brand)s": "Vaš brskalnik ne more poganjati %(brand)s", @@ -27,5 +25,8 @@ "I understand the risks and wish to continue": "Razumem riziko in želim vseeno nadaljevati", "Go to element.io": "Pojdi na element.io", "Failed to start": "Neuspel zagon", - "Use %(brand)s on mobile": "Uporabi %(brand)s na mobilni napravi" + "Use %(brand)s on mobile": "Uporabi %(brand)s na mobilni napravi", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Decentraliziran, šifriran pogovor in sodelovanje, omogočen z $matrixLogo", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s na %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s Namizni računalnik: %(platformName)s" } diff --git a/src/i18n/strings/sq.json b/src/i18n/strings/sq.json index da0efa28cb..4911cc2d3e 100644 --- a/src/i18n/strings/sq.json +++ b/src/i18n/strings/sq.json @@ -12,8 +12,6 @@ "Invalid JSON": "JSON i pavlefshëm", "Go to your browser to complete Sign In": "Që të plotësoni Hyrjen, kaloni te shfletuesi juaj", "Unable to load config file: please refresh the page to try again.": "S’arrihet të ngarkohet kartelë formësimesh: ju lutemi, rifreskoni faqen dhe riprovoni.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Shfletues i pambuluar", "Please install Chrome, Firefox, or Safari for the best experience.": "Ju lutemi, për funksionimin më të mirë, instaloni Chrome, Firefox, ose Safari.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Mund të vazhdoni të përdorni shfletuesin tuaj të tanishëm, por disa ose krejt veçoritë mund të mos funksionojnë dhe pamja dhe ndjesitë prej aplikacionit të mos jenë të sakta.", @@ -28,5 +26,7 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s përdor veçori të thelluara të shfletuesit, të cilat shfletuesi juaj i tanishëm s’i mbulon.", "Powered by Matrix": "Bazuar në Matrix", "Use %(brand)s on mobile": "Përdor %(brand)s në celular", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Fjalosje & bashkëpunim i decentralizuar, i fshehtëzuar, bazuar në $matrixLogo" + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Fjalosje & bashkëpunim i decentralizuar, i fshehtëzuar, bazuar në $matrixLogo", + "%(brand)s Desktop: %(platformName)s": "%(brand)s për Desktop: %(platformName)s", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s në %(osName)s" } diff --git a/src/i18n/strings/sr.json b/src/i18n/strings/sr.json index b835638c90..3797e6107b 100644 --- a/src/i18n/strings/sr.json +++ b/src/i18n/strings/sr.json @@ -15,9 +15,7 @@ "Unable to load config file: please refresh the page to try again.": "Не могу да учитам датотеку подешавања: освежите страницу и покушајте поново.", "Download Completed": "Преузимање завршено", "Open": "Отвори", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s радна површ (%(platformName)s)", "Go to your browser to complete Sign In": "Отворите ваш прегледач за довршавање пријаве", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Неподржан прегледач", "Your browser can't run %(brand)s": "Ваш прегледач не може покретати %(brand)s", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s користи напредне могућности које нису подржане у вашем тренутном прегледачу.", diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json index b4f5e05e6c..6bdebea183 100644 --- a/src/i18n/strings/sv.json +++ b/src/i18n/strings/sv.json @@ -12,8 +12,6 @@ "Invalid configuration: no default server specified.": "Ogiltiga inställningar: ingen standardserver specificerad.", "Go to your browser to complete Sign In": "Gå till din webbläsare för att slutföra inloggningen", "Unable to load config file: please refresh the page to try again.": "Kan inte ladda konfigurationsfilen: ladda om sidan för att försöka igen.", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s skrivbord (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "Webbläsaren stöds ej", "Please install Chrome, Firefox, or Safari for the best experience.": "Installera Chrome, Firefox, eller Safari för den bästa upplevelsen.", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "Du kan fortsätta använda din nuvarande webbläsare, men vissa eller alla funktioner kanske inte fungerar och utseendet och känslan av applikationen kan var felaktig.", diff --git a/src/i18n/strings/ta.json b/src/i18n/strings/ta.json index 5efa6310af..d940009a1a 100644 --- a/src/i18n/strings/ta.json +++ b/src/i18n/strings/ta.json @@ -20,13 +20,13 @@ "Your browser can't run %(brand)s": "உங்கள் உலாவியில் %(brand)s ஐ இயக்க முடியாது", "Unsupported browser": "ஆதரிக்கப்படாத உலாவி", "Use %(brand)s on mobile": "%(brand)s ஐ திறன்பேசியில் பயன்படுத்தவும்", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Go to your browser to complete Sign In": "உள்நுழைவை முடிவுசெய்ய உங்கள் உலாவிக்குச் செல்லவும்", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s திரைமுகப்பு (%(platformName)s)", "Open": "திற", "Download Completed": "பதிவிறக்கம் முடிவடைந்தது", "Unable to load config file: please refresh the page to try again.": "கட்டமைப்பு கோப்பை ஏற்ற முடியவில்லை: மீண்டும் முயற்சிக்க பக்கத்தைப் புதுப்பிக்கவும்.", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "உங்கள் எலிமெண்ட் உள்ளமைவில் தவறான JSON உள்ளது. தயவுசெய்து இதை சரிசெய்து பக்கத்தை மீண்டும் ஏற்றவும்.", "Your Element is misconfigured": "உங்கள் எலிமெண்ட் தவறாக உள்ளமைக்கப்பட்டுள்ளது", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "மேட்ரிக்ஸ் இனால் செயற்படுத்தபடுகின்ற பரவலாக்கப்பட்ட, மறைகுறியாக்கப்பட்ட , உரையாடல் மற்றும் ஒத்துழைப்பு பயன்பாட்டை" + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "மேட்ரிக்ஸ் இனால் செயற்படுத்தபடுகின்ற பரவலாக்கப்பட்ட, மறைகுறியாக்கப்பட்ட , உரையாடல் மற்றும் ஒத்துழைப்பு பயன்பாட்டை", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s: %(browserName)s இல் %(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s டெஸ்க்டாப்: %(platformName)s" } diff --git a/src/i18n/strings/tchap_translations.json b/src/i18n/strings/tchap_translations.json index c3de4cf296..deb7d5ba3c 100644 --- a/src/i18n/strings/tchap_translations.json +++ b/src/i18n/strings/tchap_translations.json @@ -346,7 +346,7 @@ "en": "Import from saved file", "fr": "Importer depuis le fichier sauvegardé" }, - "Sign out all devices": { + "Lock my messages and disconnect me from all my devices (in case your account is hacked or a device loss)": { "en": "Lock my messages and disconnect me from all my devices (in case your account is hacked or a device loss)", "fr": "Verrouiller mes messages et me déconnecter de tous mes appareils (en cas de piratage de votre compte ou perte d'un appareil)" }, @@ -553,8 +553,8 @@ }, "Show all your rooms in Home, even if they're in a space." : { "en": "Show all your rooms in Home", - "fr": "Affiche tous vos salons dans l’accueil" - }, + "fr": "Affiche tous vos salons dans l’accueil" + }, "This groups your chats with members of this space. Turning this off will hide those chats from your view of %(spaceName)s." : { "fr": "Cela rassemble vos messages directs avec les membres de cet espace. Le désactiver masquera ces salons de votre vue de %(spaceName)s.", "en": "This groups your direct messages with members of this space. Turning this off will hide those rooms from your view of %(spaceName)s." diff --git a/src/i18n/strings/te.json b/src/i18n/strings/te.json index 13d52b5a3f..b6917ddc74 100644 --- a/src/i18n/strings/te.json +++ b/src/i18n/strings/te.json @@ -9,6 +9,5 @@ "Create Account": "ఖాతా తెరువు", "Open": "తెరువు", "Download Completed": "దిగుమతి పూర్తయినది", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s డస్కటాప్ (%(platformName)s)", "Unexpected error preparing the app. See console for details.": "ఆప్ ని తయారు చేసే ప్రక్రియాలో అనుకోని లోపం తలెత్తింది. మరిన్ని వివరాల కోసం కాన్సోల్ ను చూడండి." } diff --git a/src/i18n/strings/th.json b/src/i18n/strings/th.json index c7f701eec5..c05c081899 100644 --- a/src/i18n/strings/th.json +++ b/src/i18n/strings/th.json @@ -20,6 +20,5 @@ "I understand the risks and wish to continue": "ฉันเข้าใจความเสี่ยง และดำเนินการต่อ", "Please install Chrome, Firefox, or Safari for the best experience.": "กรุณาติดตั้ง Chrome, Firefox, หรือ Safari เพื่อประสิทธิภาพการใช้งานที่ดีที่สุด.", "Your browser can't run %(brand)s": "เบราว์เซอร์ของคุณไม่สามารถใช้งาน %(brand)s ได้", - "Unsupported browser": "เบราว์เซอร์ไม่รองรับ", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)" + "Unsupported browser": "เบราว์เซอร์ไม่รองรับ" } diff --git a/src/i18n/strings/tr.json b/src/i18n/strings/tr.json index b1d13eaf44..aed0f38bb3 100644 --- a/src/i18n/strings/tr.json +++ b/src/i18n/strings/tr.json @@ -24,8 +24,6 @@ "Go to element.io": "element.io adresine git", "Failed to start": "Başlatılamadı", "Powered by Matrix": "Gücünü Matrix'ten alır", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Masaüstü (%(platformName)s)", "Open": "Aç", "Use %(brand)s on mobile": "Mobilde %(brand)s kullan", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "$matrixLogo tarafından merkeziyetsiz, şifrelenmiş sohbet & iş birliği" diff --git a/src/i18n/strings/tzm.json b/src/i18n/strings/tzm.json index 83459670f4..4590f58a73 100644 --- a/src/i18n/strings/tzm.json +++ b/src/i18n/strings/tzm.json @@ -6,7 +6,6 @@ "Go to your browser to complete Sign In": "Ddu ɣer umessara fad ad tsemded azemmem", "Welcome to Element": "Azul g Element", "Go to element.io": "Ddu ɣer element.io", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unknown device": "Allal arussin", "Dismiss": "Nexxel", "Open": "Ṛẓem", diff --git a/src/i18n/strings/uk.json b/src/i18n/strings/uk.json index ea334a0064..36b0e9d567 100644 --- a/src/i18n/strings/uk.json +++ b/src/i18n/strings/uk.json @@ -21,9 +21,7 @@ "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Ваша конфігурація Element містить хибний JSON. Виправте проблему та оновіть сторінку.", "Unable to load config file: please refresh the page to try again.": "Неможливо завантажити файл конфігурації. Оновіть, будь ласка, сторінку, щоб спробувати знову.", "Open": "Відкрити", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Desktop (%(platformName)s)", "Go to your browser to complete Sign In": "Перейдіть у ваш браузер щоб завершити вхід", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Powered by Matrix": "Працює на Matrix", "Your browser can't run %(brand)s": "Ваш браузер не може запустити %(brand)s", "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s використовує передові властивості, які ваш браузер не підтримує.", diff --git a/src/i18n/strings/vi.json b/src/i18n/strings/vi.json index 6835b4c761..ad7234a426 100644 --- a/src/i18n/strings/vi.json +++ b/src/i18n/strings/vi.json @@ -19,13 +19,11 @@ "Your browser can't run %(brand)s": "Trình duyệt của bạn không thể chạy %(brand)s", "Unsupported browser": "Trình duyệt không được hỗ trợ", "Go to your browser to complete Sign In": "Mở trình duyệt web để hoàn thành đăng nhập", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s Máy tính để bàn (%(platformName)s)", "Open": "Mở", "Unable to load config file: please refresh the page to try again.": "Không thể tải tệp cấu hình: hãy tải lại trang để thử lại.", "Failed to start": "Khởi động thất bại", "Use %(brand)s on mobile": "Sử dụng %(brand)s trên di động", "Powered by Matrix": "Được chạy trên giao thức Matrix", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.": "Thiết lập Element của bạn chứa JSON không hợp lệ. Vui lòng sửa vấn đề và tải lại trang.", "Your Element is misconfigured": "Element của bạn bị thiết lập sai", "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "Dịch vụ chat & liên lạc đã được mã hóa, phi tập trung. Được cung cấp bởi $matrixLogo" diff --git a/src/i18n/strings/zh_Hans.json b/src/i18n/strings/zh_Hans.json index bb93cc7a6b..3cd191ea10 100644 --- a/src/i18n/strings/zh_Hans.json +++ b/src/i18n/strings/zh_Hans.json @@ -11,9 +11,7 @@ "Invalid configuration: can only specify one of default_server_config, default_server_name, or default_hs_url.": "配置无效:只能指定default_server_config、default_server_name或default_hs_url其中之一。", "Invalid configuration: no default server specified.": "配置无效:没有指定默认服务器。", "Unable to load config file: please refresh the page to try again.": "无法加载配置文件:请刷新页面以重试。", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s 桌面版(%(platformName)s)", "Go to your browser to complete Sign In": "转到您的浏览器以完成登录", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s(%(browserName)s,%(osName)s)", "Unsupported browser": "不支持的浏览器", "Please install Chrome, Firefox, or Safari for the best experience.": "请安装 ChromeFirefoxSafari 以获得最佳体验。", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "您可以继续使用您目前的浏览器,但部分或全部功能可能无法正常工作,应用程序的外观可能也看起来不正确。", @@ -28,6 +26,7 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "当前浏览器不支持 %(brand)s 所需的高级浏览器特性。", "Powered by Matrix": "由 Matrix 驱动", "Use %(brand)s on mobile": "在移动设备上使用 %(brand)s", - "Switch to space by number": "按数字切换空间", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "去中心化、加密的聊天与协作,由 $matrixLogo 驱动" + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "去中心化、加密的聊天与协作,由 $matrixLogo 驱动", + "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s:%(browserName)s在%(osName)s", + "%(brand)s Desktop: %(platformName)s": "%(brand)s桌面版:%(platformName)s" } diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index 881918da50..fafcc895a4 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -12,8 +12,6 @@ "Invalid JSON": "無效的 JSON", "Go to your browser to complete Sign In": "到您的瀏覽器完成登入", "Unable to load config file: please refresh the page to try again.": "無法載入設定檔:請重新整理頁面以再試一次。", - "%(brand)s Desktop (%(platformName)s)": "%(brand)s 桌面版 (%(platformName)s)", - "%(appName)s (%(browserName)s, %(osName)s)": "%(appName)s (%(browserName)s, %(osName)s)", "Unsupported browser": "不支援的瀏覽器", "Please install Chrome, Firefox, or Safari for the best experience.": "請安裝 ChromeFirefoxSafari 以取得最佳體驗。", "You can continue using your current browser, but some or all features may not work and the look and feel of the application may be incorrect.": "您可以繼續使用您目前的瀏覽器,但部份或全部的功能可能會無法運作,而應用程式的外觀與感覺可能也會不正確。", @@ -28,7 +26,7 @@ "%(brand)s uses advanced browser features which aren't supported by your current browser.": "%(brand)s 使用了您目前的瀏覽器不支援的進階瀏覽器功能。", "Powered by Matrix": "由 Matrix 提供", "Use %(brand)s on mobile": "在行動裝置上使用 %(brand)s", - "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "去中心化、加密的聊天與協作,威力本源 $matrixLogo", + "Decentralised, encrypted chat & collaboration powered by $matrixLogo": "去中心化、加密的聊天與協作,由 $matrixLogo 驅動", "%(appName)s: %(browserName)s on %(osName)s": "%(appName)s:%(browserName)s 在 %(osName)s 上", "%(brand)s Desktop: %(platformName)s": "%(brand)s 桌面版:%(platformName)s" } diff --git a/src/vector/app.tsx b/src/vector/app.tsx index b63e22a891..5e0cec7f90 100644 --- a/src/vector/app.tsx +++ b/src/vector/app.tsx @@ -21,10 +21,10 @@ limitations under the License. // To ensure we load the browser-matrix version first import "matrix-js-sdk/src/browser-index"; -import React from 'react'; -import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg'; -import { _td, newTranslatableError } from 'matrix-react-sdk/src/languageHandler'; -import AutoDiscoveryUtils from 'matrix-react-sdk/src/utils/AutoDiscoveryUtils'; +import React, { ReactElement } from "react"; +import PlatformPeg from "matrix-react-sdk/src/PlatformPeg"; +import { _td, newTranslatableError } from "matrix-react-sdk/src/languageHandler"; +import AutoDiscoveryUtils from "matrix-react-sdk/src/utils/AutoDiscoveryUtils"; import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery"; import * as Lifecycle from "matrix-react-sdk/src/Lifecycle"; import SdkConfig, { parseSsoRedirectOptions } from "matrix-react-sdk/src/SdkConfig"; @@ -34,7 +34,7 @@ import { createClient } from "matrix-js-sdk/src/matrix"; import { SnakedObject } from "matrix-react-sdk/src/utils/SnakedObject"; import MatrixChat from "matrix-react-sdk/src/components/structures/MatrixChat"; -import { parseQs } from './url_utils'; +import { parseQs } from "./url_utils"; import VectorBasePlatform from "./platform/VectorBasePlatform"; import { getScreenFromLocation, init as initRouting, onNewScreen } from "./routing"; @@ -55,33 +55,28 @@ window.matrixLogger = logger; // If we're in electron, we should never pass through a file:// URL otherwise // the identity server will try to 302 the browser to it, which breaks horribly. // so in that instance, hardcode to use app.element.io for now instead. -function makeRegistrationUrl(params: object) { +function makeRegistrationUrl(params: object): string { let url; if (window.location.protocol === "vector:") { - url = 'https://app.element.io/#/register'; + url = "https://app.element.io/#/register"; } else { - url = ( - window.location.protocol + '//' + - window.location.host + - window.location.pathname + - '#/register' - ); + url = window.location.protocol + "//" + window.location.host + window.location.pathname + "#/register"; } const keys = Object.keys(params); for (let i = 0; i < keys.length; ++i) { if (i === 0) { - url += '?'; + url += "?"; } else { - url += '&'; + url += "&"; } const k = keys[i]; - url += k + '=' + encodeURIComponent(params[k]); + url += k + "=" + encodeURIComponent(params[k]); } return url; } -function onTokenLoginCompleted() { +function onTokenLoginCompleted(): void { // if we did a token login, we're now left with the token, hs and is // url as query params in the url; a little nasty but let's redirect to // clear them. @@ -93,13 +88,13 @@ function onTokenLoginCompleted() { window.history.replaceState(null, "", url.href); } -export async function loadApp(fragParams: {}) { +export async function loadApp(fragParams: {}): Promise { initRouting(); const platform = PlatformPeg.get(); const params = parseQs(window.location); - const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname; + const urlWithoutQuery = window.location.protocol + "//" + window.location.host + window.location.pathname; logger.log("Vector starting at " + urlWithoutQuery); (platform as VectorBasePlatform).startUpdater(); @@ -115,7 +110,7 @@ export async function loadApp(fragParams: {}) { const ssoRedirects = parseSsoRedirectOptions(config); let autoRedirect = ssoRedirects.immediate === true; // XXX: This path matching is a bit brittle, but better to do it early instead of in the app code. - const isWelcomeOrLanding = window.location.hash === '#/welcome' || window.location.hash === '#'; + const isWelcomeOrLanding = window.location.hash === "#/welcome" || window.location.hash === "#"; if (!autoRedirect && ssoRedirects.on_welcome_page && isWelcomeOrLanding) { autoRedirect = true; } @@ -133,20 +128,21 @@ export async function loadApp(fragParams: {}) { return; } - const defaultDeviceName = snakedConfig.get("default_device_display_name") - ?? platform.getDefaultDeviceDisplayName(); - - return ; + const defaultDeviceName = snakedConfig.get("default_device_display_name") ?? platform.getDefaultDeviceDisplayName(); + + return ( + + ); } async function verifyServerConfig(): Promise { @@ -164,18 +160,20 @@ async function verifyServerConfig(): Promise { // validators for that purpose. const config = SdkConfig.get(); - let wkConfig = config['default_server_config']; // overwritten later under some conditions - const serverName = config['default_server_name']; - const hsUrl = config['default_hs_url']; - const isUrl = config['default_is_url']; + let wkConfig = config["default_server_config"]; // overwritten later under some conditions + const serverName = config["default_server_name"]; + const hsUrl = config["default_hs_url"]; + const isUrl = config["default_is_url"]; - const incompatibleOptions = [wkConfig, serverName, hsUrl].filter(i => !!i); + const incompatibleOptions = [wkConfig, serverName, hsUrl].filter((i) => !!i); if (incompatibleOptions.length > 1) { // noinspection ExceptionCaughtLocallyJS - throw newTranslatableError(_td( - "Invalid configuration: can only specify one of default_server_config, default_server_name, " + - "or default_hs_url.", - )); + throw newTranslatableError( + _td( + "Invalid configuration: can only specify one of default_server_config, default_server_name, " + + "or default_hs_url.", + ), + ); } if (incompatibleOptions.length < 1) { // noinspection ExceptionCaughtLocallyJS @@ -186,17 +184,17 @@ async function verifyServerConfig(): Promise { logger.log("Config uses a default_hs_url - constructing a default_server_config using this information"); logger.warn( "DEPRECATED CONFIG OPTION: In the future, default_hs_url will not be accepted. Please use " + - "default_server_config instead.", + "default_server_config instead.", ); wkConfig = { "m.homeserver": { - "base_url": hsUrl, + base_url: hsUrl, }, }; if (isUrl) { wkConfig["m.identity_server"] = { - "base_url": isUrl, + base_url: isUrl, }; } } @@ -211,7 +209,7 @@ async function verifyServerConfig(): Promise { logger.log("Config uses a default_server_name - doing .well-known lookup"); logger.warn( "DEPRECATED CONFIG OPTION: In the future, default_server_name will not be accepted. Please " + - "use default_server_config instead.", + "use default_server_config instead.", ); discoveryResult = await AutoDiscovery.findClientConfig(serverName); } @@ -238,7 +236,7 @@ async function verifyServerConfig(): Promise { // Add the newly built config to the actual config for use by the app logger.log("Updating SdkConfig with validated discovery information"); - SdkConfig.add({ "validated_server_config": validatedConfig }); + SdkConfig.add({ validated_server_config: validatedConfig }); return SdkConfig.get(); } diff --git a/src/vector/devcss.ts b/src/vector/devcss.ts index 2f67803385..be4016b61f 100644 --- a/src/vector/devcss.ts +++ b/src/vector/devcss.ts @@ -28,7 +28,7 @@ limitations under the License. * * For more details, see webpack.config.js:184 (string-replace-loader) */ -if (process.env.NODE_ENV === 'development') { +if (process.env.NODE_ENV === "development") { ("use theming"); /** * Clean up old hot-module script injections as they hog up memory @@ -40,8 +40,7 @@ if (process.env.NODE_ENV === 'development') { const elements = Array.from(document.querySelectorAll("script[src*=hot-update]")); if (elements.length > 1) { const oldInjects = elements.slice(0, elements.length - 1); - oldInjects.forEach(e => e.remove()); + oldInjects.forEach((e) => e.remove()); } }, 1000); } - diff --git a/src/vector/getconfig.ts b/src/vector/getconfig.ts index 3d4bbd7bd4..4633b57d8d 100644 --- a/src/vector/getconfig.ts +++ b/src/vector/getconfig.ts @@ -18,8 +18,8 @@ import type { IConfigOptions } from "matrix-react-sdk/src/IConfigOptions"; // Load the config file. First try to load up a domain-specific config of the // form "config.$domain.json" and if that fails, fall back to config.json. -export async function getVectorConfig(relativeLocation=''): Promise { - if (relativeLocation !== '' && !relativeLocation.endsWith('/')) relativeLocation += '/'; +export async function getVectorConfig(relativeLocation = ""): Promise { + if (relativeLocation !== "" && !relativeLocation.endsWith("/")) relativeLocation += "/"; const specificConfigPromise = getConfig(`${relativeLocation}config.${document.domain}.json`); const generalConfigPromise = getConfig(relativeLocation + "config.json"); diff --git a/src/vector/index.html b/src/vector/index.html index d906b1ca37..ce69737483 100644 --- a/src/vector/index.html +++ b/src/vector/index.html @@ -25,17 +25,17 @@ <% for (var i=0; i < htmlWebpackPlugin.files.css.length; i++) { var file = htmlWebpackPlugin.files.css[i]; diff --git a/src/vector/index.ts b/src/vector/index.ts index d09b493020..1811179c81 100644 --- a/src/vector/index.ts +++ b/src/vector/index.ts @@ -29,8 +29,8 @@ import { queueClearCacheAndReload, queueOverideUserSettings, needsRefreshForVers // Require common CSS here; this will make webpack process it into bundle.css. // Our own CSS (which is themed) is imported via separate webpack entry points // in webpack.config.js -require('gfm.css/gfm.css'); -require('katex/dist/katex.css'); +require("gfm.css/gfm.css"); +require("katex/dist/katex.css"); /** * This require is necessary only for purposes of CSS hot-reload, as otherwise @@ -39,10 +39,10 @@ require('katex/dist/katex.css'); * * On production build it's going to be an empty module, so don't worry about that. */ -require('./devcss'); -require('./localstorage-fix'); +require("./devcss"); +require("./localstorage-fix"); -async function settled(...promises: Array>) { +async function settled(...promises: Array>): Promise { for (const prom of promises) { try { await prom; @@ -52,7 +52,7 @@ async function settled(...promises: Array>) { } } -function checkBrowserFeatures() { +function checkBrowserFeatures(): boolean { if (!window.Modernizr) { logger.error("Cannot check features - Modernizr global is missing."); return false; @@ -62,33 +62,30 @@ function checkBrowserFeatures() { // in it for some features we depend on. // Modernizr requires rules to be lowercase with no punctuation. // ES2018: http://262.ecma-international.org/9.0/#sec-promise.prototype.finally - window.Modernizr.addTest("promiseprototypefinally", () => - typeof window.Promise?.prototype?.finally === "function"); + window.Modernizr.addTest("promiseprototypefinally", () => typeof window.Promise?.prototype?.finally === "function"); // ES2020: http://262.ecma-international.org/#sec-promise.allsettled - window.Modernizr.addTest("promiseallsettled", () => - typeof window.Promise?.allSettled === "function"); + window.Modernizr.addTest("promiseallsettled", () => typeof window.Promise?.allSettled === "function"); // ES2018: https://262.ecma-international.org/9.0/#sec-get-regexp.prototype.dotAll - window.Modernizr.addTest("regexpdotall", () => ( - window.RegExp?.prototype && - !!Object.getOwnPropertyDescriptor(window.RegExp.prototype, "dotAll")?.get - )); + window.Modernizr.addTest( + "regexpdotall", + () => window.RegExp?.prototype && !!Object.getOwnPropertyDescriptor(window.RegExp.prototype, "dotAll")?.get, + ); // ES2019: http://262.ecma-international.org/10.0/#sec-object.fromentries - window.Modernizr.addTest("objectfromentries", () => - typeof window.Object?.fromEntries === "function"); + window.Modernizr.addTest("objectfromentries", () => typeof window.Object?.fromEntries === "function"); const featureList = Object.keys(window.Modernizr); let featureComplete = true; - for (let i = 0; i < featureList.length; i++) { - if (window.Modernizr[featureList[i]] === undefined) { + for (const feature of featureList) { + if (window.Modernizr[feature] === undefined) { logger.error( - "Looked for feature '%s' but Modernizr has no results for this. " + - "Has it been configured correctly?", featureList[i], + "Looked for feature '%s' but Modernizr has no results for this. " + "Has it been configured correctly?", + feature, ); return false; } - if (window.Modernizr[featureList[i]] === false) { - logger.error("Browser missing feature: '%s'", featureList[i]); + if (window.Modernizr[feature] === false) { + logger.error("Browser missing feature: '%s'", feature); // toggle flag rather than return early so we log all missing features rather than just the first. featureComplete = false; } @@ -104,7 +101,7 @@ const supportedBrowser = checkBrowserFeatures(); // We start loading stuff but don't block on it until as late as possible to allow // the browser to use as much parallelism as it can. // Load parallelism is based on research in https://github.com/vector-im/element-web/issues/12253 -async function start() { +async function start(): Promise { // load init.ts async so that its code is not executed immediately and we can catch any exceptions const { rageshakePromise, @@ -122,7 +119,8 @@ async function start() { } = await import( /* webpackChunkName: "init" */ /* webpackPreload: true */ - "./init"); + "./init" + ); try { // give rageshake a chance to load/fail, we don't actually assert rageshake loads, we allow it to fail if no IDB @@ -187,12 +185,12 @@ async function start() { // error handling begins here // ########################## if (!acceptBrowser) { - await new Promise(resolve => { + await new Promise((resolve) => { logger.error("Browser is missing required features."); // take to a different landing page to AWOOOOOGA at the user showIncompatibleBrowser(() => { if (window.localStorage) { - window.localStorage.setItem('mx_accepts_unsupported_browser', String(true)); + window.localStorage.setItem("mx_accepts_unsupported_browser", String(true)); } logger.log("User accepts the compatibility risks."); resolve(); @@ -208,12 +206,13 @@ async function start() { if (error.err && error.err instanceof SyntaxError) { // This uses the default brand since the app config is unavailable. return showError(_t("Your Element is misconfigured"), [ - _t("Your Element configuration contains invalid JSON. " + - "Please correct the problem and reload the page."), _t( - "The message from the parser is: %(message)s", - { message: error.err.message || _t("Invalid JSON") }, + "Your Element configuration contains invalid JSON. " + + "Please correct the problem and reload the page.", ), + _t("The message from the parser is: %(message)s", { + message: error.err.message || _t("Invalid JSON"), + }), ]); } return showError(_t("Unable to load config file: please refresh the page to try again.")); @@ -256,7 +255,7 @@ async function start() { } } -start().catch(err => { +start().catch((err) => { logger.error(err); // show the static error in an iframe to not lose any context / console data // with some basic styling to make the iframe full page diff --git a/src/vector/indexeddb-worker.ts b/src/vector/indexeddb-worker.ts index e196cdfb35..113bc87d6c 100644 --- a/src/vector/indexeddb-worker.ts +++ b/src/vector/indexeddb-worker.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IndexedDBStoreWorker } from 'matrix-js-sdk/src/indexeddb-worker'; +import { IndexedDBStoreWorker } from "matrix-js-sdk/src/indexeddb-worker"; const remoteWorker = new IndexedDBStoreWorker(postMessage as InstanceType["postMessage"]); diff --git a/src/vector/init.tsx b/src/vector/init.tsx index d8e79dde20..6ab4e4cacf 100644 --- a/src/vector/init.tsx +++ b/src/vector/init.tsx @@ -20,7 +20,7 @@ limitations under the License. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import olmWasmPath from "@matrix-org/olm/olm.wasm"; -import Olm from '@matrix-org/olm'; +import Olm from "@matrix-org/olm"; import * as ReactDOM from "react-dom"; import * as React from "react"; import * as languageHandler from "matrix-react-sdk/src/languageHandler"; @@ -41,11 +41,11 @@ import { INSTALLED_MODULES } from "../modules"; export const rageshakePromise = initRageshake(); -export function preparePlatform() { +export function preparePlatform(): void { if (window.electron) { logger.log("Using Electron platform"); PlatformPeg.set(new ElectronPlatform()); - } else if (window.matchMedia('(display-mode: standalone)').matches) { + } else if (window.matchMedia("(display-mode: standalone)").matches) { logger.log("Using PWA platform"); PlatformPeg.set(new PWAPlatform()); } else { @@ -54,7 +54,7 @@ export function preparePlatform() { } } -export function setupLogStorage() { +export function setupLogStorage(): Promise { if (SdkConfig.get().bug_report_endpoint_url) { return initRageshakeStore(); } @@ -62,7 +62,7 @@ export function setupLogStorage() { return Promise.resolve(); } -export async function loadConfig() { +export async function loadConfig(): Promise { // XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure // granular settings are loaded correctly and to avoid duplicating the override logic for the theme. // @@ -90,30 +90,35 @@ export function loadOlm(): Promise { */ return Olm.init({ locateFile: () => olmWasmPath, - }).then(() => { - logger.log("Using WebAssembly Olm"); - }).catch((wasmLoadError) => { - logger.log("Failed to load Olm: trying legacy version", wasmLoadError); - return new Promise((resolve, reject) => { - const s = document.createElement('script'); - s.src = 'olm_legacy.js'; // XXX: This should be cache-busted too - s.onload = resolve; - s.onerror = reject; - document.body.appendChild(s); - }).then(() => { - // Init window.Olm, ie. the one just loaded by the script tag, - // not 'Olm' which is still the failed wasm version. - return window.Olm.init(); - }).then(() => { - logger.log("Using legacy Olm"); - }).catch((legacyLoadError) => { - logger.log("Both WebAssembly and asm.js Olm failed!", legacyLoadError); + }) + .then(() => { + logger.log("Using WebAssembly Olm"); + }) + .catch((wasmLoadError) => { + logger.log("Failed to load Olm: trying legacy version", wasmLoadError); + return new Promise((resolve, reject) => { + const s = document.createElement("script"); + s.src = "olm_legacy.js"; // XXX: This should be cache-busted too + s.onload = resolve; + s.onerror = reject; + document.body.appendChild(s); + }) + .then(() => { + // Init window.Olm, ie. the one just loaded by the script tag, + // not 'Olm' which is still the failed wasm version. + return window.Olm.init(); + }) + .then(() => { + logger.log("Using legacy Olm"); + }) + .catch((legacyLoadError) => { + logger.log("Both WebAssembly and asm.js Olm failed!", legacyLoadError); + }); }); - }); } -export async function loadLanguage() { - const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true); +export async function loadLanguage(): Promise { + const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/ true); let langs = []; if (!prefLang) { @@ -131,37 +136,47 @@ export async function loadLanguage() { } } -export async function loadTheme() { +export async function loadTheme(): Promise { setTheme(); } -export async function loadApp(fragParams: {}) { +export async function loadApp(fragParams: {}): Promise { // load app.js async so that its code is not executed immediately and we can catch any exceptions const module = await import( /* webpackChunkName: "element-web-app" */ /* webpackPreload: true */ - "./app"); - window.matrixChat = ReactDOM.render(await module.loadApp(fragParams), - document.getElementById('matrixchat')); + "./app" + ); + window.matrixChat = ReactDOM.render(await module.loadApp(fragParams), document.getElementById("matrixchat")); } -export async function showError(title: string, messages?: string[]) { - const ErrorView = (await import( - /* webpackChunkName: "error-view" */ - "../async-components/structures/ErrorView")).default; - window.matrixChat = ReactDOM.render(, - document.getElementById('matrixchat')); +export async function showError(title: string, messages?: string[]): Promise { + const ErrorView = ( + await import( + /* webpackChunkName: "error-view" */ + "../async-components/structures/ErrorView" + ) + ).default; + window.matrixChat = ReactDOM.render( + , + document.getElementById("matrixchat"), + ); } -export async function showIncompatibleBrowser(onAccept) { - const CompatibilityView = (await import( - /* webpackChunkName: "compatibility-view" */ - "../async-components/structures/CompatibilityView")).default; - window.matrixChat = ReactDOM.render(, - document.getElementById('matrixchat')); +export async function showIncompatibleBrowser(onAccept): Promise { + const CompatibilityView = ( + await import( + /* webpackChunkName: "compatibility-view" */ + "../async-components/structures/CompatibilityView" + ) + ).default; + window.matrixChat = ReactDOM.render( + , + document.getElementById("matrixchat"), + ); } -export async function loadModules() { +export async function loadModules(): Promise { for (const InstalledModule of INSTALLED_MODULES) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - we know the constructor exists even if TypeScript can't be convinced of that diff --git a/src/vector/jitsi/index.html b/src/vector/jitsi/index.html index 1a05c60277..be84a62c2b 100644 --- a/src/vector/jitsi/index.html +++ b/src/vector/jitsi/index.html @@ -1,24 +1,24 @@ - - - Jitsi Widget - - -
-
-
-
- - -

Jitsi Video Conference

-
- + + + Jitsi Widget + + +
+
+
+
+ + +

Jitsi Video Conference

+
+ +
+
-
-
- - - + + + diff --git a/src/vector/jitsi/index.pcss b/src/vector/jitsi/index.pcss index 64e427ff9e..e9d90538fe 100644 --- a/src/vector/jitsi/index.pcss +++ b/src/vector/jitsi/index.pcss @@ -17,10 +17,10 @@ limitations under the License. /* TODO: Match the user's theme: https://github.com/vector-im/element-web/issues/12794 */ @font-face { - font-family: 'Nunito'; + font-family: "Nunito"; font-style: normal; font-weight: 400; - src: url('~matrix-react-sdk/res/fonts/Nunito/Nunito-Regular.ttf') format('truetype'); + src: url("~matrix-react-sdk/res/fonts/Nunito/Nunito-Regular.ttf") format("truetype"); } $dark-fg: #edf3ff; @@ -38,7 +38,8 @@ body.theme-light { color: $light-fg; } -body, html { +body, +html { padding: 0; margin: 0; } @@ -92,7 +93,7 @@ body, html { margin-top: -$icon-size; /* to visually center the form */ &::before { - content: ''; + content: ""; background-size: contain; background-color: $dark-fg; mask-repeat: no-repeat; diff --git a/src/vector/jitsi/index.ts b/src/vector/jitsi/index.ts index b284cdcaf8..95d3301113 100644 --- a/src/vector/jitsi/index.ts +++ b/src/vector/jitsi/index.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { KJUR } from 'jsrsasign'; +import { KJUR } from "jsrsasign"; import { IOpenIDCredentials, IWidgetApiRequest, @@ -34,7 +34,7 @@ import { getVectorConfig } from "../getconfig"; // We have to trick webpack into loading our CSS for us. require("./index.pcss"); -const JITSI_OPENIDTOKEN_JWT_AUTH = 'openidtoken-jwt'; +const JITSI_OPENIDTOKEN_JWT_AUTH = "openidtoken-jwt"; // Dev note: we use raw JS without many dependencies to reduce bundle size. // We do not need all of React to render a Jitsi conference. @@ -61,7 +61,7 @@ let widgetApi: WidgetApi; let meetApi: any; // JitsiMeetExternalAPI let skipOurWelcomeScreen = false; -const setupCompleted = (async () => { +const setupCompleted = (async (): Promise => { try { // Queue a config.json lookup asap, so we can use it later on. We want this to be concurrent with // other setup work and therefore do not block. @@ -82,9 +82,9 @@ const setupCompleted = (async () => { // If we have these params, expect a widget API to be available (ie. to be in an iframe // inside a matrix client). Otherwise, assume we're on our own, eg. have been popped // out into a browser. - const parentUrl = qsParam('parentUrl', true); - const widgetId = qsParam('widgetId', true); - const theme = qsParam('theme', true); + const parentUrl = qsParam("parentUrl", true); + const widgetId = qsParam("widgetId", true); + const theme = qsParam("theme", true); if (theme) { document.body.classList.add(`theme-${theme.replace(" ", "_")}`); @@ -93,16 +93,16 @@ const setupCompleted = (async () => { // Set this up as early as possible because Element will be hitting it almost immediately. let widgetApiReady: Promise; if (parentUrl && widgetId) { - const parentOrigin = new URL(qsParam('parentUrl')).origin; + const parentOrigin = new URL(qsParam("parentUrl")).origin; widgetApi = new WidgetApi(qsParam("widgetId"), parentOrigin); - widgetApiReady = new Promise(resolve => widgetApi.once("ready", resolve)); + widgetApiReady = new Promise((resolve) => widgetApi.once("ready", resolve)); widgetApi.requestCapabilities(VideoConferenceCapabilities); widgetApi.start(); const handleAction = ( action: WidgetApiAction, - handler: (request: IWidgetApiRequestData) => void, + handler: (request: IWidgetApiRequestData) => Promise, ): void => { widgetApi.on(`action:${action}`, async (ev: CustomEvent) => { ev.preventDefault(); @@ -134,39 +134,39 @@ const setupCompleted = (async () => { meetApi = null; closeConference(); } else { - meetApi?.executeCommand('hangup'); + meetApi?.executeCommand("hangup"); } }); handleAction(ElementWidgetActions.MuteAudio, async () => { - if (meetApi && !await meetApi.isAudioMuted()) { - meetApi.executeCommand('toggleAudio'); + if (meetApi && !(await meetApi.isAudioMuted())) { + meetApi.executeCommand("toggleAudio"); } }); handleAction(ElementWidgetActions.UnmuteAudio, async () => { - if (meetApi && await meetApi.isAudioMuted()) { - meetApi.executeCommand('toggleAudio'); + if (meetApi && (await meetApi.isAudioMuted())) { + meetApi.executeCommand("toggleAudio"); } }); handleAction(ElementWidgetActions.MuteVideo, async () => { - if (meetApi && !await meetApi.isVideoMuted()) { - meetApi.executeCommand('toggleVideo'); + if (meetApi && !(await meetApi.isVideoMuted())) { + meetApi.executeCommand("toggleVideo"); } }); handleAction(ElementWidgetActions.UnmuteVideo, async () => { - if (meetApi && await meetApi.isVideoMuted()) { - meetApi.executeCommand('toggleVideo'); + if (meetApi && (await meetApi.isVideoMuted())) { + meetApi.executeCommand("toggleVideo"); } }); handleAction(ElementWidgetActions.TileLayout, async () => { - meetApi?.executeCommand('setTileView', true); + meetApi?.executeCommand("setTileView", true); }); handleAction(ElementWidgetActions.SpotlightLayout, async () => { - meetApi?.executeCommand('setTileView', false); + meetApi?.executeCommand("setTileView", false); }); handleAction(ElementWidgetActions.StartLiveStream, async ({ rtmpStreamKey }) => { if (!meetApi) throw new Error("Conference not joined"); - meetApi.executeCommand('startRecording', { - mode: 'stream', + meetApi.executeCommand("startRecording", { + mode: "stream", // this looks like it should be rtmpStreamKey but we may be on too old // a version of jitsi meet //rtmpStreamKey, @@ -178,23 +178,23 @@ const setupCompleted = (async () => { } // Populate the Jitsi params now - jitsiDomain = qsParam('conferenceDomain'); - conferenceId = qsParam('conferenceId'); - displayName = qsParam('displayName', true); - avatarUrl = qsParam('avatarUrl', true); // http not mxc - userId = qsParam('userId'); - jitsiAuth = qsParam('auth', true); - roomId = qsParam('roomId', true); - roomName = qsParam('roomName', true); - startAudioOnly = qsParam('isAudioOnly', true) === "true"; - isVideoChannel = qsParam('isVideoChannel', true) === "true"; - supportsScreensharing = qsParam('supportsScreensharing', true) === "true"; + jitsiDomain = qsParam("conferenceDomain"); + conferenceId = qsParam("conferenceId"); + displayName = qsParam("displayName", true); + avatarUrl = qsParam("avatarUrl", true); // http not mxc + userId = qsParam("userId"); + jitsiAuth = qsParam("auth", true); + roomId = qsParam("roomId", true); + roomName = qsParam("roomName", true); + startAudioOnly = qsParam("isAudioOnly", true) === "true"; + isVideoChannel = qsParam("isVideoChannel", true) === "true"; + supportsScreensharing = qsParam("supportsScreensharing", true) === "true"; // We've reached the point where we have to wait for the config, so do that then parse it. const instanceConfig = new SnakedObject((await configPromise) ?? {}); const jitsiConfig = instanceConfig.get("jitsi_widget") ?? {}; - skipOurWelcomeScreen = (new SnakedObject(jitsiConfig)) - .get("skip_built_in_welcome_screen") ?? false; + skipOurWelcomeScreen = + new SnakedObject(jitsiConfig).get("skip_built_in_welcome_screen") ?? false; // Either reveal the prejoin screen, or skip straight to Jitsi depending on the config. // We don't set up the call yet though as this might lead to failure without the widget API. @@ -223,11 +223,11 @@ const setupCompleted = (async () => { } })(); -function enableJoinButton() { - document.getElementById("joinButton").onclick = () => joinConference(); +function enableJoinButton(): void { + document.getElementById("joinButton").onclick = (): void => joinConference(); } -function switchVisibleContainers() { +function switchVisibleContainers(): void { inConference = !inConference; // Our welcome screen is managed by other code, so just don't switch to it ever @@ -237,14 +237,14 @@ function switchVisibleContainers() { } } -function toggleConferenceVisibility(inConference: boolean) { - document.getElementById("jitsiContainer").style.visibility = inConference ? 'unset' : 'hidden'; +function toggleConferenceVisibility(inConference: boolean): void { + document.getElementById("jitsiContainer").style.visibility = inConference ? "unset" : "hidden"; // Video rooms have a separate UI for joining, so they should never show our join button document.getElementById("joinButtonContainer").style.visibility = - (inConference || isVideoChannel) ? 'hidden' : 'unset'; + inConference || isVideoChannel ? "hidden" : "unset"; } -function skipToJitsiSplashScreen() { +function skipToJitsiSplashScreen(): void { // really just a function alias for self-documenting code joinConference(); } @@ -254,9 +254,9 @@ function skipToJitsiSplashScreen() { * * See https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification */ -function createJWTToken() { +function createJWTToken(): string { // Header - const header = { alg: 'HS256', typ: 'JWT' }; + const header = { alg: "HS256", typ: "JWT" }; // Payload const payload = { // As per Jitsi token auth, `iss` needs to be set to something agreed between @@ -281,15 +281,10 @@ function createJWTToken() { // Sign JWT // The secret string here is irrelevant, we're only using the JWT // to transport data to Prosody in the Jitsi stack. - return KJUR.jws.JWS.sign( - 'HS256', - JSON.stringify(header), - JSON.stringify(payload), - 'notused', - ); + return KJUR.jws.JWS.sign("HS256", JSON.stringify(header), JSON.stringify(payload), "notused"); } -async function notifyHangup(errorMessage?: string) { +async function notifyHangup(errorMessage?: string): Promise { if (widgetApi) { // We send the hangup event before setAlwaysOnScreen, because the latter // can cause the receiving side to instantly stop listening. @@ -301,7 +296,7 @@ async function notifyHangup(errorMessage?: string) { } } -function closeConference() { +function closeConference(): void { switchVisibleContainers(); document.getElementById("jitsiContainer").innerHTML = ""; @@ -315,12 +310,13 @@ function closeConference() { // audio input it can find, while an input of null instructs it to start muted, // and a non-nullish input specifies the label of a specific device to use. // Same for video inputs. -function joinConference(audioInput?: string | null, videoInput?: string | null) { +function joinConference(audioInput?: string | null, videoInput?: string | null): void { let jwt; if (jitsiAuth === JITSI_OPENIDTOKEN_JWT_AUTH) { - if (!openIdToken?.access_token) { // eslint-disable-line camelcase + if (!openIdToken?.access_token) { + // eslint-disable-line camelcase // We've failing to get a token, don't try to init conference - logger.warn('Expected to have an OpenID credential, cannot initialize widget.'); + logger.warn("Expected to have an OpenID credential, cannot initialize widget."); document.getElementById("widgetActionContainer").innerText = "Failed to load Jitsi widget"; return; } @@ -331,8 +327,8 @@ function joinConference(audioInput?: string | null, videoInput?: string | null) logger.warn( "[Jitsi Widget] The next few errors about failing to parse URL parameters are fine if " + - "they mention 'external_api' or 'jitsi' in the stack. They're just Jitsi Meet trying to parse " + - "our fragment values and not recognizing the options.", + "they mention 'external_api' or 'jitsi' in the stack. They're just Jitsi Meet trying to parse " + + "our fragment values and not recognizing the options.", ); const options = { @@ -400,7 +396,7 @@ function joinConference(audioInput?: string | null, videoInput?: string | null) meetApi.on("audioMuteStatusChanged", onAudioMuteStatusChanged); meetApi.on("videoMuteStatusChanged", onVideoMuteStatusChanged); - ["videoConferenceJoined", "participantJoined", "participantLeft"].forEach(event => { + ["videoConferenceJoined", "participantJoined", "participantLeft"].forEach((event) => { meetApi.on(event, updateParticipants); }); @@ -408,7 +404,7 @@ function joinConference(audioInput?: string | null, videoInput?: string | null) meetApi.on("log", onLog); } -const onVideoConferenceJoined = () => { +const onVideoConferenceJoined = (): void => { // Although we set our displayName with the userInfo option above, that // option has a bug where it causes the name to be the HTML encoding of // what was actually intended. So, we use the displayName command to at @@ -432,12 +428,12 @@ const onVideoConferenceJoined = () => { if (isVideoChannel) meetApi.executeCommand("setTileView", true); }; -const onVideoConferenceLeft = () => { +const onVideoConferenceLeft = (): void => { notifyHangup(); meetApi = null; }; -const onErrorOccurred = ({ error }) => { +const onErrorOccurred = ({ error }): void => { if (error.isFatal) { // We got disconnected. Since Jitsi Meet might send us back to the // prejoin screen, we're forced to act as if we hung up entirely. @@ -447,12 +443,12 @@ const onErrorOccurred = ({ error }) => { } }; -const onAudioMuteStatusChanged = ({ muted }) => { +const onAudioMuteStatusChanged = ({ muted }): void => { const action = muted ? ElementWidgetActions.MuteAudio : ElementWidgetActions.UnmuteAudio; widgetApi?.transport.send(action, {}); }; -const onVideoMuteStatusChanged = ({ muted }) => { +const onVideoMuteStatusChanged = ({ muted }): void => { if (muted) { // Jitsi Meet always sends a "video muted" event directly before // hanging up, which we need to ignore by padding the timeout here, @@ -466,11 +462,10 @@ const onVideoMuteStatusChanged = ({ muted }) => { } }; -const updateParticipants = () => { +const updateParticipants = (): void => { widgetApi?.transport.send(ElementWidgetActions.CallParticipants, { participants: meetApi.getParticipantsInfo(), }); }; -const onLog = ({ logLevel, args }) => - (parent as unknown as typeof global).mx_rage_logger?.log(logLevel, ...args); +const onLog = ({ logLevel, args }): void => (parent as unknown as typeof global).mx_rage_logger?.log(logLevel, ...args); diff --git a/src/vector/localstorage-fix.ts b/src/vector/localstorage-fix.ts index d0ca05174f..3c3d46b8ac 100644 --- a/src/vector/localstorage-fix.ts +++ b/src/vector/localstorage-fix.ts @@ -4,8 +4,8 @@ * */ if (window.localStorage) { - Object.keys(window.localStorage).forEach(key => { - if (key.indexOf('loglevel:') === 0) { + Object.keys(window.localStorage).forEach((key) => { + if (key.indexOf("loglevel:") === 0) { window.localStorage.removeItem(key); } }); diff --git a/src/vector/mobile_guide/index.html b/src/vector/mobile_guide/index.html index 2def26fa83..c39041c501 100644 --- a/src/vector/mobile_guide/index.html +++ b/src/vector/mobile_guide/index.html @@ -1,489 +1,788 @@ - + - - Element Mobile Guide - - + + Element Mobile Guide + + - - + + - -
- -
+ +
+ +
-
-
- -

Set up Element on iOS or Android

-
-
-
-
-

Install the app

-

iOS (iPhone or iPad)

- - - Download on the App Store. - - - - - - - - - - - +
+
+ +

Set up Element on iOS or Android

+
+
+
+
+

Install the app

+

iOS (iPhone or iPad)

+
+ + Download on the App Store. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d="M31.4009,5.42432 C31.4009,4.61377 32.00442,4.14649 33.0757,4.08008 L34.29543,4.00977 L34.29543,3.6211 C34.29543,3.14551 33.98098,2.87696 33.37356,2.87696 C32.87747,2.87696 32.53372,3.05909 32.43508,3.37745 L31.57473,3.37745 C31.66555,2.60401 32.39309,2.10792 33.41457,2.10792 C34.54348,2.10792 35.1802,2.66992 35.1802,3.6211 L35.1802,6.69776 L34.32473,6.69776 L34.32473,6.06495 L34.25442,6.06495 C33.9638686,6.52707633 33.4471736,6.79716323 32.90188,6.77195 C32.5196161,6.81171181 32.1383711,6.68791066 31.8523958,6.43115244 C31.5664205,6.17439423 31.4024061,5.80864331 31.4009,5.42432 Z M34.29543,5.03955 L34.29543,4.66309 L33.19582,4.7334 C32.5757,4.7749 32.29445,4.98584 32.29445,5.38281 C32.29445,5.78808 32.64601,6.02392 33.12945,6.02392 C33.4156361,6.05288986 33.7013264,5.96447505 33.9211204,5.77891559 C34.1409144,5.59335613 34.2759916,5.32654106 34.29543,5.03955 Z" + id="Shape" + > + d="M36.34816,4.44434 C36.34816,3.02149 37.07961,2.12012 38.2173,2.12012 C38.7917768,2.09365013 39.3298275,2.40147287 39.59816,2.91012 L39.66457,2.91012 L39.66457,0.437 L40.55324,0.437 L40.55324,6.69774 L39.70168,6.69774 L39.70168,5.98631 L39.63137,5.98631 C39.3427542,6.49073698 38.7980745,6.79335648 38.21731,6.77195 C37.0718,6.772 36.34816,5.87061 36.34816,4.44434 Z M37.26616,4.44434 C37.26616,5.39942 37.71636,5.97413 38.46929,5.97413 C39.21829,5.97413 39.6812,5.39113 39.6812,4.44825 C39.6812,3.50977 39.21343,2.91846 38.46929,2.91846 C37.72121,2.91846 37.26613,3.49707 37.26613,4.44434 L37.26616,4.44434 Z" + id="Shape" + > + + + + + - + + + + +

Android

+ + + + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get it on F-Droid. + + + + + + + + + + + d="M5.68003571,6.29863415 L5.68003571,4.42449878 L4.13843589,4.42449878 L4.13843589,3.64866951 L6.61432589,3.64866951 L6.61432589,6.64455976 C6.24995506,6.90316951 5.84820327,7.09946423 5.40907054,7.2334439 C4.96995649,7.36430642 4.50125542,7.42973768 4.00296732,7.42973768 C2.91295744,7.42973768 2.0596344,7.1119263 1.44299821,6.47630354 C0.829483333,5.83757671 0.522725893,4.94958037 0.522725893,3.81231451 C0.522725893,2.67194459 0.829483333,1.78394825 1.44299821,1.14832549 C2.0596344,0.509598659 2.91295744,0.190235244 4.00296732,0.190235244 C4.45765054,0.190235244 4.88898,0.24631878 5.29695571,0.358485854 C5.70805274,0.470652927 6.08644143,0.635785447 6.43212179,0.853883415 L6.43212179,1.85873098 C6.08332012,1.56274154 5.71271601,1.33995943 5.32030946,1.19038463 C4.92790292,1.04082854 4.51525458,0.966050488 4.08236446,0.966050488 C3.22903208,0.966050488 2.58748149,1.20440902 2.15771268,1.6811261 C1.73104649,2.15784317 1.51771339,2.86824398 1.51771339,3.81232854 C1.51771339,4.75329033 1.73104649,5.46212976 2.15771268,5.93884683 C2.58748149,6.4155639 3.22903208,6.65392244 4.08236446,6.65392244 C4.41559696,6.65392244 4.71301851,6.6258802 4.97462911,6.56979573 C5.2362397,6.51059598 5.47136589,6.4202387 5.68000768,6.2987239 L5.68003571,6.29863415 Z" + id="Shape" + > + + + + + d="M37.8398036,0.956463415 C37.1546481,0.956463415 36.6096432,1.21195976 36.2047887,1.72295244 C35.803037,2.23394512 35.6021611,2.93032154 35.6021611,3.81208171 C35.6021611,4.69071911 35.803037,5.38553415 36.2047887,5.89652683 C36.6096432,6.40751951 37.1546481,6.66301585 37.8398036,6.66301585 C38.524959,6.66301585 39.066852,6.40751951 39.4654825,5.89652683 C39.8672343,5.38553415 40.0681102,4.69071911 40.0681102,3.81208171 C40.0681102,2.93032154 39.8672343,2.23394512 39.4654825,1.72295244 C39.0673754,1.21209065 38.5253515,0.956659756 37.8394111,0.956659756 L37.8398036,0.956463415 Z M37.8398036,0.18997439 C38.817708,0.18997439 39.5993998,0.518687398 40.1848789,1.17611341 C40.7703768,1.83043537 41.0631257,2.70908211 41.0631257,3.81205366 C41.0631257,4.91192114 40.7703768,5.79056789 40.1848789,6.4479939 C39.5993811,7.10231585 38.8176893,7.42947683 37.8398036,7.42947683 C36.8587965,7.42947683 36.0739835,7.10231585 35.4853643,6.4479939 C34.8998664,5.79369065 34.6071175,4.9150439 34.6071175,3.81205366 C34.6071175,2.70906341 34.8998664,1.83041667 35.4853643,1.17611341 C36.0739648,0.518687398 36.8587779,0.18997439 37.8398036,0.18997439 Z" + id="Shape" + > + + d="M14.4888571,14.6357134 L14.4888571,19.7020244 L13.8851641,19.7020244 C13.7044646,18.9049341 13.5319795,18.3009504 13.3677089,17.8900732 C13.2034365,17.4791959 12.981674,17.1176285 12.7024214,16.8053707 C11.9303365,15.9260976 10.3984651,15.486461 8.10680714,15.486461 C7.46615369,15.486461 7.03493637,15.5686346 6.81315518,15.7329817 C6.5995978,15.8891143 6.49281911,16.201372 6.49281911,16.6697549 L6.49281911,22.5369988 C7.74949196,22.5369988 8.64887768,22.269937 9.19097625,21.7358134 C9.73307482,21.2016898 10.1191173,20.2114744 10.3491036,18.7651671 L10.97744,18.7651671 L10.97744,27.3071427 L10.3491036,27.3071427 C10.1684059,25.8444362 9.80290431,24.8336516 9.25259875,24.274789 C8.70229506,23.7077923 7.78236851,23.4119618 6.49281911,23.3872976 L6.49281911,29.2668829 C6.49281911,29.9653724 6.66530417,30.4296545 7.01027429,30.6597293 C7.3552444,30.8815951 8.10678845,31.0171829 9.26490643,31.0664927 L9.26490643,31.695122 L0.184699286,31.695122 L0.184699286,31.0664927 C1.12105476,30.9678844 1.72475714,30.8076417 1.99580643,30.5857646 C2.26685571,30.3638988 2.40238036,29.9242622 2.40238036,29.2668549 L2.40238036,17.051611 C2.40238036,16.4024313 2.25042679,15.9545858 1.94651964,15.7080744 C1.6426125,15.4615443 1.05533905,15.3136337 0.184699286,15.2643427 L0.184699286,14.6357134 L14.4888571,14.6357134 Z" + id="Shape" + > + + d="M25.1956964,29.4035366 L25.1956964,16.9540854 C25.1956964,16.378861 25.0478548,15.9720976 24.7521714,15.7337951 C24.4564881,15.4954927 23.9061751,15.3393638 23.1012323,15.2654085 L23.1012323,14.6367793 L30.7891859,14.6367793 C33.7050871,14.6367793 35.9926145,15.3804553 37.651768,16.8678073 C39.3191267,18.3469504 40.1528061,20.3848813 40.1528061,22.9816 C40.1528061,25.5948114 39.3191267,27.7025837 37.651768,29.3049171 C35.9844093,30.8990976 33.7913623,31.6961878 31.072627,31.6961878 L23.1012323,31.6961878 L23.1012323,31.0675585 C23.8322355,31.0429074 24.3620171,30.8991013 24.690577,30.6361402 C25.027342,30.3731923 25.1957245,29.9623244 25.1957245,29.4035366 L25.1956964,29.4035366 Z M29.2737714,16.374878 L29.2737714,29.3541707 C29.2737714,29.9211675 29.3764382,30.3073898 29.5817718,30.5128378 C29.7871054,30.7100581 30.1731478,30.8086683 30.7398991,30.8086683 C32.3497659,30.8086683 33.585954,30.2293394 34.4484634,29.0706817 C34.8591492,28.503685 35.179476,27.7107085 35.4094436,26.6917524 C35.647635,25.6727963 35.7667307,24.5634671 35.7667307,23.3637646 C35.7667307,21.194285 35.4217606,19.4275858 34.7318204,18.0636671 C33.8776095,16.3462215 32.5552583,15.4874988 30.7647668,15.4874988 C29.7709194,15.4874988 29.2739957,15.7833293 29.2739957,16.3749902 L29.2737714,16.374878 Z" + id="Shape" + > + d="M46.4748036,20.0576829 L46.4748036,22.1284683 C47.0661889,21.2820683 47.6247164,20.6739801 48.1503861,20.3042037 C48.6842608,19.9344272 49.2633198,19.749539 49.887563,19.749539 C50.4789484,19.749539 50.9676576,19.9385411 51.3536907,20.3165451 C51.7397238,20.6863215 51.9327404,21.1547175 51.9327404,21.7217329 C51.9327404,22.2147744 51.7848987,22.6215378 51.4892154,22.9420232 C51.193532,23.2542809 50.8116015,23.4104098 50.3434237,23.4104098 C50.0148826,23.4104098 49.7397307,23.3446709 49.5179682,23.2131932 C49.2962057,23.0817136 49.0662287,22.8475156 48.8280373,22.5105993 C48.556988,22.1161586 48.3228992,21.9189383 48.1257707,21.9189383 C47.7068798,21.9189383 47.3454807,22.1572407 47.0415736,22.6338456 C46.7376664,23.1022415 46.5857129,23.6651338 46.5857129,24.3225224 L46.5857129,29.0927785 C46.5857129,29.8734322 46.6965941,30.3911285 46.9183566,30.6458676 C47.1483429,30.8923976 47.6493692,31.0403082 48.4214354,31.0895993 L48.4214354,31.6935737 L41.706879,31.6935737 L41.7068818,31.0895993 C42.2654093,30.990991 42.6309109,30.8430804 42.8033866,30.6458676 C42.9840843,30.4486472 43.0744331,30.0911936 43.0744331,29.5735066 L43.0744331,22.1532017 C43.0744331,21.6437237 42.9799808,21.28627 42.7910761,21.0808407 C42.6103766,20.8754115 42.2489776,20.7357192 41.706879,20.6617639 L41.706879,20.0577895 L46.4749129,20.0577895 L46.4748036,20.0576829 Z" + id="Shape" + > + d="M58.2021429,19.7519512 C59.8284386,19.7519512 61.1795731,20.3394984 62.2555464,21.5145927 C63.3397436,22.6814593 63.8818421,24.1482236 63.8818421,25.9148854 C63.8818421,27.673413 63.3397436,29.1361569 62.2555464,30.3031171 C61.1795731,31.4699837 59.8284386,32.0534171 58.2021429,32.0534171 C56.5512131,32.0534171 55.1877429,31.4699837 54.1117321,30.3031171 C53.0357588,29.1362504 52.4977721,27.6489171 52.4977721,25.8411171 C52.4977721,24.1236715 53.0480852,22.6814967 54.1487113,21.5145927 C55.2493373,20.3394984 56.6004718,19.7519512 58.2021148,19.7519512 L58.2021429,19.7519512 Z M58.2267862,20.5408232 C57.6929115,20.5408232 57.282235,20.7174931 56.9947568,21.0708329 C56.7155024,21.4159638 56.5142714,21.9952927 56.3910637,22.8088195 C56.2678599,23.6223463 56.2062579,24.7851553 56.2062579,26.2972463 C56.2062579,28.1461659 56.349997,29.4363163 56.6374752,30.1676976 C56.9331586,30.8990415 57.4547257,31.2647134 58.2021765,31.2647134 C58.9331797,31.2647134 59.4424204,30.8826049 59.7298986,30.1183878 C60.025582,29.3541707 60.1734236,28.0024065 60.1734236,26.0630951 C60.1734236,23.9923472 60.0296845,22.5542862 59.7422063,21.7489122 C59.4629519,20.943613 58.9578138,20.5409634 58.2267919,20.5409634 L58.2267862,20.5408232 Z" + id="Shape" + > + d="M69.7332321,20.0576829 L69.7332321,29.6472805 C69.7332321,30.1238854 69.8194747,30.4690163 69.9919597,30.6826732 C70.1644448,30.8881024 70.4724545,31.0236902 70.9159888,31.0894366 L70.9159888,31.693411 L64.891383,31.693411 L64.8913942,31.0894366 C65.4663506,30.9497406 65.8318522,30.7936117 65.987899,30.62105 C66.1439589,30.4402663 66.2219888,30.0910215 66.2219888,29.5733159 L66.2219888,22.153011 C66.2219888,21.6353053 66.1398526,21.2860606 65.9755801,21.1052768 C65.8113077,20.9244931 65.4499086,20.7765825 64.891383,20.6615451 L64.891383,20.0575707 L69.7334312,20.0575707 L69.7332321,20.0576829 Z M66.5792143,14.8313537 C66.9652474,14.4451407 67.4293132,14.2520341 67.9714118,14.2520341 C68.5135104,14.2520341 68.9693617,14.4451407 69.3389659,14.8313537 C69.7167939,15.2175667 69.9057079,15.6818488 69.9057079,16.2242 C69.9057079,16.7747602 69.7167939,17.2349378 69.3389659,17.6047329 C68.9693617,17.9745093 68.5052959,18.1593976 67.9467684,18.1593976 C67.3882409,18.1593976 66.9241751,17.9745093 66.5545709,17.6047329 C66.1849667,17.2349565 66.0001646,16.7665606 66.0001646,16.1995451 C66.0001646,15.6654215 66.1931812,15.2093577 66.5792143,14.8313537 Z" + id="Shape" + > + d="M80.0335536,32.0289024 L80.0335536,30.3895354 C79.4421682,31.0140508 78.9041815,31.4495736 78.4195936,31.6961037 C77.9349869,31.9344061 77.3559279,32.0535573 76.6824166,32.0535573 C75.360028,32.0535573 74.2676632,31.4947695 73.405322,30.3771939 C72.542906,29.2514093 72.111698,27.8298037 72.111698,26.1123768 C72.111698,24.2881028 72.5716613,22.7719728 73.4915879,21.5639866 C74.4115144,20.3560191 75.5655579,19.7520354 76.9537182,19.7520354 C77.5286746,19.7520354 78.0379154,19.8670821 78.4814404,20.0971756 C78.9249654,20.3272691 79.4177771,20.7340325 79.9598757,21.3174659 L79.9598757,16.6953073 C79.9598757,16.1200829 79.8489945,15.7502972 79.627232,15.58595 C79.4136746,15.421601 78.883893,15.3065542 78.0378873,15.2408098 L78.0378873,14.6368354 L83.4712087,14.6368354 L83.4712087,29.1447866 C83.4712087,29.6789102 83.5738755,30.0486959 83.7792091,30.2541439 C83.9927665,30.4595732 84.3870234,30.5787244 84.9619798,30.6115976 L84.9619798,31.1909171 L83.3972786,31.3881337 C82.1734636,31.5196133 81.0523154,31.7332702 80.0338339,32.0291044 L80.0335536,32.0289024 Z M79.9596318,28.8734146 L79.9596318,22.734939 C79.7789323,22.2583341 79.507883,21.8803301 79.1464839,21.6009268 C78.7933087,21.3133146 78.4072663,21.1695085 77.9883566,21.1695085 C77.2573534,21.1695085 76.7152548,21.5557309 76.3620609,22.3281756 C76.0170908,23.0923927 75.8446057,24.2880187 75.8446057,25.9150537 C75.8446057,27.5174431 76.0047738,28.7048415 76.3251098,29.4772488 C76.6454459,30.2496935 77.1423696,30.6359159 77.8158809,30.6359159 C78.3744084,30.6359159 78.90419,30.3483037 79.4052256,29.7730793 C79.553071,29.6087302 79.6803811,29.4361648 79.7871561,29.2553829 C79.9021474,29.0746011 79.959643,28.9472315 79.959643,28.8732744 L79.9596318,28.8734146 Z" + id="Shape" + > - - - - - - + d="M40.46675,6.67476829 L37.3323571,10.7342683" + id="Shape" + stroke="#769616" + stroke-width="1.84532927" + fill="#8AB000" + fill-rule="nonzero" + stroke-linecap="round" + > - + d="M40.4527321,5.75 C40.7872823,5.75886341 41.014708,5.88950341 41.1763059,6.08111585 C39.6808809,7.85918415 39.428952,8.14166341 37.3875595,10.6732622 C36.6353612,11.6468354 35.8517911,11.1436683 36.6039893,10.1700951 L39.7395036,6.11031463 C39.9084496,5.88474354 40.1711695,5.75748902 40.4527882,5.7498878 L40.4527321,5.75 Z" + id="Shape" + fill-opacity="0.29804" + fill="#FFFFFF" + fill-rule="nonzero" + > + d="M41.1816607,6.09023171 C41.2730684,6.19940037 41.5956921,6.68413659 41.1982579,7.23888537 L38.0627436,11.2986659 C37.3105454,12.272239 37.2143829,10.8467159 37.2143829,10.8467159 C37.2143829,10.8467159 39.9695927,7.51788659 41.1817168,6.09020366 L41.1816607,6.09023171 Z" + id="Shape" + fill-opacity="0.2" + fill="#263238" + fill-rule="nonzero" + > + d="M40.6545893,5.92334146 C40.9778691,5.92334146 41.3627714,6.02785963 41.2626839,6.51281463 C41.1862782,6.88305854 37.8241036,10.9964122 37.8241036,10.9964122 C37.0719054,11.9699854 35.9844561,11.4955963 36.7366543,10.5221634 L39.8606739,6.48257805 C40.0526737,6.26852098 40.3096379,5.93371951 40.6546454,5.92322927 L40.6545893,5.92334146 Z" + id="Shape" + fill="#8AB000" + fill-rule="nonzero" + > + d="M8.87470536,6.67476829 L12.0105,10.7342683" + id="Shape" + stroke="#769616" + stroke-width="1.84532927" + fill="#8AB000" + fill-rule="nonzero" + stroke-linecap="round" + > + d="M8.89124643,5.75 C8.55669625,5.75886341 8.32927054,5.88950341 8.16767268,6.08111585 C9.66309768,7.85918415 9.91502661,8.14166341 11.9564191,10.6732622 C12.7086173,11.6468354 13.4921875,11.1436683 12.7399893,10.1700951 L9.604475,6.11087561 C9.43552898,5.88530451 9.17280911,5.75805 8.89119036,5.75044878 L8.89124643,5.75 Z" + id="Shape" + fill-opacity="0.29804" + fill="#FFFFFF" + fill-rule="nonzero" + > + d="M8.16147679,6.09023171 C8.07006914,6.19940037 7.74744536,6.68413659 8.14487964,7.23888537 L11.2803939,11.2986659 C12.0325921,12.272239 12.1287546,10.8467159 12.1287546,10.8467159 C12.1287546,10.8467159 9.37354482,7.51788659 8.16142071,6.09020366 L8.16147679,6.09023171 Z" + id="Shape" + fill-opacity="0.2" + fill="#263238" + fill-rule="nonzero" + > + d="M8.68966964,5.92334146 C8.36638982,5.92334146 7.9814875,6.02785963 8.081575,6.51281463 C8.15798073,6.88305854 11.5201554,10.9964122 11.5201554,10.9964122 C12.2723536,11.9699854 13.3598029,11.4955963 12.6076046,10.5221634 L9.483585,6.48257805 C9.29154036,6.26856585 9.03445286,5.93366341 8.68961357,5.92328537 L8.68966964,5.92334146 Z" + id="Shape" + fill="#8AB000" + fill-rule="nonzero" + > + + + + + + + + + d="M24.6714286,24.5735366 C22.5461252,24.5735366 20.7467089,26.0384683 20.2201982,28.0061463 L22.5906179,28.0061463 C22.9995748,27.2788415 23.767473,26.7879598 24.6714005,26.7879598 C26.0087882,26.7879598 27.0692111,27.8488768 27.0692111,29.1868598 C27.0692111,30.5248427 26.0087882,31.5857598 24.6714005,31.5857598 C23.7068318,31.5857598 22.8924223,31.0301695 22.5099311,30.2205134 L20.1827425,30.2205134 C20.6565741,32.2619878 22.49339,33.8000988 24.6715407,33.8000988 C27.2051002,33.8000988 29.2825746,31.7215439 29.2825746,29.1869159 C29.2825746,26.6521756 27.204988,24.5737329 24.6715407,24.5737329 L24.6714286,24.5735366 Z" + id="Shape" + fill="#0D47A1" + fill-rule="nonzero" + > + + + + + + d="M8.89152679,5.74242683 C8.53321466,5.73295225 8.20186636,5.93202601 8.04184972,6.25291205 C7.88183308,6.57379808 7.92213189,6.95837436 8.14518804,7.23908171 L10.8014598,10.6784232 C10.7075486,10.9245568 10.6536163,11.19065 10.6536163,11.4705768 L10.6536163,16.5785402 C10.6536163,17.8053098 11.6406977,18.7928512 12.8668957,18.7928512 L36.4760511,18.7928512 C37.7022491,18.7928512 38.6893306,17.8052817 38.6893306,16.5785402 L38.6893306,11.4705768 C38.6893306,11.1904873 38.6360487,10.9241305 38.5420337,10.6778622 L41.1977728,7.23908171 C41.4136365,6.96742572 41.4588967,6.59756916 41.3149131,6.28183678 C41.1709296,5.96610439 40.8620538,5.75789519 40.5154957,5.74295976 C40.2117646,5.72988939 39.9211038,5.86740249 39.7384859,6.11056707 L37.2114307,9.3827378 C36.9843414,9.30055488 36.7376271,9.25483537 36.4796986,9.25483537 L12.8705432,9.25483537 C12.6122305,9.25483537 12.3657882,9.30072317 12.1356991,9.38138305 L9.60687766,6.10921232 C9.43781797,5.88409848 9.17527379,5.74853032 8.89392945,5.74107207 L8.89152679,5.74242683 Z M12.8669911,19.6341463 C11.640793,19.6341463 10.6537116,20.6216878 10.6537116,21.8484573 L10.6537116,36.4930061 C10.6537116,37.7197756 11.640793,38.7073171 12.8669911,38.7073171 L36.4761464,38.7073171 C37.7023445,38.7073171 38.6894259,37.7197756 38.6894259,36.4930061 L38.6894259,21.8484573 C38.6922295,20.6232866 37.7053723,19.635689 36.4802116,19.635689 L12.8710562,19.635689 L12.8669911,19.6341463 Z" + id="Shape" + fill="url(#radialGradient-1)" + fill-rule="nonzero" + > - - - - -

Android

- - - - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Get it on F-Droid. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+
-
-
- - - + diff --git a/src/vector/mobile_guide/index.ts b/src/vector/mobile_guide/index.ts index 334f758905..0a0a351eef 100644 --- a/src/vector/mobile_guide/index.ts +++ b/src/vector/mobile_guide/index.ts @@ -1,17 +1,17 @@ import { logger } from "matrix-js-sdk/src/logger"; -import { getVectorConfig } from '../getconfig'; +import { getVectorConfig } from "../getconfig"; function onBackToElementClick(): void { // Cookie should expire in 4 hours - document.cookie = 'element_mobile_redirect_to_guide=false;path=/;max-age=14400'; - window.location.href = '../'; + document.cookie = "element_mobile_redirect_to_guide=false;path=/;max-age=14400"; + window.location.href = "../"; } // NEVER pass user-controlled content to this function! Hardcoded strings only please. function renderConfigError(message: string): void { - const contactMsg = "If this is unexpected, please contact your system administrator " + - "or technical support representative."; + const contactMsg = + "If this is unexpected, please contact your system administrator " + "or technical support representative."; message = `

Error loading Element

${message}

${contactMsg}

`; const toHide = document.getElementsByClassName("mx_HomePage_container"); @@ -22,46 +22,46 @@ function renderConfigError(message: string): void { for (const e of toHide) { // We have to clear the content because .style.display='none'; doesn't work // due to an !important in the CSS. - e.innerHTML = ''; + e.innerHTML = ""; } for (const e of errorContainers) { - e.style.display = 'block'; + e.style.display = "block"; e.innerHTML = message; } } async function initPage(): Promise { - document.getElementById('back_to_element_button').onclick = onBackToElementClick; + document.getElementById("back_to_element_button").onclick = onBackToElementClick; - const config = await getVectorConfig('..'); + const config = await getVectorConfig(".."); // We manually parse the config similar to how validateServerConfig works because // calling that function pulls in roughly 4mb of JS we don't use. - const wkConfig = config['default_server_config']; // overwritten later under some conditions - const serverName = config['default_server_name']; - const defaultHsUrl = config['default_hs_url']; - const defaultIsUrl = config['default_is_url']; + const wkConfig = config["default_server_config"]; // overwritten later under some conditions + const serverName = config["default_server_name"]; + const defaultHsUrl = config["default_hs_url"]; + const defaultIsUrl = config["default_is_url"]; - const incompatibleOptions = [wkConfig, serverName, defaultHsUrl].filter(i => !!i); + const incompatibleOptions = [wkConfig, serverName, defaultHsUrl].filter((i) => !!i); if (incompatibleOptions.length > 1) { return renderConfigError( "Invalid configuration: can only specify one of default_server_config, default_server_name, " + - "or default_hs_url.", + "or default_hs_url.", ); } if (incompatibleOptions.length < 1) { return renderConfigError("Invalid configuration: no default server specified."); } - let hsUrl = ''; - let isUrl = ''; + let hsUrl = ""; + let isUrl = ""; - if (wkConfig && wkConfig['m.homeserver']) { - hsUrl = wkConfig['m.homeserver']['base_url']; + if (wkConfig && wkConfig["m.homeserver"]) { + hsUrl = wkConfig["m.homeserver"]["base_url"]; - if (wkConfig['m.identity_server']) { - isUrl = wkConfig['m.identity_server']['base_url']; + if (wkConfig["m.identity_server"]) { + isUrl = wkConfig["m.identity_server"]["base_url"]; } } @@ -70,11 +70,11 @@ async function initPage(): Promise { try { const result = await fetch(`https://${serverName}/.well-known/matrix/client`); const wkConfig = await result.json(); - if (wkConfig && wkConfig['m.homeserver']) { - hsUrl = wkConfig['m.homeserver']['base_url']; + if (wkConfig && wkConfig["m.homeserver"]) { + hsUrl = wkConfig["m.homeserver"]["base_url"]; - if (wkConfig['m.identity_server']) { - isUrl = wkConfig['m.identity_server']['base_url']; + if (wkConfig["m.identity_server"]) { + isUrl = wkConfig["m.identity_server"]["base_url"]; } } } catch (e) { @@ -92,21 +92,20 @@ async function initPage(): Promise { return renderConfigError("Unable to locate homeserver"); } - if (hsUrl && !hsUrl.endsWith('/')) hsUrl += '/'; - if (isUrl && !isUrl.endsWith('/')) isUrl += '/'; + if (hsUrl && !hsUrl.endsWith("/")) hsUrl += "/"; + if (isUrl && !isUrl.endsWith("/")) isUrl += "/"; - if (hsUrl !== 'https://matrix.org/') { - (document.getElementById('configure_element_button') as HTMLAnchorElement).href = - "https://mobile.element.io?hs_url=" + encodeURIComponent(hsUrl) + - "&is_url=" + encodeURIComponent(isUrl); - document.getElementById('step1_heading').innerHTML= '1: Install the app'; - document.getElementById('step2_container').style.display = 'block'; - document.getElementById('hs_url').innerText = hsUrl; + if (hsUrl !== "https://matrix.org/") { + (document.getElementById("configure_element_button") as HTMLAnchorElement).href = + "https://mobile.element.io?hs_url=" + encodeURIComponent(hsUrl) + "&is_url=" + encodeURIComponent(isUrl); + document.getElementById("step1_heading").innerHTML = "1: Install the app"; + document.getElementById("step2_container").style.display = "block"; + document.getElementById("hs_url").innerText = hsUrl; if (isUrl) { - document.getElementById('custom_is').style.display = 'block'; - document.getElementById('is_url').style.display = 'block'; - document.getElementById('is_url').innerText = isUrl; + document.getElementById("custom_is").style.display = "block"; + document.getElementById("is_url").style.display = "block"; + document.getElementById("is_url").innerText = isUrl; } } } diff --git a/src/vector/platform/ElectronPlatform.tsx b/src/vector/platform/ElectronPlatform.tsx index 635660d43f..36c3137ab6 100644 --- a/src/vector/platform/ElectronPlatform.tsx +++ b/src/vector/platform/ElectronPlatform.tsx @@ -19,12 +19,12 @@ limitations under the License. */ import { UpdateCheckStatus, UpdateStatus } from "matrix-react-sdk/src/BasePlatform"; -import BaseEventIndexManager from 'matrix-react-sdk/src/indexing/BaseEventIndexManager'; -import dis from 'matrix-react-sdk/src/dispatcher/dispatcher'; -import { _t } from 'matrix-react-sdk/src/languageHandler'; -import SdkConfig from 'matrix-react-sdk/src/SdkConfig'; +import BaseEventIndexManager from "matrix-react-sdk/src/indexing/BaseEventIndexManager"; +import dis from "matrix-react-sdk/src/dispatcher/dispatcher"; +import { _t } from "matrix-react-sdk/src/languageHandler"; +import SdkConfig from "matrix-react-sdk/src/SdkConfig"; import { IConfigOptions } from "matrix-react-sdk/src/IConfigOptions"; -import * as rageshake from 'matrix-react-sdk/src/rageshake/rageshake'; +import * as rageshake from "matrix-react-sdk/src/rageshake/rageshake"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { Room } from "matrix-js-sdk/src/models/room"; import Modal from "matrix-react-sdk/src/Modal"; @@ -41,35 +41,35 @@ import GenericExpiringToast from "matrix-react-sdk/src/components/views/toasts/G import { logger } from "matrix-js-sdk/src/logger"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import VectorBasePlatform from './VectorBasePlatform'; +import VectorBasePlatform from "./VectorBasePlatform"; import { SeshatIndexManager } from "./SeshatIndexManager"; import { IPCManager } from "./IPCManager"; -const isMac = navigator.platform.toUpperCase().includes('MAC'); +const isMac = navigator.platform.toUpperCase().includes("MAC"); function platformFriendlyName(): string { // used to use window.process but the same info is available here - if (navigator.userAgent.includes('Macintosh')) { - return 'macOS'; - } else if (navigator.userAgent.includes('FreeBSD')) { - return 'FreeBSD'; - } else if (navigator.userAgent.includes('OpenBSD')) { - return 'OpenBSD'; - } else if (navigator.userAgent.includes('SunOS')) { - return 'SunOS'; - } else if (navigator.userAgent.includes('Windows')) { - return 'Windows'; - } else if (navigator.userAgent.includes('Linux')) { - return 'Linux'; + if (navigator.userAgent.includes("Macintosh")) { + return "macOS"; + } else if (navigator.userAgent.includes("FreeBSD")) { + return "FreeBSD"; + } else if (navigator.userAgent.includes("OpenBSD")) { + return "OpenBSD"; + } else if (navigator.userAgent.includes("SunOS")) { + return "SunOS"; + } else if (navigator.userAgent.includes("Windows")) { + return "Windows"; + } else if (navigator.userAgent.includes("Linux")) { + return "Linux"; } else { - return 'Unknown'; + return "Unknown"; } } function onAction(payload: ActionPayload): void { // Whitelist payload actions, no point sending most across - if (['call_state'].includes(payload.action)) { - window.electron.send('app_onAction', payload); + if (["call_state"].includes(payload.action)) { + window.electron.send("app_onAction", payload); } } @@ -92,7 +92,7 @@ export default class ElectronPlatform extends VectorBasePlatform { // this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile private readonly ssoID: string = randomString(32); - constructor() { + public constructor() { super(); dis.register(onAction); @@ -102,7 +102,7 @@ export default class ElectronPlatform extends VectorBasePlatform { false if there is not or the error if one is encountered */ - window.electron.on('check_updates', (event, status) => { + window.electron.on("check_updates", (event, status) => { dis.dispatch({ action: Action.CheckUpdates, ...getUpdateCheckStatus(status), @@ -110,27 +110,27 @@ export default class ElectronPlatform extends VectorBasePlatform { }); // try to flush the rageshake logs to indexeddb before quit. - window.electron.on('before-quit', function() { - logger.log('element-desktop closing'); + window.electron.on("before-quit", function () { + logger.log("element-desktop closing"); rageshake.flush(); }); - window.electron.on('update-downloaded', this.onUpdateDownloaded); + window.electron.on("update-downloaded", this.onUpdateDownloaded); - window.electron.on('preferences', () => { + window.electron.on("preferences", () => { dis.fire(Action.ViewUserSettings); }); - window.electron.on('userDownloadCompleted', (ev, { id, name }) => { + window.electron.on("userDownloadCompleted", (ev, { id, name }) => { const key = `DOWNLOAD_TOAST_${id}`; - const onAccept = () => { - window.electron.send('userDownloadAction', { id, open: true }); + const onAccept = (): void => { + window.electron.send("userDownloadAction", { id, open: true }); ToastStore.sharedInstance().dismissToast(key); }; - const onDismiss = () => { - window.electron.send('userDownloadAction', { id }); + const onDismiss = (): void => { + window.electron.send("userDownloadAction", { id }); }; ToastStore.sharedInstance().addOrReplaceToast({ @@ -153,10 +153,10 @@ export default class ElectronPlatform extends VectorBasePlatform { } public async getConfig(): Promise { - return this.ipc.call('getConfig'); + return this.ipc.call("getConfig"); } - private onUpdateDownloaded = async (ev, { releaseNotes, releaseName }) => { + private onUpdateDownloaded = async (ev, { releaseNotes, releaseName }): Promise => { dis.dispatch({ action: Action.CheckUpdates, status: UpdateCheckStatus.Ready, @@ -167,7 +167,7 @@ export default class ElectronPlatform extends VectorBasePlatform { }; public getHumanReadableName(): string { - return 'Electron Platform'; // no translation required: only used for analytics + return "Electron Platform"; // no translation required: only used for analytics } /** @@ -186,7 +186,7 @@ export default class ElectronPlatform extends VectorBasePlatform { if (this.notificationCount === count) return; super.setNotificationCount(count); - window.electron.send('setBadgeCount', count); + window.electron.send("setBadgeCount", count); } public supportsNotifications(): boolean { @@ -210,29 +210,23 @@ export default class ElectronPlatform extends VectorBasePlatform { // maybe we should pass basic styling (italics, bold, underline) through from MD // we only have to strip out < and > as the spec doesn't include anything about things like & // so we shouldn't assume that all implementations will treat those properly. Very basic tag parsing is done. - if (navigator.userAgent.includes('Linux')) { - msg = msg.replace(//g, '>'); + if (navigator.userAgent.includes("Linux")) { + msg = msg.replace(//g, ">"); } - const notification = super.displayNotification( - title, - msg, - avatarUrl, - room, - ev, - ); + const notification = super.displayNotification(title, msg, avatarUrl, room, ev); const handler = notification.onclick as Function; - notification.onclick = () => { + notification.onclick = (): void => { handler?.(); - this.ipc.call('focusWindow'); + this.ipc.call("focusWindow"); }; return notification; } - public loudNotification(ev: MatrixEvent, room: Room) { - window.electron.send('loudNotification'); + public loudNotification(ev: MatrixEvent, room: Room): void { + window.electron.send("loudNotification"); } public needsUrlTooltips(): boolean { @@ -240,7 +234,7 @@ export default class ElectronPlatform extends VectorBasePlatform { } public async getAppVersion(): Promise { - return this.ipc.call('getAppVersion'); + return this.ipc.call("getAppVersion"); } public supportsSetting(settingName?: string): boolean { @@ -261,36 +255,36 @@ export default class ElectronPlatform extends VectorBasePlatform { return this.ipc.call("setSettingValue", settingName, value); } - async canSelfUpdate(): Promise { - const feedUrl = await this.ipc.call('getUpdateFeedUrl'); + public async canSelfUpdate(): Promise { + const feedUrl = await this.ipc.call("getUpdateFeedUrl"); return Boolean(feedUrl); } - public startUpdateCheck() { + public startUpdateCheck(): void { super.startUpdateCheck(); - window.electron.send('check_updates'); + window.electron.send("check_updates"); } - public installUpdate() { + public installUpdate(): void { // IPC to the main process to install the update, since quitAndInstall // doesn't fire the before-quit event so the main process needs to know // it should exit. - window.electron.send('install_update'); + window.electron.send("install_update"); } public getDefaultDeviceDisplayName(): string { const brand = SdkConfig.get().brand; - return _t('%(brand)s Desktop: %(platformName)s', { + return _t("%(brand)s Desktop: %(platformName)s", { brand, platformName: platformFriendlyName(), }); } public requestNotificationPermission(): Promise { - return Promise.resolve('granted'); + return Promise.resolve("granted"); } - public reload() { + public reload(): void { window.location.reload(); } @@ -298,34 +292,34 @@ export default class ElectronPlatform extends VectorBasePlatform { return this.eventIndexManager; } - public async setLanguage(preferredLangs: string[]) { - return this.ipc.call('setLanguage', preferredLangs); + public async setLanguage(preferredLangs: string[]): Promise { + return this.ipc.call("setLanguage", preferredLangs); } public setSpellCheckEnabled(enabled: boolean): void { - this.ipc.call('setSpellCheckEnabled', enabled).catch(error => { + this.ipc.call("setSpellCheckEnabled", enabled).catch((error) => { logger.log("Failed to send setSpellCheckEnabled IPC to Electron"); logger.error(error); }); } public async getSpellCheckEnabled(): Promise { - return this.ipc.call('getSpellCheckEnabled'); + return this.ipc.call("getSpellCheckEnabled"); } public setSpellCheckLanguages(preferredLangs: string[]): void { - this.ipc.call('setSpellCheckLanguages', preferredLangs).catch(error => { + this.ipc.call("setSpellCheckLanguages", preferredLangs).catch((error) => { logger.log("Failed to send setSpellCheckLanguages IPC to Electron"); logger.error(error); }); } public async getSpellCheckLanguages(): Promise { - return this.ipc.call('getSpellCheckLanguages'); + return this.ipc.call("getSpellCheckLanguages"); } public async getDesktopCapturerSources(options: GetSourcesOptions): Promise> { - return this.ipc.call('getDesktopCapturerSources', options); + return this.ipc.call("getDesktopCapturerSources", options); } public supportsDesktopCapturer(): boolean { @@ -338,7 +332,7 @@ export default class ElectronPlatform extends VectorBasePlatform { } public async getAvailableSpellCheckLanguages(): Promise { - return this.ipc.call('getAvailableSpellCheckLanguages'); + return this.ipc.call("getAvailableSpellCheckLanguages"); } public getSSOCallbackUrl(fragmentAfterLogin: string): URL { @@ -353,7 +347,7 @@ export default class ElectronPlatform extends VectorBasePlatform { loginType: "sso" | "cas", fragmentAfterLogin: string, idpId?: string, - ) { + ): void { // this will get intercepted by electron-main will-navigate super.startSingleSignOn(mxClient, loginType, fragmentAfterLogin, idpId); Modal.createDialog(InfoDialog, { @@ -372,7 +366,7 @@ export default class ElectronPlatform extends VectorBasePlatform { public async getPickleKey(userId: string, deviceId: string): Promise { try { - return await this.ipc.call('getPickleKey', userId, deviceId); + return await this.ipc.call("getPickleKey", userId, deviceId); } catch (e) { // if we can't connect to the password storage, assume there's no // pickle key @@ -382,7 +376,7 @@ export default class ElectronPlatform extends VectorBasePlatform { public async createPickleKey(userId: string, deviceId: string): Promise { try { - return await this.ipc.call('createPickleKey', userId, deviceId); + return await this.ipc.call("createPickleKey", userId, deviceId); } catch (e) { // if we can't connect to the password storage, assume there's no // pickle key @@ -392,7 +386,7 @@ export default class ElectronPlatform extends VectorBasePlatform { public async destroyPickleKey(userId: string, deviceId: string): Promise { try { - await this.ipc.call('destroyPickleKey', userId, deviceId); + await this.ipc.call("destroyPickleKey", userId, deviceId); } catch (e) {} } } diff --git a/src/vector/platform/IPCManager.ts b/src/vector/platform/IPCManager.ts index 6e9abf16f2..868f528d3e 100644 --- a/src/vector/platform/IPCManager.ts +++ b/src/vector/platform/IPCManager.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { defer, IDeferred } from 'matrix-js-sdk/src/utils'; +import { defer, IDeferred } from "matrix-js-sdk/src/utils"; import { logger } from "matrix-js-sdk/src/logger"; import { ElectronChannel } from "../../@types/global"; diff --git a/src/vector/platform/PWAPlatform.ts b/src/vector/platform/PWAPlatform.ts index ea0c9cf168..3cd73d1e6c 100644 --- a/src/vector/platform/PWAPlatform.ts +++ b/src/vector/platform/PWAPlatform.ts @@ -24,7 +24,7 @@ export default class PWAPlatform extends WebPlatform { if (this.notificationCount === count) return; this.notificationCount = count; - navigator.setAppBadge(count).catch(e => { + navigator.setAppBadge(count).catch((e) => { logger.error("Failed to update PWA app badge", e); }); } diff --git a/src/vector/platform/SeshatIndexManager.ts b/src/vector/platform/SeshatIndexManager.ts index 2f08f49296..3526bcc464 100644 --- a/src/vector/platform/SeshatIndexManager.ts +++ b/src/vector/platform/SeshatIndexManager.ts @@ -19,7 +19,7 @@ import BaseEventIndexManager, { IEventAndProfile, IIndexStats, ISearchArgs, -} from 'matrix-react-sdk/src/indexing/BaseEventIndexManager'; +} from "matrix-react-sdk/src/indexing/BaseEventIndexManager"; import { IMatrixProfile, IEventWithRoomId as IMatrixEvent, IResultRoomEvents } from "matrix-js-sdk/src/@types/search"; import { IPCManager } from "./IPCManager"; @@ -28,35 +28,35 @@ export class SeshatIndexManager extends BaseEventIndexManager { private readonly ipc = new IPCManager("seshat", "seshatReply"); public async supportsEventIndexing(): Promise { - return this.ipc.call('supportsEventIndexing'); + return this.ipc.call("supportsEventIndexing"); } public async initEventIndex(userId: string, deviceId: string): Promise { - return this.ipc.call('initEventIndex', userId, deviceId); + return this.ipc.call("initEventIndex", userId, deviceId); } public async addEventToIndex(ev: IMatrixEvent, profile: IMatrixProfile): Promise { - return this.ipc.call('addEventToIndex', ev, profile); + return this.ipc.call("addEventToIndex", ev, profile); } public async deleteEvent(eventId: string): Promise { - return this.ipc.call('deleteEvent', eventId); + return this.ipc.call("deleteEvent", eventId); } public async isEventIndexEmpty(): Promise { - return this.ipc.call('isEventIndexEmpty'); + return this.ipc.call("isEventIndexEmpty"); } public async isRoomIndexed(roomId: string): Promise { - return this.ipc.call('isRoomIndexed', roomId); + return this.ipc.call("isRoomIndexed", roomId); } public async commitLiveEvents(): Promise { - return this.ipc.call('commitLiveEvents'); + return this.ipc.call("commitLiveEvents"); } public async searchEventIndex(searchConfig: ISearchArgs): Promise { - return this.ipc.call('searchEventIndex', searchConfig); + return this.ipc.call("searchEventIndex", searchConfig); } public async addHistoricEvents( @@ -64,42 +64,42 @@ export class SeshatIndexManager extends BaseEventIndexManager { checkpoint: ICrawlerCheckpoint | null, oldCheckpoint: ICrawlerCheckpoint | null, ): Promise { - return this.ipc.call('addHistoricEvents', events, checkpoint, oldCheckpoint); + return this.ipc.call("addHistoricEvents", events, checkpoint, oldCheckpoint); } public async addCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise { - return this.ipc.call('addCrawlerCheckpoint', checkpoint); + return this.ipc.call("addCrawlerCheckpoint", checkpoint); } public async removeCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise { - return this.ipc.call('removeCrawlerCheckpoint', checkpoint); + return this.ipc.call("removeCrawlerCheckpoint", checkpoint); } public async loadFileEvents(args): Promise { - return this.ipc.call('loadFileEvents', args); + return this.ipc.call("loadFileEvents", args); } public async loadCheckpoints(): Promise { - return this.ipc.call('loadCheckpoints'); + return this.ipc.call("loadCheckpoints"); } public async closeEventIndex(): Promise { - return this.ipc.call('closeEventIndex'); + return this.ipc.call("closeEventIndex"); } public async getStats(): Promise { - return this.ipc.call('getStats'); + return this.ipc.call("getStats"); } public async getUserVersion(): Promise { - return this.ipc.call('getUserVersion'); + return this.ipc.call("getUserVersion"); } public async setUserVersion(version: number): Promise { - return this.ipc.call('setUserVersion', version); + return this.ipc.call("setUserVersion", version); } public async deleteEventIndex(): Promise { - return this.ipc.call('deleteEventIndex'); + return this.ipc.call("deleteEventIndex"); } } diff --git a/src/vector/platform/VectorBasePlatform.ts b/src/vector/platform/VectorBasePlatform.ts index cca39ea45e..cbb3b9eeb5 100644 --- a/src/vector/platform/VectorBasePlatform.ts +++ b/src/vector/platform/VectorBasePlatform.ts @@ -17,8 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import BasePlatform from 'matrix-react-sdk/src/BasePlatform'; -import { _t } from 'matrix-react-sdk/src/languageHandler'; +import BasePlatform from "matrix-react-sdk/src/BasePlatform"; +import { _t } from "matrix-react-sdk/src/languageHandler"; import type { IConfigOptions } from "matrix-react-sdk/src/IConfigOptions"; import { getVectorConfig } from "../getconfig"; @@ -35,7 +35,7 @@ export default abstract class VectorBasePlatform extends BasePlatform { } public getHumanReadableName(): string { - return 'Vector Base Platform'; // no translation required: only used for analytics + return "Vector Base Platform"; // no translation required: only used for analytics } /** @@ -43,7 +43,7 @@ export default abstract class VectorBasePlatform extends BasePlatform { * it uses canvas, which can trigger a permission prompt in Firefox's resist fingerprinting mode. * See https://github.com/vector-im/element-web/issues/9605. */ - public get favicon() { + public get favicon(): Favicon { if (this._favicon) { return this._favicon; } @@ -51,7 +51,7 @@ export default abstract class VectorBasePlatform extends BasePlatform { return this._favicon; } - private updateFavicon() { + private updateFavicon(): void { let bgColor = "#d00"; let notif: string | number = this.notificationCount; @@ -63,13 +63,13 @@ export default abstract class VectorBasePlatform extends BasePlatform { this.favicon.badge(notif, { bgColor }); } - public setNotificationCount(count: number) { + public setNotificationCount(count: number): void { if (this.notificationCount === count) return; super.setNotificationCount(count); this.updateFavicon(); } - public setErrorStatus(errorDidOccur: boolean) { + public setErrorStatus(errorDidOccur: boolean): void { if (this.errorDidOccur === errorDidOccur) return; super.setErrorStatus(errorDidOccur); this.updateFavicon(); @@ -78,8 +78,7 @@ export default abstract class VectorBasePlatform extends BasePlatform { /** * Begin update polling, if applicable */ - public startUpdater() { - } + public startUpdater(): void {} /** * Get a sensible default display name for the diff --git a/src/vector/platform/WebPlatform.ts b/src/vector/platform/WebPlatform.ts index 4a1f8140c4..938fc8fd88 100644 --- a/src/vector/platform/WebPlatform.ts +++ b/src/vector/platform/WebPlatform.ts @@ -17,15 +17,15 @@ limitations under the License. */ import { UpdateCheckStatus, UpdateStatus } from "matrix-react-sdk/src/BasePlatform"; -import dis from 'matrix-react-sdk/src/dispatcher/dispatcher'; -import { _t } from 'matrix-react-sdk/src/languageHandler'; +import dis from "matrix-react-sdk/src/dispatcher/dispatcher"; +import { _t } from "matrix-react-sdk/src/languageHandler"; import { hideToast as hideUpdateToast, showToast as showUpdateToast } from "matrix-react-sdk/src/toasts/UpdateToast"; import { Action } from "matrix-react-sdk/src/dispatcher/actions"; -import { CheckUpdatesPayload } from 'matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload'; -import UAParser from 'ua-parser-js'; +import { CheckUpdatesPayload } from "matrix-react-sdk/src/dispatcher/payloads/CheckUpdatesPayload"; +import UAParser from "ua-parser-js"; import { logger } from "matrix-js-sdk/src/logger"; -import VectorBasePlatform from './VectorBasePlatform'; +import VectorBasePlatform from "./VectorBasePlatform"; import { parseQs } from "../url_utils"; const POKE_RATE_MS = 10 * 60 * 1000; // 10 min @@ -40,16 +40,16 @@ function getNormalizedAppVersion(version: string): string { } export default class WebPlatform extends VectorBasePlatform { - constructor() { + public constructor() { super(); // Register service worker if available on this platform - if ('serviceWorker' in navigator) { - navigator.serviceWorker.register('sw.js'); + if ("serviceWorker" in navigator) { + navigator.serviceWorker.register("sw.js"); } } public getHumanReadableName(): string { - return 'Web Platform'; // no translation required: only used for analytics + return "Web Platform"; // no translation required: only used for analytics } /** @@ -65,7 +65,7 @@ export default class WebPlatform extends VectorBasePlatform { * to display notifications. Otherwise false. */ public maySendNotifications(): boolean { - return window.Notification.permission === 'granted'; + return window.Notification.permission === "granted"; } /** @@ -79,7 +79,7 @@ export default class WebPlatform extends VectorBasePlatform { // annoyingly, the latest spec says this returns a // promise, but this is only supported in Chrome 46 // and Firefox 47, so adapt the callback API. - return new Promise(function(resolve) { + return new Promise(function (resolve) { window.Notification.requestPermission((result) => { resolve(result); }); @@ -142,30 +142,33 @@ export default class WebPlatform extends VectorBasePlatform { showUpdate: (currentVersion: string, mostRecentVersion: string) => void, showNoUpdate?: () => void, ): Promise => { - return this.getMostRecentVersion().then((mostRecentVersion) => { - const currentVersion = getNormalizedAppVersion(process.env.VERSION); - - if (currentVersion !== mostRecentVersion) { - if (this.shouldShowUpdate(mostRecentVersion)) { - console.log("Update available to " + mostRecentVersion + ", will notify user"); - showUpdate(currentVersion, mostRecentVersion); + return this.getMostRecentVersion().then( + (mostRecentVersion) => { + const currentVersion = getNormalizedAppVersion(process.env.VERSION); + + if (currentVersion !== mostRecentVersion) { + if (this.shouldShowUpdate(mostRecentVersion)) { + console.log("Update available to " + mostRecentVersion + ", will notify user"); + showUpdate(currentVersion, mostRecentVersion); + } else { + console.log("Update available to " + mostRecentVersion + " but won't be shown"); + } + return { status: UpdateCheckStatus.Ready }; } else { - console.log("Update available to " + mostRecentVersion + " but won't be shown"); + console.log("No update available, already on " + mostRecentVersion); + showNoUpdate?.(); } - return { status: UpdateCheckStatus.Ready }; - } else { - console.log("No update available, already on " + mostRecentVersion); - showNoUpdate?.(); - } - return { status: UpdateCheckStatus.NotAvailable }; - }, (err) => { - logger.error("Failed to poll for update", err); - return { - status: UpdateCheckStatus.Error, - detail: err.message || err.status ? err.status.toString() : 'Unknown Error', - }; - }); + return { status: UpdateCheckStatus.NotAvailable }; + }, + (err) => { + logger.error("Failed to poll for update", err); + return { + status: UpdateCheckStatus.Error, + detail: err.message || err.status ? err.status.toString() : "Unknown Error", + }; + }, + ); }; public startUpdateCheck(): void { @@ -197,7 +200,7 @@ export default class WebPlatform extends VectorBasePlatform { let osName = ua.getOS().name || "unknown OS"; // Stylise the value from the parser to match Apple's current branding. if (osName === "Mac OS") osName = "macOS"; - return _t('%(appName)s: %(browserName)s on %(osName)s', { + return _t("%(appName)s: %(browserName)s on %(osName)s", { appName, browserName, osName, diff --git a/src/vector/rageshakesetup.ts b/src/vector/rageshakesetup.ts index cddd7adc98..a5d2df4464 100644 --- a/src/vector/rageshakesetup.ts +++ b/src/vector/rageshakesetup.ts @@ -31,32 +31,36 @@ import SdkConfig from "matrix-react-sdk/src/SdkConfig"; import sendBugReport from "matrix-react-sdk/src/rageshake/submit-rageshake"; import { logger } from "matrix-js-sdk/src/logger"; -export function initRageshake() { +export function initRageshake(): Promise { // we manually check persistence for rageshakes ourselves - const prom = rageshake.init(/*setUpPersistence=*/false); - prom.then(() => { - logger.log("Initialised rageshake."); - logger.log("To fix line numbers in Chrome: " + - "Meatball menu → Settings → Ignore list → Add /rageshake\\.js$"); + const prom = rageshake.init(/*setUpPersistence=*/ false); + prom.then( + () => { + logger.log("Initialised rageshake."); + logger.log( + "To fix line numbers in Chrome: " + "Meatball menu → Settings → Ignore list → Add /rageshake\\.js$", + ); - window.addEventListener('beforeunload', () => { - logger.log('element-web closing'); - // try to flush the logs to indexeddb - rageshake.flush(); - }); + window.addEventListener("beforeunload", () => { + logger.log("element-web closing"); + // try to flush the logs to indexeddb + rageshake.flush(); + }); - rageshake.cleanup(); - }, (err) => { - logger.error("Failed to initialise rageshake: " + err); - }); + rageshake.cleanup(); + }, + (err) => { + logger.error("Failed to initialise rageshake: " + err); + }, + ); return prom; } -export function initRageshakeStore() { +export function initRageshakeStore(): Promise { return rageshake.tryInitStorage(); } -window.mxSendRageshake = function(text: string, withLogs?: boolean) { +window.mxSendRageshake = function (text: string, withLogs?: boolean): void { const url = SdkConfig.get().bug_report_endpoint_url; if (!url) { logger.error("Cannot send a rageshake - no bug_report_endpoint_url configured"); @@ -72,9 +76,12 @@ window.mxSendRageshake = function(text: string, withLogs?: boolean) { userText: text, sendLogs: withLogs, progressCallback: logger.log.bind(console), - }).then(() => { - logger.log("Bug report sent!"); - }, (err) => { - logger.error(err); - }); + }).then( + () => { + logger.log("Bug report sent!"); + }, + (err) => { + logger.error(err); + }, + ); }; diff --git a/src/vector/routing.ts b/src/vector/routing.ts index d2633cb8e3..92b2c7a59b 100644 --- a/src/vector/routing.ts +++ b/src/vector/routing.ts @@ -17,13 +17,14 @@ limitations under the License. // Parse the given window.location and return parameters that can be used when calling // MatrixChat.showScreen(screen, params) import { logger } from "matrix-js-sdk/src/logger"; +import { QueryDict } from "matrix-js-sdk/src/utils"; import MatrixChatType from "matrix-react-sdk/src/components/structures/MatrixChat"; import { parseQsFromFragment } from "./url_utils"; let lastLocationHashSet: string = null; -export function getScreenFromLocation(location: Location) { +export function getScreenFromLocation(location: Location): { screen: string; params: QueryDict } { const fragparts = parseQsFromFragment(location); return { screen: fragparts.location.substring(1), @@ -33,7 +34,7 @@ export function getScreenFromLocation(location: Location) { // Here, we do some crude URL analysis to allow // deep-linking. -function routeUrl(location: Location) { +function routeUrl(location: Location): void { if (!window.matrixChat) return; logger.log("Routing URL ", location.href); @@ -41,7 +42,7 @@ function routeUrl(location: Location) { (window.matrixChat as MatrixChatType).showScreen(s.screen, s.params); } -function onHashChange() { +function onHashChange(): void { if (decodeURIComponent(window.location.hash) === lastLocationHashSet) { // we just set this: no need to route it! return; @@ -51,13 +52,14 @@ function onHashChange() { // This will be called whenever the SDK changes screens, // so a web page can update the URL bar appropriately. -export function onNewScreen(screen: string, replaceLast = false) { +export function onNewScreen(screen: string, replaceLast = false): void { logger.log("newscreen " + screen); - const hash = '#/' + screen; + const hash = "#/" + screen; lastLocationHashSet = hash; // if the new hash is a substring of the old one then we are stripping fields e.g `via` so replace history - if (screen.startsWith("room/") && + if ( + screen.startsWith("room/") && window.location.hash.includes("/$") === hash.includes("/$") && // only if both did or didn't contain event link window.location.hash.startsWith(hash) ) { @@ -71,6 +73,6 @@ export function onNewScreen(screen: string, replaceLast = false) { } } -export function init() { - window.addEventListener('hashchange', onHashChange); +export function init(): void { + window.addEventListener("hashchange", onHashChange); } diff --git a/src/vector/static/incompatible-browser.html b/src/vector/static/incompatible-browser.html index 7fc193465f..38d3ee18af 100644 --- a/src/vector/static/incompatible-browser.html +++ b/src/vector/static/incompatible-browser.html @@ -1,10 +1,10 @@ - + - + - -
-
- -

Unsupported browser

-
-
-
-
-

Your browser can't run Element

-

Element uses many advanced browser features, some of which are not available or experimental in your current browser.

-

Please install Chrome, Firefox, - or Safari for the best experience.

+
+
+ +

Unsupported browser

+
+
+
+
+

Your browser can't run Element

+

+ Element uses many advanced browser features, some of which are not available or experimental in + your current browser. +

+

+ Please install Chrome, + Firefox, or Safari for + the best experience. +

+
-
-
-
-
-

Use Element on mobile

-

iOS (iPhone or iPad)

- - - Download on the App Store. - - - - - - - - - - - +
+
+
+

Use Element on mobile

+

iOS (iPhone or iPad)

+
+ + Download on the App Store. + + + + + + + + + + + + + + + + + + + + + + d="M52.065,8.96973 C52.065,6.1211 53.74273,4.33106 56.35895,4.33106 C58.98395,4.33106 60.65387,6.12106 60.65387,8.96973 C60.65387,11.82618 58.99274,13.6084 56.35895,13.6084 C53.72609,13.6084 52.065,11.82617 52.065,8.96973 Z M58.76031,8.96973 C58.76031,7.01563 57.8648,5.86231 56.35894,5.86231 C54.85308,5.86231 53.95855,7.02442 53.95855,8.96973 C53.95855,10.93164 54.85308,12.07618 56.35894,12.07618 C57.8648,12.07618 58.76027,10.93164 58.76027,8.96973 L58.76031,8.96973 Z" + id="Shape" + > + d="M62.18606,4.44238 L63.95852,4.44238 L63.95852,5.98338 L64.00152,5.98338 C64.248696,4.99136841 65.1576526,4.30863156 66.17925,4.34764 C66.393414,4.34689223 66.6069872,4.37015075 66.81597,4.41698 L66.81597,6.15526 C66.545601,6.07264332 66.2635596,6.03471129 65.98097,6.04296 C65.4346182,6.02079544 64.9058709,6.23853473 64.5335615,6.63900597 C64.161252,7.03947722 63.9825766,7.58267074 64.04445,8.12596 L64.04445,13.49608 L62.18605,13.49608 L62.18606,4.44238 Z" + id="Shape" + > + - + + + + + d="M6.68068,4.44434 C6.60346713,3.63722505 6.99048366,2.85611193 7.67941593,2.42859737 C8.36834819,2.0010828 9.24008181,2.0010828 9.92901407,2.42859737 C10.6179463,2.85611193 11.0049629,3.63722505 10.92775,4.44434 C11.0064319,5.25232226 10.6197687,6.03495038 9.93022554,6.4633853 C9.24068243,6.89182022 8.36774757,6.89182022 7.67820446,6.4633853 C6.98866134,6.03495038 6.60199806,5.25232226 6.68068,4.44434 Z M10.01368,4.44434 C10.01368,3.46827 9.5752,2.89747 8.80568,2.89747 C8.03322,2.89747 7.59868,3.46827 7.59868,4.44435 C7.59868,5.42824 8.03325,5.99464 8.80568,5.99464 C9.57522,5.99463 10.01369,5.42432 10.01369,4.44434 L10.01368,4.44434 Z" + id="Shape" + > + + d="M18.85354,2.19482 L19.709,2.19482 L19.709,2.91015 L19.77541,2.91015 C20.0063449,2.38347794 20.5459729,2.06130747 21.11916,2.1079 C21.5629768,2.07453177 21.9978859,2.2447899 22.3010908,2.57060207 C22.6042957,2.89641424 22.7428931,3.34242376 22.67775,3.7827 L22.67775,6.6977 L21.78908,6.6977 L21.78908,4.00586 C21.78908,3.28223 21.47463,2.92236 20.8174,2.92236 C20.5163658,2.90833912 20.2242202,3.02648257 20.0175546,3.24581678 C19.810889,3.465151 19.710315,3.76380101 19.7422,4.06347 L19.7422,6.69775 L18.85353,6.69775 L18.85354,2.19482 Z" + id="Shape" + > + + d="M26.21779,4.44434 C26.1406364,3.63717225 26.527714,2.85603936 27.2166974,2.4285182 C27.9056808,2.00099704 28.7774592,2.00099704 29.4664426,2.4285182 C30.155426,2.85603936 30.5425036,3.63717225 30.46535,4.44434 C30.543932,5.25235119 30.1571979,6.03495719 29.4676205,6.46337324 C28.7780432,6.89178929 27.9050968,6.89178929 27.2155195,6.46337324 C26.5259421,6.03495719 26.139208,5.25235119 26.21779,4.44434 Z M29.55079,4.44434 C29.55079,3.46827 29.11231,2.89747 28.34279,2.89747 C27.57033,2.89747 27.13579,3.46827 27.13579,4.44435 C27.13579,5.42824 27.57036,5.99464 28.34279,5.99464 C29.11232,5.99463 29.5508,5.42432 29.5508,4.44434 L29.55079,4.44434 Z" + id="Shape" + > + d="M31.4009,5.42432 C31.4009,4.61377 32.00442,4.14649 33.0757,4.08008 L34.29543,4.00977 L34.29543,3.6211 C34.29543,3.14551 33.98098,2.87696 33.37356,2.87696 C32.87747,2.87696 32.53372,3.05909 32.43508,3.37745 L31.57473,3.37745 C31.66555,2.60401 32.39309,2.10792 33.41457,2.10792 C34.54348,2.10792 35.1802,2.66992 35.1802,3.6211 L35.1802,6.69776 L34.32473,6.69776 L34.32473,6.06495 L34.25442,6.06495 C33.9638686,6.52707633 33.4471736,6.79716323 32.90188,6.77195 C32.5196161,6.81171181 32.1383711,6.68791066 31.8523958,6.43115244 C31.5664205,6.17439423 31.4024061,5.80864331 31.4009,5.42432 Z M34.29543,5.03955 L34.29543,4.66309 L33.19582,4.7334 C32.5757,4.7749 32.29445,4.98584 32.29445,5.38281 C32.29445,5.78808 32.64601,6.02392 33.12945,6.02392 C33.4156361,6.05288986 33.7013264,5.96447505 33.9211204,5.77891559 C34.1409144,5.59335613 34.2759916,5.32654106 34.29543,5.03955 Z" + id="Shape" + > + d="M36.34816,4.44434 C36.34816,3.02149 37.07961,2.12012 38.2173,2.12012 C38.7917768,2.09365013 39.3298275,2.40147287 39.59816,2.91012 L39.66457,2.91012 L39.66457,0.437 L40.55324,0.437 L40.55324,6.69774 L39.70168,6.69774 L39.70168,5.98631 L39.63137,5.98631 C39.3427542,6.49073698 38.7980745,6.79335648 38.21731,6.77195 C37.0718,6.772 36.34816,5.87061 36.34816,4.44434 Z M37.26616,4.44434 C37.26616,5.39942 37.71636,5.97413 38.46929,5.97413 C39.21829,5.97413 39.6812,5.39113 39.6812,4.44825 C39.6812,3.50977 39.21343,2.91846 38.46929,2.91846 C37.72121,2.91846 37.26613,3.49707 37.26613,4.44434 L37.26616,4.44434 Z" + id="Shape" + > + d="M44.23,4.44434 C44.1527871,3.63722505 44.5398037,2.85611193 45.2287359,2.42859737 C45.9176682,2.0010828 46.7894018,2.0010828 47.4783341,2.42859737 C48.1672663,2.85611193 48.5542829,3.63722505 48.47707,4.44434 C48.5557519,5.25232226 48.1690887,6.03495038 47.4795455,6.4633853 C46.7900024,6.89182022 45.9170676,6.89182022 45.2275245,6.4633853 C44.5379813,6.03495038 44.1513181,5.25232226 44.23,4.44434 Z M47.563,4.44434 C47.563,3.46827 47.12452,2.89747 46.355,2.89747 C45.58254,2.89747 45.148,3.46827 45.148,4.44435 C45.148,5.42824 45.58257,5.99464 46.355,5.99464 C47.12453,5.99463 47.563,5.42432 47.563,4.44434 Z" + id="Shape" + > + d="M49.66945,2.19482 L50.52492,2.19482 L50.52492,2.91015 L50.59133,2.91015 C50.8222649,2.38347794 51.3618929,2.06130747 51.93508,2.1079 C52.3788968,2.07453177 52.8138059,2.2447899 53.1170108,2.57060207 C53.4202157,2.89641424 53.5588131,3.34242376 53.49367,3.7827 L53.49367,6.6977 L52.605,6.6977 L52.605,4.00586 C52.605,3.28223 52.29055,2.92236 51.63332,2.92236 C51.3322858,2.90833912 51.0401402,3.02648257 50.8334746,3.24581678 C50.626809,3.465151 50.526235,3.76380101 50.55812,4.06347 L50.55812,6.69775 L49.66945,6.69775 L49.66945,2.19482 Z" + id="Shape" + > + d="M58.51516,1.07373 L58.51516,2.21533 L59.49075,2.21533 L59.49075,2.96387 L58.51516,2.96387 L58.51516,5.2793 C58.51516,5.75098 58.7095,5.95752 59.15188,5.95752 C59.2651356,5.95715754 59.3782775,5.95030966 59.49075,5.93701 L59.49075,6.67724 C59.3311595,6.70579072 59.1694656,6.72098004 59.00735,6.72265 C58.01907,6.72265 57.62551,6.37499 57.62551,5.50683 L57.62551,2.96383 L56.91067,2.96383 L56.91067,2.21529 L57.62551,2.21529 L57.62551,1.07373 L58.51516,1.07373 Z" + id="Shape" + > + + - - - - - - - + + + +

Android

+ + + + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Get it on F-Droid. + + + + + + + + + + + d="M5.68003571,6.29863415 L5.68003571,4.42449878 L4.13843589,4.42449878 L4.13843589,3.64866951 L6.61432589,3.64866951 L6.61432589,6.64455976 C6.24995506,6.90316951 5.84820327,7.09946423 5.40907054,7.2334439 C4.96995649,7.36430642 4.50125542,7.42973768 4.00296732,7.42973768 C2.91295744,7.42973768 2.0596344,7.1119263 1.44299821,6.47630354 C0.829483333,5.83757671 0.522725893,4.94958037 0.522725893,3.81231451 C0.522725893,2.67194459 0.829483333,1.78394825 1.44299821,1.14832549 C2.0596344,0.509598659 2.91295744,0.190235244 4.00296732,0.190235244 C4.45765054,0.190235244 4.88898,0.24631878 5.29695571,0.358485854 C5.70805274,0.470652927 6.08644143,0.635785447 6.43212179,0.853883415 L6.43212179,1.85873098 C6.08332012,1.56274154 5.71271601,1.33995943 5.32030946,1.19038463 C4.92790292,1.04082854 4.51525458,0.966050488 4.08236446,0.966050488 C3.22903208,0.966050488 2.58748149,1.20440902 2.15771268,1.6811261 C1.73104649,2.15784317 1.51771339,2.86824398 1.51771339,3.81232854 C1.51771339,4.75329033 1.73104649,5.46212976 2.15771268,5.93884683 C2.58748149,6.4155639 3.22903208,6.65392244 4.08236446,6.65392244 C4.41559696,6.65392244 4.71301851,6.6258802 4.97462911,6.56979573 C5.2362397,6.51059598 5.47136589,6.4202387 5.68000768,6.2987239 L5.68003571,6.29863415 Z" + id="Shape" + > + + + + + d="M37.8398036,0.956463415 C37.1546481,0.956463415 36.6096432,1.21195976 36.2047887,1.72295244 C35.803037,2.23394512 35.6021611,2.93032154 35.6021611,3.81208171 C35.6021611,4.69071911 35.803037,5.38553415 36.2047887,5.89652683 C36.6096432,6.40751951 37.1546481,6.66301585 37.8398036,6.66301585 C38.524959,6.66301585 39.066852,6.40751951 39.4654825,5.89652683 C39.8672343,5.38553415 40.0681102,4.69071911 40.0681102,3.81208171 C40.0681102,2.93032154 39.8672343,2.23394512 39.4654825,1.72295244 C39.0673754,1.21209065 38.5253515,0.956659756 37.8394111,0.956659756 L37.8398036,0.956463415 Z M37.8398036,0.18997439 C38.817708,0.18997439 39.5993998,0.518687398 40.1848789,1.17611341 C40.7703768,1.83043537 41.0631257,2.70908211 41.0631257,3.81205366 C41.0631257,4.91192114 40.7703768,5.79056789 40.1848789,6.4479939 C39.5993811,7.10231585 38.8176893,7.42947683 37.8398036,7.42947683 C36.8587965,7.42947683 36.0739835,7.10231585 35.4853643,6.4479939 C34.8998664,5.79369065 34.6071175,4.9150439 34.6071175,3.81205366 C34.6071175,2.70906341 34.8998664,1.83041667 35.4853643,1.17611341 C36.0739648,0.518687398 36.8587779,0.18997439 37.8398036,0.18997439 Z" + id="Shape" + > + + d="M14.4888571,14.6357134 L14.4888571,19.7020244 L13.8851641,19.7020244 C13.7044646,18.9049341 13.5319795,18.3009504 13.3677089,17.8900732 C13.2034365,17.4791959 12.981674,17.1176285 12.7024214,16.8053707 C11.9303365,15.9260976 10.3984651,15.486461 8.10680714,15.486461 C7.46615369,15.486461 7.03493637,15.5686346 6.81315518,15.7329817 C6.5995978,15.8891143 6.49281911,16.201372 6.49281911,16.6697549 L6.49281911,22.5369988 C7.74949196,22.5369988 8.64887768,22.269937 9.19097625,21.7358134 C9.73307482,21.2016898 10.1191173,20.2114744 10.3491036,18.7651671 L10.97744,18.7651671 L10.97744,27.3071427 L10.3491036,27.3071427 C10.1684059,25.8444362 9.80290431,24.8336516 9.25259875,24.274789 C8.70229506,23.7077923 7.78236851,23.4119618 6.49281911,23.3872976 L6.49281911,29.2668829 C6.49281911,29.9653724 6.66530417,30.4296545 7.01027429,30.6597293 C7.3552444,30.8815951 8.10678845,31.0171829 9.26490643,31.0664927 L9.26490643,31.695122 L0.184699286,31.695122 L0.184699286,31.0664927 C1.12105476,30.9678844 1.72475714,30.8076417 1.99580643,30.5857646 C2.26685571,30.3638988 2.40238036,29.9242622 2.40238036,29.2668549 L2.40238036,17.051611 C2.40238036,16.4024313 2.25042679,15.9545858 1.94651964,15.7080744 C1.6426125,15.4615443 1.05533905,15.3136337 0.184699286,15.2643427 L0.184699286,14.6357134 L14.4888571,14.6357134 Z" + id="Shape" + > + + d="M25.1956964,29.4035366 L25.1956964,16.9540854 C25.1956964,16.378861 25.0478548,15.9720976 24.7521714,15.7337951 C24.4564881,15.4954927 23.9061751,15.3393638 23.1012323,15.2654085 L23.1012323,14.6367793 L30.7891859,14.6367793 C33.7050871,14.6367793 35.9926145,15.3804553 37.651768,16.8678073 C39.3191267,18.3469504 40.1528061,20.3848813 40.1528061,22.9816 C40.1528061,25.5948114 39.3191267,27.7025837 37.651768,29.3049171 C35.9844093,30.8990976 33.7913623,31.6961878 31.072627,31.6961878 L23.1012323,31.6961878 L23.1012323,31.0675585 C23.8322355,31.0429074 24.3620171,30.8991013 24.690577,30.6361402 C25.027342,30.3731923 25.1957245,29.9623244 25.1957245,29.4035366 L25.1956964,29.4035366 Z M29.2737714,16.374878 L29.2737714,29.3541707 C29.2737714,29.9211675 29.3764382,30.3073898 29.5817718,30.5128378 C29.7871054,30.7100581 30.1731478,30.8086683 30.7398991,30.8086683 C32.3497659,30.8086683 33.585954,30.2293394 34.4484634,29.0706817 C34.8591492,28.503685 35.179476,27.7107085 35.4094436,26.6917524 C35.647635,25.6727963 35.7667307,24.5634671 35.7667307,23.3637646 C35.7667307,21.194285 35.4217606,19.4275858 34.7318204,18.0636671 C33.8776095,16.3462215 32.5552583,15.4874988 30.7647668,15.4874988 C29.7709194,15.4874988 29.2739957,15.7833293 29.2739957,16.3749902 L29.2737714,16.374878 Z" + id="Shape" + > + d="M46.4748036,20.0576829 L46.4748036,22.1284683 C47.0661889,21.2820683 47.6247164,20.6739801 48.1503861,20.3042037 C48.6842608,19.9344272 49.2633198,19.749539 49.887563,19.749539 C50.4789484,19.749539 50.9676576,19.9385411 51.3536907,20.3165451 C51.7397238,20.6863215 51.9327404,21.1547175 51.9327404,21.7217329 C51.9327404,22.2147744 51.7848987,22.6215378 51.4892154,22.9420232 C51.193532,23.2542809 50.8116015,23.4104098 50.3434237,23.4104098 C50.0148826,23.4104098 49.7397307,23.3446709 49.5179682,23.2131932 C49.2962057,23.0817136 49.0662287,22.8475156 48.8280373,22.5105993 C48.556988,22.1161586 48.3228992,21.9189383 48.1257707,21.9189383 C47.7068798,21.9189383 47.3454807,22.1572407 47.0415736,22.6338456 C46.7376664,23.1022415 46.5857129,23.6651338 46.5857129,24.3225224 L46.5857129,29.0927785 C46.5857129,29.8734322 46.6965941,30.3911285 46.9183566,30.6458676 C47.1483429,30.8923976 47.6493692,31.0403082 48.4214354,31.0895993 L48.4214354,31.6935737 L41.706879,31.6935737 L41.7068818,31.0895993 C42.2654093,30.990991 42.6309109,30.8430804 42.8033866,30.6458676 C42.9840843,30.4486472 43.0744331,30.0911936 43.0744331,29.5735066 L43.0744331,22.1532017 C43.0744331,21.6437237 42.9799808,21.28627 42.7910761,21.0808407 C42.6103766,20.8754115 42.2489776,20.7357192 41.706879,20.6617639 L41.706879,20.0577895 L46.4749129,20.0577895 L46.4748036,20.0576829 Z" + id="Shape" + > + d="M58.2021429,19.7519512 C59.8284386,19.7519512 61.1795731,20.3394984 62.2555464,21.5145927 C63.3397436,22.6814593 63.8818421,24.1482236 63.8818421,25.9148854 C63.8818421,27.673413 63.3397436,29.1361569 62.2555464,30.3031171 C61.1795731,31.4699837 59.8284386,32.0534171 58.2021429,32.0534171 C56.5512131,32.0534171 55.1877429,31.4699837 54.1117321,30.3031171 C53.0357588,29.1362504 52.4977721,27.6489171 52.4977721,25.8411171 C52.4977721,24.1236715 53.0480852,22.6814967 54.1487113,21.5145927 C55.2493373,20.3394984 56.6004718,19.7519512 58.2021148,19.7519512 L58.2021429,19.7519512 Z M58.2267862,20.5408232 C57.6929115,20.5408232 57.282235,20.7174931 56.9947568,21.0708329 C56.7155024,21.4159638 56.5142714,21.9952927 56.3910637,22.8088195 C56.2678599,23.6223463 56.2062579,24.7851553 56.2062579,26.2972463 C56.2062579,28.1461659 56.349997,29.4363163 56.6374752,30.1676976 C56.9331586,30.8990415 57.4547257,31.2647134 58.2021765,31.2647134 C58.9331797,31.2647134 59.4424204,30.8826049 59.7298986,30.1183878 C60.025582,29.3541707 60.1734236,28.0024065 60.1734236,26.0630951 C60.1734236,23.9923472 60.0296845,22.5542862 59.7422063,21.7489122 C59.4629519,20.943613 58.9578138,20.5409634 58.2267919,20.5409634 L58.2267862,20.5408232 Z" + id="Shape" + > + d="M69.7332321,20.0576829 L69.7332321,29.6472805 C69.7332321,30.1238854 69.8194747,30.4690163 69.9919597,30.6826732 C70.1644448,30.8881024 70.4724545,31.0236902 70.9159888,31.0894366 L70.9159888,31.693411 L64.891383,31.693411 L64.8913942,31.0894366 C65.4663506,30.9497406 65.8318522,30.7936117 65.987899,30.62105 C66.1439589,30.4402663 66.2219888,30.0910215 66.2219888,29.5733159 L66.2219888,22.153011 C66.2219888,21.6353053 66.1398526,21.2860606 65.9755801,21.1052768 C65.8113077,20.9244931 65.4499086,20.7765825 64.891383,20.6615451 L64.891383,20.0575707 L69.7334312,20.0575707 L69.7332321,20.0576829 Z M66.5792143,14.8313537 C66.9652474,14.4451407 67.4293132,14.2520341 67.9714118,14.2520341 C68.5135104,14.2520341 68.9693617,14.4451407 69.3389659,14.8313537 C69.7167939,15.2175667 69.9057079,15.6818488 69.9057079,16.2242 C69.9057079,16.7747602 69.7167939,17.2349378 69.3389659,17.6047329 C68.9693617,17.9745093 68.5052959,18.1593976 67.9467684,18.1593976 C67.3882409,18.1593976 66.9241751,17.9745093 66.5545709,17.6047329 C66.1849667,17.2349565 66.0001646,16.7665606 66.0001646,16.1995451 C66.0001646,15.6654215 66.1931812,15.2093577 66.5792143,14.8313537 Z" + id="Shape" + > + d="M80.0335536,32.0289024 L80.0335536,30.3895354 C79.4421682,31.0140508 78.9041815,31.4495736 78.4195936,31.6961037 C77.9349869,31.9344061 77.3559279,32.0535573 76.6824166,32.0535573 C75.360028,32.0535573 74.2676632,31.4947695 73.405322,30.3771939 C72.542906,29.2514093 72.111698,27.8298037 72.111698,26.1123768 C72.111698,24.2881028 72.5716613,22.7719728 73.4915879,21.5639866 C74.4115144,20.3560191 75.5655579,19.7520354 76.9537182,19.7520354 C77.5286746,19.7520354 78.0379154,19.8670821 78.4814404,20.0971756 C78.9249654,20.3272691 79.4177771,20.7340325 79.9598757,21.3174659 L79.9598757,16.6953073 C79.9598757,16.1200829 79.8489945,15.7502972 79.627232,15.58595 C79.4136746,15.421601 78.883893,15.3065542 78.0378873,15.2408098 L78.0378873,14.6368354 L83.4712087,14.6368354 L83.4712087,29.1447866 C83.4712087,29.6789102 83.5738755,30.0486959 83.7792091,30.2541439 C83.9927665,30.4595732 84.3870234,30.5787244 84.9619798,30.6115976 L84.9619798,31.1909171 L83.3972786,31.3881337 C82.1734636,31.5196133 81.0523154,31.7332702 80.0338339,32.0291044 L80.0335536,32.0289024 Z M79.9596318,28.8734146 L79.9596318,22.734939 C79.7789323,22.2583341 79.507883,21.8803301 79.1464839,21.6009268 C78.7933087,21.3133146 78.4072663,21.1695085 77.9883566,21.1695085 C77.2573534,21.1695085 76.7152548,21.5557309 76.3620609,22.3281756 C76.0170908,23.0923927 75.8446057,24.2880187 75.8446057,25.9150537 C75.8446057,27.5174431 76.0047738,28.7048415 76.3251098,29.4772488 C76.6454459,30.2496935 77.1423696,30.6359159 77.8158809,30.6359159 C78.3744084,30.6359159 78.90419,30.3483037 79.4052256,29.7730793 C79.553071,29.6087302 79.6803811,29.4361648 79.7871561,29.2553829 C79.9021474,29.0746011 79.959643,28.9472315 79.959643,28.8732744 L79.9596318,28.8734146 Z" + id="Shape" + > - - - - - -

Android

- - - - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Get it on F-Droid. - - - - - - - - - - - - - - + d="M40.46675,6.67476829 L37.3323571,10.7342683" + id="Shape" + stroke="#769616" + stroke-width="1.84532927" + fill="#8AB000" + fill-rule="nonzero" + stroke-linecap="round" + > + + - + d="M40.6545893,5.92334146 C40.9778691,5.92334146 41.3627714,6.02785963 41.2626839,6.51281463 C41.1862782,6.88305854 37.8241036,10.9964122 37.8241036,10.9964122 C37.0719054,11.9699854 35.9844561,11.4955963 36.7366543,10.5221634 L39.8606739,6.48257805 C40.0526737,6.26852098 40.3096379,5.93371951 40.6546454,5.92322927 L40.6545893,5.92334146 Z" + id="Shape" + fill="#8AB000" + fill-rule="nonzero" + > - + d="M8.87470536,6.67476829 L12.0105,10.7342683" + id="Shape" + stroke="#769616" + stroke-width="1.84532927" + fill="#8AB000" + fill-rule="nonzero" + stroke-linecap="round" + > + d="M8.89124643,5.75 C8.55669625,5.75886341 8.32927054,5.88950341 8.16767268,6.08111585 C9.66309768,7.85918415 9.91502661,8.14166341 11.9564191,10.6732622 C12.7086173,11.6468354 13.4921875,11.1436683 12.7399893,10.1700951 L9.604475,6.11087561 C9.43552898,5.88530451 9.17280911,5.75805 8.89119036,5.75044878 L8.89124643,5.75 Z" + id="Shape" + fill-opacity="0.29804" + fill="#FFFFFF" + fill-rule="nonzero" + > + d="M8.16147679,6.09023171 C8.07006914,6.19940037 7.74744536,6.68413659 8.14487964,7.23888537 L11.2803939,11.2986659 C12.0325921,12.272239 12.1287546,10.8467159 12.1287546,10.8467159 C12.1287546,10.8467159 9.37354482,7.51788659 8.16142071,6.09020366 L8.16147679,6.09023171 Z" + id="Shape" + fill-opacity="0.2" + fill="#263238" + fill-rule="nonzero" + > + d="M8.68966964,5.92334146 C8.36638982,5.92334146 7.9814875,6.02785963 8.081575,6.51281463 C8.15798073,6.88305854 11.5201554,10.9964122 11.5201554,10.9964122 C12.2723536,11.9699854 13.3598029,11.4955963 12.6076046,10.5221634 L9.483585,6.48257805 C9.29154036,6.26856585 9.03445286,5.93366341 8.68961357,5.92328537 L8.68966964,5.92334146 Z" + id="Shape" + fill="#8AB000" + fill-rule="nonzero" + > + + + + + + + + + d="M24.6714286,24.5735366 C22.5461252,24.5735366 20.7467089,26.0384683 20.2201982,28.0061463 L22.5906179,28.0061463 C22.9995748,27.2788415 23.767473,26.7879598 24.6714005,26.7879598 C26.0087882,26.7879598 27.0692111,27.8488768 27.0692111,29.1868598 C27.0692111,30.5248427 26.0087882,31.5857598 24.6714005,31.5857598 C23.7068318,31.5857598 22.8924223,31.0301695 22.5099311,30.2205134 L20.1827425,30.2205134 C20.6565741,32.2619878 22.49339,33.8000988 24.6715407,33.8000988 C27.2051002,33.8000988 29.2825746,31.7215439 29.2825746,29.1869159 C29.2825746,26.6521756 27.204988,24.5737329 24.6715407,24.5737329 L24.6714286,24.5735366 Z" + id="Shape" + fill="#0D47A1" + fill-rule="nonzero" + > + + + + + + d="M8.89152679,5.74242683 C8.53321466,5.73295225 8.20186636,5.93202601 8.04184972,6.25291205 C7.88183308,6.57379808 7.92213189,6.95837436 8.14518804,7.23908171 L10.8014598,10.6784232 C10.7075486,10.9245568 10.6536163,11.19065 10.6536163,11.4705768 L10.6536163,16.5785402 C10.6536163,17.8053098 11.6406977,18.7928512 12.8668957,18.7928512 L36.4760511,18.7928512 C37.7022491,18.7928512 38.6893306,17.8052817 38.6893306,16.5785402 L38.6893306,11.4705768 C38.6893306,11.1904873 38.6360487,10.9241305 38.5420337,10.6778622 L41.1977728,7.23908171 C41.4136365,6.96742572 41.4588967,6.59756916 41.3149131,6.28183678 C41.1709296,5.96610439 40.8620538,5.75789519 40.5154957,5.74295976 C40.2117646,5.72988939 39.9211038,5.86740249 39.7384859,6.11056707 L37.2114307,9.3827378 C36.9843414,9.30055488 36.7376271,9.25483537 36.4796986,9.25483537 L12.8705432,9.25483537 C12.6122305,9.25483537 12.3657882,9.30072317 12.1356991,9.38138305 L9.60687766,6.10921232 C9.43781797,5.88409848 9.17527379,5.74853032 8.89392945,5.74107207 L8.89152679,5.74242683 Z M12.8669911,19.6341463 C11.640793,19.6341463 10.6537116,20.6216878 10.6537116,21.8484573 L10.6537116,36.4930061 C10.6537116,37.7197756 11.640793,38.7073171 12.8669911,38.7073171 L36.4761464,38.7073171 C37.7023445,38.7073171 38.6894259,37.7197756 38.6894259,36.4930061 L38.6894259,21.8484573 C38.6922295,20.6232866 37.7053723,19.635689 36.4802116,19.635689 L12.8710562,19.635689 L12.8669911,19.6341463 Z" + id="Shape" + fill="url(#radialGradient-1)" + fill-rule="nonzero" + > - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+
- -
- diff --git a/src/vector/static/unable-to-load.html b/src/vector/static/unable-to-load.html index 7e6af16c5b..5cb007a1a7 100644 --- a/src/vector/static/unable-to-load.html +++ b/src/vector/static/unable-to-load.html @@ -1,11 +1,10 @@ - - + - - + - -
- -
- -
-
- -

Unable to load

+
+
-
-
-
-

Element can't load

-

Something went wrong and Element was unable to load.

+ +
+
+ +

Unable to load

+
+
+
+
+

Element can't load

+

Something went wrong and Element was unable to load.

+
+
- -
- diff --git a/src/vector/url_utils.ts b/src/vector/url_utils.ts index 98c6e39366..f4b09eed41 100644 --- a/src/vector/url_utils.ts +++ b/src/vector/url_utils.ts @@ -19,8 +19,7 @@ import { QueryDict, decodeParams } from "matrix-js-sdk/src/utils"; // We want to support some name / value pairs in the fragment // so we're re-using query string like format // -// returns {location, params} -export function parseQsFromFragment(location: Location) { +export function parseQsFromFragment(location: Location): { location: string; params: QueryDict } { // if we have a fragment, it will start with '#', which we need to drop. // (if we don't, this will return ''). const fragment = location.hash.substring(1); @@ -28,7 +27,7 @@ export function parseQsFromFragment(location: Location) { // our fragment may contain a query-param-like section. we need to fish // this out *before* URI-decoding because the params may contain ? and & // characters which are only URI-encoded once. - const hashparts = fragment.split('?'); + const hashparts = fragment.split("?"); const result = { location: decodeURIComponent(hashparts[0]), diff --git a/test/app-tests/loading-test.tsx b/test/app-tests/loading-test.tsx index d9b9008387..be705f79ad 100644 --- a/test/app-tests/loading-test.tsx +++ b/test/app-tests/loading-test.tsx @@ -18,27 +18,27 @@ limitations under the License. /* loading.js: test the myriad paths we have for loading the application */ import "fake-indexeddb/auto"; -import React from 'react'; +import React from "react"; import { render, screen, fireEvent, waitFor, RenderResult, waitForElementToBeRemoved } from "@testing-library/react"; -import PlatformPeg from 'matrix-react-sdk/src/PlatformPeg'; -import { MatrixClientPeg } from 'matrix-react-sdk/src/MatrixClientPeg'; -import MatrixChat from 'matrix-react-sdk/src/components/structures/MatrixChat'; -import dis from 'matrix-react-sdk/src/dispatcher/dispatcher'; -import MockHttpBackend from 'matrix-mock-request'; +import PlatformPeg from "matrix-react-sdk/src/PlatformPeg"; +import { MatrixClientPeg } from "matrix-react-sdk/src/MatrixClientPeg"; +import MatrixChat from "matrix-react-sdk/src/components/structures/MatrixChat"; +import dis from "matrix-react-sdk/src/dispatcher/dispatcher"; +import MockHttpBackend from "matrix-mock-request"; import { makeType } from "matrix-react-sdk/src/utils/TypeUtils"; -import { ValidatedServerConfig } from 'matrix-react-sdk/src/utils/ValidatedServerConfig'; +import { ValidatedServerConfig } from "matrix-react-sdk/src/utils/ValidatedServerConfig"; import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store"; -import { sleep } from "matrix-js-sdk/src/utils"; +import { QueryDict, sleep } from "matrix-js-sdk/src/utils"; import "../jest-mocks"; -import WebPlatform from '../../src/vector/platform/WebPlatform'; -import { parseQs, parseQsFromFragment } from '../../src/vector/url_utils'; +import WebPlatform from "../../src/vector/platform/WebPlatform"; +import { parseQs, parseQsFromFragment } from "../../src/vector/url_utils"; import { cleanLocalstorage, deleteIndexedDB } from "../test-utils"; -const DEFAULT_HS_URL = 'http://my_server'; -const DEFAULT_IS_URL = 'http://my_is'; +const DEFAULT_HS_URL = "http://my_server"; +const DEFAULT_IS_URL = "http://my_is"; -describe('loading:', function() { +describe("loading:", function () { let parentDiv; let httpBackend; @@ -51,10 +51,10 @@ describe('loading:', function() { // a promise which resolves when the MatrixChat calls onTokenLoginCompleted let tokenLoginCompletePromise; - beforeEach(function() { + beforeEach(function () { httpBackend = new MockHttpBackend(); window.fetch = httpBackend.fetchFn; - parentDiv = document.createElement('div'); + parentDiv = document.createElement("div"); // uncomment this to actually add the div to the UI, to help with // debugging (but slow things down) @@ -64,17 +64,14 @@ describe('loading:', function() { matrixChat = null; }); - afterEach(async function() { + afterEach(async function () { console.log(`${Date.now()}: loading: afterEach`); matrixChat?.unmount(); // unmounting should have cleared the MatrixClientPeg expect(MatrixClientPeg.get()).toBe(null); // clear the indexeddbs so we can start from a clean slate next time. - await Promise.all([ - deleteIndexedDB('matrix-js-sdk:crypto'), - deleteIndexedDB('matrix-js-sdk:riot-web-sync'), - ]); + await Promise.all([deleteIndexedDB("matrix-js-sdk:crypto"), deleteIndexedDB("matrix-js-sdk:riot-web-sync")]); cleanLocalstorage(); console.log(`${Date.now()}: loading: afterEach complete`); }); @@ -84,7 +81,7 @@ describe('loading:', function() { * TODO: it would be nice to factor some of this stuff out of index.js so * that we can test it rather than our own implementation of it. */ - function loadApp(opts?) { + function loadApp(opts?): void { opts = opts || {}; const queryString = opts.queryString || ""; const uriFragment = opts.uriFragment || ""; @@ -92,19 +89,21 @@ describe('loading:', function() { windowLocation = { search: queryString, hash: uriFragment, - toString: function() { return this.search + this.hash; }, + toString: function (): string { + return this.search + this.hash; + }, }; - function onNewScreen(screen) { - console.log(Date.now() + " newscreen "+screen); - const hash = '#/' + screen; + function onNewScreen(screen): void { + console.log(Date.now() + " newscreen " + screen); + const hash = "#/" + screen; windowLocation.hash = hash; - console.log(Date.now() + " browser URI now "+ windowLocation); + console.log(Date.now() + " browser URI now " + windowLocation); } // Parse the given window.location and return parameters that can be used when calling // MatrixChat.showScreen(screen, params) - function getScreenFromLocation(location) { + function getScreenFromLocation(location): { screen: string; params: QueryDict } { const fragparts = parseQsFromFragment(location); return { screen: fragparts.location.substring(1), @@ -114,25 +113,28 @@ describe('loading:', function() { const fragParts = parseQsFromFragment(windowLocation); - const config = Object.assign({ - default_hs_url: DEFAULT_HS_URL, - default_is_url: DEFAULT_IS_URL, - validated_server_config: makeType(ValidatedServerConfig, { - hsUrl: DEFAULT_HS_URL, - hsName: "TEST_ENVIRONMENT", - hsNameIsDifferent: false, // yes, we lie - isUrl: DEFAULT_IS_URL, - }), - embeddedPages: { - homeUrl: 'data:text/html;charset=utf-8;base64,PGh0bWw+PC9odG1sPg==', + const config = Object.assign( + { + default_hs_url: DEFAULT_HS_URL, + default_is_url: DEFAULT_IS_URL, + validated_server_config: makeType(ValidatedServerConfig, { + hsUrl: DEFAULT_HS_URL, + hsName: "TEST_ENVIRONMENT", + hsNameIsDifferent: false, // yes, we lie + isUrl: DEFAULT_IS_URL, + }), + embeddedPages: { + homeUrl: "data:text/html;charset=utf-8;base64,PGh0bWw+PC9odG1sPg==", + }, }, - }, opts.config || {}); + opts.config || {}, + ); PlatformPeg.set(new WebPlatform()); const params = parseQs(windowLocation); - tokenLoginCompletePromise = new Promise(resolve => { + tokenLoginCompletePromise = new Promise((resolve) => { matrixChat = render( {throw new Error('Not implemented');}} - />, parentDiv, + makeRegistrationUrl={(): string => { + throw new Error("Not implemented"); + }} + />, + parentDiv, ); }); } @@ -153,23 +158,25 @@ describe('loading:', function() { // http requests until we do. // // returns a promise resolving to the received request - async function expectAndAwaitSync(opts?) { + async function expectAndAwaitSync(opts?): Promise { let syncRequest = null; - httpBackend.when('GET', '/_matrix/client/versions') - .respond(200, { - "versions": ["r0.3.0"], - "unstable_features": { - "m.lazy_load_members": true, - }, - }); + httpBackend.when("GET", "/_matrix/client/versions").respond(200, { + versions: ["r0.3.0"], + unstable_features: { + "m.lazy_load_members": true, + }, + }); const isGuest = opts && opts.isGuest; if (!isGuest) { // the call to create the LL filter - httpBackend.when('POST', '/filter').respond(200, { filter_id: 'llfid' }); - httpBackend.when('GET', '/pushrules').respond(200, {}); + httpBackend.when("POST", "/filter").respond(200, { filter_id: "llfid" }); + httpBackend.when("GET", "/pushrules").respond(200, {}); } - httpBackend.when('GET', '/sync') - .check((r) => {syncRequest = r;}) + httpBackend + .when("GET", "/sync") + .check((r) => { + syncRequest = r; + }) .respond(200, {}); for (let attempts = 10; attempts > 0; attempts--) { @@ -182,29 +189,35 @@ describe('loading:', function() { throw new Error("Gave up waiting for /sync"); } - describe("Clean load with no stored credentials:", function() { - it('gives a welcome page by default', function() { + describe("Clean load with no stored credentials:", function () { + it("gives a welcome page by default", function () { loadApp(); - return sleep(1).then(async () => { - // at this point, we're trying to do a guest registration; - // we expect a spinner - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/register').check(function(req) { - expect(req.queryParams.kind).toEqual('guest'); - }).respond(403, "Guest access is disabled"); - - return httpBackend.flush(); - }).then(() => { - // Wait for another trip around the event loop for the UI to update - return awaitWelcomeComponent(matrixChat); - }).then(() => { - return waitFor(() => expect(windowLocation.hash).toEqual("#/welcome")); - }); + return sleep(1) + .then(async () => { + // at this point, we're trying to do a guest registration; + // we expect a spinner + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(403, "Guest access is disabled"); + + return httpBackend.flush(); + }) + .then(() => { + // Wait for another trip around the event loop for the UI to update + return awaitWelcomeComponent(matrixChat); + }) + .then(() => { + return waitFor(() => expect(windowLocation.hash).toEqual("#/welcome")); + }); }); - it('should follow the original link after successful login', function() { + it("should follow the original link after successful login", function () { loadApp({ uriFragment: "#/room/!room:id", }); @@ -213,39 +226,48 @@ describe('loading:', function() { httpBackend.when("GET", "/versions").respond(200, { versions: ["r0.4.0"] }); httpBackend.when("GET", "/api/v1").respond(200, {}); - return sleep(1).then(async () => { - // at this point, we're trying to do a guest registration; - // we expect a spinner - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/register').check(function(req) { - expect(req.queryParams.kind).toEqual('guest'); - }).respond(403, "Guest access is disabled"); - - return httpBackend.flush(); - }).then(() => { - // Wait for another trip around the event loop for the UI to update - return sleep(10); - }).then(() => { - return moveFromWelcomeToLogin(matrixChat); - }).then(() => { - return completeLogin(matrixChat); - }).then(() => { - // once the sync completes, we should have a room view - return awaitRoomView(matrixChat); - }).then(() => { - httpBackend.verifyNoOutstandingExpectation(); - expect(windowLocation.hash).toEqual("#/room/!room:id"); - - // and the localstorage should have been updated - expect(localStorage.getItem('mx_user_id')).toEqual('@user:id'); - expect(localStorage.getItem('mx_access_token')).toEqual('access_token'); - expect(localStorage.getItem('mx_hs_url')).toEqual(DEFAULT_HS_URL); - expect(localStorage.getItem('mx_is_url')).toEqual(DEFAULT_IS_URL); - }); + return sleep(1) + .then(async () => { + // at this point, we're trying to do a guest registration; + // we expect a spinner + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(403, "Guest access is disabled"); + + return httpBackend.flush(); + }) + .then(() => { + // Wait for another trip around the event loop for the UI to update + return sleep(10); + }) + .then(() => { + return moveFromWelcomeToLogin(matrixChat); + }) + .then(() => { + return completeLogin(matrixChat); + }) + .then(() => { + // once the sync completes, we should have a room view + return awaitRoomView(matrixChat); + }) + .then(() => { + httpBackend.verifyNoOutstandingExpectation(); + expect(windowLocation.hash).toEqual("#/room/!room:id"); + + // and the localstorage should have been updated + expect(localStorage.getItem("mx_user_id")).toEqual("@user:id"); + expect(localStorage.getItem("mx_access_token")).toEqual("access_token"); + expect(localStorage.getItem("mx_hs_url")).toEqual(DEFAULT_HS_URL); + expect(localStorage.getItem("mx_is_url")).toEqual(DEFAULT_IS_URL); + }); }); - it.skip('should not register as a guest when using a #/login link', function() { + it.skip("should not register as a guest when using a #/login link", function () { loadApp({ uriFragment: "#/login", }); @@ -254,37 +276,35 @@ describe('loading:', function() { httpBackend.when("GET", "/versions").respond(200, { versions: ["r0.4.0"] }); httpBackend.when("GET", "/api/v1").respond(200, {}); - return awaitLoginComponent(matrixChat).then(async () => { - await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading...")); - // we expect a single component - await screen.findByRole("main"); - screen.getAllByText("Sign in"); - - // the only outstanding request should be a GET /login - // (in particular there should be no /register request for - // guest registration). - const allowedRequests = [ - "/_matrix/client/r0/login", - "/versions", - "/api/v1", - ]; - for (const req of httpBackend.requests) { - if (req.method === 'GET' && allowedRequests.find(p => req.path.endsWith(p))) { - continue; + return awaitLoginComponent(matrixChat) + .then(async () => { + await waitForElementToBeRemoved(() => screen.queryAllByLabelText("Loading...")); + // we expect a single component + await screen.findByRole("main"); + screen.getAllByText("Sign in"); + + // the only outstanding request should be a GET /login + // (in particular there should be no /register request for + // guest registration). + const allowedRequests = ["/_matrix/client/r0/login", "/versions", "/api/v1"]; + for (const req of httpBackend.requests) { + if (req.method === "GET" && allowedRequests.find((p) => req.path.endsWith(p))) { + continue; + } + + throw new Error(`Unexpected HTTP request to ${req}`); } - - throw new Error(`Unexpected HTTP request to ${req}`); - } - return completeLogin(matrixChat); - }).then(() => { - expect(matrixChat.container.querySelector(".mx_HomePage")).toBeTruthy(); - expect(windowLocation.hash).toEqual("#/home"); - }); + return completeLogin(matrixChat); + }) + .then(() => { + expect(matrixChat.container.querySelector(".mx_HomePage")).toBeTruthy(); + expect(windowLocation.hash).toEqual("#/home"); + }); }); }); - describe("MatrixClient rehydrated from stored credentials:", function() { - beforeEach(async function() { + describe("MatrixClient rehydrated from stored credentials:", function () { + beforeEach(async function () { localStorage.setItem("mx_hs_url", "http://localhost"); localStorage.setItem("mx_is_url", "http://localhost"); localStorage.setItem("mx_access_token", "access_token"); @@ -292,63 +312,68 @@ describe('loading:', function() { localStorage.setItem("mx_last_room_id", "!last_room:id"); // Create a crypto store as well to satisfy storage consistency checks - const cryptoStore = new IndexedDBCryptoStore( - indexedDB, - "matrix-js-sdk:crypto", - ); + const cryptoStore = new IndexedDBCryptoStore(indexedDB, "matrix-js-sdk:crypto"); await cryptoStore.startup(); }); - it('shows the last known room by default', function() { + it("shows the last known room by default", function () { loadApp(); - return awaitLoggedIn(matrixChat).then(() => { - // we are logged in - let the sync complete - return expectAndAwaitSync(); - }).then(() => { - // once the sync completes, we should have a room view - return awaitRoomView(matrixChat); - }).then(() => { - httpBackend.verifyNoOutstandingExpectation(); - expect(windowLocation.hash).toEqual("#/room/!last_room:id"); - }); + return awaitLoggedIn(matrixChat) + .then(() => { + // we are logged in - let the sync complete + return expectAndAwaitSync(); + }) + .then(() => { + // once the sync completes, we should have a room view + return awaitRoomView(matrixChat); + }) + .then(() => { + httpBackend.verifyNoOutstandingExpectation(); + expect(windowLocation.hash).toEqual("#/room/!last_room:id"); + }); }); - it('shows a home page by default if we have no joined rooms', function() { + it("shows a home page by default if we have no joined rooms", function () { localStorage.removeItem("mx_last_room_id"); loadApp(); - return awaitLoggedIn(matrixChat).then(() => { - // we are logged in - let the sync complete - return expectAndAwaitSync(); - }).then(() => { - // once the sync completes, we should have a home page - httpBackend.verifyNoOutstandingExpectation(); - expect(matrixChat.container.querySelector(".mx_HomePage")).toBeTruthy(); - expect(windowLocation.hash).toEqual("#/home"); - }); + return awaitLoggedIn(matrixChat) + .then(() => { + // we are logged in - let the sync complete + return expectAndAwaitSync(); + }) + .then(() => { + // once the sync completes, we should have a home page + httpBackend.verifyNoOutstandingExpectation(); + expect(matrixChat.container.querySelector(".mx_HomePage")).toBeTruthy(); + expect(windowLocation.hash).toEqual("#/home"); + }); }); - it('shows a room view if we followed a room link', function() { + it("shows a room view if we followed a room link", function () { loadApp({ uriFragment: "#/room/!room:id", }); - return awaitLoggedIn(matrixChat).then(() => { - // we are logged in - let the sync complete - return expectAndAwaitSync(); - }).then(() => { - // once the sync completes, we should have a room view - return awaitRoomView(matrixChat); - }).then(() => { - httpBackend.verifyNoOutstandingExpectation(); - expect(windowLocation.hash).toEqual("#/room/!room:id"); - }); + return awaitLoggedIn(matrixChat) + .then(() => { + // we are logged in - let the sync complete + return expectAndAwaitSync(); + }) + .then(() => { + // once the sync completes, we should have a room view + return awaitRoomView(matrixChat); + }) + .then(() => { + httpBackend.verifyNoOutstandingExpectation(); + expect(windowLocation.hash).toEqual("#/room/!room:id"); + }); }); - describe('/#/login link:', function() { - beforeEach(function() { + describe("/#/login link:", function () { + beforeEach(function () { loadApp({ uriFragment: "#/login", }); @@ -357,7 +382,7 @@ describe('loading:', function() { return expectAndAwaitSync(); }); - it('does not show a login view', async function() { + it("does not show a login view", async function () { await awaitRoomView(matrixChat); await screen.findByLabelText("Spaces"); @@ -366,136 +391,165 @@ describe('loading:', function() { }); }); - describe('Guest auto-registration:', function() { - it('shows a welcome page by default', function() { + describe("Guest auto-registration:", function () { + it("shows a welcome page by default", function () { loadApp(); - return sleep(1).then(async () => { - // at this point, we're trying to do a guest registration; - // we expect a spinner - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/register').check(function(req) { - expect(req.queryParams.kind).toEqual('guest'); - }).respond(200, { - user_id: "@guest:localhost", - access_token: "secret_token", + return sleep(1) + .then(async () => { + // at this point, we're trying to do a guest registration; + // we expect a spinner + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(200, { + user_id: "@guest:localhost", + access_token: "secret_token", + }); + + return httpBackend.flush(); + }) + .then(() => { + return awaitLoggedIn(matrixChat); + }) + .then(() => { + // we are logged in - let the sync complete + return expectAndAwaitSync({ isGuest: true }); + }) + .then(() => { + // once the sync completes, we should have a welcome page + httpBackend.verifyNoOutstandingExpectation(); + expect(matrixChat.container.querySelector(".mx_Welcome")).toBeTruthy(); + expect(windowLocation.hash).toEqual("#/welcome"); }); - - return httpBackend.flush(); - }).then(() => { - return awaitLoggedIn(matrixChat); - }).then(() => { - // we are logged in - let the sync complete - return expectAndAwaitSync({ isGuest: true }); - }).then(() => { - // once the sync completes, we should have a welcome page - httpBackend.verifyNoOutstandingExpectation(); - expect(matrixChat.container.querySelector(".mx_Welcome")).toBeTruthy(); - expect(windowLocation.hash).toEqual("#/welcome"); - }); }); - it('uses the default homeserver to register with', function() { + it("uses the default homeserver to register with", function () { loadApp(); - return sleep(1).then(async () => { - // at this point, we're trying to do a guest registration; - // we expect a spinner - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/register').check(function(req) { + return sleep(1) + .then(async () => { + // at this point, we're trying to do a guest registration; + // we expect a spinner + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.path.startsWith(DEFAULT_HS_URL)).toBe(true); + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(200, { + user_id: "@guest:localhost", + access_token: "secret_token", + }); + + return httpBackend.flush(); + }) + .then(() => { + return awaitLoggedIn(matrixChat); + }) + .then(() => { + return expectAndAwaitSync({ isGuest: true }); + }) + .then((req) => { expect(req.path.startsWith(DEFAULT_HS_URL)).toBe(true); - expect(req.queryParams.kind).toEqual('guest'); - }).respond(200, { - user_id: "@guest:localhost", - access_token: "secret_token", - }); - - return httpBackend.flush(); - }).then(() => { - return awaitLoggedIn(matrixChat); - }).then(() => { - return expectAndAwaitSync({ isGuest: true }); - }).then((req) => { - expect(req.path.startsWith(DEFAULT_HS_URL)).toBe(true); - // once the sync completes, we should have a welcome page - httpBackend.verifyNoOutstandingExpectation(); - expect(matrixChat.container.querySelector(".mx_Welcome")).toBeTruthy(); - expect(windowLocation.hash).toEqual("#/welcome"); - expect(MatrixClientPeg.get().baseUrl).toEqual(DEFAULT_HS_URL); - expect(MatrixClientPeg.get().idBaseUrl).toEqual(DEFAULT_IS_URL); - }); + // once the sync completes, we should have a welcome page + httpBackend.verifyNoOutstandingExpectation(); + expect(matrixChat.container.querySelector(".mx_Welcome")).toBeTruthy(); + expect(windowLocation.hash).toEqual("#/welcome"); + expect(MatrixClientPeg.get().baseUrl).toEqual(DEFAULT_HS_URL); + expect(MatrixClientPeg.get().idBaseUrl).toEqual(DEFAULT_IS_URL); + }); }); - it('shows a room view if we followed a room link', function() { + it("shows a room view if we followed a room link", function () { loadApp({ uriFragment: "#/room/!room:id", }); - return sleep(1).then(async () => { - // at this point, we're trying to do a guest registration; - // we expect a spinner - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/register').check(function(req) { - expect(req.queryParams.kind).toEqual('guest'); - }).respond(200, { - user_id: "@guest:localhost", - access_token: "secret_token", + return sleep(1) + .then(async () => { + // at this point, we're trying to do a guest registration; + // we expect a spinner + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(200, { + user_id: "@guest:localhost", + access_token: "secret_token", + }); + + return httpBackend.flush(); + }) + .then(() => { + return awaitLoggedIn(matrixChat); + }) + .then(() => { + return expectAndAwaitSync({ isGuest: true }); + }) + .then(() => { + // once the sync completes, we should have a room view + return awaitRoomView(matrixChat); + }) + .then(() => { + httpBackend.verifyNoOutstandingExpectation(); + expect(windowLocation.hash).toEqual("#/room/!room:id"); }); - - return httpBackend.flush(); - }).then(() => { - return awaitLoggedIn(matrixChat); - }).then(() => { - return expectAndAwaitSync({ isGuest: true }); - }).then(() => { - // once the sync completes, we should have a room view - return awaitRoomView(matrixChat); - }).then(() => { - httpBackend.verifyNoOutstandingExpectation(); - expect(windowLocation.hash).toEqual("#/room/!room:id"); - }); }); - describe('Login as user', function() { - beforeEach(function() { + describe("Login as user", function () { + beforeEach(function () { // first we have to load the homepage loadApp(); - httpBackend.when('POST', '/register').check(function(req) { - expect(req.queryParams.kind).toEqual('guest'); - }).respond(200, { - user_id: "@guest:localhost", - access_token: "secret_token", - }); - - return httpBackend.flush().then(() => { - return awaitLoggedIn(matrixChat); - }).then(() => { - // we got a sync spinner - let the sync complete - return expectAndAwaitSync(); - }).then(async () => { - // once the sync completes, we should have a home page - await waitFor(() => matrixChat.container.querySelector(".mx_HomePage")); - - // we simulate a click on the 'login' button by firing off - // the relevant dispatch. - // - // XXX: is it an anti-pattern to access the react-sdk's - // dispatcher in this way? Is it better to find the login - // button and simulate a click? (we might have to arrange - // for it to be shown - it's not always, due to the - // collapsing left panel - - dis.dispatch({ action: 'start_login' }); - - return awaitLoginComponent(matrixChat); - }); + httpBackend + .when("POST", "/register") + .check(function (req) { + expect(req.queryParams.kind).toEqual("guest"); + }) + .respond(200, { + user_id: "@guest:localhost", + access_token: "secret_token", + }); + + return httpBackend + .flush() + .then(() => { + return awaitLoggedIn(matrixChat); + }) + .then(() => { + // we got a sync spinner - let the sync complete + return expectAndAwaitSync(); + }) + .then(async () => { + // once the sync completes, we should have a home page + await waitFor(() => matrixChat.container.querySelector(".mx_HomePage")); + + // we simulate a click on the 'login' button by firing off + // the relevant dispatch. + // + // XXX: is it an anti-pattern to access the react-sdk's + // dispatcher in this way? Is it better to find the login + // button and simulate a click? (we might have to arrange + // for it to be shown - it's not always, due to the + // collapsing left panel + + dis.dispatch({ action: "start_login" }); + + return awaitLoginComponent(matrixChat); + }); }); - it('should give us a login page', async function() { + it("should give us a login page", async function () { // we expect a single component await screen.findByRole("main"); screen.getAllByText("Sign in"); @@ -505,97 +559,109 @@ describe('loading:', function() { }); }); - describe('Token login:', function() { - it('logs in successfully', function() { + describe("Token login:", function () { + it("logs in successfully", function () { localStorage.setItem("mx_sso_hs_url", "https://homeserver"); localStorage.setItem("mx_sso_is_url", "https://idserver"); loadApp({ queryString: "?loginToken=secretToken", }); - return sleep(1).then(async () => { - // we expect a spinner while we're logging in - await assertAtLoadingSpinner(); - - httpBackend.when('POST', '/login').check(function(req) { - expect(req.path).toMatch(new RegExp("^https://homeserver/")); - expect(req.data.type).toEqual("m.login.token"); - expect(req.data.token).toEqual("secretToken"); - }).respond(200, { - user_id: "@user:localhost", - device_id: 'DEVICE_ID', - access_token: "access_token", + return sleep(1) + .then(async () => { + // we expect a spinner while we're logging in + await assertAtLoadingSpinner(); + + httpBackend + .when("POST", "/login") + .check(function (req) { + expect(req.path).toMatch(new RegExp("^https://homeserver/")); + expect(req.data.type).toEqual("m.login.token"); + expect(req.data.token).toEqual("secretToken"); + }) + .respond(200, { + user_id: "@user:localhost", + device_id: "DEVICE_ID", + access_token: "access_token", + }); + + return httpBackend.flush(); + }) + .then(() => { + // at this point, MatrixChat should fire onTokenLoginCompleted, which + // makes index.js reload the app. We're not going to attempt to + // simulate the reload - just check that things are left in the + // right state for the reloaded app. + + return tokenLoginCompletePromise; + }) + .then(() => { + // check that the localstorage has been set up in such a way that + // the reloaded app can pick up where we leave off. + expect(localStorage.getItem("mx_user_id")).toEqual("@user:localhost"); + expect(localStorage.getItem("mx_access_token")).toEqual("access_token"); + expect(localStorage.getItem("mx_hs_url")).toEqual("https://homeserver"); + expect(localStorage.getItem("mx_is_url")).toEqual("https://idserver"); }); - - return httpBackend.flush(); - }).then(() => { - // at this point, MatrixChat should fire onTokenLoginCompleted, which - // makes index.js reload the app. We're not going to attempt to - // simulate the reload - just check that things are left in the - // right state for the reloaded app. - - return tokenLoginCompletePromise; - }).then(() => { - // check that the localstorage has been set up in such a way that - // the reloaded app can pick up where we leave off. - expect(localStorage.getItem('mx_user_id')).toEqual('@user:localhost'); - expect(localStorage.getItem('mx_access_token')).toEqual('access_token'); - expect(localStorage.getItem('mx_hs_url')).toEqual('https://homeserver'); - expect(localStorage.getItem('mx_is_url')).toEqual('https://idserver'); - }); }); }); // check that we have a Login component, send a 'user:pass' login, // and await the HTTP requests. - async function completeLogin(matrixChat: RenderResult) { + async function completeLogin(matrixChat: RenderResult): Promise { // When we switch to the login component, it'll hit the login endpoint // for proof of life and to get flows. We'll only give it one option. - httpBackend.when('GET', '/login') - .respond(200, { flows: [{ type: "m.login.password" }] }); + httpBackend.when("GET", "/login").respond(200, { flows: [{ type: "m.login.password" }] }); httpBackend.flush(); // We already would have tried the GET /login request // Give the component some time to finish processing the login flows before // continuing. await sleep(100); - httpBackend.when('POST', '/login').check(function(req) { - expect(req.data.type).toEqual('m.login.password'); - expect(req.data.identifier.type).toEqual('m.id.user'); - expect(req.data.identifier.user).toEqual('user'); - expect(req.data.password).toEqual('pass'); - }).respond(200, { - user_id: '@user:id', - device_id: 'DEVICE_ID', - access_token: 'access_token', - }); + httpBackend + .when("POST", "/login") + .check(function (req) { + expect(req.data.type).toEqual("m.login.password"); + expect(req.data.identifier.type).toEqual("m.id.user"); + expect(req.data.identifier.user).toEqual("user"); + expect(req.data.password).toEqual("pass"); + }) + .respond(200, { + user_id: "@user:id", + device_id: "DEVICE_ID", + access_token: "access_token", + }); fireEvent.change(matrixChat.container.querySelector("#mx_LoginForm_username"), { target: { value: "user" } }); fireEvent.change(matrixChat.container.querySelector("#mx_LoginForm_password"), { target: { value: "pass" } }); fireEvent.click(screen.getByText("Sign in", { selector: ".mx_Login_submit" })); - return httpBackend.flush().then(() => { - // Wait for another trip around the event loop for the UI to update - return sleep(1); - }).then(() => { - return expectAndAwaitSync().catch((e) => { - throw new Error("Never got /sync after login: did the client start?"); + return httpBackend + .flush() + .then(() => { + // Wait for another trip around the event loop for the UI to update + return sleep(1); + }) + .then(() => { + return expectAndAwaitSync().catch((e) => { + throw new Error("Never got /sync after login: did the client start?"); + }); + }) + .then(() => { + httpBackend.verifyNoOutstandingExpectation(); }); - }).then(() => { - httpBackend.verifyNoOutstandingExpectation(); - }); } }); // assert that we are on the loading page -async function assertAtLoadingSpinner() { +async function assertAtLoadingSpinner(): Promise { await screen.findByRole("progressbar"); } -async function awaitLoggedIn(matrixChat: RenderResult) { +async function awaitLoggedIn(matrixChat: RenderResult): Promise { if (matrixChat.container.querySelector(".mx_MatrixChat_wrapper")) return; // already logged in - return new Promise(resolve => { - const onAction = ({ action }) => { + return new Promise((resolve) => { + const onAction = ({ action }): void => { if (action !== "on_logged_in") { return; } @@ -608,19 +674,19 @@ async function awaitLoggedIn(matrixChat: RenderResult) { }); } -async function awaitRoomView(matrixChat: RenderResult) { +async function awaitRoomView(matrixChat: RenderResult): Promise { await waitFor(() => matrixChat.container.querySelector(".mx_RoomView")); } -async function awaitLoginComponent(matrixChat: RenderResult) { +async function awaitLoginComponent(matrixChat: RenderResult): Promise { await waitFor(() => matrixChat.container.querySelector(".mx_AuthPage")); } -async function awaitWelcomeComponent(matrixChat: RenderResult) { +async function awaitWelcomeComponent(matrixChat: RenderResult): Promise { await waitFor(() => matrixChat.container.querySelector(".mx_Welcome")); } -function moveFromWelcomeToLogin(matrixChat: RenderResult) { - dis.dispatch({ action: 'start_login' }); +function moveFromWelcomeToLogin(matrixChat: RenderResult): Promise { + dis.dispatch({ action: "start_login" }); return awaitLoginComponent(matrixChat); } diff --git a/test/jest-mocks.ts b/test/jest-mocks.ts index 7a5503667a..3302ea9ff9 100644 --- a/test/jest-mocks.ts +++ b/test/jest-mocks.ts @@ -15,9 +15,9 @@ limitations under the License. */ // https://jestjs.io/docs/en/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom -Object.defineProperty(window, 'matchMedia', { +Object.defineProperty(window, "matchMedia", { writable: true, - value: jest.fn().mockImplementation(query => ({ + value: jest.fn().mockImplementation((query) => ({ matches: false, media: query, onchange: null, diff --git a/test/test-utils.ts b/test/test-utils.ts index 2960d4f83c..84234ef34e 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -29,19 +29,17 @@ export function deleteIndexedDB(dbName: string): Promise { console.log(`${startTime}: Removing indexeddb instance: ${dbName}`); const req = window.indexedDB.deleteDatabase(dbName); - req.onblocked = () => { + req.onblocked = (): void => { console.log(`${Date.now()}: can't yet delete indexeddb ${dbName} because it is open elsewhere`); }; - req.onerror = (ev) => { - reject(new Error( - `${Date.now()}: unable to delete indexeddb ${dbName}: ${req.error}`, - )); + req.onerror = (ev): void => { + reject(new Error(`${Date.now()}: unable to delete indexeddb ${dbName}: ${req.error}`)); }; - req.onsuccess = () => { + req.onsuccess = (): void => { const now = Date.now(); - console.log(`${now}: Removed indexeddb instance: ${dbName} in ${now-startTime} ms`); + console.log(`${now}: Removed indexeddb instance: ${dbName} in ${now - startTime} ms`); resolve(); }; }).catch((e) => { diff --git a/test/unit-tests/components/views/dialogs/TchapCreateRoomDialog-test.tsx b/test/unit-tests/components/views/dialogs/TchapCreateRoomDialog-test.tsx index b80e4b8105..a76b795ce7 100644 --- a/test/unit-tests/components/views/dialogs/TchapCreateRoomDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/TchapCreateRoomDialog-test.tsx @@ -75,12 +75,6 @@ describe("TchapCreateRoomDialog", () => { { showRoomFederationOption: true, roomFederationDefault: false }); }); - it('should render the whole component', () => { - const component = getComponent(); - // If this breaks too often, it may not be useful, we will remove it. Leaving for now. - expect(toJson(component)).toMatchSnapshot("all the component"); - }); - it('should render the whole component with with the allow access switch', () => { jest.spyOn(TchapUtils, 'getRoomFederationOptions').mockReturnValue( { showRoomFederationOption: true, roomFederationDefault: false }); diff --git a/test/unit-tests/components/views/dialogs/__snapshots__/TchapCreateRoomDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/__snapshots__/TchapCreateRoomDialog-test.tsx.snap index d0a48720aa..85a85b5856 100644 --- a/test/unit-tests/components/views/dialogs/__snapshots__/TchapCreateRoomDialog-test.tsx.snap +++ b/test/unit-tests/components/views/dialogs/__snapshots__/TchapCreateRoomDialog-test.tsx.snap @@ -60,833 +60,3 @@ exports[`TchapCreateRoomDialog should render the whole component with with the a
`; - -exports[`TchapCreateRoomDialog should render the whole component: all the component 1`] = ` - - - - - -
- -
-

- Create a room -

-
-
-
-
-
- - -
-
-