diff --git a/.eslintrc.js b/.eslintrc.js index c759eae9e3..bf6e245b93 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,9 @@ module.exports = { - extends: ["matrix-org", "matrix-org/react-legacy"], - parser: "babel-eslint", - + plugins: ["matrix-org"], + extends: [ + "plugin:matrix-org/babel", + "plugin:matrix-org/react", + ], env: { browser: true, node: true, @@ -15,12 +17,32 @@ module.exports = { "prefer-promise-reject-errors": "off", "no-async-promise-executor": "off", "quotes": "off", - }, + "no-extra-boolean-cast": "off", + // Bind or arrow functions in props causes performance issues (but we + // currently use them in some places). + // It's disabled here, but we should using it sparingly. + "react/jsx-no-bind": "off", + "react/jsx-key": ["error"], + }, overrides: [{ - "files": ["src/**/*.{ts,tsx}", "test/**/*.{ts,tsx}"], - "extends": ["matrix-org/ts"], - "rules": { + files: [ + "src/**/*.{ts,tsx}", + "test/**/*.{ts,tsx}", + ], + extends: [ + "plugin:matrix-org/typescript", + "plugin:matrix-org/react", + ], + rules: { + // Things we do that break the ideal style + "prefer-promise-reject-errors": "off", + "quotes": "off", + "no-extra-boolean-cast": "off", + + // Remove Babel things manually due to override limitations + "@babel/no-invalid-this": ["off"], + // We're okay being explicit at the moment "@typescript-eslint/no-empty-interface": "off", // We disable this while we're transitioning @@ -28,8 +50,6 @@ module.exports = { // We'd rather not do this but we do "@typescript-eslint/ban-ts-comment": "off", - "quotes": "off", - "no-extra-boolean-cast": "off", "no-restricted-properties": [ "error", ...buildRestrictedPropertiesOptions( diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 81770c6585..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,6 +0,0 @@ -[include] -src/**/*.js -test/**/*.js - -[ignore] -node_modules/ diff --git a/babel.config.js b/babel.config.js index 0a3a34a391..f00e83652c 100644 --- a/babel.config.js +++ b/babel.config.js @@ -10,7 +10,6 @@ module.exports = { ], }], "@babel/preset-typescript", - "@babel/preset-flow", "@babel/preset-react", ], "plugins": [ @@ -19,7 +18,6 @@ module.exports = { "@babel/plugin-proposal-numeric-separator", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-object-rest-spread", - "@babel/plugin-transform-flow-comments", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-transform-runtime", ], diff --git a/package.json b/package.json index bae7b1e4cf..4ad585ba7d 100644 --- a/package.json +++ b/package.json @@ -104,16 +104,16 @@ "devDependencies": { "@babel/cli": "^7.12.10", "@babel/core": "^7.12.10", + "@babel/eslint-parser": "^7.12.10", + "@babel/eslint-plugin": "^7.12.10", "@babel/parser": "^7.12.11", "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-proposal-decorators": "^7.12.12", "@babel/plugin-proposal-export-default-from": "^7.12.1", "@babel/plugin-proposal-numeric-separator": "^7.12.7", "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-transform-flow-comments": "^7.12.1", "@babel/plugin-transform-runtime": "^7.12.10", "@babel/preset-env": "^7.12.11", - "@babel/preset-flow": "^7.12.1", "@babel/preset-react": "^7.12.10", "@babel/preset-typescript": "^7.12.7", "@babel/register": "^7.12.10", @@ -139,18 +139,16 @@ "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "^2.3.1", "@types/zxcvbn": "^4.4.0", - "@typescript-eslint/eslint-plugin": "^4.14.0", - "@typescript-eslint/parser": "^4.14.0", + "@typescript-eslint/eslint-plugin": "^4.17.0", + "@typescript-eslint/parser": "^4.17.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.6.1", - "babel-eslint": "^10.1.0", "babel-jest": "^26.6.3", "chokidar": "^3.5.1", "concurrently": "^5.3.0", "enzyme": "^3.11.0", "eslint": "7.18.0", - "eslint-config-matrix-org": "^0.2.0", - "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-flowtype": "^5.2.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#main", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", "glob": "^7.1.6", diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index c7dd678c07..f254ca3226 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -111,6 +111,29 @@ $roomListCollapsedWidth: 68px; } } + .mx_LeftPanel_dialPadButton { + width: 32px; + height: 32px; + border-radius: 8px; + background-color: $roomlist-button-bg-color; + position: relative; + margin-left: 8px; + + &::before { + content: ''; + position: absolute; + top: 8px; + left: 8px; + width: 16px; + height: 16px; + mask-image: url('$(res)/img/element-icons/call/dialpad.svg'); + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background: $secondary-fg-color; + } + } + .mx_LeftPanel_exploreButton { width: 32px; height: 32px; @@ -185,6 +208,12 @@ $roomListCollapsedWidth: 68px; flex-direction: column; justify-content: center; + .mx_LeftPanel_dialPadButton { + margin-left: 0; + margin-top: 8px; + background-color: transparent; + } + .mx_LeftPanel_exploreButton { margin-left: 0; margin-top: 8px; diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index 8cc00aba0f..de9e049165 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -112,7 +112,7 @@ limitations under the License. .mx_AccessibleButton { padding: 5px 10px; - padding-left: 28px; // 16px for the icon, 2px margin to text, 10px regular padding + padding-left: 30px; // 18px for the icon, 2px margin to text, 10px regular padding display: inline-block; position: relative; @@ -128,13 +128,14 @@ limitations under the License. mask-repeat: no-repeat; mask-position: center; mask-size: contain; + width: 18px; + height: 18px; + top: 50%; // text sizes are dynamic + transform: translateY(-50%); } &.mx_RoomStatusBar_unsentCancelAllBtn::before { mask-image: url('$(res)/img/element-icons/trashcan.svg'); - width: 12px; - height: 16px; - top: calc(50% - 8px); // text sizes are dynamic } &.mx_RoomStatusBar_unsentResendAllBtn { @@ -142,9 +143,6 @@ limitations under the License. &::before { mask-image: url('$(res)/img/element-icons/retry.svg'); - width: 18px; - height: 18px; - top: calc(50% - 9px); // text sizes are dynamic } } } diff --git a/res/css/structures/_ToastContainer.scss b/res/css/structures/_ToastContainer.scss index 35d6087a1b..d248568740 100644 --- a/res/css/structures/_ToastContainer.scss +++ b/res/css/structures/_ToastContainer.scss @@ -134,12 +134,15 @@ limitations under the License. .mx_Toast_buttons { float: right; display: flex; - gap: 5px; .mx_AccessibleButton { min-width: 96px; box-sizing: border-box; } + + .mx_AccessibleButton + .mx_AccessibleButton { + margin-left: 5px; + } } .mx_Toast_description { diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss index 2ecb93e734..338841cce4 100644 --- a/res/css/views/context_menus/_MessageContextMenu.scss +++ b/res/css/views/context_menus/_MessageContextMenu.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2021 Michael Weimann Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,16 +16,69 @@ limitations under the License. */ .mx_MessageContextMenu { - padding: 6px; -} -.mx_MessageContextMenu_field { - display: block; - padding: 3px 6px 3px 6px; - cursor: pointer; - white-space: nowrap; -} + .mx_IconizedContextMenu_icon { + width: 16px; + height: 16px; + display: block; -.mx_MessageContextMenu_field.mx_MessageContextMenu_fieldSet { - font-weight: bold; + &::before { + content: ''; + width: 16px; + height: 16px; + display: block; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background: $primary-fg-color; + } + } + + .mx_MessageContextMenu_iconCollapse::before { + mask-image: url('$(res)/img/element-icons/message/chevron-up.svg'); + } + + .mx_MessageContextMenu_iconReport::before { + mask-image: url('$(res)/img/element-icons/warning-badge.svg'); + } + + .mx_MessageContextMenu_iconLink::before { + mask-image: url('$(res)/img/element-icons/link.svg'); + } + + .mx_MessageContextMenu_iconPermalink::before { + mask-image: url('$(res)/img/element-icons/room/share.svg'); + } + + .mx_MessageContextMenu_iconUnhidePreview::before { + mask-image: url('$(res)/img/element-icons/settings/appearance.svg'); + } + + .mx_MessageContextMenu_iconForward::before { + mask-image: url('$(res)/img/element-icons/message/fwd.svg'); + } + + .mx_MessageContextMenu_iconRedact::before { + mask-image: url('$(res)/img/element-icons/trashcan.svg'); + } + + .mx_MessageContextMenu_iconResend::before { + mask-image: url('$(res)/img/element-icons/retry.svg'); + } + + .mx_MessageContextMenu_iconSource::before { + mask-image: url('$(res)/img/element-icons/room/format-bar/code.svg'); + } + + .mx_MessageContextMenu_iconQuote::before { + mask-image: url('$(res)/img/element-icons/room/format-bar/quote.svg'); + } + + .mx_MessageContextMenu_iconPin::before { + mask-image: url('$(res)/img/element-icons/room/pin-upright.svg'); + } + + .mx_MessageContextMenu_iconUnpin::before { + mask-image: url('$(res)/img/element-icons/room/pin.svg'); + } } diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index 1976a43ab9..95d7ce74c4 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -34,7 +34,7 @@ limitations under the License. > .mx_ForwardDialog_preview { max-height: 30%; flex-shrink: 0; - overflow: scroll; + overflow-y: auto; div { pointer-events: none; diff --git a/res/css/views/messages/_TextualEvent.scss b/res/css/views/messages/_TextualEvent.scss index be7565b3c5..e87fed90de 100644 --- a/res/css/views/messages/_TextualEvent.scss +++ b/res/css/views/messages/_TextualEvent.scss @@ -17,4 +17,9 @@ limitations under the License. .mx_TextualEvent { opacity: 0.5; overflow-y: hidden; + + a { + color: $accent-color; + cursor: pointer; + } } diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss index ae8d22a462..5e61c3b8a3 100644 --- a/res/css/views/rooms/_IRCLayout.scss +++ b/res/css/views/rooms/_IRCLayout.scss @@ -29,6 +29,7 @@ $irc-line-height: $font-18px; // timestamps are links which shouldn't be underlined > a { text-decoration: none; + min-width: 45px; } display: flex; @@ -49,18 +50,6 @@ $irc-line-height: $font-18px; } } - > .mx_SenderProfile { - order: 2; - flex-shrink: 0; - width: var(--name-width); - text-overflow: ellipsis; - text-align: left; - display: flex; - align-items: center; - overflow: visible; - justify-content: flex-end; - } - .mx_EventTile_line, .mx_EventTile_reply { padding: 0; display: flex; @@ -173,27 +162,37 @@ $irc-line-height: $font-18px; border-left: 0; } - .mx_SenderProfile_hover { - background-color: $primary-bg-color; - overflow: hidden; + .mx_SenderProfile { + width: var(--name-width); display: flex; + order: 2; + flex-shrink: 0; + justify-content: flex-start; + align-items: center; > .mx_SenderProfile_displayName { + width: 100%; + text-align: end; overflow: hidden; text-overflow: ellipsis; - min-width: var(--name-width); - text-align: end; + } + + > .mx_SenderProfile_mxid { + visibility: collapse; } } .mx_SenderProfile:hover { - justify-content: flex-start; - } - - .mx_SenderProfile_hover:hover { overflow: visible; - width: max(auto, 100%); z-index: 10; + + > .mx_SenderProfile_displayName { + overflow: visible; + } + + > .mx_SenderProfile_mxid { + visibility: visible; + } } .mx_ReplyThread { @@ -201,16 +200,7 @@ $irc-line-height: $font-18px; .mx_SenderProfile { width: unset; max-width: var(--name-width); - } - - .mx_SenderProfile_hover { background: transparent; - - > span { - > .mx_SenderProfile_displayName { - min-width: inherit; - } - } } .mx_EventTile_emote { diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss index a3ee104bd8..5501ab343e 100644 --- a/res/css/views/rooms/_VoiceRecordComposerTile.scss +++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss @@ -36,10 +36,10 @@ limitations under the License. } .mx_VoiceRecordComposerTile_delete { - width: 14px; // w&h are size of icon - height: 18px; + width: 24px; + height: 24px; vertical-align: middle; - margin-right: 11px; // distance from left edge of waveform container (container has some margin too) + margin-right: 8px; // distance from left edge of waveform container (container has some margin too) background-color: $voice-record-icon-color; mask-repeat: no-repeat; mask-size: contain; diff --git a/res/css/views/spaces/_SpaceBasicSettings.scss b/res/css/views/spaces/_SpaceBasicSettings.scss index 68e8723f11..c73e0715dd 100644 --- a/res/css/views/spaces/_SpaceBasicSettings.scss +++ b/res/css/views/spaces/_SpaceBasicSettings.scss @@ -73,7 +73,7 @@ limitations under the License. } } - .mx_AccessibleButton { + .mx_AccessibleButton_hasKind { padding: 8px 22px; margin-left: auto; display: block; diff --git a/res/css/views/voice_messages/_PlaybackContainer.scss b/res/css/views/voice_messages/_PlaybackContainer.scss index 20def16d6a..f0e29900ab 100644 --- a/res/css/views/voice_messages/_PlaybackContainer.scss +++ b/res/css/views/voice_messages/_PlaybackContainer.scss @@ -33,9 +33,14 @@ limitations under the License. font-size: $font-14px; line-height: $font-24px; + contain: content; + .mx_Waveform { .mx_Waveform_bar { background-color: $voice-record-waveform-incomplete-fg-color; + height: 100%; + /* Variable set by a JS component */ + transform: scaleY(max(0.05, var(--barHeight))); &.mx_Waveform_bar_100pct { // Small animation to remove the mechanical feel of progress diff --git a/res/img/element-icons/call/dialpad.svg b/res/img/element-icons/call/dialpad.svg new file mode 100644 index 0000000000..a97e80aa0b --- /dev/null +++ b/res/img/element-icons/call/dialpad.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/message/chevron-up.svg b/res/img/element-icons/message/chevron-up.svg new file mode 100644 index 0000000000..4eb5ecc33e --- /dev/null +++ b/res/img/element-icons/message/chevron-up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/corner-up-right.svg b/res/img/element-icons/message/corner-up-right.svg new file mode 100644 index 0000000000..0b8f961b7b --- /dev/null +++ b/res/img/element-icons/message/corner-up-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/fwd.svg b/res/img/element-icons/message/fwd.svg new file mode 100644 index 0000000000..8bcc70d092 --- /dev/null +++ b/res/img/element-icons/message/fwd.svg @@ -0,0 +1,3 @@ + + + diff --git a/res/img/element-icons/message/link.svg b/res/img/element-icons/message/link.svg new file mode 100644 index 0000000000..c89dd41c23 --- /dev/null +++ b/res/img/element-icons/message/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/repeat.svg b/res/img/element-icons/message/repeat.svg new file mode 100644 index 0000000000..c7657b08ed --- /dev/null +++ b/res/img/element-icons/message/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/message/share.svg b/res/img/element-icons/message/share.svg new file mode 100644 index 0000000000..df38c14d63 --- /dev/null +++ b/res/img/element-icons/message/share.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/img/element-icons/trashcan.svg b/res/img/element-icons/trashcan.svg index f8fb8b5c46..4106f0bd60 100644 --- a/res/img/element-icons/trashcan.svg +++ b/res/img/element-icons/trashcan.svg @@ -1,3 +1,3 @@ - - + + diff --git a/res/img/element-icons/warning-badge.svg b/res/img/element-icons/warning-badge.svg index 1ae4e40ffe..1c8da9aa8e 100644 --- a/res/img/element-icons/warning-badge.svg +++ b/res/img/element-icons/warning-badge.svg @@ -1,5 +1,32 @@ - - - - + + + + + + image/svg+xml + + + + + + + diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile index 1d1425c865..6d33987d8c 100644 --- a/scripts/ci/Dockerfile +++ b/scripts/ci/Dockerfile @@ -5,4 +5,4 @@ FROM node:14-buster RUN apt-get update RUN apt-get -y install jq build-essential python3-dev libffi-dev python-pip python-setuptools sqlite3 libssl-dev python-virtualenv libjpeg-dev libxslt1-dev uuid-runtime # dependencies for chrome (installed by puppeteer) -RUN apt-get -y install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget +RUN apt-get -y install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm-dev libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget diff --git a/src/@types/common.ts b/src/@types/common.ts index b887bd4090..1fb9ba4303 100644 --- a/src/@types/common.ts +++ b/src/@types/common.ts @@ -17,7 +17,7 @@ limitations under the License. import { JSXElementConstructor } from "react"; // Based on https://stackoverflow.com/a/53229857/3532235 -export type Without = {[P in Exclude] ? : never}; +export type Without = {[P in Exclude]?: never}; export type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; export type Writeable = { -readonly [P in keyof T]: T[P] }; diff --git a/src/AddThreepid.js b/src/AddThreepid.js index f06f7c187d..eb822c6d75 100644 --- a/src/AddThreepid.js +++ b/src/AddThreepid.js @@ -16,12 +16,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import * as sdk from './index'; import Modal from './Modal'; import { _t } from './languageHandler'; import IdentityAuthClient from './IdentityAuthClient'; -import {SSOAuthEntry} from "./components/views/auth/InteractiveAuthEntryComponents"; +import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryComponents"; function getIdServerDomain() { return MatrixClientPeg.get().idBaseUrl.split("://")[1]; @@ -189,7 +189,6 @@ export default class AddThreepid { // pop up an interactive auth dialog const InteractiveAuthDialog = sdk.getComponent("dialogs.InteractiveAuthDialog"); - const dialogAesthetics = { [SSOAuthEntry.PHASE_PREAUTH]: { title: _t("Use Single Sign On to continue"), diff --git a/src/Analytics.tsx b/src/Analytics.tsx index 212bfd3757..8c82639b5f 100644 --- a/src/Analytics.tsx +++ b/src/Analytics.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; -import {getCurrentLanguage, _t, _td, IVariables} from './languageHandler'; +import { getCurrentLanguage, _t, _td, IVariables } from './languageHandler'; import PlatformPeg from './PlatformPeg'; import SdkConfig from './SdkConfig'; import Modal from './Modal'; diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 5483ea6874..5b4b15cc67 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -17,16 +17,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClient} from "matrix-js-sdk/src/client"; -import {encodeUnpaddedBase64} from "matrix-js-sdk/src/crypto/olmlib"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { encodeUnpaddedBase64 } from "matrix-js-sdk/src/crypto/olmlib"; import dis from './dispatcher/dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; -import {ActionPayload} from "./dispatcher/payloads"; -import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload"; -import {Action} from "./dispatcher/actions"; -import {hideToast as hideUpdateToast} from "./toasts/UpdateToast"; -import {MatrixClientPeg} from "./MatrixClientPeg"; -import {idbLoad, idbSave, idbDelete} from "./utils/StorageManager"; +import { ActionPayload } from "./dispatcher/payloads"; +import { CheckUpdatesPayload } from "./dispatcher/payloads/CheckUpdatesPayload"; +import { Action } from "./dispatcher/actions"; +import { hideToast as hideUpdateToast } from "./toasts/UpdateToast"; +import { MatrixClientPeg } from "./MatrixClientPeg"; +import { idbLoad, idbSave, idbDelete } from "./utils/StorageManager"; export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url"; export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url"; @@ -335,7 +335,7 @@ export default abstract class BasePlatform { try { const key = await crypto.subtle.decrypt( - {name: "AES-GCM", iv: data.iv, additionalData}, data.cryptoKey, + { name: "AES-GCM", iv: data.iv, additionalData }, data.cryptoKey, data.encrypted, ); return encodeUnpaddedBase64(key); @@ -348,7 +348,7 @@ export default abstract class BasePlatform { /** * Create and store a pickle key for encrypting libolm objects. * @param {string} userId the user ID for the user that the pickle key is for. - * @param {string} userId the device ID that the pickle key is for. + * @param {string} deviceId the device ID that the pickle key is for. * @returns {string|null} the pickle key, or null if the platform does not * support storing pickle keys. */ @@ -360,7 +360,7 @@ export default abstract class BasePlatform { const randomArray = new Uint8Array(32); crypto.getRandomValues(randomArray); const cryptoKey = await crypto.subtle.generateKey( - {name: "AES-GCM", length: 256}, false, ["encrypt", "decrypt"], + { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"], ); const iv = new Uint8Array(32); crypto.getRandomValues(iv); @@ -375,11 +375,11 @@ export default abstract class BasePlatform { } const encrypted = await crypto.subtle.encrypt( - {name: "AES-GCM", iv, additionalData}, cryptoKey, randomArray, + { name: "AES-GCM", iv, additionalData }, cryptoKey, randomArray, ); try { - await idbSave("pickleKey", [userId, deviceId], {encrypted, iv, cryptoKey}); + await idbSave("pickleKey", [userId, deviceId], { encrypted, iv, cryptoKey }); } catch (e) { return null; } diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index 448b1cb780..cb54db3f8a 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -55,7 +55,7 @@ limitations under the License. import React from 'react'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import PlatformPeg from './PlatformPeg'; import Modal from './Modal'; import { _t } from './languageHandler'; @@ -63,11 +63,11 @@ import dis from './dispatcher/dispatcher'; import WidgetUtils from './utils/WidgetUtils'; import WidgetEchoStore from './stores/WidgetEchoStore'; import SettingsStore from './settings/SettingsStore'; -import {Jitsi} from "./widgets/Jitsi"; -import {WidgetType} from "./widgets/WidgetType"; -import {SettingLevel} from "./settings/SettingLevel"; +import { Jitsi } from "./widgets/Jitsi"; +import { WidgetType } from "./widgets/WidgetType"; +import { SettingLevel } from "./settings/SettingLevel"; import { ActionPayload } from "./dispatcher/payloads"; -import {base32} from "rfc4648"; +import { base32 } from "rfc4648"; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; @@ -77,10 +77,10 @@ import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; import { MatrixCall, CallErrorCode, CallState, CallEvent, CallParty, CallType } from "matrix-js-sdk/src/webrtc/call"; import Analytics from './Analytics'; import CountlyAnalytics from "./CountlyAnalytics"; -import {UIFeature} from "./settings/UIFeature"; +import { UIFeature } from "./settings/UIFeature"; import { CallError } from "matrix-js-sdk/src/webrtc/call"; import { logger } from 'matrix-js-sdk/src/logger'; -import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker" +import DesktopCapturerSourcePicker from "./components/views/elements/DesktopCapturerSourcePicker"; import { Action } from './dispatcher/actions'; import VoipUserMapper from './VoipUserMapper'; import { addManagedHybridWidget, isManagedHybridWidgetEnabled } from './widgets/ManagedHybrid'; @@ -166,7 +166,7 @@ export default class CallHandler extends EventEmitter { static sharedInstance() { if (!window.mxCallHandler) { - window.mxCallHandler = new CallHandler() + window.mxCallHandler = new CallHandler(); } return window.mxCallHandler; @@ -185,7 +185,7 @@ export default class CallHandler extends EventEmitter { const nativeUser = this.assertedIdentityNativeUsers[call.callId]; if (nativeUser) { const room = findDMForUser(MatrixClientPeg.get(), nativeUser); - if (room) return room.roomId + if (room) return room.roomId; } } @@ -238,7 +238,7 @@ export default class CallHandler extends EventEmitter { this.supportsPstnProtocol = null; } - dis.dispatch({action: Action.PstnSupportUpdated}); + dis.dispatch({ action: Action.PstnSupportUpdated }); if (protocols[PROTOCOL_SIP_NATIVE] !== undefined && protocols[PROTOCOL_SIP_VIRTUAL] !== undefined) { this.supportsSipNativeVirtual = Boolean( @@ -246,7 +246,7 @@ export default class CallHandler extends EventEmitter { ); } - dis.dispatch({action: Action.VirtualRoomSupportUpdated}); + dis.dispatch({ action: Action.VirtualRoomSupportUpdated }); } catch (e) { if (maxTries === 1) { console.log("Failed to check for protocol support and no retries remain: assuming no support", e); @@ -299,7 +299,7 @@ export default class CallHandler extends EventEmitter { action: 'incoming_call', call: call, }, true); - } + }; getCallForRoom(roomId: string): MatrixCall { return this.calls.get(roomId) || null; @@ -711,7 +711,7 @@ export default class CallHandler extends EventEmitter { call.placeScreenSharingCall( async (): Promise => { - const {finished} = Modal.createDialog(DesktopCapturerSourcePicker); + const { finished } = Modal.createDialog(DesktopCapturerSourcePicker); const [source] = await finished; return source; }, @@ -816,7 +816,7 @@ export default class CallHandler extends EventEmitter { Analytics.trackEvent('voip', 'receiveCall', 'type', call.type); console.log("Adding call for room ", mappedRoomId); - this.calls.set(mappedRoomId, call) + this.calls.set(mappedRoomId, call); this.emit(CallHandlerEvent.CallsChanged, this.calls); this.setCallListeners(call); @@ -872,7 +872,7 @@ export default class CallHandler extends EventEmitter { this.dialNumber(payload.number); break; } - } + }; private async dialNumber(number: string) { const results = await this.pstnLookup(number); @@ -966,7 +966,7 @@ export default class CallHandler extends EventEmitter { confId = 'Jitsi' + random; } - let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl({auth: jitsiAuth}); + let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl({ auth: jitsiAuth }); // TODO: Remove URL hacks when the mobile clients eventually support v2 widgets const parsedUrl = new URL(widgetUrl); diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index 9042d47243..ef0a89a690 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -18,8 +18,8 @@ limitations under the License. import React from "react"; import dis from './dispatcher/dispatcher'; -import {MatrixClientPeg} from './MatrixClientPeg'; -import {MatrixClient} from "matrix-js-sdk/src/client"; +import { MatrixClientPeg } from './MatrixClientPeg'; +import { MatrixClient } from "matrix-js-sdk/src/client"; import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; @@ -37,7 +37,7 @@ import { UploadProgressPayload, UploadStartedPayload, } from "./dispatcher/payloads/UploadPayload"; -import {IUpload} from "./models/IUpload"; +import { IUpload } from "./models/IUpload"; import { IImageInfo } from "matrix-js-sdk/src/@types/partials"; const MAX_WIDTH = 800; @@ -189,7 +189,7 @@ async function loadImageElement(imageFile: File) { const [hidpi] = await Promise.all([parsePromise, imgPromise]); const width = hidpi ? (img.width >> 1) : img.width; const height = hidpi ? (img.height >> 1) : img.height; - return {width, height, img}; + return { width, height, img }; } /** @@ -307,7 +307,7 @@ function readFileAsArrayBuffer(file: File | Blob): Promise { * If the file is unencrypted then the object will have a "url" key. * If the file is encrypted then the object will have a "file" key. */ -function uploadFile( +export function uploadFile( matrixClient: MatrixClient, roomId: string, file: File | Blob, @@ -343,7 +343,7 @@ function uploadFile( if (file.type) { encryptInfo.mimetype = file.type; } - return {"file": encryptInfo}; + return { "file": encryptInfo }; }); (prom as IAbortablePromise).abort = () => { canceled = true; @@ -357,7 +357,7 @@ function uploadFile( const promise1 = basePromise.then(function(url) { if (canceled) throw new UploadCanceledError(); // If the attachment isn't encrypted then include the URL directly. - return {"url": url}; + return { "url": url }; }); (promise1 as any).abort = () => { canceled = true; @@ -377,7 +377,7 @@ export default class ContentMessages { console.warn(`Failed to send content with URL ${url} to room ${roomId}`, e); throw e; }); - CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, false, false, {msgtype: "m.sticker"}); + CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, false, false, { msgtype: "m.sticker" }); return prom; } @@ -391,14 +391,14 @@ export default class ContentMessages { async sendContentListToRoom(files: File[], roomId: string, matrixClient: MatrixClient) { if (matrixClient.isGuest()) { - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); if (isQuoting) { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - const {finished} = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, { + const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, { title: _t('Replying With Files'), description: (
{_t( @@ -432,7 +432,7 @@ export default class ContentMessages { if (tooBigFiles.length > 0) { const UploadFailureDialog = sdk.getComponent("dialogs.UploadFailureDialog"); - const {finished} = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, { + const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Failure', '', UploadFailureDialog, { badFiles: tooBigFiles, totalFiles: files.length, contentMessages: this, @@ -449,7 +449,7 @@ export default class ContentMessages { for (let i = 0; i < okFiles.length; ++i) { const file = okFiles[i]; if (!uploadAll) { - const {finished} = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', + const { finished } = Modal.createTrackedDialog<[boolean, boolean]>('Upload Files confirmation', '', UploadConfirmDialog, { file, currentIndex: i, @@ -481,7 +481,7 @@ export default class ContentMessages { if (upload) { upload.canceled = true; MatrixClientPeg.get().cancelUpload(upload.promise); - dis.dispatch({action: Action.UploadCanceled, upload}); + dis.dispatch({ action: Action.UploadCanceled, upload }); } } @@ -542,7 +542,7 @@ export default class ContentMessages { promise: prom, }; this.inprogress.push(upload); - dis.dispatch({action: Action.UploadStarted, upload}); + dis.dispatch({ action: Action.UploadStarted, upload }); // Focus the composer view dis.fire(Action.FocusComposer); @@ -550,7 +550,7 @@ export default class ContentMessages { function onProgress(ev) { upload.total = ev.total; upload.loaded = ev.loaded; - dis.dispatch({action: Action.UploadProgress, upload}); + dis.dispatch({ action: Action.UploadProgress, upload }); } let error; @@ -577,11 +577,11 @@ export default class ContentMessages { }, function(err) { error = err; if (!upload.canceled) { - let desc = _t("The file '%(fileName)s' failed to upload.", {fileName: upload.fileName}); + let desc = _t("The file '%(fileName)s' failed to upload.", { fileName: upload.fileName }); if (err.http_status === 413) { desc = _t( "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", - {fileName: upload.fileName}, + { fileName: upload.fileName }, ); } const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -604,10 +604,10 @@ export default class ContentMessages { if (error && error.http_status === 413) { this.mediaConfig = null; } - dis.dispatch({action: Action.UploadFailed, upload, error}); + dis.dispatch({ action: Action.UploadFailed, upload, error }); } else { - dis.dispatch({action: Action.UploadFinished, upload}); - dis.dispatch({action: 'message_sent'}); + dis.dispatch({ action: Action.UploadFinished, upload }); + dis.dispatch({ action: 'message_sent' }); } }); } diff --git a/src/CountlyAnalytics.ts b/src/CountlyAnalytics.ts index f494c1eb22..39dcac4048 100644 --- a/src/CountlyAnalytics.ts +++ b/src/CountlyAnalytics.ts @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {randomString} from "matrix-js-sdk/src/randomstring"; +import { randomString } from "matrix-js-sdk/src/randomstring"; -import {getCurrentLanguage} from './languageHandler'; +import { getCurrentLanguage } from './languageHandler'; import PlatformPeg from './PlatformPeg'; import SdkConfig from './SdkConfig'; -import {MatrixClientPeg} from "./MatrixClientPeg"; -import {sleep} from "./utils/promise"; +import { MatrixClientPeg } from "./MatrixClientPeg"; +import { sleep } from "./utils/promise"; import RoomViewStore from "./stores/RoomViewStore"; import { Action } from "./dispatcher/actions"; @@ -338,8 +338,8 @@ const getRoomStats = (roomId: string) => { "is_encrypted": cli?.isRoomEncrypted(roomId), // eslint-disable-next-line camelcase "is_public": room?.currentState.getStateEvents("m.room.join_rules", "")?.getContent()?.join_rule === "public", - } -} + }; +}; // async wrapper for regex-powered String.prototype.replace const strReplaceAsync = async (str: string, regex: RegExp, fn: (...args: string[]) => Promise) => { @@ -414,7 +414,7 @@ export default class CountlyAnalytics { this.anonymous = anonymous; if (anonymous) { - await this.changeUserKey(randomString(64)) + await this.changeUserKey(randomString(64)); } else { await this.changeUserKey(await hashHex(MatrixClientPeg.get().getUserId()), true); } @@ -438,7 +438,7 @@ export default class CountlyAnalytics { await this.track("Opt-Out" ); this.endSession(); window.clearInterval(this.heartbeatIntervalId); - window.clearTimeout(this.activityIntervalId) + window.clearTimeout(this.activityIntervalId); this.baseUrl = null; // remove listeners bound in trackSessions() window.removeEventListener("beforeunload", this.endSession); @@ -662,14 +662,14 @@ export default class CountlyAnalytics { } private queue(args: Omit & Partial>) { - const {count = 1, ...rest} = args; + const { count = 1, ...rest } = args; const ev = { ...this.getTimeParams(), ...rest, count, platform: this.appPlatform, app_version: this.appVersion, - } + }; this.pendingEvents.push(ev); if (this.pendingEvents.length > MAX_PENDING_EVENTS) { @@ -680,7 +680,7 @@ export default class CountlyAnalytics { private getOrientation = (): Orientation => { return window.matchMedia("(orientation: landscape)").matches ? Orientation.Landscape - : Orientation.Portrait + : Orientation.Portrait; }; private reportOrientation = () => { @@ -749,7 +749,7 @@ export default class CountlyAnalytics { const request: Parameters[0] = { begin_session: 1, user_details: JSON.stringify(userDetails), - } + }; const metrics = this.getMetrics(); if (metrics) { @@ -773,7 +773,7 @@ export default class CountlyAnalytics { private endSession = () => { if (this.sessionStarted) { - window.removeEventListener("resize", this.reportOrientation) + window.removeEventListener("resize", this.reportOrientation); this.reportViewDuration(); this.request({ diff --git a/src/DecryptionFailureTracker.ts b/src/DecryptionFailureTracker.ts index 07c0c546fe..d40574a6db 100644 --- a/src/DecryptionFailureTracker.ts +++ b/src/DecryptionFailureTracker.ts @@ -168,7 +168,7 @@ export class DecryptionFailureTracker { const trackedEventIds = [...dedupedFailuresMap.keys()]; this.trackedEventHashMap = trackedEventIds.reduce( - (result, eventId) => ({...result, [eventId]: true}), + (result, eventId) => ({ ...result, [eventId]: true }), this.trackedEventHashMap, ); diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index df494e6bdd..d70585e5ec 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import dis from "./dispatcher/dispatcher"; import { hideToast as hideBulkUnverifiedSessionsToast, diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index 9497d9de4c..ea1813876c 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -19,7 +19,7 @@ import Modal from './Modal'; import * as sdk from './'; import MultiInviter from './utils/MultiInviter'; import { _t } from './languageHandler'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import GroupStore from './stores/GroupStore'; import StyledCheckbox from './components/views/elements/StyledCheckbox'; @@ -103,7 +103,7 @@ function _onGroupInviteFinished(groupId, addrs) { if (errorList.length > 0) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to invite the following users to the group', '', ErrorDialog, { - title: _t("Failed to invite the following users to %(groupId)s:", {groupId: groupId}), + title: _t("Failed to invite the following users to %(groupId)s:", { groupId: groupId }), description: errorList.join(", "), }); } @@ -111,7 +111,7 @@ function _onGroupInviteFinished(groupId, addrs) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to invite users to group', '', ErrorDialog, { title: _t("Failed to invite users to community"), - description: _t("Failed to invite users to %(groupId)s", {groupId: groupId}), + description: _t("Failed to invite users to %(groupId)s", { groupId: groupId }), }); }); } @@ -137,7 +137,7 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) { // Add this group as related if (!groups.includes(groupId)) { groups.push(groupId); - return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', {groups}, ''); + return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.related_groups', { groups }, ''); } }); })).then(() => { @@ -152,7 +152,7 @@ function _onGroupAddRoomFinished(groupId, addrs, addRoomsPublicly) { { title: _t( "Failed to add the following rooms to %(groupId)s:", - {groupId}, + { groupId }, ), description: errorList.join(", "), }, diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 983538d65b..c80b50c566 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -138,7 +138,7 @@ export function getHtmlText(insaneHtml: string): string { selfClosing: [], allowedSchemes: [], disallowedTagsMode: 'discard', - }) + }); } /** @@ -183,7 +183,7 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to // images" preference is disabled. Future work might expose some UI to reveal them // like standalone image events have. if (!attribs.src || !attribs.src.startsWith('mxc://') || !SettingsStore.getValue("showImages")) { - return { tagName, attribs: {}}; + return { tagName, attribs: {} }; } const width = Number(attribs.width) || 800; const height = Number(attribs.height) || 600; diff --git a/src/IdentityAuthClient.js b/src/IdentityAuthClient.js index 9239c1bc75..31a5021317 100644 --- a/src/IdentityAuthClient.js +++ b/src/IdentityAuthClient.js @@ -17,7 +17,7 @@ limitations under the License. import { SERVICE_TYPES } from 'matrix-js-sdk/src/service-types'; import { createClient } from 'matrix-js-sdk/src/matrix'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import Modal from './Modal'; import * as sdk from './index'; import { _t } from './languageHandler'; diff --git a/src/KeyBindingsDefaults.ts b/src/KeyBindingsDefaults.ts index 63c4ac0f86..b2f70abff7 100644 --- a/src/KeyBindingsDefaults.ts +++ b/src/KeyBindingsDefaults.ts @@ -156,7 +156,7 @@ const messageComposerBindings = (): KeyBinding[] => { } } return bindings; -} +}; const autocompleteBindings = (): KeyBinding[] => { return [ @@ -207,7 +207,7 @@ const autocompleteBindings = (): KeyBinding[] => { }, }, ]; -} +}; const roomListBindings = (): KeyBinding[] => { return [ @@ -248,7 +248,7 @@ const roomListBindings = (): KeyBinding[] => { }, }, ]; -} +}; const roomBindings = (): KeyBinding[] => { const bindings: KeyBinding[] = [ @@ -312,7 +312,7 @@ const roomBindings = (): KeyBinding[] => { } return bindings; -} +}; const navigationBindings = (): KeyBinding[] => { return [ @@ -396,7 +396,7 @@ const navigationBindings = (): KeyBinding[] => { }, }, ]; -} +}; export const defaultBindingsProvider: IKeyBindingsProvider = { getMessageComposerBindings: messageComposerBindings, @@ -404,4 +404,4 @@ export const defaultBindingsProvider: IKeyBindingsProvider = { getRoomListBindings: roomListBindings, getRoomBindings: roomBindings, getNavigationBindings: navigationBindings, -} +}; diff --git a/src/KeyBindingsManager.ts b/src/KeyBindingsManager.ts index aac14bde20..4225d2f449 100644 --- a/src/KeyBindingsManager.ts +++ b/src/KeyBindingsManager.ts @@ -140,12 +140,12 @@ export type KeyCombo = { ctrlKey?: boolean; metaKey?: boolean; shiftKey?: boolean; -} +}; export type KeyBinding = { action: T; keyCombo: KeyCombo; -} +}; /** * Helper method to check if a KeyboardEvent matches a KeyCombo diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index b0a1292ba1..76dee5ab55 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -20,9 +20,9 @@ limitations under the License. import { createClient } from 'matrix-js-sdk/src/matrix'; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; import { MatrixClient } from "matrix-js-sdk/src/client"; -import {decryptAES, encryptAES} from "matrix-js-sdk/src/crypto/aes"; +import { decryptAES, encryptAES, IEncryptedPayload } from "matrix-js-sdk/src/crypto/aes"; -import {IMatrixClientCreds, MatrixClientPeg} from './MatrixClientPeg'; +import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg'; import SecurityCustomisations from "./customisations/Security"; import EventIndexPeg from './indexing/EventIndexPeg'; import createMatrixClient from './utils/createMatrixClient'; @@ -41,17 +41,17 @@ import * as StorageManager from './utils/StorageManager'; import SettingsStore from "./settings/SettingsStore"; import TypingStore from "./stores/TypingStore"; import ToastStore from "./stores/ToastStore"; -import {IntegrationManagers} from "./integrations/IntegrationManagers"; -import {Mjolnir} from "./mjolnir/Mjolnir"; +import { IntegrationManagers } from "./integrations/IntegrationManagers"; +import { Mjolnir } from "./mjolnir/Mjolnir"; import DeviceListener from "./DeviceListener"; -import {Jitsi} from "./widgets/Jitsi"; -import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY} from "./BasePlatform"; +import { Jitsi } from "./widgets/Jitsi"; +import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY } from "./BasePlatform"; import ThreepidInviteStore from "./stores/ThreepidInviteStore"; import CountlyAnalytics from "./CountlyAnalytics"; import CallHandler from './CallHandler'; import LifecycleCustomisations from "./customisations/Lifecycle"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; -import {_t} from "./languageHandler"; +import { _t } from "./languageHandler"; const HOMESERVER_URL_KEY = "mx_hs_url"; const ID_SERVER_URL_KEY = "mx_is_url"; @@ -154,7 +154,7 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise * return [null, null]. */ export async function getStoredSessionOwner(): Promise<[string, boolean]> { - const {hsUrl, userId, hasAccessToken, isGuest} = await getStoredSessionVars(); + const { hsUrl, userId, hasAccessToken, isGuest } = await getStoredSessionVars(); return hsUrl && userId && hasAccessToken ? [userId, isGuest] : [null, null]; } @@ -303,7 +303,7 @@ export interface IStoredSession { hsUrl: string; isUrl: string; hasAccessToken: boolean; - accessToken: string | object; + accessToken: string | IEncryptedPayload; userId: string; deviceId: string; isGuest: boolean; @@ -346,11 +346,11 @@ export async function getStoredSessionVars(): Promise { isGuest = localStorage.getItem("matrix-is-guest") === "true"; } - return {hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest}; + return { hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest }; } // The pickle key is a string of unspecified length and format. For AES, we -// need a 256-bit Uint8Array. So we HKDF the pickle key to generate the AES +// need a 256-bit Uint8Array. So we HKDF the pickle key to generate the AES // key. The AES key should be zeroed after it is used. async function pickleKeyToAesKey(pickleKey: string): Promise { const pickleKeyBuffer = new Uint8Array(pickleKey.length); @@ -402,7 +402,7 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }): return false; } - const {hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest} = await getStoredSessionVars(); + const { hsUrl, isUrl, hasAccessToken, accessToken, userId, deviceId, isGuest } = await getStoredSessionVars(); if (hasAccessToken && !accessToken) { abortLogin(); @@ -495,7 +495,7 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise { // to add listeners for the 'sync' event so otherwise we'd have // a race condition (and we need to dispatch synchronously for this // to work). - dis.dispatch({action: 'will_start_client'}, true); + dis.dispatch({ action: 'will_start_client' }, true); // reset things first just in case TypingStore.sharedInstance().reset(); @@ -814,7 +814,7 @@ async function startMatrixClient(startSyncing = true): Promise { // dispatch that we finished starting up to wire up any other bits // of the matrix client that cannot be set prior to starting up. - dis.dispatch({action: 'client_started'}); + dis.dispatch({ action: 'client_started' }); if (isSoftLogout()) { softLogout(); @@ -830,9 +830,9 @@ export async function onLoggedOut(): Promise { // Ensure that we dispatch a view change **before** stopping the client so // so that React components unmount first. This avoids React soft crashes // that can occur when components try to use a null client. - dis.dispatch({action: 'on_logged_out'}, true); + dis.dispatch({ action: 'on_logged_out' }, true); stopMatrixClient(); - await clearStorage({deleteEverything: true}); + await clearStorage({ deleteEverything: true }); LifecycleCustomisations.onLoggedOutAndStorageCleared?.(); } diff --git a/src/Login.ts b/src/Login.ts index 7caab22d88..a8848210be 100644 --- a/src/Login.ts +++ b/src/Login.ts @@ -16,7 +16,7 @@ limitations under the License. */ // @ts-ignore - XXX: tsc doesn't like this: our js-sdk imports are complex so this isn't surprising -import {createClient} from "matrix-js-sdk/src/matrix"; +import { createClient } from "matrix-js-sdk/src/matrix"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { IMatrixClientCreds } from "./MatrixClientPeg"; import SecurityCustomisations from "./customisations/Security"; @@ -190,7 +190,6 @@ export default class Login { } } - /** * Send a login request to the given server, and format the response * as a MatrixClientCreds diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index 7db5ed1a4e..cb6cb5c65c 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -18,22 +18,22 @@ limitations under the License. */ import { ICreateClientOpts } from 'matrix-js-sdk/src/matrix'; -import {MatrixClient} from 'matrix-js-sdk/src/client'; -import {MemoryStore} from 'matrix-js-sdk/src/store/memory'; +import { MatrixClient } from 'matrix-js-sdk/src/client'; +import { MemoryStore } from 'matrix-js-sdk/src/store/memory'; import * as utils from 'matrix-js-sdk/src/utils'; -import {EventTimeline} from 'matrix-js-sdk/src/models/event-timeline'; -import {EventTimelineSet} from 'matrix-js-sdk/src/models/event-timeline-set'; +import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline'; +import { EventTimelineSet } from 'matrix-js-sdk/src/models/event-timeline-set'; import * as sdk from './index'; import createMatrixClient from './utils/createMatrixClient'; import SettingsStore from './settings/SettingsStore'; import MatrixActionCreators from './actions/MatrixActionCreators'; import Modal from './Modal'; -import {verificationMethods} from 'matrix-js-sdk/src/crypto'; +import { verificationMethods } from 'matrix-js-sdk/src/crypto'; import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler"; import * as StorageManager from './utils/StorageManager'; import IdentityAuthClient from './IdentityAuthClient'; import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from './SecurityManager'; -import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode"; +import { SHOW_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode"; import SecurityCustomisations from "./customisations/Security"; export interface IMatrixClientCreds { diff --git a/src/Modal.tsx b/src/Modal.tsx index 2f2d5a2d52..0b0e621e89 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -15,14 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ - import React from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; import Analytics from './Analytics'; import dis from './dispatcher/dispatcher'; -import {defer} from './utils/promise'; +import { defer } from './utils/promise'; import AsyncWrapper from './AsyncWrapper'; const DIALOG_CONTAINER_ID = "mx_Dialog_Container"; @@ -193,7 +192,7 @@ export class ModalManager { modal.elem = ; modal.close = closeDialog; - return {modal, closeDialog, onFinishedProm}; + return { modal, closeDialog, onFinishedProm }; } private getCloseFn( @@ -282,7 +281,7 @@ export class ModalManager { isStaticModal = false, options: IOptions = {}, ): IHandle { - const {modal, closeDialog, onFinishedProm} = this.buildModal(prom, props, className, options); + const { modal, closeDialog, onFinishedProm } = this.buildModal(prom, props, className, options); if (isPriorityModal) { // XXX: This is destructive this.priorityModal = modal; @@ -305,7 +304,7 @@ export class ModalManager { props?: IProps, className?: string, ): IHandle { - const {modal, closeDialog, onFinishedProm} = this.buildModal(prom, props, className, {}); + const { modal, closeDialog, onFinishedProm } = this.buildModal(prom, props, className, {}); this.modals.push(modal); this.reRender(); diff --git a/src/Notifier.ts b/src/Notifier.ts index 4f55046e72..2335dc59ac 100644 --- a/src/Notifier.ts +++ b/src/Notifier.ts @@ -32,11 +32,11 @@ import { _t } from './languageHandler'; import Modal from './Modal'; import SettingsStore from "./settings/SettingsStore"; import { hideToast as hideNotificationsToast } from "./toasts/DesktopNotificationsToast"; -import {SettingLevel} from "./settings/SettingLevel"; -import {isPushNotifyDisabled} from "./settings/controllers/NotificationControllers"; +import { SettingLevel } from "./settings/SettingLevel"; +import { isPushNotifyDisabled } from "./settings/controllers/NotificationControllers"; import RoomViewStore from "./stores/RoomViewStore"; import UserActivity from "./UserActivity"; -import {mediaFromMxc} from "./customisations/Media"; +import { mediaFromMxc } from "./customisations/Media"; /* * Dispatches: @@ -68,7 +68,7 @@ export const Notifier = { // or not pendingEncryptedEventIds: [], - notificationMessageForEvent: function(ev: MatrixEvent) { + notificationMessageForEvent: function(ev: MatrixEvent): string { if (typehandlers.hasOwnProperty(ev.getContent().msgtype)) { return typehandlers[ev.getContent().msgtype](ev); } diff --git a/src/Presence.ts b/src/Presence.ts index 8f2e127cb4..af35060363 100644 --- a/src/Presence.ts +++ b/src/Presence.ts @@ -16,10 +16,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from "./MatrixClientPeg"; +import { MatrixClientPeg } from "./MatrixClientPeg"; import dis from "./dispatcher/dispatcher"; import Timer from './utils/Timer'; -import {ActionPayload} from "./dispatcher/payloads"; +import { ActionPayload } from "./dispatcher/payloads"; // Time in ms after that a user is considered as unavailable/away const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins @@ -78,7 +78,7 @@ class Presence { this.setState(State.Online); this.unavailableTimer.restart(); } - } + }; /** * Set the presence state. @@ -98,7 +98,7 @@ class Presence { } try { - await MatrixClientPeg.get().setPresence({presence: this.state}); + await MatrixClientPeg.get().setPresence({ presence: this.state }); console.info("Presence:", newState); } catch (err) { console.error("Failed to set presence:", err); diff --git a/src/Registration.js b/src/Registration.js index 0df2ec3eb3..70dcd38454 100644 --- a/src/Registration.js +++ b/src/Registration.js @@ -53,16 +53,16 @@ export async function startAnyRegistrationFlow(options) { extraButtons: [ , ], onFinished: (proceed) => { if (proceed) { - dis.dispatch({action: 'start_registration', screenAfterLogin: options.screen_after}); + dis.dispatch({ action: 'start_registration', screenAfterLogin: options.screen_after }); } else if (options.go_home_on_cancel) { - dis.dispatch({action: 'view_home_page'}); + dis.dispatch({ action: 'view_home_page' }); } else if (options.go_welcome_on_cancel) { - dis.dispatch({action: 'view_welcome_page'}); + dis.dispatch({ action: 'view_welcome_page' }); } }, }); diff --git a/src/Roles.ts b/src/Roles.ts index b4be97fdce..ae0d316d30 100644 --- a/src/Roles.ts +++ b/src/Roles.ts @@ -31,6 +31,6 @@ export function textualPowerLevel(level: number, usersDefault: number): string { if (LEVEL_ROLE_MAP[level]) { return LEVEL_ROLE_MAP[level]; } else { - return _t("Custom (%(level)s)", {level}); + return _t("Custom (%(level)s)", { level }); } } diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index c86f832b90..c7f377b6e8 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -53,7 +53,7 @@ export function showStartChatInviteDialog(initialText = ""): void { // This dialog handles the room creation internally - we don't need to worry about it. const InviteDialog = sdk.getComponent("dialogs.InviteDialog"); Modal.createTrackedDialog( - 'Start DM', '', InviteDialog, {kind: KIND_DM, initialText}, + 'Start DM', '', InviteDialog, { kind: KIND_DM, initialText }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, ); } @@ -72,7 +72,7 @@ export function showRoomInviteDialog(roomId: string, initialText = ""): void { export function showCommunityRoomInviteDialog(roomId: string, communityName: string): void { Modal.createTrackedDialog( - 'Invite Users to Community', '', CommunityPrototypeInviteDialog, {communityName, roomId}, + 'Invite Users to Community', '', CommunityPrototypeInviteDialog, { communityName, roomId }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, ); } @@ -133,7 +133,7 @@ export function showAnyInviteErrors( // pointless for us to list who failed exactly. const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to invite users to the room', '', ErrorDialog, { - title: _t("Failed to invite users to the room:", {roomName: room.name}), + title: _t("Failed to invite users to the room:", { roomName: room.name }), description: inviter.getErrorText(failedUsers[0]), }); return false; diff --git a/src/RoomNotifs.js b/src/RoomNotifs.js index 600655f635..5d109094af 100644 --- a/src/RoomNotifs.js +++ b/src/RoomNotifs.js @@ -15,8 +15,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from './MatrixClientPeg'; -import {PushProcessor} from 'matrix-js-sdk/src/pushprocessor'; +import { MatrixClientPeg } from './MatrixClientPeg'; +import { PushProcessor } from 'matrix-js-sdk/src/pushprocessor'; export const ALL_MESSAGES_LOUD = 'all_messages_loud'; export const ALL_MESSAGES = 'all_messages'; @@ -52,7 +52,7 @@ export function aggregateNotificationCount(rooms) { } } return result; - }, {count: 0, highlight: false}); + }, { count: 0, highlight: false }); } export function getRoomHasBadge(room) { diff --git a/src/Rooms.ts b/src/Rooms.ts index 19d1c9ee05..4d1682660b 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -104,7 +104,6 @@ export function setDMRoom(roomId: string, userId: string): Promise { dmRoomMap[userId] = roomList; } - return MatrixClientPeg.get().setAccountData('m.direct', dmRoomMap); } diff --git a/src/ScalarAuthClient.ts b/src/ScalarAuthClient.ts index a09c3494a8..86dd4b7a0f 100644 --- a/src/ScalarAuthClient.ts +++ b/src/ScalarAuthClient.ts @@ -17,12 +17,12 @@ limitations under the License. import url from 'url'; import SettingsStore from "./settings/SettingsStore"; import { Service, startTermsFlow, TermsInteractionCallback, TermsNotSignedError } from './Terms'; -import {MatrixClientPeg} from "./MatrixClientPeg"; +import { MatrixClientPeg } from "./MatrixClientPeg"; import request from "browser-request"; import SdkConfig from "./SdkConfig"; -import {WidgetType} from "./widgets/WidgetType"; -import {SERVICE_TYPES} from "matrix-js-sdk/src/service-types"; +import { WidgetType } from "./widgets/WidgetType"; +import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; import { Room } from "matrix-js-sdk/src/models/room"; // The version of the integration manager API we're intending to work with @@ -109,7 +109,7 @@ export default class ScalarAuthClient { request({ method: "GET", uri: url, - qs: {scalar_token: token, v: imApiVersion}, + qs: { scalar_token: token, v: imApiVersion }, json: true, }, (err, response, body) => { if (err) { @@ -189,7 +189,7 @@ export default class ScalarAuthClient { request({ method: 'POST', uri: scalarRestUrl + '/register', - qs: {v: imApiVersion}, + qs: { v: imApiVersion }, body: openidTokenObject, json: true, }, (err, response, body) => { diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index 3f75b3788c..600241bc06 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -208,7 +208,6 @@ Example: ] } - membership_state AND bot_options -------------------------------- Get the content of the "m.room.member" or "m.room.bot.options" state event respectively. @@ -236,15 +235,15 @@ Example: } */ -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import dis from './dispatcher/dispatcher'; import WidgetUtils from './utils/WidgetUtils'; import RoomViewStore from './stores/RoomViewStore'; import { _t } from './languageHandler'; -import {IntegrationManagers} from "./integrations/IntegrationManagers"; -import {WidgetType} from "./widgets/WidgetType"; -import {objectClone} from "./utils/objects"; +import { IntegrationManagers } from "./integrations/IntegrationManagers"; +import { WidgetType } from "./widgets/WidgetType"; +import { objectClone } from "./utils/objects"; function sendResponse(event, res) { const data = objectClone(event.data); @@ -608,7 +607,7 @@ const onMessage = function(event) { } if (roomId !== RoomViewStore.getRoomId()) { - sendError(event, _t('Room %(roomId)s not visible', {roomId: roomId})); + sendError(event, _t('Room %(roomId)s not visible', { roomId: roomId })); return; } diff --git a/src/Searching.js b/src/Searching.js index 596dd2f3d4..d0666b1760 100644 --- a/src/Searching.js +++ b/src/Searching.js @@ -15,7 +15,7 @@ limitations under the License. */ import EventIndexPeg from "./indexing/EventIndexPeg"; -import {MatrixClientPeg} from "./MatrixClientPeg"; +import { MatrixClientPeg } from "./MatrixClientPeg"; const SEARCH_LIMIT = 10; @@ -43,7 +43,7 @@ async function serverSideSearch(term, roomId = undefined) { }, }; - const response = await client.search({body: body}); + const response = await client.search({ body: body }); const result = { response: response, @@ -498,7 +498,7 @@ async function combinedPagination(searchResult) { // Fetch events from the server if we have a token for it and if it's the // local indexes turn or the local index has exhausted its results. if (searchResult.serverSideNextBatch && (oldestEventFrom === "local" || !searchArgs.next_batch)) { - const body = {body: searchResult._query, next_batch: searchResult.serverSideNextBatch}; + const body = { body: searchResult._query, next_batch: searchResult.serverSideNextBatch }; serverSideResult = await client.search(body); } diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 1ba0d6439b..6b372bba28 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -18,7 +18,7 @@ import { ICryptoCallbacks, ISecretStorageKeyInfo } from 'matrix-js-sdk/src/matri import { MatrixClient } from 'matrix-js-sdk/src/client'; import Modal from './Modal'; import * as sdk from './index'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import { deriveKey } from 'matrix-js-sdk/src/crypto/key_passphrase'; import { decodeRecoveryKey } from 'matrix-js-sdk/src/crypto/recoverykey'; import { _t } from './languageHandler'; @@ -135,7 +135,7 @@ async function getSecretStorageKey( const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.(); if (keyFromCustomisations) { - console.log("Using key from security customisations (secret storage)") + console.log("Using key from security customisations (secret storage)"); cacheSecretStorageKey(keyId, keyInfo, keyFromCustomisations); return [keyId, keyFromCustomisations]; } @@ -185,7 +185,7 @@ export async function getDehydrationKey( ): Promise { const keyFromCustomisations = SecurityCustomisations.getSecretStorageKey?.(); if (keyFromCustomisations) { - console.log("Using key from security customisations (dehydration)") + console.log("Using key from security customisations (dehydration)"); return keyFromCustomisations; } @@ -224,7 +224,7 @@ export async function getDehydrationKey( const key = await inputToKey(input); // need to copy the key because rehydration (unpickling) will clobber it - dehydrationCache = {key: new Uint8Array(key), keyInfo}; + dehydrationCache = { key: new Uint8Array(key), keyInfo }; return key; } diff --git a/src/SendHistoryManager.ts b/src/SendHistoryManager.ts index e9268ad642..eeba643d81 100644 --- a/src/SendHistoryManager.ts +++ b/src/SendHistoryManager.ts @@ -1,4 +1,3 @@ -//@flow /* Copyright 2017 Aviral Dasgupta @@ -15,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {clamp} from "lodash"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { clamp } from "lodash"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import {SerializedPart} from "./editor/parts"; +import { SerializedPart } from "./editor/parts"; import EditorModel from "./editor/model"; interface IHistoryItem { diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index bd2133f3d9..0f38c5fffc 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -21,21 +21,21 @@ import * as React from 'react'; import { User } from "matrix-js-sdk/src/models/user"; import * as ContentHelpers from 'matrix-js-sdk/src/content-helpers'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import dis from './dispatcher/dispatcher'; import * as sdk from './index'; -import {_t, _td} from './languageHandler'; +import { _t, _td } from './languageHandler'; import Modal from './Modal'; import MultiInviter from './utils/MultiInviter'; import { linkifyAndSanitizeHtml } from './HtmlUtils'; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; import WidgetUtils from "./utils/WidgetUtils"; -import {textToHtmlRainbow} from "./utils/colour"; +import { textToHtmlRainbow } from "./utils/colour"; import { getAddressType } from './UserAddress'; import { abbreviateUrl } from './utils/UrlUtils'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils'; -import {isPermalinkHost, parsePermalink} from "./utils/permalinks/Permalinks"; -import {inviteUsersToRoom} from "./RoomInvite"; +import { isPermalinkHost, parsePermalink } from "./utils/permalinks/Permalinks"; +import { inviteUsersToRoom } from "./RoomInvite"; import { WidgetType } from "./widgets/WidgetType"; import { Jitsi } from "./widgets/Jitsi"; import { parseFragment as parseHtml, Element as ChildElement } from "parse5"; @@ -46,10 +46,10 @@ import { Action } from "./dispatcher/actions"; import { EffectiveMembership, getEffectiveMembership, leaveRoomBehaviour } from "./utils/membership"; import SdkConfig from "./SdkConfig"; import SettingsStore from "./settings/SettingsStore"; -import {UIFeature} from "./settings/UIFeature"; -import {CHAT_EFFECTS} from "./effects" +import { UIFeature } from "./settings/UIFeature"; +import { CHAT_EFFECTS } from "./effects"; import CallHandler from "./CallHandler"; -import {guessAndSetDMRoom} from "./Rooms"; +import { guessAndSetDMRoom } from "./Rooms"; // XXX: workaround for https://github.com/microsoft/TypeScript/issues/31816 interface HTMLInputEvent extends Event { @@ -143,11 +143,11 @@ export class Command { } function reject(error) { - return {error}; + return { error }; } function success(promise?: Promise) { - return {promise}; + return { promise }; } function successSync(value: any) { @@ -271,8 +271,8 @@ export const Commands = [ const RoomUpgradeWarningDialog = sdk.getComponent("dialogs.RoomUpgradeWarningDialog"); - const {finished} = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation', - RoomUpgradeWarningDialog, {roomId: roomId, targetVersion: args}, /*className=*/null, + const { finished } = Modal.createTrackedDialog('Slash Commands', 'upgrade room confirmation', + RoomUpgradeWarningDialog, { roomId: roomId, targetVersion: args }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); return success(finished.then(async ([resp]) => { @@ -288,7 +288,7 @@ export const Commands = [ if (resp.invite) { checkForUpgradeFn = async (newRoom) => { // The upgradePromise should be done by the time we await it here. - const {replacement_room: newRoomId} = await upgradePromise; + const { replacement_room: newRoomId } = await upgradePromise; if (newRoom.roomId !== newRoomId) return; const toInvite = [ @@ -370,7 +370,7 @@ export const Commands = [ return success(promise.then((url) => { if (!url) return; - return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.avatar', {url}, ''); + return MatrixClientPeg.get().sendStateEvent(roomId, 'm.room.avatar', { url }, ''); })); }, category: CommandCategories.actions, @@ -741,7 +741,7 @@ export const Commands = [ Modal.createTrackedDialog('Slash Commands', 'User ignored', InfoDialog, { title: _t('Ignored user'), description:
-

{ _t('You are now ignoring %(userId)s', {userId}) }

+

{ _t('You are now ignoring %(userId)s', { userId }) }

, }); }), @@ -772,7 +772,7 @@ export const Commands = [ Modal.createTrackedDialog('Slash Commands', 'User unignored', InfoDialog, { title: _t('Unignored user'), description:
-

{ _t('You are no longer ignoring %(userId)s', {userId}) }

+

{ _t('You are no longer ignoring %(userId)s', { userId }) }

, }); }), @@ -839,7 +839,7 @@ export const Commands = [ description: _td('Opens the Developer Tools dialog'), runFn: function(roomId) { const DevtoolsDialog = sdk.getComponent('dialogs.DevtoolsDialog'); - Modal.createDialog(DevtoolsDialog, {roomId}); + Modal.createDialog(DevtoolsDialog, { roomId }); return success(); }, category: CommandCategories.advanced, @@ -951,7 +951,7 @@ export const Commands = [ { _t('The signing key you provided matches the signing key you received ' + 'from %(userId)s\'s session %(deviceId)s. Session marked as verified.', - {userId, deviceId}) + { userId, deviceId }) }

, @@ -1172,11 +1172,11 @@ export const Commands = [ }; MatrixClientPeg.get().sendMessage(roomId, content); } - dis.dispatch({action: `effects.${effect.command}`}); + dis.dispatch({ action: `effects.${effect.command}` }); })()); }, category: CommandCategories.effects, - }) + }); }), ]; @@ -1205,7 +1205,7 @@ export function parseCommandString(input: string) { cmd = input; } - return {cmd, args}; + return { cmd, args }; } /** @@ -1217,7 +1217,7 @@ export function parseCommandString(input: string) { * Returns null if the input didn't match a command. */ export function getCommand(input: string) { - const {cmd, args} = parseCommandString(input); + const { cmd, args } = parseCommandString(input); if (CommandMap.has(cmd) && CommandMap.get(cmd).isEnabled()) { return { diff --git a/src/Terms.ts b/src/Terms.ts index a6ea40a6e8..3859cc1c73 100644 --- a/src/Terms.ts +++ b/src/Terms.ts @@ -16,7 +16,7 @@ limitations under the License. import classNames from 'classnames'; -import {MatrixClientPeg} from './MatrixClientPeg'; +import { MatrixClientPeg } from './MatrixClientPeg'; import * as sdk from '.'; import Modal from './Modal'; @@ -117,7 +117,7 @@ export async function startTermsFlow( // but that is not a thing the API supports, so probably best to just show // things they've not agreed to yet. const unagreedPoliciesAndServicePairs = []; - for (const {service, policies} of policiesAndServicePairs) { + for (const { service, policies } of policiesAndServicePairs) { const unagreedPolicies = {}; for (const [policyName, policy] of Object.entries(policies)) { let policyAgreed = false; @@ -131,7 +131,7 @@ export async function startTermsFlow( if (!policyAgreed) unagreedPolicies[policyName] = policy; } if (Object.keys(unagreedPolicies).length > 0) { - unagreedPoliciesAndServicePairs.push({service, policies: unagreedPolicies}); + unagreedPoliciesAndServicePairs.push({ service, policies: unagreedPolicies }); } } @@ -148,7 +148,7 @@ export async function startTermsFlow( // We only ever add to the set of URLs, so if anything has changed then we'd see a different length if (agreedUrlSet.size !== numAcceptedBeforeAgreement) { - const newAcceptedTerms = {accepted: Array.from(agreedUrlSet)}; + const newAcceptedTerms = { accepted: Array.from(agreedUrlSet) }; await MatrixClientPeg.get().setAccountData('m.accepted_terms', newAcceptedTerms); } diff --git a/src/TextForEvent.ts b/src/TextForEvent.tsx similarity index 87% rename from src/TextForEvent.ts rename to src/TextForEvent.tsx index ebf1645303..844c79fbae 100644 --- a/src/TextForEvent.ts +++ b/src/TextForEvent.tsx @@ -13,13 +13,20 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg} from './MatrixClientPeg'; + +import React from 'react'; +import { MatrixClientPeg } from './MatrixClientPeg'; import { _t } from './languageHandler'; import * as Roles from './Roles'; -import {isValid3pidInvite} from "./RoomInvite"; +import { isValid3pidInvite } from "./RoomInvite"; import SettingsStore from "./settings/SettingsStore"; -import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList"; -import {WIDGET_LAYOUT_EVENT_TYPE} from "./stores/widgets/WidgetLayoutStore"; +import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList"; +import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore"; +import { RightPanelPhases } from './stores/RightPanelStorePhases'; +import { Action } from './dispatcher/actions'; +import defaultDispatcher from './dispatcher/dispatcher'; +import { SetRightPanelPhasePayload } from './dispatcher/payloads/SetRightPanelPhasePayload'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; // These functions are frequently used just to check whether an event has // any text to display at all. For this reason they return deferred values @@ -105,7 +112,7 @@ function textForMemberEvent(ev): () => string | null { targetName, reason, }) - : _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName }) + : _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName }); } else if (prevContent.membership === "join") { return () => reason ? _t('%(senderName)s kicked %(targetName)s: %(reason)s', { @@ -132,7 +139,7 @@ function textForRoomNameEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); if (!ev.getContent().name || ev.getContent().name.trim().length === 0) { - return () => _t('%(senderDisplayName)s removed the room name.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s removed the room name.', { senderDisplayName }); } if (ev.getPrevContent().name) { return () => _t('%(senderDisplayName)s changed the room name from %(oldRoomName)s to %(newRoomName)s.', { @@ -149,7 +156,7 @@ function textForRoomNameEvent(ev): () => string | null { function textForTombstoneEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); - return () => _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s upgraded this room.', { senderDisplayName }); } function textForJoinRulesEvent(ev): () => string | null { @@ -176,9 +183,9 @@ function textForGuestAccessEvent(ev): () => string | null { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); switch (ev.getContent().guest_access) { case "can_join": - return () => _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s has allowed guests to join the room.', { senderDisplayName }); case "forbidden": - return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName}); + return () => _t('%(senderDisplayName)s has prevented guests from joining the room.', { senderDisplayName }); default: // There's no other options we can expect, however just for safety's sake we'll do this. return () => _t('%(senderDisplayName)s changed guest access to %(rule)s', { @@ -230,9 +237,9 @@ function textForServerACLEvent(ev): () => string | null { let getText = null; if (prev.deny.length === 0 && prev.allow.length === 0) { - getText = () => _t("%(senderDisplayName)s set the server ACLs for this room.", {senderDisplayName}); + getText = () => _t("%(senderDisplayName)s set the server ACLs for this room.", { senderDisplayName }); } else { - getText = () => _t("%(senderDisplayName)s changed the server ACLs for this room.", {senderDisplayName}); + getText = () => _t("%(senderDisplayName)s changed the server ACLs for this room.", { senderDisplayName }); } if (!Array.isArray(current.allow)) { @@ -255,7 +262,7 @@ function textForMessageEvent(ev): () => string | null { if (ev.getContent().msgtype === "m.emote") { message = "* " + senderDisplayName + " " + message; } else if (ev.getContent().msgtype === "m.image") { - message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName}); + message = _t('%(senderDisplayName)s sent an image.', { senderDisplayName }); } return message; }; @@ -316,7 +323,7 @@ function textForCallAnswerEvent(event): () => string | null { return () => { const senderName = event.sender ? event.sender.name : _t('Someone'); const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)'); - return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported; + return _t('%(senderName)s answered the call.', { senderName }) + ' ' + supported; }; } @@ -351,16 +358,16 @@ function textForCallHangupEvent(event): () => string | null { // Also the correct hangup code as of VoIP v1 (with underscore) getReason = () => ''; } else { - getReason = () => _t('(unknown failure: %(reason)s)', {reason: eventContent.reason}); + getReason = () => _t('(unknown failure: %(reason)s)', { reason: eventContent.reason }); } } - return () => _t('%(senderName)s ended the call.', {senderName: getSenderName()}) + ' ' + getReason(); + return () => _t('%(senderName)s ended the call.', { senderName: getSenderName() }) + ' ' + getReason(); } function textForCallRejectEvent(event): () => string | null { return () => { const senderName = event.sender ? event.sender.name : _t('Someone'); - return _t('%(senderName)s declined the call.', {senderName}); + return _t('%(senderName)s declined the call.', { senderName }); }; } @@ -417,14 +424,14 @@ function textForHistoryVisibilityEvent(event): () => string | null { switch (event.getContent().history_visibility) { case 'invited': return () => _t('%(senderName)s made future room history visible to all room members, ' - + 'from the point they are invited.', {senderName}); + + 'from the point they are invited.', { senderName }); case 'joined': return () => _t('%(senderName)s made future room history visible to all room members, ' - + 'from the point they joined.', {senderName}); + + 'from the point they joined.', { senderName }); case 'shared': - return () => _t('%(senderName)s made future room history visible to all room members.', {senderName}); + return () => _t('%(senderName)s made future room history visible to all room members.', { senderName }); case 'world_readable': - return () => _t('%(senderName)s made future room history visible to anyone.', {senderName}); + return () => _t('%(senderName)s made future room history visible to anyone.', { senderName }); default: return () => _t('%(senderName)s made future room history visible to unknown (%(visibility)s).', { senderName, @@ -479,15 +486,39 @@ function textForPowerEvent(event): () => string | null { }); } -function textForPinnedEvent(event): () => string | null { +const onPinnedMessagesClick = (): void => { + defaultDispatcher.dispatch({ + action: Action.SetRightPanelPhase, + phase: RightPanelPhases.PinnedMessages, + allowClose: false, + }); +}; + +function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null { + if (!SettingsStore.getValue("feature_pinning")) return null; const senderName = event.sender ? event.sender.name : event.getSender(); - return () => _t("%(senderName)s changed the pinned messages for the room.", {senderName}); + + if (allowJSX) { + return () => ( + + { + _t( + "%(senderName)s changed the pinned messages for the room.", + { senderName }, + { "a": (sub) => { sub } }, + ) + } + + ); + } + + return () => _t("%(senderName)s changed the pinned messages for the room.", { senderName }); } function textForWidgetEvent(event): () => string | null { const senderName = event.getSender(); - const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent(); - const {name, type, url} = event.getContent() || {}; + const { name: prevName, type: prevType, url: prevUrl } = event.getPrevContent(); + const { name, type, url } = event.getContent() || {}; let widgetName = name || prevName || type || prevType || ''; // Apply sentence case to widget name @@ -516,68 +547,68 @@ function textForWidgetEvent(event): () => string | null { function textForWidgetLayoutEvent(event): () => string | null { const senderName = event.sender?.name || event.getSender(); - return () => _t("%(senderName)s has updated the widget layout", {senderName}); + return () => _t("%(senderName)s has updated the widget layout", { senderName }); } function textForMjolnirEvent(event): () => string | null { const senderName = event.getSender(); - const {entity: prevEntity} = event.getPrevContent(); - const {entity, recommendation, reason} = event.getContent(); + const { entity: prevEntity } = event.getPrevContent(); + const { entity, recommendation, reason } = event.getContent(); // Rule removed if (!entity) { if (USER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s removed the rule banning users matching %(glob)s", - {senderName, glob: prevEntity}); + { senderName, glob: prevEntity }); } else if (ROOM_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s removed the rule banning rooms matching %(glob)s", - {senderName, glob: prevEntity}); + { senderName, glob: prevEntity }); } else if (SERVER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s removed the rule banning servers matching %(glob)s", - {senderName, glob: prevEntity}); + { senderName, glob: prevEntity }); } // Unknown type. We'll say something, but we shouldn't end up here. - return () => _t("%(senderName)s removed a ban rule matching %(glob)s", {senderName, glob: prevEntity}); + return () => _t("%(senderName)s removed a ban rule matching %(glob)s", { senderName, glob: prevEntity }); } // Invalid rule - if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, {senderName}); + if (!recommendation || !reason) return () => _t(`%(senderName)s updated an invalid ban rule`, { senderName }); // Rule updated if (entity === prevEntity) { if (USER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s updated the rule banning users matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } else if (ROOM_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s updated the rule banning rooms matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } else if (SERVER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s updated the rule banning servers matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } // Unknown type. We'll say something but we shouldn't end up here. return () => _t("%(senderName)s updated a ban rule matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } // New rule if (!prevEntity) { if (USER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s created a rule banning users matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } else if (ROOM_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s created a rule banning rooms matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } else if (SERVER_RULE_TYPES.includes(event.getType())) { return () => _t("%(senderName)s created a rule banning servers matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } // Unknown type. We'll say something but we shouldn't end up here. return () => _t("%(senderName)s created a ban rule matching %(glob)s for %(reason)s", - {senderName, glob: entity, reason}); + { senderName, glob: entity, reason }); } // else the entity !== prevEntity - count as a removal & add @@ -585,29 +616,29 @@ function textForMjolnirEvent(event): () => string | null { return () => _t( "%(senderName)s changed a rule that was banning users matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", - {senderName, oldGlob: prevEntity, newGlob: entity, reason}, + { senderName, oldGlob: prevEntity, newGlob: entity, reason }, ); } else if (ROOM_RULE_TYPES.includes(event.getType())) { return () => _t( "%(senderName)s changed a rule that was banning rooms matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", - {senderName, oldGlob: prevEntity, newGlob: entity, reason}, + { senderName, oldGlob: prevEntity, newGlob: entity, reason }, ); } else if (SERVER_RULE_TYPES.includes(event.getType())) { return () => _t( "%(senderName)s changed a rule that was banning servers matching %(oldGlob)s to matching " + "%(newGlob)s for %(reason)s", - {senderName, oldGlob: prevEntity, newGlob: entity, reason}, + { senderName, oldGlob: prevEntity, newGlob: entity, reason }, ); } // Unknown type. We'll say something but we shouldn't end up here. return () => _t("%(senderName)s updated a ban rule that was matching %(oldGlob)s to matching %(newGlob)s " + - "for %(reason)s", {senderName, oldGlob: prevEntity, newGlob: entity, reason}); + "for %(reason)s", { senderName, oldGlob: prevEntity, newGlob: entity, reason }); } interface IHandlers { - [type: string]: (ev: any) => (() => string | null); + [type: string]: (ev: MatrixEvent, allowJSX?: boolean) => (() => string | JSX.Element | null); } const handlers: IHandlers = { @@ -648,7 +679,9 @@ export function hasText(ev): boolean { return Boolean(handler?.(ev)); } -export function textForEvent(ev): string { +export function textForEvent(ev: MatrixEvent): string; +export function textForEvent(ev: MatrixEvent, allowJSX: true): string | JSX.Element; +export function textForEvent(ev: MatrixEvent, allowJSX = false): string | JSX.Element { const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; - return handler?.(ev)?.() || ''; + return handler?.(ev, allowJSX)?.() || ''; } diff --git a/src/Tinter.js b/src/Tinter.js deleted file mode 100644 index ca5a460e16..0000000000 --- a/src/Tinter.js +++ /dev/null @@ -1,458 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd -Copyright 2017 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -const DEBUG = 0; - -// utility to turn #rrggbb or rgb(r,g,b) into [red,green,blue] -function colorToRgb(color) { - if (!color) { - return [0, 0, 0]; - } - - if (color[0] === '#') { - color = color.slice(1); - if (color.length === 3) { - color = color[0] + color[0] + - color[1] + color[1] + - color[2] + color[2]; - } - const val = parseInt(color, 16); - const r = (val >> 16) & 255; - const g = (val >> 8) & 255; - const b = val & 255; - return [r, g, b]; - } else { - const match = color.match(/rgb\((.*?),(.*?),(.*?)\)/); - if (match) { - return [ - parseInt(match[1]), - parseInt(match[2]), - parseInt(match[3]), - ]; - } - } - return [0, 0, 0]; -} - -// utility to turn [red,green,blue] into #rrggbb -function rgbToColor(rgb) { - const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; - return '#' + (0x1000000 + val).toString(16).slice(1); -} - -class Tinter { - constructor() { - // The default colour keys to be replaced as referred to in CSS - // (should be overridden by .mx_theme_accentColor and .mx_theme_secondaryAccentColor) - this.keyRgb = [ - "rgb(118, 207, 166)", // Vector Green - "rgb(234, 245, 240)", // Vector Light Green - "rgb(211, 239, 225)", // roomsublist-label-bg-color (20% Green overlaid on Light Green) - ]; - - // Some algebra workings for calculating the tint % of Vector Green & Light Green - // x * 118 + (1 - x) * 255 = 234 - // x * 118 + 255 - 255 * x = 234 - // x * 118 - x * 255 = 234 - 255 - // (255 - 118) x = 255 - 234 - // x = (255 - 234) / (255 - 118) = 0.16 - - // The colour keys to be replaced as referred to in SVGs - this.keyHex = [ - "#76CFA6", // Vector Green - "#EAF5F0", // Vector Light Green - "#D3EFE1", // roomsublist-label-bg-color (20% Green overlaid on Light Green) - "#FFFFFF", // white highlights of the SVGs (for switching to dark theme) - "#000000", // black lowlights of the SVGs (for switching to dark theme) - ]; - - // track the replacement colours actually being used - // defaults to our keys. - this.colors = [ - this.keyHex[0], - this.keyHex[1], - this.keyHex[2], - this.keyHex[3], - this.keyHex[4], - ]; - - // track the most current tint request inputs (which may differ from the - // end result stored in this.colors - this.currentTint = [ - undefined, - undefined, - undefined, - undefined, - undefined, - ]; - - this.cssFixups = [ - // { theme: { - // style: a style object that should be fixed up taken from a stylesheet - // attr: name of the attribute to be clobbered, e.g. 'color' - // index: ordinal of primary, secondary or tertiary - // }, - // } - ]; - - // CSS attributes to be fixed up - this.cssAttrs = [ - "color", - "backgroundColor", - "borderColor", - "borderTopColor", - "borderBottomColor", - "borderLeftColor", - ]; - - this.svgAttrs = [ - "fill", - "stroke", - ]; - - // List of functions to call when the tint changes. - this.tintables = []; - - // the currently loaded theme (if any) - this.theme = undefined; - - // whether to force a tint (e.g. after changing theme) - this.forceTint = false; - } - - /** - * Register a callback to fire when the tint changes. - * This is used to rewrite the tintable SVGs with the new tint. - * - * It's not possible to unregister a tintable callback. So this can only be - * used to register a static callback. If a set of tintables will change - * over time then the best bet is to register a single callback for the - * entire set. - * - * To ensure the tintable work happens at least once, it is also called as - * part of registration. - * - * @param {Function} tintable Function to call when the tint changes. - */ - registerTintable(tintable) { - this.tintables.push(tintable); - tintable(); - } - - getKeyRgb() { - return this.keyRgb; - } - - tint(primaryColor, secondaryColor, tertiaryColor) { - return; - // eslint-disable-next-line no-unreachable - this.currentTint[0] = primaryColor; - this.currentTint[1] = secondaryColor; - this.currentTint[2] = tertiaryColor; - - this.calcCssFixups(); - - if (DEBUG) { - console.log("Tinter.tint(" + primaryColor + ", " + - secondaryColor + ", " + - tertiaryColor + ")"); - } - - if (!primaryColor) { - primaryColor = this.keyRgb[0]; - secondaryColor = this.keyRgb[1]; - tertiaryColor = this.keyRgb[2]; - } - - if (!secondaryColor) { - const x = 0.16; // average weighting factor calculated from vector green & light green - const rgb = colorToRgb(primaryColor); - rgb[0] = x * rgb[0] + (1 - x) * 255; - rgb[1] = x * rgb[1] + (1 - x) * 255; - rgb[2] = x * rgb[2] + (1 - x) * 255; - secondaryColor = rgbToColor(rgb); - } - - if (!tertiaryColor) { - const x = 0.19; - const rgb1 = colorToRgb(primaryColor); - const rgb2 = colorToRgb(secondaryColor); - rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0]; - rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1]; - rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2]; - tertiaryColor = rgbToColor(rgb1); - } - - if (this.forceTint == false && - this.colors[0] === primaryColor && - this.colors[1] === secondaryColor && - this.colors[2] === tertiaryColor) { - return; - } - - this.forceTint = false; - - this.colors[0] = primaryColor; - this.colors[1] = secondaryColor; - this.colors[2] = tertiaryColor; - - if (DEBUG) { - console.log("Tinter.tint final: (" + primaryColor + ", " + - secondaryColor + ", " + - tertiaryColor + ")"); - } - - // go through manually fixing up the stylesheets. - this.applyCssFixups(); - - // tell all the SVGs to go fix themselves up - // we don't do this as a dispatch otherwise it will visually lag - this.tintables.forEach(function(tintable) { - tintable(); - }); - } - - tintSvgWhite(whiteColor) { - this.currentTint[3] = whiteColor; - - if (!whiteColor) { - whiteColor = this.colors[3]; - } - if (this.colors[3] === whiteColor) { - return; - } - this.colors[3] = whiteColor; - this.tintables.forEach(function(tintable) { - tintable(); - }); - } - - tintSvgBlack(blackColor) { - this.currentTint[4] = blackColor; - - if (!blackColor) { - blackColor = this.colors[4]; - } - if (this.colors[4] === blackColor) { - return; - } - this.colors[4] = blackColor; - this.tintables.forEach(function(tintable) { - tintable(); - }); - } - - - setTheme(theme) { - this.theme = theme; - - // update keyRgb from the current theme CSS itself, if it defines it - if (document.getElementById('mx_theme_accentColor')) { - this.keyRgb[0] = window.getComputedStyle( - document.getElementById('mx_theme_accentColor')).color; - } - if (document.getElementById('mx_theme_secondaryAccentColor')) { - this.keyRgb[1] = window.getComputedStyle( - document.getElementById('mx_theme_secondaryAccentColor')).color; - } - if (document.getElementById('mx_theme_tertiaryAccentColor')) { - this.keyRgb[2] = window.getComputedStyle( - document.getElementById('mx_theme_tertiaryAccentColor')).color; - } - - this.calcCssFixups(); - this.forceTint = true; - - this.tint(this.currentTint[0], this.currentTint[1], this.currentTint[2]); - - if (theme === 'dark') { - // abuse the tinter to change all the SVG's #fff to #2d2d2d - // XXX: obviously this shouldn't be hardcoded here. - this.tintSvgWhite('#2d2d2d'); - this.tintSvgBlack('#dddddd'); - } else { - this.tintSvgWhite('#ffffff'); - this.tintSvgBlack('#000000'); - } - } - - calcCssFixups() { - // cache our fixups - if (this.cssFixups[this.theme]) return; - - if (DEBUG) { - console.debug("calcCssFixups start for " + this.theme + " (checking " + - document.styleSheets.length + - " stylesheets)"); - } - - this.cssFixups[this.theme] = []; - - for (let i = 0; i < document.styleSheets.length; i++) { - const ss = document.styleSheets[i]; - try { - if (!ss) continue; // well done safari >:( - // Chromium apparently sometimes returns null here; unsure why. - // see $14534907369972FRXBx:matrix.org in HQ - // ...ah, it's because there's a third party extension like - // privacybadger inserting its own stylesheet in there with a - // resource:// URI or something which results in a XSS error. - // See also #vector:matrix.org/$145357669685386ebCfr:matrix.org - // ...except some browsers apparently return stylesheets without - // hrefs, which we have no choice but ignore right now - - // XXX seriously? we are hardcoding the name of vector's CSS file in - // here? - // - // Why do we need to limit it to vector's CSS file anyway - if there - // are other CSS files affecting the doc don't we want to apply the - // same transformations to them? - // - // Iterating through the CSS looking for matches to hack on feels - // pretty horrible anyway. And what if the application skin doesn't use - // Vector Green as its primary color? - // --richvdh - - // Yes, tinting assumes that you are using the Element skin for now. - // The right solution will be to move the CSS over to react-sdk. - // And yes, the default assets for the base skin might as well use - // Vector Green as any other colour. - // --matthew - - // stylesheets we don't have permission to access (eg. ones from extensions) have a null - // href and will throw exceptions if we try to access their rules. - if (!ss.href || !ss.href.match(new RegExp('/theme-' + this.theme + '.css$'))) continue; - if (ss.disabled) continue; - if (!ss.cssRules) continue; - - if (DEBUG) console.debug("calcCssFixups checking " + ss.cssRules.length + " rules for " + ss.href); - - for (let j = 0; j < ss.cssRules.length; j++) { - const rule = ss.cssRules[j]; - if (!rule.style) continue; - if (rule.selectorText && rule.selectorText.match(/#mx_theme/)) continue; - for (let k = 0; k < this.cssAttrs.length; k++) { - const attr = this.cssAttrs[k]; - for (let l = 0; l < this.keyRgb.length; l++) { - if (rule.style[attr] === this.keyRgb[l]) { - this.cssFixups[this.theme].push({ - style: rule.style, - attr: attr, - index: l, - }); - } - } - } - } - } catch (e) { - // Catch any random exceptions that happen here: all sorts of things can go - // wrong with this (nulls, SecurityErrors) and mostly it's for other - // stylesheets that we don't want to proces anyway. We should not propagate an - // exception out since this will cause the app to fail to start. - console.log("Failed to calculate CSS fixups for a stylesheet: " + ss.href, e); - } - } - if (DEBUG) { - console.log("calcCssFixups end (" + - this.cssFixups[this.theme].length + - " fixups)"); - } - } - - applyCssFixups() { - if (DEBUG) { - console.log("applyCssFixups start (" + - this.cssFixups[this.theme].length + - " fixups)"); - } - for (let i = 0; i < this.cssFixups[this.theme].length; i++) { - const cssFixup = this.cssFixups[this.theme][i]; - try { - cssFixup.style[cssFixup.attr] = this.colors[cssFixup.index]; - } catch (e) { - // Firefox Quantum explodes if you manually edit the CSS in the - // inspector and then try to do a tint, as apparently all the - // fixups are then stale. - console.error("Failed to apply cssFixup in Tinter! ", e.name); - } - } - if (DEBUG) console.log("applyCssFixups end"); - } - - // XXX: we could just move this all into TintableSvg, but as it's so similar - // to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg) - // keeping it here for now. - calcSvgFixups(svgs) { - // go through manually fixing up SVG colours. - // we could do this by stylesheets, but keeping the stylesheets - // updated would be a PITA, so just brute-force search for the - // key colour; cache the element and apply. - - if (DEBUG) console.log("calcSvgFixups start for " + svgs); - const fixups = []; - for (let i = 0; i < svgs.length; i++) { - let svgDoc; - try { - svgDoc = svgs[i].contentDocument; - } catch (e) { - let msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString(); - if (e.message) { - msg += e.message; - } - if (e.stack) { - msg += ' | stack: ' + e.stack; - } - console.error(msg); - } - if (!svgDoc) continue; - const tags = svgDoc.getElementsByTagName("*"); - for (let j = 0; j < tags.length; j++) { - const tag = tags[j]; - for (let k = 0; k < this.svgAttrs.length; k++) { - const attr = this.svgAttrs[k]; - for (let l = 0; l < this.keyHex.length; l++) { - if (tag.getAttribute(attr) && - tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) { - fixups.push({ - node: tag, - attr: attr, - index: l, - }); - } - } - } - } - } - if (DEBUG) console.log("calcSvgFixups end"); - - return fixups; - } - - applySvgFixups(fixups) { - if (DEBUG) console.log("applySvgFixups start for " + fixups); - for (let i = 0; i < fixups.length; i++) { - const svgFixup = fixups[i]; - svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]); - } - if (DEBUG) console.log("applySvgFixups end"); - } -} - -if (global.singletonTinter === undefined) { - global.singletonTinter = new Tinter(); -} -export default global.singletonTinter; diff --git a/src/Unread.ts b/src/Unread.ts index b733f4175a..72f0bb4642 100644 --- a/src/Unread.ts +++ b/src/Unread.ts @@ -16,7 +16,7 @@ limitations under the License. import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { EventType, MsgType } from "matrix-js-sdk/src/@types/event"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from "./MatrixClientPeg"; import shouldHideEvent from './shouldHideEvent'; @@ -43,12 +43,6 @@ export function eventTriggersUnreadCount(ev: MatrixEvent): boolean { case EventType.RoomCanonicalAlias: case EventType.RoomServerAcl: return false; - - case EventType.RoomMessage: - if (ev.getContent().msgtype === MsgType.Notice) { - return false; - } - break; } if (ev.isRedacted()) return false; diff --git a/src/UserActivity.ts b/src/UserActivity.ts index 606075ec7c..c35ced0cc4 100644 --- a/src/UserActivity.ts +++ b/src/UserActivity.ts @@ -191,10 +191,10 @@ export default class UserActivity { this.lastScreenY = event.screenY; } - dis.dispatch({action: 'user_activity'}); + dis.dispatch({ action: 'user_activity' }); if (!this.activeNowTimeout.isRunning()) { this.activeNowTimeout.start(); - dis.dispatch({action: 'user_activity_start'}); + dis.dispatch({ action: 'user_activity_start' }); UserActivity.runTimersUntilTimeout(this.attachedActiveNowTimers, this.activeNowTimeout); } else { diff --git a/src/WhoIsTyping.ts b/src/WhoIsTyping.ts index a8ca425ea8..938218d270 100644 --- a/src/WhoIsTyping.ts +++ b/src/WhoIsTyping.ts @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Room} from "matrix-js-sdk/src/models/room"; -import {RoomMember} from "matrix-js-sdk/src/models/room-member"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; -import {MatrixClientPeg} from "./MatrixClientPeg"; +import { MatrixClientPeg } from "./MatrixClientPeg"; import { _t } from './languageHandler'; export function usersTypingApartFromMeAndIgnored(room: Room): RoomMember[] { @@ -61,7 +61,7 @@ export function whoIsTypingString(whoIsTyping: RoomMember[], limit: number): str if (whoIsTyping.length === 0) { return ''; } else if (whoIsTyping.length === 1) { - return _t('%(displayName)s is typing …', {displayName: whoIsTyping[0].name}); + return _t('%(displayName)s is typing …', { displayName: whoIsTyping[0].name }); } const names = whoIsTyping.map(m => m.name); @@ -73,6 +73,6 @@ export function whoIsTypingString(whoIsTyping: RoomMember[], limit: number): str }); } else { const lastPerson = names.pop(); - return _t('%(names)s and %(lastPerson)s are typing …', {names: names.join(', '), lastPerson: lastPerson}); + return _t('%(names)s and %(lastPerson)s are typing …', { names: names.join(', '), lastPerson: lastPerson }); } } diff --git a/src/accessibility/KeyboardShortcuts.tsx b/src/accessibility/KeyboardShortcuts.tsx index 1cd5408210..25c41f9db5 100644 --- a/src/accessibility/KeyboardShortcuts.tsx +++ b/src/accessibility/KeyboardShortcuts.tsx @@ -20,7 +20,7 @@ import classNames from "classnames"; import * as sdk from "../index"; import Modal from "../Modal"; import { _t, _td } from "../languageHandler"; -import {isMac, Key} from "../Keyboard"; +import { isMac, Key } from "../Keyboard"; // TS: once languageHandler is TS we can probably inline this into the enum _td("Navigation"); @@ -332,7 +332,7 @@ const keyIcon: Record = { const Shortcut: React.FC<{ shortcut: IShortcut; -}> = ({shortcut}) => { +}> = ({ shortcut }) => { const classes = classNames({ "mx_KeyboardShortcutsDialog_inline": shortcut.keybinds.every(k => !k.modifiers || k.modifiers.length === 0), }); diff --git a/src/accessibility/RovingTabIndex.tsx b/src/accessibility/RovingTabIndex.tsx index 4cb537f318..87f525bdfc 100644 --- a/src/accessibility/RovingTabIndex.tsx +++ b/src/accessibility/RovingTabIndex.tsx @@ -26,8 +26,8 @@ import React, { Dispatch, } from "react"; -import {Key} from "../Keyboard"; -import {FocusHandler, Ref} from "./roving/types"; +import { Key } from "../Keyboard"; +import { FocusHandler, Ref } from "./roving/types"; /** * Module to simplify implementing the Roving TabIndex accessibility technique @@ -156,13 +156,13 @@ interface IProps { onKeyDown?(ev: React.KeyboardEvent, state: IState); } -export const RovingTabIndexProvider: React.FC = ({children, handleHomeEnd, onKeyDown}) => { +export const RovingTabIndexProvider: React.FC = ({ children, handleHomeEnd, onKeyDown }) => { const [state, dispatch] = useReducer>(reducer, { activeRef: null, refs: [], }); - const context = useMemo(() => ({state, dispatch}), [state]); + const context = useMemo(() => ({ state, dispatch }), [state]); const onKeyDownHandler = useCallback((ev) => { let handled = false; @@ -196,7 +196,7 @@ export const RovingTabIndexProvider: React.FC = ({children, handleHomeEn }, [context.state, onKeyDown, handleHomeEnd]); return - { children({onKeyDownHandler}) } + { children({ onKeyDownHandler }) } ; }; @@ -218,13 +218,13 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref] useLayoutEffect(() => { context.dispatch({ type: Type.Register, - payload: {ref}, + payload: { ref }, }); // teardown return () => { context.dispatch({ type: Type.Unregister, - payload: {ref}, + payload: { ref }, }); }; }, []); // eslint-disable-line react-hooks/exhaustive-deps @@ -232,7 +232,7 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref] const onFocus = useCallback(() => { context.dispatch({ type: Type.SetFocus, - payload: {ref}, + payload: { ref }, }); }, [ref, context]); @@ -241,6 +241,6 @@ export const useRovingTabIndex = (inputRef?: Ref): [FocusHandler, boolean, Ref] }; // re-export the semantic helper components for simplicity -export {RovingTabIndexWrapper} from "./roving/RovingTabIndexWrapper"; -export {RovingAccessibleButton} from "./roving/RovingAccessibleButton"; -export {RovingAccessibleTooltipButton} from "./roving/RovingAccessibleTooltipButton"; +export { RovingTabIndexWrapper } from "./roving/RovingTabIndexWrapper"; +export { RovingAccessibleButton } from "./roving/RovingAccessibleButton"; +export { RovingAccessibleTooltipButton } from "./roving/RovingAccessibleTooltipButton"; diff --git a/src/accessibility/Toolbar.tsx b/src/accessibility/Toolbar.tsx index e756d948e5..8d882fadea 100644 --- a/src/accessibility/Toolbar.tsx +++ b/src/accessibility/Toolbar.tsx @@ -16,8 +16,8 @@ limitations under the License. import React from "react"; -import {IState, RovingTabIndexProvider} from "./RovingTabIndex"; -import {Key} from "../Keyboard"; +import { IState, RovingTabIndexProvider } from "./RovingTabIndex"; +import { Key } from "../Keyboard"; interface IProps extends Omit, "onKeyDown"> { } @@ -25,7 +25,7 @@ interface IProps extends Omit, "onKeyDown"> { // This component implements the Toolbar design pattern from the WAI-ARIA Authoring Practices guidelines. // https://www.w3.org/TR/wai-aria-practices-1.1/#toolbar // All buttons passed in children must use RovingTabIndex to set `onFocus`, `isActive`, `ref` -const Toolbar: React.FC = ({children, ...props}) => { +const Toolbar: React.FC = ({ children, ...props }) => { const onKeyDown = (ev: React.KeyboardEvent, state: IState) => { const target = ev.target as HTMLElement; // Don't interfere with input default keydown behaviour @@ -62,7 +62,7 @@ const Toolbar: React.FC = ({children, ...props}) => { }; return - {({onKeyDownHandler}) =>
+ {({ onKeyDownHandler }) =>
{ children }
} ; diff --git a/src/accessibility/context_menu/MenuGroup.tsx b/src/accessibility/context_menu/MenuGroup.tsx index 9334e17a18..97f9694f83 100644 --- a/src/accessibility/context_menu/MenuGroup.tsx +++ b/src/accessibility/context_menu/MenuGroup.tsx @@ -23,7 +23,7 @@ interface IProps extends React.HTMLAttributes { } // Semantic component for representing a role=group for grouping menu radios/checkboxes -export const MenuGroup: React.FC = ({children, label, ...props}) => { +export const MenuGroup: React.FC = ({ children, label, ...props }) => { return
{ children }
; diff --git a/src/accessibility/context_menu/MenuItem.tsx b/src/accessibility/context_menu/MenuItem.tsx index 9a7c1d1f0a..9c0b248274 100644 --- a/src/accessibility/context_menu/MenuItem.tsx +++ b/src/accessibility/context_menu/MenuItem.tsx @@ -27,7 +27,7 @@ interface IProps extends React.ComponentProps { } // Semantic component for representing a role=menuitem -export const MenuItem: React.FC = ({children, label, tooltip, ...props}) => { +export const MenuItem: React.FC = ({ children, label, tooltip, ...props }) => { const ariaLabel = props["aria-label"] || label; if (tooltip) { diff --git a/src/accessibility/context_menu/MenuItemCheckbox.tsx b/src/accessibility/context_menu/MenuItemCheckbox.tsx index 5eb8cc4819..67da4cc85a 100644 --- a/src/accessibility/context_menu/MenuItemCheckbox.tsx +++ b/src/accessibility/context_menu/MenuItemCheckbox.tsx @@ -26,7 +26,7 @@ interface IProps extends React.ComponentProps { } // Semantic component for representing a role=menuitemcheckbox -export const MenuItemCheckbox: React.FC = ({children, label, active, disabled, ...props}) => { +export const MenuItemCheckbox: React.FC = ({ children, label, active, disabled, ...props }) => { return ( { } // Semantic component for representing a role=menuitemradio -export const MenuItemRadio: React.FC = ({children, label, active, disabled, ...props}) => { +export const MenuItemRadio: React.FC = ({ children, label, active, disabled, ...props }) => { return ( { @@ -28,7 +28,7 @@ interface IProps extends React.ComponentProps { } // Semantic component for representing a styled role=menuitemcheckbox -export const StyledMenuItemCheckbox: React.FC = ({children, label, onChange, onClose, ...props}) => { +export const StyledMenuItemCheckbox: React.FC = ({ children, label, onChange, onClose, ...props }) => { const onKeyDown = (e: React.KeyboardEvent) => { if (e.key === Key.ENTER || e.key === Key.SPACE) { e.stopPropagation(); diff --git a/src/accessibility/context_menu/StyledMenuItemRadio.tsx b/src/accessibility/context_menu/StyledMenuItemRadio.tsx index 5e5aa90a38..e3d340ef3e 100644 --- a/src/accessibility/context_menu/StyledMenuItemRadio.tsx +++ b/src/accessibility/context_menu/StyledMenuItemRadio.tsx @@ -18,7 +18,7 @@ limitations under the License. import React from "react"; -import {Key} from "../../Keyboard"; +import { Key } from "../../Keyboard"; import StyledRadioButton from "../../components/views/elements/StyledRadioButton"; interface IProps extends React.ComponentProps { @@ -28,7 +28,7 @@ interface IProps extends React.ComponentProps { } // Semantic component for representing a styled role=menuitemradio -export const StyledMenuItemRadio: React.FC = ({children, label, onChange, onClose, ...props}) => { +export const StyledMenuItemRadio: React.FC = ({ children, label, onChange, onClose, ...props }) => { const onKeyDown = (e: React.KeyboardEvent) => { if (e.key === Key.ENTER || e.key === Key.SPACE) { e.stopPropagation(); diff --git a/src/accessibility/roving/RovingAccessibleButton.tsx b/src/accessibility/roving/RovingAccessibleButton.tsx index 3473ef1bc9..f9ce87db6a 100644 --- a/src/accessibility/roving/RovingAccessibleButton.tsx +++ b/src/accessibility/roving/RovingAccessibleButton.tsx @@ -17,15 +17,15 @@ limitations under the License. import React from "react"; import AccessibleButton from "../../components/views/elements/AccessibleButton"; -import {useRovingTabIndex} from "../RovingTabIndex"; -import {Ref} from "./types"; +import { useRovingTabIndex } from "../RovingTabIndex"; +import { Ref } from "./types"; interface IProps extends Omit, "onFocus" | "inputRef" | "tabIndex"> { inputRef?: Ref; } // Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components. -export const RovingAccessibleButton: React.FC = ({inputRef, ...props}) => { +export const RovingAccessibleButton: React.FC = ({ inputRef, ...props }) => { const [onFocus, isActive, ref] = useRovingTabIndex(inputRef); return ; }; diff --git a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx index 2cb974d60e..d9e393d728 100644 --- a/src/accessibility/roving/RovingAccessibleTooltipButton.tsx +++ b/src/accessibility/roving/RovingAccessibleTooltipButton.tsx @@ -17,8 +17,8 @@ limitations under the License. import React from "react"; import AccessibleTooltipButton from "../../components/views/elements/AccessibleTooltipButton"; -import {useRovingTabIndex} from "../RovingTabIndex"; -import {Ref} from "./types"; +import { useRovingTabIndex } from "../RovingTabIndex"; +import { Ref } from "./types"; type ATBProps = React.ComponentProps; interface IProps extends Omit { @@ -26,7 +26,7 @@ interface IProps extends Omit { } // Wrapper to allow use of useRovingTabIndex for simple AccessibleTooltipButtons outside of React Functional Components. -export const RovingAccessibleTooltipButton: React.FC = ({inputRef, ...props}) => { +export const RovingAccessibleTooltipButton: React.FC = ({ inputRef, ...props }) => { const [onFocus, isActive, ref] = useRovingTabIndex(inputRef); return ; }; diff --git a/src/accessibility/roving/RovingTabIndexWrapper.tsx b/src/accessibility/roving/RovingTabIndexWrapper.tsx index 5211f30215..974bb9a388 100644 --- a/src/accessibility/roving/RovingTabIndexWrapper.tsx +++ b/src/accessibility/roving/RovingTabIndexWrapper.tsx @@ -16,8 +16,8 @@ limitations under the License. import React from "react"; -import {useRovingTabIndex} from "../RovingTabIndex"; -import {FocusHandler, Ref} from "./types"; +import { useRovingTabIndex } from "../RovingTabIndex"; +import { FocusHandler, Ref } from "./types"; interface IProps { inputRef?: Ref; @@ -29,7 +29,7 @@ interface IProps { } // Wrapper to allow use of useRovingTabIndex outside of React Functional Components. -export const RovingTabIndexWrapper: React.FC = ({children, inputRef}) => { +export const RovingTabIndexWrapper: React.FC = ({ children, inputRef }) => { const [onFocus, isActive, ref] = useRovingTabIndex(inputRef); - return children({onFocus, isActive, ref}); + return children({ onFocus, isActive, ref }); }; diff --git a/src/accessibility/roving/types.ts b/src/accessibility/roving/types.ts index f0a43e5fb8..cc6a98e1d7 100644 --- a/src/accessibility/roving/types.ts +++ b/src/accessibility/roving/types.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {RefObject} from "react"; +import { RefObject } from "react"; export type Ref = RefObject; diff --git a/src/actions/MatrixActionCreators.ts b/src/actions/MatrixActionCreators.ts index 33e72becd2..70b86f8ee5 100644 --- a/src/actions/MatrixActionCreators.ts +++ b/src/actions/MatrixActionCreators.ts @@ -20,7 +20,7 @@ import { Room } from "matrix-js-sdk/src/models/room"; import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline"; import dis from "../dispatcher/dispatcher"; -import {ActionPayload} from "../dispatcher/payloads"; +import { ActionPayload } from "../dispatcher/payloads"; // TODO: migrate from sync_state to MatrixActions.sync so that more js-sdk events // become dispatches in the same place. diff --git a/src/actions/RoomListActions.ts b/src/actions/RoomListActions.ts index 88946ee26f..81e05f8678 100644 --- a/src/actions/RoomListActions.ts +++ b/src/actions/RoomListActions.ts @@ -112,7 +112,7 @@ export default class RoomListActions { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to remove tag " + oldTag + " from room: " + err); Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, { - title: _t('Failed to remove tag %(tagName)s from room', {tagName: oldTag}), + title: _t('Failed to remove tag %(tagName)s from room', { tagName: oldTag }), description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); @@ -132,7 +132,7 @@ export default class RoomListActions { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to add tag " + newTag + " to room: " + err); Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, { - title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}), + title: _t('Failed to add tag %(tagName)s to room', { tagName: newTag }), description: ((err && err.message) ? err.message : _t('Operation failed')), }); diff --git a/src/actions/TagOrderActions.ts b/src/actions/TagOrderActions.ts index 021cd11b55..dc538134a1 100644 --- a/src/actions/TagOrderActions.ts +++ b/src/actions/TagOrderActions.ts @@ -53,11 +53,11 @@ export default class TagOrderActions { Analytics.trackEvent('TagOrderActions', 'commitTagOrdering'); return matrixClient.setAccountData( 'im.vector.web.tag_ordering', - {tags, removedTags, _storeId: storeId}, + { tags, removedTags, _storeId: storeId }, ); }, () => { // For an optimistic update - return {tags, removedTags}; + return { tags, removedTags }; }); } @@ -100,11 +100,11 @@ export default class TagOrderActions { Analytics.trackEvent('TagOrderActions', 'removeTag'); return matrixClient.setAccountData( 'im.vector.web.tag_ordering', - {tags, removedTags, _storeId: storeId}, + { tags, removedTags, _storeId: storeId }, ); }, () => { // For an optimistic update - return {removedTags}; + return { removedTags }; }); } } diff --git a/src/actions/actionCreators.ts b/src/actions/actionCreators.ts index c789e3cd07..81e0b95098 100644 --- a/src/actions/actionCreators.ts +++ b/src/actions/actionCreators.ts @@ -51,9 +51,9 @@ export function asyncAction(id: string, fn: () => Promise, pendingFn: () => request: typeof pendingFn === 'function' ? pendingFn() : undefined, }); fn().then((result) => { - dispatch({action: id + '.success', result}); + dispatch({ action: id + '.success', result }); }).catch((err) => { - dispatch({action: id + '.failure', err}); + dispatch({ action: id + '.failure', err }); }); }; return new AsyncActionPayload(helper); diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index de50feaedb..a19494c753 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -22,8 +22,8 @@ import { _t } from '../../../../languageHandler'; import SettingsStore from "../../../../settings/SettingsStore"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; -import {Action} from "../../../../dispatcher/actions"; -import {SettingLevel} from "../../../../settings/SettingLevel"; +import { Action } from "../../../../dispatcher/actions"; +import { SettingLevel } from "../../../../settings/SettingLevel"; /* * Allows the user to disable the Event Index. diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx index 0710c513da..76c3373ba4 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx @@ -21,9 +21,9 @@ import SdkConfig from '../../../../SdkConfig'; import SettingsStore from "../../../../settings/SettingsStore"; import Modal from '../../../../Modal'; -import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils"; +import { formatBytes, formatCountLong } from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; -import {SettingLevel} from "../../../../settings/SettingLevel"; +import { SettingLevel } from "../../../../settings/SettingLevel"; interface IProps { onFinished: (confirmed: boolean) => void; @@ -139,7 +139,7 @@ export default class ManageEventIndexDialog extends React.Component { - this.setState({crawlerSleepTime: e.target.value}); + this.setState({ crawlerSleepTime: e.target.value }); SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); }; diff --git a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js index 549494b5cb..92fb37ef16 100644 --- a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js +++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.js @@ -15,15 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; import FileSaver from 'file-saver'; import * as sdk from '../../../../index'; -import {MatrixClientPeg} from '../../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import PropTypes from 'prop-types'; -import {_t, _td} from '../../../../languageHandler'; +import { _t, _td } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../SecurityManager'; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; -import {copyNode} from "../../../../utils/strings"; +import { copyNode } from "../../../../utils/strings"; import PassphraseField from "../../../../components/views/auth/PassphraseField"; const PHASE_PASSPHRASE = 0; @@ -152,11 +152,11 @@ export default class CreateKeyBackupDialog extends React.PureComponent { } _onOptOutClick = () => { - this.setState({phase: PHASE_OPTOUT_CONFIRM}); + this.setState({ phase: PHASE_OPTOUT_CONFIRM }); } _onSetUpClick = () => { - this.setState({phase: PHASE_PASSPHRASE}); + this.setState({ phase: PHASE_PASSPHRASE }); } _onSkipPassPhraseClick = async () => { @@ -179,7 +179,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent { return; } - this.setState({phase: PHASE_PASSPHRASE_CONFIRM}); + this.setState({ phase: PHASE_PASSPHRASE_CONFIRM }); }; _onPassPhraseConfirmNextClick = async (e) => { @@ -370,21 +370,21 @@ export default class CreateKeyBackupDialog extends React.PureComponent { if (this.state.copied) { introText = _t( "Your Security Key has been copied to your clipboard, paste it to:", - {}, {b: s => {s}}, + {}, { b: s => {s} }, ); } else if (this.state.downloaded) { introText = _t( "Your Security Key is in your Downloads folder.", - {}, {b: s => {s}}, + {}, { b: s => {s} }, ); } const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return
{introText}
    -
  • {_t("Print it and store it somewhere safe", {}, {b: s => {s}})}
  • -
  • {_t("Save it on a USB key or backup drive", {}, {b: s => {s}})}
  • -
  • {_t("Copy it to your personal cloud storage", {}, {b: s => {s}})}
  • +
  • {_t("Print it and store it somewhere safe", {}, { b: s => {s} })}
  • +
  • {_t("Save it on a USB key or backup drive", {}, { b: s => {s} })}
  • +
  • {_t("Copy it to your personal cloud storage", {}, { b: s => {s} })}
{ - this.setState({phase: PHASE_LOADING}); + this.setState({ phase: PHASE_LOADING }); this._fetchBackupInfo(); } @@ -394,11 +394,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent { } _onCancelClick = () => { - this.setState({phase: PHASE_CONFIRM_SKIP}); + this.setState({ phase: PHASE_CONFIRM_SKIP }); } _onGoBackClick = () => { - this.setState({phase: PHASE_CHOOSE_KEY_PASSPHRASE}); + this.setState({ phase: PHASE_CHOOSE_KEY_PASSPHRASE }); } _onPassPhraseNextClick = async (e) => { @@ -412,7 +412,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { return; } - this.setState({phase: PHASE_PASSPHRASE_CONFIRM}); + this.setState({ phase: PHASE_PASSPHRASE_CONFIRM }); }; _onPassPhraseConfirmNextClick = async (e) => { diff --git a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.js b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.js index 60f2ca9168..0435d81968 100644 --- a/src/async-components/views/dialogs/security/ExportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/security/ExportE2eKeysDialog.js @@ -15,7 +15,7 @@ limitations under the License. */ import FileSaver from 'file-saver'; -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; @@ -55,11 +55,11 @@ export default class ExportE2eKeysDialog extends React.Component { const passphrase = this._passphrase1.current.value; if (passphrase !== this._passphrase2.current.value) { - this.setState({errStr: _t('Passphrases must match')}); + this.setState({ errStr: _t('Passphrases must match') }); return false; } if (!passphrase) { - this.setState({errStr: _t('Passphrase must not be empty')}); + this.setState({ errStr: _t('Passphrase must not be empty') }); return false; } diff --git a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.js b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.js index 70fc997230..6017d07047 100644 --- a/src/async-components/views/dialogs/security/ImportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/security/ImportE2eKeysDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; import PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk/src/client'; diff --git a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js index 8c09cc6d16..4a0aa37da0 100644 --- a/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js +++ b/src/async-components/views/dialogs/security/NewRecoveryMethodDialog.js @@ -18,12 +18,12 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import * as sdk from "../../../../index"; -import {MatrixClientPeg} from '../../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import dis from "../../../../dispatcher/dispatcher"; import { _t } from "../../../../languageHandler"; import Modal from "../../../../Modal"; import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog"; -import {Action} from "../../../../dispatcher/actions"; +import { Action } from "../../../../dispatcher/actions"; export default class NewRecoveryMethodDialog extends React.PureComponent { static propTypes = { diff --git a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js index b60e6fd3cb..f0f8a5273b 100644 --- a/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js +++ b/src/async-components/views/dialogs/security/RecoveryMethodRemovedDialog.js @@ -21,7 +21,7 @@ import * as sdk from "../../../../index"; import dis from "../../../../dispatcher/dispatcher"; import { _t } from "../../../../languageHandler"; import Modal from "../../../../Modal"; -import {Action} from "../../../../dispatcher/actions"; +import { Action } from "../../../../dispatcher/actions"; export default class RecoveryMethodRemovedDialog extends React.PureComponent { static propTypes = { diff --git a/src/autocomplete/AutocompleteProvider.tsx b/src/autocomplete/AutocompleteProvider.tsx index 2242fec914..51ab2e2cf7 100644 --- a/src/autocomplete/AutocompleteProvider.tsx +++ b/src/autocomplete/AutocompleteProvider.tsx @@ -17,7 +17,7 @@ limitations under the License. */ import React from 'react'; -import type {ICompletion, ISelectionRange} from './Autocompleter'; +import type { ICompletion, ISelectionRange } from './Autocompleter'; export interface ICommand { command: string | null; diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts index 7f3f5d2c01..7ab2ae70ea 100644 --- a/src/autocomplete/Autocompleter.ts +++ b/src/autocomplete/Autocompleter.ts @@ -26,7 +26,7 @@ import UserProvider from './UserProvider'; import EmojiProvider from './EmojiProvider'; import NotifProvider from './NotifProvider'; import { timeout } from "../utils/promise"; -import AutocompleteProvider, {ICommand} from "./AutocompleteProvider"; +import AutocompleteProvider, { ICommand } from "./AutocompleteProvider"; import SettingsStore from "../settings/SettingsStore"; import SpaceProvider from "./SpaceProvider"; diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index 9de25c0d84..e9a7742dee 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -18,12 +18,12 @@ limitations under the License. */ import React from 'react'; -import {_t} from '../languageHandler'; +import { _t } from '../languageHandler'; import AutocompleteProvider from './AutocompleteProvider'; import QueryMatcher from './QueryMatcher'; -import {TextualCompletion} from './Components'; -import {ICompletion, ISelectionRange} from "./Autocompleter"; -import {Command, Commands, CommandMap} from '../SlashCommands'; +import { TextualCompletion } from './Components'; +import { ICompletion, ISelectionRange } from "./Autocompleter"; +import { Command, Commands, CommandMap } from '../SlashCommands'; const COMMAND_RE = /(^\/\w*)(?: .*)?/g; @@ -34,7 +34,7 @@ export default class CommandProvider extends AutocompleteProvider { super(COMMAND_RE); this.matcher = new QueryMatcher(Commands, { keys: ['command', 'args', 'description'], - funcs: [({aliases}) => aliases.join(" ")], // aliases + funcs: [({ aliases }) => aliases.join(" ")], // aliases }); } @@ -44,7 +44,7 @@ export default class CommandProvider extends AutocompleteProvider { force?: boolean, limit = -1, ): Promise { - const {command, range} = this.getCurrentCommand(query, selection); + const { command, range } = this.getCurrentCommand(query, selection); if (!command) return []; let matches = []; @@ -68,7 +68,6 @@ export default class CommandProvider extends AutocompleteProvider { } } - return matches.filter(cmd => cmd.isEnabled()).map((result) => { let completion = result.getCommand() + ' '; const usedAlias = result.aliases.find(alias => `/${alias}` === command[1]); diff --git a/src/autocomplete/CommunityProvider.tsx b/src/autocomplete/CommunityProvider.tsx index c9358b0c61..48c1921539 100644 --- a/src/autocomplete/CommunityProvider.tsx +++ b/src/autocomplete/CommunityProvider.tsx @@ -19,15 +19,15 @@ import React from 'react'; import Group from "matrix-js-sdk/src/models/group"; import { _t } from '../languageHandler'; import AutocompleteProvider from './AutocompleteProvider'; -import {MatrixClientPeg} from '../MatrixClientPeg'; +import { MatrixClientPeg } from '../MatrixClientPeg'; import QueryMatcher from './QueryMatcher'; -import {PillCompletion} from './Components'; +import { PillCompletion } from './Components'; import * as sdk from '../index'; -import {sortBy} from "lodash"; -import {makeGroupPermalink} from "../utils/permalinks/Permalinks"; -import {ICompletion, ISelectionRange} from "./Autocompleter"; +import { sortBy } from "lodash"; +import { makeGroupPermalink } from "../utils/permalinks/Permalinks"; +import { ICompletion, ISelectionRange } from "./Autocompleter"; import FlairStore from "../stores/FlairStore"; -import {mediaFromMxc} from "../customisations/Media"; +import { mediaFromMxc } from "../customisations/Media"; const COMMUNITY_REGEX = /\B\+\S*/g; @@ -66,11 +66,11 @@ export default class CommunityProvider extends AutocompleteProvider { const cli = MatrixClientPeg.get(); let completions = []; - const {command, range} = this.getCurrentCommand(query, selection, force); + const { command, range } = this.getCurrentCommand(query, selection, force); if (command) { - const joinedGroups = cli.getGroups().filter(({myMembership}) => myMembership === 'join'); + const joinedGroups = cli.getGroups().filter(({ myMembership }) => myMembership === 'join'); - const groups = (await Promise.all(joinedGroups.map(async ({groupId}) => { + const groups = (await Promise.all(joinedGroups.map(async ({ groupId }) => { try { return FlairStore.getGroupProfileCached(cli, groupId); } catch (e) { // if FlairStore failed, fall back to just groupId @@ -90,7 +90,7 @@ export default class CommunityProvider extends AutocompleteProvider { completions = sortBy(completions, [ (c) => score(matchedString, c.groupId), (c) => c.groupId.length, - ]).map(({avatarUrl, groupId, name}) => ({ + ]).map(({ avatarUrl, groupId, name }) => ({ completion: groupId, suffix: ' ', type: "community", diff --git a/src/autocomplete/Components.tsx b/src/autocomplete/Components.tsx index 4b0d35698d..8f155f7f55 100644 --- a/src/autocomplete/Components.tsx +++ b/src/autocomplete/Components.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {forwardRef} from 'react'; +import React, { forwardRef } from 'react'; import classNames from 'classnames'; /* These were earlier stateless functional components but had to be converted @@ -31,7 +31,7 @@ interface ITextualCompletionProps { } export const TextualCompletion = forwardRef((props, ref) => { - const {title, subtitle, description, className, ...restProps} = props; + const { title, subtitle, description, className, ...restProps } = props; return (
((props, ref) => { - const {title, subtitle, description, className, children, ...restProps} = props; + const { title, subtitle, description, className, children, ...restProps } = props; return (
{ - const {command, range} = this.getCurrentCommand(query, selection); + const { command, range } = this.getCurrentCommand(query, selection); if (!query || !command) { return []; } diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx index b7c4a5120a..2fc77e9a17 100644 --- a/src/autocomplete/EmojiProvider.tsx +++ b/src/autocomplete/EmojiProvider.tsx @@ -21,9 +21,9 @@ import React from 'react'; import { _t } from '../languageHandler'; import AutocompleteProvider from './AutocompleteProvider'; import QueryMatcher from './QueryMatcher'; -import {PillCompletion} from './Components'; -import {ICompletion, ISelectionRange} from './Autocompleter'; -import {uniq, sortBy} from 'lodash'; +import { PillCompletion } from './Components'; +import { ICompletion, ISelectionRange } from './Autocompleter'; +import { uniq, sortBy } from 'lodash'; import SettingsStore from "../settings/SettingsStore"; import { shortcodeToUnicode } from '../HtmlUtils'; import { EMOJI, IEmoji } from '../emoji'; @@ -95,7 +95,7 @@ export default class EmojiProvider extends AutocompleteProvider { } let completions = []; - const {command, range} = this.getCurrentCommand(query, selection); + const { command, range } = this.getCurrentCommand(query, selection); if (command) { const matchedString = command[0]; completions = this.matcher.match(matchedString, limit); @@ -121,7 +121,7 @@ export default class EmojiProvider extends AutocompleteProvider { sorters.push((c) => c._orderBy); completions = sortBy(uniq(completions), sorters); - completions = completions.map(({shortname}) => { + completions = completions.map(({ shortname }) => { const unicode = shortcodeToUnicode(shortname); return { completion: unicode, diff --git a/src/autocomplete/NotifProvider.tsx b/src/autocomplete/NotifProvider.tsx index 827f4aa885..1d42915ec9 100644 --- a/src/autocomplete/NotifProvider.tsx +++ b/src/autocomplete/NotifProvider.tsx @@ -19,10 +19,10 @@ import { Room } from "matrix-js-sdk/src/models/room"; import AutocompleteProvider from './AutocompleteProvider'; import { _t } from '../languageHandler'; -import {MatrixClientPeg} from '../MatrixClientPeg'; -import {PillCompletion} from './Components'; +import { MatrixClientPeg } from '../MatrixClientPeg'; +import { PillCompletion } from './Components'; import * as sdk from '../index'; -import {ICompletion, ISelectionRange} from "./Autocompleter"; +import { ICompletion, ISelectionRange } from "./Autocompleter"; const AT_ROOM_REGEX = /@\S*/g; @@ -46,7 +46,7 @@ export default class NotifProvider extends AutocompleteProvider { if (!this.room.currentState.mayTriggerNotifOfType('room', client.credentials.userId)) return []; - const {command, range} = this.getCurrentCommand(query, selection, force); + const { command, range } = this.getCurrentCommand(query, selection, force); if (command && command[0] && '@room'.startsWith(command[0]) && command[0].length > 1) { return [{ completion: '@room', diff --git a/src/autocomplete/QueryMatcher.ts b/src/autocomplete/QueryMatcher.ts index 73bb37ff0f..3948be301c 100644 --- a/src/autocomplete/QueryMatcher.ts +++ b/src/autocomplete/QueryMatcher.ts @@ -16,8 +16,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {at, uniq} from 'lodash'; -import {removeHiddenChars} from "matrix-js-sdk/src/utils"; +import { at, uniq } from 'lodash'; +import { removeHiddenChars } from "matrix-js-sdk/src/utils"; interface IOptions { keys: Array; @@ -112,7 +112,7 @@ export default class QueryMatcher { const index = resultKey.indexOf(query); if (index !== -1) { matches.push( - ...candidates.map((candidate) => ({index, ...candidate})), + ...candidates.map((candidate) => ({ index, ...candidate })), ); } } diff --git a/src/autocomplete/RoomProvider.tsx b/src/autocomplete/RoomProvider.tsx index 5240db6955..7865a76daa 100644 --- a/src/autocomplete/RoomProvider.tsx +++ b/src/autocomplete/RoomProvider.tsx @@ -73,7 +73,7 @@ export default class RoomProvider extends AutocompleteProvider { limit = -1, ): Promise { let completions = []; - const {command, range} = this.getCurrentCommand(query, selection, force); + const { command, range } = this.getCurrentCommand(query, selection, force); if (command) { // the only reason we need to do this is because Fuse only matches on properties let matcherObjects = this.getRooms().reduce((aliases, room) => { diff --git a/src/autocomplete/SpaceProvider.tsx b/src/autocomplete/SpaceProvider.tsx index 0361a2c91e..1c99aee5ac 100644 --- a/src/autocomplete/SpaceProvider.tsx +++ b/src/autocomplete/SpaceProvider.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import { _t } from '../languageHandler'; -import {MatrixClientPeg} from '../MatrixClientPeg'; +import { MatrixClientPeg } from '../MatrixClientPeg'; import RoomProvider from "./RoomProvider"; export default class SpaceProvider extends RoomProvider { diff --git a/src/autocomplete/UserProvider.tsx b/src/autocomplete/UserProvider.tsx index 687b477133..470e018e22 100644 --- a/src/autocomplete/UserProvider.tsx +++ b/src/autocomplete/UserProvider.tsx @@ -114,7 +114,7 @@ export default class UserProvider extends AutocompleteProvider { if (!this.users) this._makeUsers(); let completions = []; - const {command, range} = this.getCurrentCommand(rawQuery, selection, force); + const { command, range } = this.getCurrentCommand(rawQuery, selection, force); if (!command) return completions; @@ -158,7 +158,7 @@ export default class UserProvider extends AutocompleteProvider { } const currentUserId = MatrixClientPeg.get().credentials.userId; - this.users = this.room.getJoinedMembers().filter(({userId}) => userId !== currentUserId); + this.users = this.room.getJoinedMembers().filter(({ userId }) => userId !== currentUserId); this.users = this.users.concat(this.room.getMembersWithMembership("invite")); this.users = sortBy(this.users, (member) => 1E20 - lastSpoken[member.userId] || 1E20); diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 9d8665c176..407dc6f04c 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -16,13 +16,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {CSSProperties, RefObject, useRef, useState} from "react"; +import React, { CSSProperties, RefObject, useRef, useState } from "react"; import ReactDOM from "react-dom"; import classNames from "classnames"; -import {Key} from "../../Keyboard"; -import {Writeable} from "../../@types/common"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { Key } from "../../Keyboard"; +import { Writeable } from "../../@types/common"; +import { replaceableComponent } from "../../utils/replaceableComponent"; import UIStore from "../../stores/UIStore"; // Shamelessly ripped off Modal.js. There's probably a better way @@ -371,7 +371,7 @@ export class ContextMenu extends React.PureComponent { return (
@@ -399,7 +399,7 @@ export const toRightOf = (elementRect: Pick const left = elementRect.right + window.pageXOffset + 3; let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset; top -= chevronOffset + 8; // where 8 is half the height of the chevron - return {left, top, chevronOffset}; + return { left, top, chevronOffset }; }; // Placement method for to position context menu right-aligned and flowing to the left of elementRect, @@ -498,15 +498,15 @@ export function createMenu(ElementClass, props) { ReactDOM.render(menu, getOrCreateContainer()); - return {close: onFinished}; + return { close: onFinished }; } // re-export the semantic helper components for simplicity -export {ContextMenuButton} from "../../accessibility/context_menu/ContextMenuButton"; -export {ContextMenuTooltipButton} from "../../accessibility/context_menu/ContextMenuTooltipButton"; -export {MenuGroup} from "../../accessibility/context_menu/MenuGroup"; -export {MenuItem} from "../../accessibility/context_menu/MenuItem"; -export {MenuItemCheckbox} from "../../accessibility/context_menu/MenuItemCheckbox"; -export {MenuItemRadio} from "../../accessibility/context_menu/MenuItemRadio"; -export {StyledMenuItemCheckbox} from "../../accessibility/context_menu/StyledMenuItemCheckbox"; -export {StyledMenuItemRadio} from "../../accessibility/context_menu/StyledMenuItemRadio"; +export { ContextMenuButton } from "../../accessibility/context_menu/ContextMenuButton"; +export { ContextMenuTooltipButton } from "../../accessibility/context_menu/ContextMenuTooltipButton"; +export { MenuGroup } from "../../accessibility/context_menu/MenuGroup"; +export { MenuItem } from "../../accessibility/context_menu/MenuItem"; +export { MenuItemCheckbox } from "../../accessibility/context_menu/MenuItemCheckbox"; +export { MenuItemRadio } from "../../accessibility/context_menu/MenuItemRadio"; +export { StyledMenuItemCheckbox } from "../../accessibility/context_menu/StyledMenuItemCheckbox"; +export { StyledMenuItemRadio } from "../../accessibility/context_menu/StyledMenuItemRadio"; diff --git a/src/components/structures/CustomRoomTagPanel.js b/src/components/structures/CustomRoomTagPanel.js index 73359f17a5..037d7c251c 100644 --- a/src/components/structures/CustomRoomTagPanel.js +++ b/src/components/structures/CustomRoomTagPanel.js @@ -21,7 +21,7 @@ import * as sdk from '../../index'; import dis from '../../dispatcher/dispatcher'; import classNames from 'classnames'; import * as FormattingUtils from '../../utils/FormattingUtils'; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; @replaceableComponent("structures.CustomRoomTagPanel") class CustomRoomTagPanel extends React.Component { @@ -34,7 +34,7 @@ class CustomRoomTagPanel extends React.Component { componentDidMount() { this._tagStoreToken = CustomRoomTagStore.addListener(() => { - this.setState({tags: CustomRoomTagStore.getSortedTags()}); + this.setState({ tags: CustomRoomTagStore.getSortedTags() }); }); } @@ -64,7 +64,7 @@ class CustomRoomTagPanel extends React.Component { class CustomRoomTagTile extends React.Component { onClick = () => { - dis.dispatch({action: 'select_custom_room_tag', tag: this.props.tag.name}); + dis.dispatch({ action: 'select_custom_room_tag', tag: this.props.tag.name }); }; render() { diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index c37ab3df48..628c16f322 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -22,7 +22,7 @@ import request from 'browser-request'; import { _t } from '../../languageHandler'; import sanitizeHtml from 'sanitize-html'; import dis from '../../dispatcher/dispatcher'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import classnames from 'classnames'; import MatrixClientContext from "../../contexts/MatrixClientContext"; import AutoHideScrollbar from "./AutoHideScrollbar"; diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.tsx similarity index 85% rename from src/components/structures/FilePanel.js rename to src/components/structures/FilePanel.tsx index bb7c1f9642..21ef0c4f31 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.tsx @@ -16,37 +16,49 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import {Filter} from 'matrix-js-sdk/src/filter'; +import { Filter } from 'matrix-js-sdk/src/filter'; +import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from 'matrix-js-sdk/src/models/room'; +import { TimelineWindow } from 'matrix-js-sdk/src/timeline-window'; + import * as sdk from '../../index'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import EventIndexPeg from "../../indexing/EventIndexPeg"; import { _t } from '../../languageHandler'; import BaseCard from "../views/right_panel/BaseCard"; -import {RightPanelPhases} from "../../stores/RightPanelStorePhases"; -import DesktopBuildsNotice, {WarningKind} from "../views/elements/DesktopBuildsNotice"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; +import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice"; +import { replaceableComponent } from "../../utils/replaceableComponent"; + +import ResizeNotifier from '../../utils/ResizeNotifier'; + +interface IProps { + roomId: string; + onClose: () => void; + resizeNotifier: ResizeNotifier +} + +interface IState { + timelineSet: EventTimelineSet; +} /* * Component which shows the filtered file using a TimelinePanel */ @replaceableComponent("structures.FilePanel") -class FilePanel extends React.Component { - static propTypes = { - roomId: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - }; - +class FilePanel extends React.Component { // This is used to track if a decrypted event was a live event and should be // added to the timeline. - decryptingEvents = new Set(); + private decryptingEvents = new Set(); + public noRoom: boolean; state = { timelineSet: null, }; - onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => { + private onRoomTimeline = (ev: MatrixEvent, room: Room, toStartOfTimeline: true, removed: true, data: any): void => { if (room?.roomId !== this.props?.roomId) return; if (toStartOfTimeline || !data || !data.liveEvent || ev.isRedacted()) return; @@ -60,7 +72,7 @@ class FilePanel extends React.Component { } }; - onEventDecrypted = (ev, err) => { + private onEventDecrypted = (ev: MatrixEvent, err?: any): void => { if (ev.getRoomId() !== this.props.roomId) return; const eventId = ev.getId(); @@ -70,7 +82,7 @@ class FilePanel extends React.Component { this.addEncryptedLiveEvent(ev); }; - addEncryptedLiveEvent(ev, toStartOfTimeline) { + public addEncryptedLiveEvent(ev: MatrixEvent): void { if (!this.state.timelineSet) return; const timeline = this.state.timelineSet.getLiveTimeline(); @@ -84,7 +96,7 @@ class FilePanel extends React.Component { } } - async componentDidMount() { + public async componentDidMount(): Promise { const client = MatrixClientPeg.get(); await this.updateTimelineSet(this.props.roomId); @@ -105,7 +117,7 @@ class FilePanel extends React.Component { } } - componentWillUnmount() { + public componentWillUnmount(): void { const client = MatrixClientPeg.get(); if (client === null) return; @@ -117,7 +129,7 @@ class FilePanel extends React.Component { } } - async fetchFileEventsServer(room) { + public async fetchFileEventsServer(room: Room): Promise { const client = MatrixClientPeg.get(); const filter = new Filter(client.credentials.userId); @@ -141,7 +153,7 @@ class FilePanel extends React.Component { return timelineSet; } - onPaginationRequest = (timelineWindow, direction, limit) => { + private onPaginationRequest = (timelineWindow: TimelineWindow, direction: string, limit: number): void => { const client = MatrixClientPeg.get(); const eventIndex = EventIndexPeg.get(); const roomId = this.props.roomId; @@ -159,7 +171,7 @@ class FilePanel extends React.Component { } }; - async updateTimelineSet(roomId: string) { + public async updateTimelineSet(roomId: string): Promise { const client = MatrixClientPeg.get(); const room = client.getRoom(roomId); const eventIndex = EventIndexPeg.get(); @@ -195,7 +207,7 @@ class FilePanel extends React.Component { } } - render() { + public render() { if (MatrixClientPeg.get().isGuest()) { return { // only dispatch if its not a no-op if (this.state.selectedTags.length > 0) { - dis.dispatch({action: 'deselect_tags'}); + dis.dispatch({ action: 'deselect_tags' }); } }; onClearFilterClick = ev => { - dis.dispatch({action: 'deselect_tags'}); + dis.dispatch({ action: 'deselect_tags' }); }; renderGlobalIcon() { diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 3a2c611cc9..93c44c4e50 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import * as sdk from '../../index'; import dis from '../../dispatcher/dispatcher'; import { getHostingLink } from '../../utils/HostingLink'; @@ -34,13 +34,13 @@ import classnames from 'classnames'; import GroupStore from '../../stores/GroupStore'; import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; -import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks"; -import {Group} from "matrix-js-sdk/src/models/group"; -import {sleep} from "../../utils/promise"; +import { makeGroupPermalink, makeUserPermalink } from "../../utils/permalinks/Permalinks"; +import { Group } from "matrix-js-sdk/src/models/group"; +import { sleep } from "../../utils/promise"; import RightPanelStore from "../../stores/RightPanelStore"; import AutoHideScrollbar from "./AutoHideScrollbar"; -import {mediaFromMxc} from "../../customisations/Media"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../customisations/Media"; +import { replaceableComponent } from "../../utils/replaceableComponent"; const LONG_DESC_PLACEHOLDER = _td( `

HTML for your community's page

@@ -115,7 +115,7 @@ class CategoryRoomList extends React.Component { { title: _t( "Failed to add the following rooms to the summary of %(groupId)s:", - {groupId: this.props.groupId}, + { groupId: this.props.groupId }, ), description: errorList.join(", "), }, @@ -126,12 +126,11 @@ class CategoryRoomList extends React.Component { }; render() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); const addButton = this.props.editing ? ( - +
{ _t('Add a Room') }
@@ -195,9 +194,9 @@ class FeaturedRoom extends React.Component { { title: _t( "Failed to remove the room from the summary of %(groupId)s", - {groupId: this.props.groupId}, + { groupId: this.props.groupId }, ), - description: _t("The room '%(roomName)s' could not be removed from the summary.", {roomName}), + description: _t("The room '%(roomName)s' could not be removed from the summary.", { roomName }), }, ); }); @@ -289,7 +288,7 @@ class RoleUserList extends React.Component { { title: _t( "Failed to add the following users to the summary of %(groupId)s:", - {groupId: this.props.groupId}, + { groupId: this.props.groupId }, ), description: errorList.join(", "), }, @@ -300,10 +299,9 @@ class RoleUserList extends React.Component { }; render() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); const addButton = this.props.editing ? ( - +
{ _t('Add a User') }
@@ -361,9 +359,12 @@ class FeaturedUser extends React.Component { { title: _t( "Failed to remove a user from the summary of %(groupId)s", - {groupId: this.props.groupId}, + { groupId: this.props.groupId }, + ), + description: _t( + "The user '%(displayName)s' could not be removed from the summary.", + { displayName }, ), - description: _t("The user '%(displayName)s' could not be removed from the summary.", {displayName}), }, ); }); @@ -470,7 +471,7 @@ export default class GroupView extends React.Component { // Leave settings - the user might have clicked the "Leave" button this._closeSettings(); } - this.setState({membershipBusy: false}); + this.setState({ membershipBusy: false }); }; _initGroupStore(groupId, firstInit) { @@ -491,7 +492,7 @@ export default class GroupView extends React.Component { group_id: groupId, }, }); - dis.dispatch({action: 'require_registration', screen_after: {screen: `group/${groupId}`}}); + dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${groupId}` } }); willDoOnboarding = true; } if (stateKey === GroupStore.STATE_KEY.Summary) { @@ -592,7 +593,7 @@ export default class GroupView extends React.Component { }; _closeSettings = () => { - dis.dispatch({action: 'close_settings'}); + dis.dispatch({ action: 'close_settings' }); }; _onNameChange = (value) => { @@ -620,7 +621,7 @@ export default class GroupView extends React.Component { const file = ev.target.files[0]; if (!file) return; - this.setState({uploadingAvatar: true}); + this.setState({ uploadingAvatar: true }); this._matrixClient.uploadContent(file).then((url) => { const newProfileForm = Object.assign(this.state.profileForm, { avatar_url: url }); this.setState({ @@ -632,7 +633,7 @@ export default class GroupView extends React.Component { avatarChanged: true, }); }).catch((e) => { - this.setState({uploadingAvatar: false}); + this.setState({ uploadingAvatar: false }); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to upload avatar image", e); Modal.createTrackedDialog('Failed to upload image', '', ErrorDialog, { @@ -649,7 +650,7 @@ export default class GroupView extends React.Component { }; _onSaveClick = () => { - this.setState({saving: true}); + this.setState({ saving: true }); const savePromise = this.state.isUserPrivileged ? this._saveGroup() : Promise.resolve(); savePromise.then((result) => { this.setState({ @@ -688,7 +689,7 @@ export default class GroupView extends React.Component { } _onAcceptInviteClick = async () => { - this.setState({membershipBusy: true}); + this.setState({ membershipBusy: true }); // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. @@ -697,7 +698,7 @@ export default class GroupView extends React.Component { GroupStore.acceptGroupInvite(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync }).catch((e) => { - this.setState({membershipBusy: false}); + this.setState({ membershipBusy: false }); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Error accepting invite', '', ErrorDialog, { title: _t("Error"), @@ -707,7 +708,7 @@ export default class GroupView extends React.Component { }; _onRejectInviteClick = async () => { - this.setState({membershipBusy: true}); + this.setState({ membershipBusy: true }); // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. @@ -716,7 +717,7 @@ export default class GroupView extends React.Component { GroupStore.leaveGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync }).catch((e) => { - this.setState({membershipBusy: false}); + this.setState({ membershipBusy: false }); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Error rejecting invite', '', ErrorDialog, { title: _t("Error"), @@ -727,11 +728,11 @@ export default class GroupView extends React.Component { _onJoinClick = async () => { if (this._matrixClient.isGuest()) { - dis.dispatch({action: 'require_registration', screen_after: {screen: `group/${this.props.groupId}`}}); + dis.dispatch({ action: 'require_registration', screen_after: { screen: `group/${this.props.groupId}` } }); return; } - this.setState({membershipBusy: true}); + this.setState({ membershipBusy: true }); // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. @@ -740,7 +741,7 @@ export default class GroupView extends React.Component { GroupStore.joinGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync }).catch((e) => { - this.setState({membershipBusy: false}); + this.setState({ membershipBusy: false }); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Error joining room', '', ErrorDialog, { title: _t("Error"), @@ -773,7 +774,7 @@ export default class GroupView extends React.Component { title: _t("Leave Community"), description: ( - { _t("Leave %(groupName)s?", {groupName: this.props.groupId}) } + { _t("Leave %(groupName)s?", { groupName: this.props.groupId }) } { warnings } ), @@ -782,7 +783,7 @@ export default class GroupView extends React.Component { onFinished: async (confirmed) => { if (!confirmed) return; - this.setState({membershipBusy: true}); + this.setState({ membershipBusy: true }); // Wait 500ms to prevent flashing. Do this before sending a request otherwise we risk the // spinner disappearing after we have fetched new group data. @@ -791,7 +792,7 @@ export default class GroupView extends React.Component { GroupStore.leaveGroup(this.props.groupId).then(() => { // don't reset membershipBusy here: wait for the membership change to come down the sync }).catch((e) => { - this.setState({membershipBusy: false}); + this.setState({ membershipBusy: false }); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Error leaving community', '', ErrorDialog, { title: _t("Error"), @@ -855,7 +856,6 @@ export default class GroupView extends React.Component { _getRoomsNode() { const RoomDetailList = sdk.getComponent('rooms.RoomDetailList'); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const TintableSvg = sdk.getComponent('elements.TintableSvg'); const Spinner = sdk.getComponent('elements.Spinner'); const TooltipButton = sdk.getComponent('elements.TooltipButton'); @@ -871,7 +871,7 @@ export default class GroupView extends React.Component { onClick={this._onAddRoomsClick} >
- +
{ _t('Add rooms to this community') } @@ -1336,7 +1336,7 @@ export default class GroupView extends React.Component { if (this.state.error.httpStatus === 404) { return (
- { _t('Community %(groupId)s not found', {groupId: this.props.groupId}) } + { _t('Community %(groupId)s not found', { groupId: this.props.groupId }) }
); } else { @@ -1346,7 +1346,7 @@ export default class GroupView extends React.Component { } return (
- { _t('Failed to load %(groupId)s', {groupId: this.props.groupId }) } + { _t('Failed to load %(groupId)s', { groupId: this.props.groupId }) } { extraText }
); diff --git a/src/components/structures/HomePage.tsx b/src/components/structures/HomePage.tsx index 68bb4322e6..046e07f455 100644 --- a/src/components/structures/HomePage.tsx +++ b/src/components/structures/HomePage.tsx @@ -15,29 +15,29 @@ limitations under the License. */ import * as React from "react"; -import {useContext, useState} from "react"; +import { useContext, useState } from "react"; import AutoHideScrollbar from './AutoHideScrollbar'; -import {getHomePageUrl} from "../../utils/pages"; -import {_t} from "../../languageHandler"; +import { getHomePageUrl } from "../../utils/pages"; +import { _t } from "../../languageHandler"; import SdkConfig from "../../SdkConfig"; import * as sdk from "../../index"; import dis from "../../dispatcher/dispatcher"; -import {Action} from "../../dispatcher/actions"; +import { Action } from "../../dispatcher/actions"; import BaseAvatar from "../views/avatars/BaseAvatar"; -import {OwnProfileStore} from "../../stores/OwnProfileStore"; +import { OwnProfileStore } from "../../stores/OwnProfileStore"; import AccessibleButton from "../views/elements/AccessibleButton"; -import {UPDATE_EVENT} from "../../stores/AsyncStore"; -import {useEventEmitter} from "../../hooks/useEventEmitter"; +import { UPDATE_EVENT } from "../../stores/AsyncStore"; +import { useEventEmitter } from "../../hooks/useEventEmitter"; import MatrixClientContext from "../../contexts/MatrixClientContext"; -import MiniAvatarUploader, {AVATAR_SIZE} from "../views/elements/MiniAvatarUploader"; +import MiniAvatarUploader, { AVATAR_SIZE } from "../views/elements/MiniAvatarUploader"; import Analytics from "../../Analytics"; import CountlyAnalytics from "../../CountlyAnalytics"; const onClickSendDm = () => { Analytics.trackEvent('home_page', 'button', 'dm'); CountlyAnalytics.instance.track("home_page_button", { button: "dm" }); - dis.dispatch({action: 'view_create_chat'}); + dis.dispatch({ action: 'view_create_chat' }); }; const onClickExplore = () => { @@ -49,7 +49,7 @@ const onClickExplore = () => { const onClickNewRoom = () => { Analytics.trackEvent('home_page', 'button', 'create_room'); CountlyAnalytics.instance.track("home_page_button", { button: "create_room" }); - dis.dispatch({action: 'view_create_room'}); + dis.dispatch({ action: 'view_create_room' }); }; interface IProps { @@ -117,7 +117,6 @@ const HomePage: React.FC = ({ justRegistered = false }) => { ; } - return
{ introSection } diff --git a/src/components/structures/HostSignupAction.tsx b/src/components/structures/HostSignupAction.tsx index 46e158d6c8..41dc8a6da8 100644 --- a/src/components/structures/HostSignupAction.tsx +++ b/src/components/structures/HostSignupAction.tsx @@ -22,7 +22,7 @@ import { import { _t } from "../../languageHandler"; import { HostSignupStore } from "../../stores/HostSignupStore"; import SdkConfig from "../../SdkConfig"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; interface IProps { onClick?(): void; @@ -35,7 +35,7 @@ export default class HostSignupAction extends React.PureComponent { this.props.onClick?.(); await HostSignupStore.instance.setHostSignupActive(true); - } + }; public render(): React.ReactNode { const hostSignupConfig = SdkConfig.get().hostSignup; diff --git a/src/components/structures/IndicatorScrollbar.js b/src/components/structures/IndicatorScrollbar.js index 25dcaeed39..3e1940955b 100644 --- a/src/components/structures/IndicatorScrollbar.js +++ b/src/components/structures/IndicatorScrollbar.js @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import AutoHideScrollbar from "./AutoHideScrollbar"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; @replaceableComponent("structures.IndicatorScrollbar") export default class IndicatorScrollbar extends React.Component { @@ -70,7 +70,6 @@ export default class IndicatorScrollbar extends React.Component { this._autoHideScrollbar = autoHideScrollbar; } - componentDidUpdate(prevProps) { const prevLen = prevProps && prevProps.children && prevProps.children.length || 0; const curLen = this.props.children && this.props.children.length || 0; @@ -188,8 +187,8 @@ export default class IndicatorScrollbar extends React.Component { // eslint-disable-next-line no-unused-vars const { children, trackHorizontalOverflow, verticalScrollsHorizontally, ...otherProps } = this.props; - const leftIndicatorStyle = {left: this.state.leftIndicatorOffset}; - const rightIndicatorStyle = {right: this.state.rightIndicatorOffset}; + const leftIndicatorStyle = { left: this.state.leftIndicatorOffset }; + const rightIndicatorStyle = { right: this.state.rightIndicatorOffset }; const leftOverflowIndicator = trackHorizontalOverflow ?
: null; const rightOverflowIndicator = trackHorizontalOverflow diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js index d419c9de6e..9ff830f66a 100644 --- a/src/components/structures/InteractiveAuth.js +++ b/src/components/structures/InteractiveAuth.js @@ -15,14 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {InteractiveAuth} from "matrix-js-sdk/src/interactive-auth"; -import React, {createRef} from 'react'; +import { InteractiveAuth } from "matrix-js-sdk/src/interactive-auth"; +import React, { createRef } from 'react'; import PropTypes from 'prop-types'; import getEntryComponentForLoginType from '../views/auth/InteractiveAuthEntryComponents'; import * as sdk from '../../index'; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; export const ERROR_USER_CANCELLED = new Error("User cancelled auth session"); diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index af22db1350..3d5e386b00 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -24,6 +24,7 @@ import CustomRoomTagPanel from "./CustomRoomTagPanel"; import dis from "../../dispatcher/dispatcher"; import { _t } from "../../languageHandler"; import RoomList from "../views/rooms/RoomList"; +import CallHandler from "../../CallHandler"; import { HEADER_HEIGHT } from "../views/rooms/RoomSublist"; import { Action } from "../../dispatcher/actions"; import UserMenu from "./UserMenu"; @@ -39,9 +40,9 @@ import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; import { OwnProfileStore } from "../../stores/OwnProfileStore"; import RoomListNumResults from "../views/rooms/RoomListNumResults"; import LeftPanelWidget from "./LeftPanelWidget"; -import {replaceableComponent} from "../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../customisations/Media"; -import SpaceStore, {UPDATE_SELECTED_SPACE} from "../../stores/SpaceStore"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../customisations/Media"; +import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore"; import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager"; import UIStore from "../../stores/UIStore"; @@ -90,7 +91,7 @@ export default class LeftPanel extends React.Component { this.bgImageWatcherRef = SettingsStore.watchSetting( "RoomList.backgroundImage", null, this.onBackgroundImageUpdate); this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => { - this.setState({showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel")}); + this.setState({ showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel") }); }); } @@ -124,6 +125,10 @@ export default class LeftPanel extends React.Component { this.setState({ activeSpace }); }; + private onDialPad = () => { + dis.fire(Action.OpenDialPad); + }; + private onExplore = () => { dis.fire(Action.ViewRoomDirectory); }; @@ -131,12 +136,12 @@ export default class LeftPanel extends React.Component { private refreshStickyHeaders = () => { if (!this.listContainerRef.current) return; // ignore: no headers to sticky this.handleStickyHeaders(this.listContainerRef.current); - } + }; private onBreadcrumbsUpdate = () => { const newVal = BreadcrumbsStore.instance.visible; if (newVal !== this.state.showBreadcrumbs) { - this.setState({showBreadcrumbs: newVal}); + this.setState({ showBreadcrumbs: newVal }); // Update the sticky headers too as the breadcrumbs will be popping in or out. if (!this.listContainerRef.current) return; // ignore: no headers to sticky @@ -397,7 +402,20 @@ export default class LeftPanel extends React.Component { } } - private renderSearchExplore(): React.ReactNode { + private renderSearchDialExplore(): React.ReactNode { + let dialPadButton = null; + + // If we have dialer support, show a button to bring up the dial pad + // to start a new call + if (CallHandler.sharedInstance().getSupportsPstnProtocol()) { + dialPadButton = + ; + } + return (
{ onKeyDown={this.onKeyDown} onSelectRoom={this.selectRoom} /> + + {dialPadButton} + { {leftLeftPanel}