diff --git a/.eslintrc.js b/.eslintrc.js index c759eae9e3..827b373949 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,35 +17,60 @@ 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"], + + "no-restricted-properties": [ + "error", + ...buildRestrictedPropertiesOptions( + ["window.innerHeight", "window.innerWidth", "window.visualViewport"], + "Use UIStore to access window dimensions instead.", + ), + ...buildRestrictedPropertiesOptions( + ["*.mxcUrlToHttp", "*.getHttpUriForMxc"], + "Use Media helper instead to centralise access for customisation.", + ), + ], + }, 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 "@typescript-eslint/no-explicit-any": "off", // 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( - ["window.innerHeight", "window.innerWidth", "window.visualViewport"], - "Use UIStore to access window dimensions instead", - ), - ], }, }], }; function buildRestrictedPropertiesOptions(properties, message) { return properties.map(prop => { - const [object, property] = prop.split("."); + let [object, property] = prop.split("."); + if (object === "*") { + object = undefined; + } return { object, property, 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/_components.scss b/res/css/_components.scss index ec3af8655e..1517527034 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -37,6 +37,11 @@ @import "./structures/_ViewSource.scss"; @import "./structures/auth/_CompleteSecurity.scss"; @import "./structures/auth/_Login.scss"; +@import "./views/audio_messages/_AudioPlayer.scss"; +@import "./views/audio_messages/_PlayPauseButton.scss"; +@import "./views/audio_messages/_PlaybackContainer.scss"; +@import "./views/audio_messages/_SeekBar.scss"; +@import "./views/audio_messages/_Waveform.scss"; @import "./views/auth/_AuthBody.scss"; @import "./views/auth/_AuthButtons.scss"; @import "./views/auth/_AuthFooter.scss"; @@ -165,6 +170,7 @@ @import "./views/messages/_MTextBody.scss"; @import "./views/messages/_MVideoBody.scss"; @import "./views/messages/_MVoiceMessageBody.scss"; +@import "./views/messages/_MediaBody.scss"; @import "./views/messages/_MessageActionBar.scss"; @import "./views/messages/_MessageTimestamp.scss"; @import "./views/messages/_MjolnirBody.scss"; @@ -253,9 +259,6 @@ @import "./views/toasts/_AnalyticsToast.scss"; @import "./views/toasts/_NonUrgentEchoFailureToast.scss"; @import "./views/verification/_VerificationShowSas.scss"; -@import "./views/voice_messages/_PlayPauseButton.scss"; -@import "./views/voice_messages/_PlaybackContainer.scss"; -@import "./views/voice_messages/_Waveform.scss"; @import "./views/voip/_CallContainer.scss"; @import "./views/voip/_CallView.scss"; @import "./views/voip/_CallViewForRoom.scss"; diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index 2350d9f28a..60f9ebdd08 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -323,7 +323,7 @@ limitations under the License. } .mx_GroupView_featuredThing .mx_BaseAvatar { - /* To prevent misalignment with mx_TintableSvg (in addButton) */ + /* To prevent misalignment with img (in addButton) */ vertical-align: initial; } 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/audio_messages/_AudioPlayer.scss b/res/css/views/audio_messages/_AudioPlayer.scss new file mode 100644 index 0000000000..9a65ad008f --- /dev/null +++ b/res/css/views/audio_messages/_AudioPlayer.scss @@ -0,0 +1,68 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_AudioPlayer_container { + padding: 16px 12px 12px 12px; + max-width: 267px; // use max to make the control fit in the files/pinned panels + + .mx_AudioPlayer_primaryContainer { + display: flex; + + .mx_PlayPauseButton { + margin-right: 8px; + } + + .mx_AudioPlayer_mediaInfo { + flex: 1; + overflow: hidden; // makes the ellipsis on the file name work + + & > * { + display: block; + } + + .mx_AudioPlayer_mediaName { + color: $primary-fg-color; + font-size: $font-15px; + line-height: $font-15px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + padding-bottom: 4px; // mimics the line-height differences in the Figma + } + + .mx_AudioPlayer_byline { + font-size: $font-12px; + line-height: $font-12px; + } + } + } + + .mx_AudioPlayer_seek { + display: flex; + align-items: center; + + .mx_SeekBar { + flex: 1; + } + + .mx_Clock { + width: $font-42px; // we're not using a monospace font, so fake it + min-width: $font-42px; // for flexbox + padding-left: 4px; // isolate from seek bar + text-align: right; + } + } +} diff --git a/res/css/views/voice_messages/_PlayPauseButton.scss b/res/css/views/audio_messages/_PlayPauseButton.scss similarity index 91% rename from res/css/views/voice_messages/_PlayPauseButton.scss rename to res/css/views/audio_messages/_PlayPauseButton.scss index 6caedafa29..714da3e605 100644 --- a/res/css/views/voice_messages/_PlayPauseButton.scss +++ b/res/css/views/audio_messages/_PlayPauseButton.scss @@ -18,6 +18,8 @@ limitations under the License. position: relative; width: 32px; height: 32px; + min-width: 32px; // for when the button is used in a flexbox + min-height: 32px; // for when the button is used in a flexbox border-radius: 32px; background-color: $voice-playback-button-bg-color; diff --git a/res/css/views/voice_messages/_PlaybackContainer.scss b/res/css/views/audio_messages/_PlaybackContainer.scss similarity index 88% rename from res/css/views/voice_messages/_PlaybackContainer.scss rename to res/css/views/audio_messages/_PlaybackContainer.scss index f0e29900ab..fd01864bba 100644 --- a/res/css/views/voice_messages/_PlaybackContainer.scss +++ b/res/css/views/audio_messages/_PlaybackContainer.scss @@ -22,17 +22,11 @@ limitations under the License. // 7px top and bottom for visual design. 12px left & right, but the waveform (right) // has a 1px padding on it that we want to account for. padding: 7px 12px 7px 11px; - background-color: $voice-record-waveform-bg-color; - border-radius: 12px; // Cheat at alignment a bit display: flex; align-items: center; - color: $voice-record-waveform-fg-color; - font-size: $font-14px; - line-height: $font-24px; - contain: content; .mx_Waveform { @@ -45,7 +39,7 @@ limitations under the License. &.mx_Waveform_bar_100pct { // Small animation to remove the mechanical feel of progress transition: background-color 250ms ease; - background-color: $voice-record-waveform-fg-color; + background-color: $message-body-panel-fg-color; } } } diff --git a/res/css/views/audio_messages/_SeekBar.scss b/res/css/views/audio_messages/_SeekBar.scss new file mode 100644 index 0000000000..d13fe4ac6a --- /dev/null +++ b/res/css/views/audio_messages/_SeekBar.scss @@ -0,0 +1,103 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// CSS inspiration from: +// * https://www.w3schools.com/howto/howto_js_rangeslider.asp +// * https://stackoverflow.com/a/28283806 +// * https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ + +.mx_SeekBar { + // Dev note: we deliberately do not have the -ms-track (and friends) selectors because we don't + // need to support IE. + + appearance: none; // default style override + + width: 100%; + height: 1px; + background: $quaternary-fg-color; + outline: none; // remove blue selection border + position: relative; // for before+after pseudo elements later on + + cursor: pointer; + + &::-webkit-slider-thumb { + appearance: none; // default style override + + // Dev note: This needs to be duplicated with the -moz-range-thumb selector + // because otherwise Edge (webkit) will fail to see the styles and just refuse + // to apply them. + width: 8px; + height: 8px; + border-radius: 8px; + background-color: $tertiary-fg-color; + cursor: pointer; + } + + &::-moz-range-thumb { + width: 8px; + height: 8px; + border-radius: 8px; + background-color: $tertiary-fg-color; + cursor: pointer; + + // Firefox adds a border on the thumb + border: none; + } + + // This is for webkit support, but we can't limit the functionality of it to just webkit + // browsers. Firefox responds to webkit-prefixed values now, which means we can't use media + // or support queries to selectively apply the rule. An upside is that this CSS doesn't work + // in firefox, so it's just wasted CPU/GPU time. + &::before { // ::before to ensure it ends up under the thumb + content: ''; + background-color: $tertiary-fg-color; + + // Absolute positioning to ensure it overlaps with the existing bar + position: absolute; + top: 0; + left: 0; + + // Sizing to match the bar + width: 100%; + height: 1px; + + // And finally dynamic width without overly hurting the rendering engine. + transform-origin: 0 100%; + transform: scaleX(var(--fillTo)); + } + + // This is firefox's built-in support for the above, with 100% less hacks. + &::-moz-range-progress { + background-color: $tertiary-fg-color; + height: 1px; + } + + &:disabled { + opacity: 0.5; + } + + // Increase clickable area for the slider (approximately same size as browser default) + // We do it this way to keep the same padding and margins of the element, avoiding margin math. + // Source: https://front-back.com/expand-clickable-areas-for-a-better-touch-experience/ + &::after { + content: ''; + position: absolute; + top: -6px; + bottom: -6px; + left: 0; + right: 0; + } +} diff --git a/res/css/views/voice_messages/_Waveform.scss b/res/css/views/audio_messages/_Waveform.scss similarity index 100% rename from res/css/views/voice_messages/_Waveform.scss rename to res/css/views/audio_messages/_Waveform.scss diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss index 1c773c2f06..515d867da5 100644 --- a/res/css/views/messages/_MImageBody.scss +++ b/res/css/views/messages/_MImageBody.scss @@ -43,7 +43,7 @@ limitations under the License. top: 50%; } -// Inner img and TintableSvg should be centered around 0, 0 +// Inner img should be centered around 0, 0 .mx_MImageBody_thumbnail_spinner > * { transform: translate(-50%, -50%); } diff --git a/res/css/views/messages/_MediaBody.scss b/res/css/views/messages/_MediaBody.scss new file mode 100644 index 0000000000..12e441750c --- /dev/null +++ b/res/css/views/messages/_MediaBody.scss @@ -0,0 +1,28 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// A "media body" is any file upload looking thing, apart from images and videos (they +// have unique styles). + +.mx_MediaBody { + background-color: $message-body-panel-bg-color; + border-radius: 12px; + + color: $message-body-panel-fg-color; + font-size: $font-14px; + line-height: $font-24px; +} + diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 8b5fde3bd1..81fd3c892a 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -215,8 +215,6 @@ $message-body-panel-icon-fg-color: #21262C; // "Separator" $message-body-panel-icon-bg-color: $tertiary-fg-color; $voice-record-stop-border-color: $quaternary-fg-color; -$voice-record-waveform-bg-color: $message-body-panel-bg-color; -$voice-record-waveform-fg-color: $message-body-panel-fg-color; $voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; $voice-record-icon-color: $quaternary-fg-color; $voice-playback-button-bg-color: $message-body-panel-icon-bg-color; diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index eb6dc40599..df01efbe1e 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -20,6 +20,9 @@ $tertiary-fg-color: $primary-fg-color; $primary-bg-color: $bg-color; $muted-fg-color: $header-panel-text-primary-color; +// Legacy theme backports +$quaternary-fg-color: #6F7882; + // used for dialog box text $light-fg-color: $header-panel-text-secondary-color; @@ -209,8 +212,6 @@ $message-body-panel-icon-bg-color: $secondary-fg-color; // See non-legacy dark for variable information $voice-record-stop-border-color: #6F7882; -$voice-record-waveform-bg-color: $message-body-panel-bg-color; -$voice-record-waveform-fg-color: $message-body-panel-fg-color; $voice-record-waveform-incomplete-fg-color: #6F7882; $voice-record-icon-color: #6F7882; $voice-playback-button-bg-color: $tertiary-fg-color; diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index a6b180bab4..c7debcdabe 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -28,6 +28,9 @@ $tertiary-fg-color: $primary-fg-color; $primary-bg-color: #ffffff; $muted-fg-color: #61708b; // Commonly used in headings and relevant alt text +// Legacy theme backports +$quaternary-fg-color: #C1C6CD; + // used for dialog box text $light-fg-color: #747474; @@ -334,8 +337,6 @@ $message-body-panel-icon-bg-color: $primary-bg-color; $voice-record-stop-symbol-color: #ff4b55; $voice-record-live-circle-color: #ff4b55; $voice-record-stop-border-color: #E3E8F0; -$voice-record-waveform-bg-color: $message-body-panel-bg-color; -$voice-record-waveform-fg-color: $message-body-panel-fg-color; $voice-record-waveform-incomplete-fg-color: #C1C6CD; $voice-record-icon-color: $tertiary-fg-color; $voice-playback-button-bg-color: $message-body-panel-icon-bg-color; diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index d8dab9c9c4..7e958c2af6 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -335,8 +335,6 @@ $voice-record-stop-symbol-color: #ff4b55; $voice-record-live-circle-color: #ff4b55; $voice-record-stop-border-color: #E3E8F0; // "Separator" -$voice-record-waveform-bg-color: $message-body-panel-bg-color; -$voice-record-waveform-fg-color: $message-body-panel-fg-color; $voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; $voice-record-icon-color: $tertiary-fg-color; $voice-playback-button-bg-color: $message-body-panel-icon-bg-color; 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/@types/global.d.ts b/src/@types/global.d.ts index 7eff341095..f75c17aaf4 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -16,6 +16,7 @@ limitations under the License. import "matrix-js-sdk/src/@types/global"; // load matrix-js-sdk's type extensions first import * as ModernizrStatic from "modernizr"; + import ContentMessages from "../ContentMessages"; import { IMatrixClientPeg } from "../MatrixClientPeg"; import ToastStore from "../stores/ToastStore"; @@ -23,25 +24,25 @@ import DeviceListener from "../DeviceListener"; import { RoomListStoreClass } from "../stores/room-list/RoomListStore"; import { PlatformPeg } from "../PlatformPeg"; import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore"; -import {IntegrationManagers} from "../integrations/IntegrationManagers"; -import {ModalManager} from "../Modal"; +import { IntegrationManagers } from "../integrations/IntegrationManagers"; +import { ModalManager } from "../Modal"; import SettingsStore from "../settings/SettingsStore"; -import {ActiveRoomObserver} from "../ActiveRoomObserver"; -import {Notifier} from "../Notifier"; -import type {Renderer} from "react-dom"; +import { ActiveRoomObserver } from "../ActiveRoomObserver"; +import { Notifier } from "../Notifier"; +import type { Renderer } from "react-dom"; import RightPanelStore from "../stores/RightPanelStore"; import WidgetStore from "../stores/WidgetStore"; import CallHandler from "../CallHandler"; -import {Analytics} from "../Analytics"; +import { Analytics } from "../Analytics"; import CountlyAnalytics from "../CountlyAnalytics"; import UserActivity from "../UserActivity"; -import {ModalWidgetStore} from "../stores/ModalWidgetStore"; +import { ModalWidgetStore } from "../stores/ModalWidgetStore"; import { WidgetLayoutStore } from "../stores/widgets/WidgetLayoutStore"; import VoipUserMapper from "../VoipUserMapper"; -import {SpaceStoreClass} from "../stores/SpaceStore"; +import { SpaceStoreClass } from "../stores/SpaceStore"; import TypingStore from "../stores/TypingStore"; import { EventIndexPeg } from "../indexing/EventIndexPeg"; -import {VoiceRecordingStore} from "../stores/VoiceRecordingStore"; +import { VoiceRecordingStore } from "../stores/VoiceRecordingStore"; import PerformanceMonitor from "../performance"; import UIStore from "../stores/UIStore"; import { SetupEncryptionStore } from "../stores/SetupEncryptionStore"; @@ -127,11 +128,24 @@ declare global { setSinkId(outputId: string); } + // Add Chrome-specific `instant` ScrollBehaviour + type _ScrollBehavior = ScrollBehavior | "instant"; + + interface _ScrollOptions { + behavior?: _ScrollBehavior; + } + + interface _ScrollIntoViewOptions extends _ScrollOptions { + block?: ScrollLogicalPosition; + inline?: ScrollLogicalPosition; + } + interface Element { // Safari & IE11 only have this prefixed: we used prefixed versions // previously so let's continue to support them for now webkitRequestFullScreen(options?: FullscreenOptions): Promise; msRequestFullscreen(options?: FullscreenOptions): Promise; + scrollIntoView(arg?: boolean | _ScrollIntoViewOptions): void; } interface Error { 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 7a3cf5d50f..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 }; } /** @@ -343,7 +343,7 @@ export 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 @@ export 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 2afc7d9901..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: 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.tsx b/src/TextForEvent.tsx index def0ac2cb8..844c79fbae 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -15,13 +15,13 @@ limitations under the License. */ import React from 'react'; -import {MatrixClientPeg} from './MatrixClientPeg'; +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'; @@ -112,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', { @@ -139,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.', { @@ -156,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 { @@ -183,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', { @@ -237,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)) { @@ -262,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; }; @@ -323,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; }; } @@ -358,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 }); }; } @@ -424,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, @@ -492,7 +492,7 @@ const onPinnedMessagesClick = (): void => { phase: RightPanelPhases.PinnedMessages, allowClose: false, }); -} +}; function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null { if (!SettingsStore.getValue("feature_pinning")) return null; @@ -517,8 +517,8 @@ function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string 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 @@ -547,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 @@ -616,25 +616,25 @@ 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 { 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/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/AutoHideScrollbar.tsx b/src/components/structures/AutoHideScrollbar.tsx index 8650224fb3..e8a9872b48 100644 --- a/src/components/structures/AutoHideScrollbar.tsx +++ b/src/components/structures/AutoHideScrollbar.tsx @@ -15,12 +15,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { HTMLAttributes } from "react"; +import React, { HTMLAttributes, WheelEvent } from "react"; -interface IProps extends HTMLAttributes { +interface IProps extends Omit, "onScroll"> { className?: string; - onScroll?: () => void; - onWheel?: () => void; + onScroll?: (event: Event) => void; + onWheel?: (event: WheelEvent) => void; style?: React.CSSProperties tabIndex?: number, wrappedRef?: (ref: HTMLDivElement) => void; 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 dec4e4c13e..3d5e386b00 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -40,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"; @@ -91,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") }); }); } @@ -127,7 +127,7 @@ export default class LeftPanel extends React.Component { private onDialPad = () => { dis.fire(Action.OpenDialPad); - } + }; private onExplore = () => { dis.fire(Action.ViewRoomDirectory); @@ -136,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 diff --git a/src/components/structures/LeftPanelWidget.tsx b/src/components/structures/LeftPanelWidget.tsx index 16142069c4..e0b597b883 100644 --- a/src/components/structures/LeftPanelWidget.tsx +++ b/src/components/structures/LeftPanelWidget.tsx @@ -14,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useContext, useMemo} from "react"; -import {Resizable} from "re-resizable"; +import React, { useContext, useMemo } from "react"; +import { Resizable } from "re-resizable"; import classNames from "classnames"; import AccessibleButton from "../views/elements/AccessibleButton"; -import {useRovingTabIndex} from "../../accessibility/RovingTabIndex"; -import {Key} from "../../Keyboard"; -import {useLocalStorageState} from "../../hooks/useLocalStorageState"; +import { useRovingTabIndex } from "../../accessibility/RovingTabIndex"; +import { Key } from "../../Keyboard"; +import { useLocalStorageState } from "../../hooks/useLocalStorageState"; import MatrixClientContext from "../../contexts/MatrixClientContext"; -import WidgetUtils, {IWidgetEvent} from "../../utils/WidgetUtils"; -import {useAccountData} from "../../hooks/useAccountData"; +import WidgetUtils, { IWidgetEvent } from "../../utils/WidgetUtils"; +import { useAccountData } from "../../hooks/useAccountData"; import AppTile from "../views/elements/AppTile"; -import {useSettingValue} from "../../hooks/useSettings"; +import { useSettingValue } from "../../hooks/useSettings"; import UIStore from "../../stores/UIStore"; const MIN_HEIGHT = 100; @@ -62,14 +62,14 @@ const LeftPanelWidget: React.FC = () => { let content; if (expanded) { content = { setHeight(height + d.height); }} handleWrapperClass="mx_LeftPanelWidget_resizerHandles" - handleClasses={{top: "mx_LeftPanelWidget_resizerHandle"}} + handleClasses={{ top: "mx_LeftPanelWidget_resizerHandle" }} className="mx_LeftPanelWidget_resizeBox" enable={{ top: true }} > diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 5ad67232a4..26bb0fe24a 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk/src/client'; -import {Key} from '../../Keyboard'; +import { Key } from '../../Keyboard'; import PageTypes from '../../PageTypes'; import MediaDeviceHandler from '../../MediaDeviceHandler'; import { fixupColorFonts } from '../../utils/FontManager'; @@ -30,7 +30,7 @@ import { IMatrixClientCreds } from '../../MatrixClientPeg'; import SettingsStore from "../../settings/SettingsStore"; import ResizeHandle from '../views/elements/ResizeHandle'; -import {Resizer, CollapseDistributor} from '../../resizer'; +import { Resizer, CollapseDistributor } from '../../resizer'; import MatrixClientContext from "../../contexts/MatrixClientContext"; import * as KeyboardShortcuts from "../../accessibility/KeyboardShortcuts"; import HomePage from "./HomePage"; @@ -55,7 +55,7 @@ import HostSignupContainer from '../views/host_signup/HostSignupContainer'; import { getKeyBindingsManager, NavigationAction, RoomAction } from '../../KeyBindingsManager'; import { IOpts } from "../../createRoom"; import SpacePanel from "../views/spaces/SpacePanel"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; import CallHandler, { CallHandlerEvent } from '../../CallHandler'; import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall'; @@ -232,10 +232,10 @@ class LoggedInView extends React.Component { onCollapsed: (_collapsed) => { collapsed = _collapsed; if (_collapsed) { - dis.dispatch({action: "hide_left_panel"}); + dis.dispatch({ action: "hide_left_panel" }); window.localStorage.setItem("mx_lhs_size", '0'); } else { - dis.dispatch({action: "show_left_panel"}); + dis.dispatch({ action: "show_left_panel" }); } }, onResized: (_size) => { @@ -272,7 +272,7 @@ class LoggedInView extends React.Component { onAccountData = (event) => { if (event.getType() === "m.ignored_user_list") { - dis.dispatch({action: "ignore_state_changed"}); + dis.dispatch({ action: "ignore_state_changed" }); } }; @@ -319,7 +319,7 @@ class LoggedInView extends React.Component { this.setState({ usageLimitDismissed: true, }); - } + }; _calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) { const error = syncError && syncError.error && syncError.error.errcode === "M_RESOURCE_LIMIT_EXCEEDED"; diff --git a/src/components/structures/MainSplit.js b/src/components/structures/MainSplit.js index 5818d303fc..69d3bd0b51 100644 --- a/src/components/structures/MainSplit.js +++ b/src/components/structures/MainSplit.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import { Resizable } from 're-resizable'; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; @replaceableComponent("structures.MainSplit") export default class MainSplit extends React.Component { @@ -73,7 +73,7 @@ export default class MainSplit extends React.Component { onResize={this._onResize} onResizeStop={this._onResizeStop} className="mx_RightPanel_ResizeWrapper" - handleClasses={{left: "mx_RightPanel_ResizeHandle"}} + handleClasses={{ left: "mx_RightPanel_ResizeHandle" }} > { panelView } ; diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 7986da203d..c1e0b8d7cb 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -34,7 +34,6 @@ import dis from "../../dispatcher/dispatcher"; import Notifier from '../../Notifier'; import Modal from "../../Modal"; -import Tinter from "../../Tinter"; import * as sdk from '../../index'; import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite'; import * as Rooms from '../../Rooms'; @@ -44,8 +43,8 @@ import * as Lifecycle from '../../Lifecycle'; import '../../stores/LifecycleStore'; import PageTypes from '../../PageTypes'; -import createRoom, {IOpts} from "../../createRoom"; -import {_t, _td, getCurrentLanguage} from '../../languageHandler'; +import createRoom, { IOpts } from "../../createRoom"; +import { _t, _td, getCurrentLanguage } from '../../languageHandler'; import SettingsStore from "../../settings/SettingsStore"; import ThemeController from "../../settings/controllers/ThemeController"; import { startAnyRegistrationFlow } from "../../Registration"; @@ -66,7 +65,7 @@ import { showToast as showAnalyticsToast, hideToast as hideAnalyticsToast, } from "../../toasts/AnalyticsToast"; -import {showToast as showNotificationsToast} from "../../toasts/DesktopNotificationsToast"; +import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import ErrorDialog from "../views/dialogs/ErrorDialog"; import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore"; @@ -74,15 +73,15 @@ import { SettingLevel } from "../../settings/SettingLevel"; import { leaveRoomBehaviour } from "../../utils/membership"; import CreateCommunityPrototypeDialog from "../views/dialogs/CreateCommunityPrototypeDialog"; import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore"; -import {UIFeature} from "../../settings/UIFeature"; +import { UIFeature } from "../../settings/UIFeature"; import { CommunityPrototypeStore } from "../../stores/CommunityPrototypeStore"; import DialPadModal from "../views/voip/DialPadModal"; import { showToast as showMobileGuideToast } from '../../toasts/MobileGuideToast'; import { shouldUseLoginForWelcome } from "../../utils/pages"; import SpaceStore from "../../stores/SpaceStore"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; import RoomListStore from "../../stores/room-list/RoomListStore"; -import {RoomUpdateCause} from "../../stores/room-list/models"; +import { RoomUpdateCause } from "../../stores/room-list/models"; import defaultDispatcher from "../../dispatcher/dispatcher"; import SecurityCustomisations from "../../customisations/Security"; @@ -283,11 +282,6 @@ export default class MatrixChat extends React.PureComponent { this.pageChanging = false; - // check we have the right tint applied for this theme. - // N.B. we don't call the whole of setTheme() here as we may be - // racing with the theme CSS download finishing from index.js - Tinter.tint(); - // For PersistentElement this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize); @@ -401,7 +395,7 @@ export default class MatrixChat extends React.PureComponent { if (SecurityCustomisations.SHOW_ENCRYPTION_SETUP_UI === false) { this.onLoggedIn(); } else { - this.setStateForNewView({view: Views.COMPLETE_SECURITY}); + this.setStateForNewView({ view: Views.COMPLETE_SECURITY }); } } else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) { this.setStateForNewView({ view: Views.E2E_SETUP }); @@ -454,7 +448,7 @@ export default class MatrixChat extends React.PureComponent { let props = this.state.serverConfig; if (!props) props = this.props.serverConfig; // for unit tests if (!props) props = SdkConfig.get()["validated_server_config"]; - return {serverConfig: props}; + return { serverConfig: props }; } private loadSession() { @@ -472,9 +466,9 @@ export default class MatrixChat extends React.PureComponent { if (!loadedSession) { // fall back to showing the welcome screen... unless we have a 3pid invite pending if (ThreepidInviteStore.instance.pickBestInvite()) { - dis.dispatch({action: 'start_registration'}); + dis.dispatch({ action: 'start_registration' }); } else { - dis.dispatch({action: "view_welcome_page"}); + dis.dispatch({ action: "view_welcome_page" }); } } else if (SettingsStore.getValue("analyticsOptIn")) { CountlyAnalytics.instance.enable(/* anonymous = */ false); @@ -538,7 +532,7 @@ export default class MatrixChat extends React.PureComponent { action: 'do_after_sync_prepared', deferred_action: payload, }); - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } @@ -563,11 +557,11 @@ export default class MatrixChat extends React.PureComponent { } // redispatch the change with a more specific action - dis.dispatch({action: 'id_server_changed'}); + dis.dispatch({ action: 'id_server_changed' }); } break; case 'logout': - dis.dispatch({action: "hangup_all"}); + dis.dispatch({ action: "hangup_all" }); Lifecycle.logout(); break; case 'require_registration': @@ -624,7 +618,7 @@ export default class MatrixChat extends React.PureComponent { MatrixClientPeg.get().leave(payload.room_id).then(() => { modal.close(); if (this.state.currentRoomId === payload.room_id) { - dis.dispatch({action: 'view_home_page'}); + dis.dispatch({ action: 'view_home_page' }); } }, (err) => { modal.close(); @@ -657,7 +651,7 @@ export default class MatrixChat extends React.PureComponent { const tabPayload = payload as OpenToTabPayload; const UserSettingsDialog = sdk.getComponent("dialogs.UserSettingsDialog"); Modal.createTrackedDialog('User settings', '', UserSettingsDialog, - {initialTabId: tabPayload.initialTabId}, + { initialTabId: tabPayload.initialTabId }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); // View the welcome or home page if we need something to look at @@ -668,7 +662,7 @@ export default class MatrixChat extends React.PureComponent { this.createRoom(payload.public, payload.defaultName); break; case 'view_create_group': { - let CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog") + let CreateGroupDialog = sdk.getComponent("dialogs.CreateGroupDialog"); if (SettingsStore.getValue("feature_communities_v2_prototypes")) { CreateGroupDialog = CreateCommunityPrototypeDialog; } @@ -727,9 +721,9 @@ export default class MatrixChat extends React.PureComponent { // We just dispatch the page change rather than have to worry about // what the logic is for each of these branches. if (this.state.page_type === PageTypes.MyGroups) { - dis.dispatch({action: 'view_last_screen'}); + dis.dispatch({ action: 'view_last_screen' }); } else { - dis.dispatch({action: 'view_my_groups'}); + dis.dispatch({ action: 'view_my_groups' }); } break; case 'hide_left_panel': @@ -770,7 +764,7 @@ export default class MatrixChat extends React.PureComponent { this.onLoggedOut(); break; case 'will_start_client': - this.setState({ready: false}, () => { + this.setState({ ready: false }, () => { // if the client is about to start, we are, by definition, not ready. // Set ready to false now, then it'll be set to true when the sync // listener we set below fires. @@ -1006,7 +1000,7 @@ export default class MatrixChat extends React.PureComponent { return; } this.notifyNewScreen('user/' + userId); - this.setState({currentUserId: userId}); + this.setState({ currentUserId: userId }); this.setPage(PageTypes.UserView); }); } @@ -1131,8 +1125,14 @@ export default class MatrixChat extends React.PureComponent { description: ( { isSpace - ? _t("Are you sure you want to leave the space '%(spaceName)s'?", {spaceName: roomToLeave.name}) - : _t("Are you sure you want to leave the room '%(roomName)s'?", {roomName: roomToLeave.name}) } + ? _t( + "Are you sure you want to leave the space '%(spaceName)s'?", + { spaceName: roomToLeave.name }, + ) + : _t( + "Are you sure you want to leave the room '%(roomName)s'?", + { roomName: roomToLeave.name }, + )} { warnings } ), @@ -1170,7 +1170,7 @@ export default class MatrixChat extends React.PureComponent { }).catch((err) => { const errCode = err.errcode || _td("unknown error code"); Modal.createTrackedDialog("Failed to forget room", '', ErrorDialog, { - title: _t("Failed to forget room %(errCode)s", {errCode}), + title: _t("Failed to forget room %(errCode)s", { errCode }), description: ((err && err.message) ? err.message : _t("Operation failed")), }); }); @@ -1254,7 +1254,7 @@ export default class MatrixChat extends React.PureComponent { if (welcomeUserRoom === null) { // We didn't redirect to the welcome user room, so show // the homepage. - dis.dispatch({action: 'view_home_page', justRegistered: true}); + dis.dispatch({ action: 'view_home_page', justRegistered: true }); } } else if (ThreepidInviteStore.instance.pickBestInvite()) { // The user has a 3pid invite pending - show them that @@ -1263,11 +1263,11 @@ export default class MatrixChat extends React.PureComponent { // HACK: This is a pretty brutal way of threading the invite back through // our systems, but it's the safest we have for now. const params = ThreepidInviteStore.instance.translateToWireFormat(threepidInvite); - this.showScreen(`room/${threepidInvite.roomId}`, params) + this.showScreen(`room/${threepidInvite.roomId}`, params); } else { // The user has just logged in after registering, // so show the homepage. - dis.dispatch({action: 'view_home_page', justRegistered: true}); + dis.dispatch({ action: 'view_home_page', justRegistered: true }); } } else { this.showScreenAfterLogin(); @@ -1303,9 +1303,9 @@ export default class MatrixChat extends React.PureComponent { this.viewLastRoom(); } else { if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'view_welcome_page'}); + dis.dispatch({ action: 'view_welcome_page' }); } else { - dis.dispatch({action: 'view_home_page'}); + dis.dispatch({ action: 'view_home_page' }); } } } @@ -1385,15 +1385,15 @@ export default class MatrixChat extends React.PureComponent { // So dispatch directly from here. Ideally we'd use a SyncStateStore that // would do this dispatch and expose the sync state itself (by listening to // its own dispatch). - dis.dispatch({action: 'sync_state', prevState, state}); + dis.dispatch({ action: 'sync_state', prevState, state }); if (state === "ERROR" || state === "RECONNECTING") { if (data.error instanceof InvalidStoreError) { Lifecycle.handleInvalidStoreError(data.error); } - this.setState({syncError: data.error || true}); + this.setState({ syncError: data.error || true }); } else if (this.state.syncError) { - this.setState({syncError: null}); + this.setState({ syncError: null }); } this.updateStatusIndicator(state, prevState); @@ -1567,16 +1567,12 @@ export default class MatrixChat extends React.PureComponent { key: 'verifreq_' + request.channel.transactionId, title: _t("Verification requested"), icon: "verification", - props: {request}, + props: { request }, component: sdk.getComponent("toasts.VerificationRequestToast"), priority: 90, }); } }); - // Fire the tinter right on startup to ensure the default theme is applied - // A later sync can/will correct the tint to be the right value for the user - const colorScheme = SettingsStore.getValue("roomColor"); - Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color); } /** @@ -1668,7 +1664,7 @@ export default class MatrixChat extends React.PureComponent { // TODO if logged in, skip SSO let cli = MatrixClientPeg.get(); if (!cli) { - const {hsUrl, isUrl} = this.props.serverConfig; + const { hsUrl, isUrl } = this.props.serverConfig; cli = createClient({ baseUrl: hsUrl, idBaseUrl: isUrl, @@ -1792,7 +1788,7 @@ export default class MatrixChat extends React.PureComponent { onAliasClick(event: MouseEvent, alias: string) { event.preventDefault(); - dis.dispatch({action: 'view_room', room_alias: alias}); + dis.dispatch({ action: 'view_room', room_alias: alias }); } onUserClick(event: MouseEvent, userId: string) { @@ -1808,7 +1804,7 @@ export default class MatrixChat extends React.PureComponent { onGroupClick(event: MouseEvent, groupId: string) { event.preventDefault(); - dis.dispatch({action: 'view_group', group_id: groupId}); + dis.dispatch({ action: 'view_group', group_id: groupId }); } onLogoutClick(event: React.MouseEvent) { @@ -1870,14 +1866,14 @@ export default class MatrixChat extends React.PureComponent { onSendEvent(roomId: string, event: MatrixEvent) { const cli = MatrixClientPeg.get(); if (!cli) { - dis.dispatch({action: 'message_send_failed'}); + dis.dispatch({ action: 'message_send_failed' }); return; } cli.sendEvent(roomId, event.getType(), event.getContent()).then(() => { - dis.dispatch({action: 'message_sent'}); + dis.dispatch({ action: 'message_sent' }); }, (err) => { - dis.dispatch({action: 'message_send_failed'}); + dis.dispatch({ action: 'message_send_failed' }); }); } @@ -1924,7 +1920,7 @@ export default class MatrixChat extends React.PureComponent { } onServerConfigChange = (serverConfig: ValidatedServerConfig) => { - this.setState({serverConfig}); + this.setState({ serverConfig }); }; private makeRegistrationUrl = (params: {[key: string]: string}) => { diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.tsx similarity index 64% rename from src/components/structures/MessagePanel.js rename to src/components/structures/MessagePanel.tsx index 49855eb99c..a0a1ac9b10 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.tsx @@ -1,7 +1,5 @@ /* -Copyright 2016 OpenMarket Ltd -Copyright 2018 New Vector Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2016 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,33 +14,47 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from 'react'; +import React, { createRef, KeyboardEvent, ReactNode, SyntheticEvent, TransitionEvent } from 'react'; import ReactDOM from 'react-dom'; -import PropTypes from 'prop-types'; -import shouldHideEvent from '../../shouldHideEvent'; -import {wantsDateSeparator} from '../../DateUtils'; -import * as sdk from '../../index'; +import { Room } from 'matrix-js-sdk/src/models/room'; +import { EventType } from 'matrix-js-sdk/src/@types/event'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; +import { Relations } from "matrix-js-sdk/src/models/relations"; +import { RoomMember } from 'matrix-js-sdk/src/models/room-member'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import shouldHideEvent from '../../shouldHideEvent'; +import { wantsDateSeparator } from '../../DateUtils'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import SettingsStore from '../../settings/SettingsStore'; import RoomContext from "../../contexts/RoomContext"; -import {Layout, LayoutPropType} from "../../settings/Layout"; -import {_t} from "../../languageHandler"; -import {haveTileForEvent} from "../views/rooms/EventTile"; -import {hasText} from "../../TextForEvent"; +import { Layout } from "../../settings/Layout"; +import { _t } from "../../languageHandler"; +import EventTile, { haveTileForEvent, IReadReceiptProps, TileShape } from "../views/rooms/EventTile"; +import { hasText } from "../../TextForEvent"; import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer"; import DMRoomMap from "../../utils/DMRoomMap"; import NewRoomIntro from "../views/rooms/NewRoomIntro"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; import defaultDispatcher from '../../dispatcher/dispatcher'; +import WhoIsTypingTile from '../views/rooms/WhoIsTypingTile'; +import ScrollPanel, { IScrollState } from "./ScrollPanel"; +import EventListSummary from '../views/elements/EventListSummary'; +import MemberEventListSummary from '../views/elements/MemberEventListSummary'; +import DateSeparator from '../views/messages/DateSeparator'; +import ErrorBoundary from '../views/elements/ErrorBoundary'; +import ResizeNotifier from "../../utils/ResizeNotifier"; +import Spinner from "../views/elements/Spinner"; +import TileErrorBoundary from '../views/messages/TileErrorBoundary'; +import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; +import EditorStateTransfer from "../../utils/EditorStateTransfer"; const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes -const continuedTypes = ['m.sticker', 'm.room.message']; -const membershipTypes = ['m.room.member', 'm.room.third_party_invite', 'm.room.server_acl']; +const continuedTypes = [EventType.Sticker, EventType.RoomMessage]; +const membershipTypes = [EventType.RoomMember, EventType.RoomThirdPartyInvite, EventType.RoomServerAcl]; // check if there is a previous event and it has the same sender as this event // and the types are the same/is in continuedTypes and the time between them is <= CONTINUATION_MAX_INTERVAL -function shouldFormContinuation(prevEvent, mxEvent) { +function shouldFormContinuation(prevEvent: MatrixEvent, mxEvent: MatrixEvent): boolean { // sanity check inputs if (!prevEvent || !prevEvent.sender || !mxEvent.sender) return false; // check if within the max continuation period @@ -53,8 +65,8 @@ function shouldFormContinuation(prevEvent, mxEvent) { // Some events should appear as continuations from previous events of different types. if (mxEvent.getType() !== prevEvent.getType() && - (!continuedTypes.includes(mxEvent.getType()) || - !continuedTypes.includes(prevEvent.getType()))) return false; + (!continuedTypes.includes(mxEvent.getType() as EventType) || + !continuedTypes.includes(prevEvent.getType() as EventType))) return false; // Check if the sender is the same and hasn't changed their displayname/avatar between these events if (mxEvent.sender.userId !== prevEvent.sender.userId || @@ -67,94 +79,157 @@ function shouldFormContinuation(prevEvent, mxEvent) { return true; } +interface IProps { + // the list of MatrixEvents to display + events: MatrixEvent[]; + + // true to give the component a 'display: none' style. + hidden?: boolean; + + // true to show a spinner at the top of the timeline to indicate + // back-pagination in progress + backPaginating?: boolean; + + // true to show a spinner at the end of the timeline to indicate + // forward-pagination in progress + forwardPaginating?: boolean; + + // ID of an event to highlight. If undefined, no event will be highlighted. + highlightedEventId?: string; + + // The room these events are all in together, if any. + // (The notification panel won't have a room here, for example.) + room?: Room; + + // Should we show URL Previews + showUrlPreview?: boolean; + + // event after which we should show a read marker + readMarkerEventId?: string; + + // whether the read marker should be visible + readMarkerVisible?: boolean; + + // the userid of our user. This is used to suppress the read marker + // for pending messages. + ourUserId?: string; + + // true to suppress the date at the start of the timeline + suppressFirstDateSeparator?: boolean; + + // whether to show read receipts + showReadReceipts?: boolean; + + // true if updates to the event list should cause the scroll panel to + // scroll down when we are at the bottom of the window. See ScrollPanel + // for more details. + stickyBottom?: boolean; + + // className for the panel + className: string; + + // shape parameter to be passed to EventTiles + tileShape?: TileShape; + + // show twelve hour timestamps + isTwelveHour?: boolean; + + // show timestamps always + alwaysShowTimestamps?: boolean; + + // whether to show reactions for an event + showReactions?: boolean; + + // which layout to use + layout?: Layout; + + // whether or not to show flair at all + enableFlair?: boolean; + + resizeNotifier: ResizeNotifier; + permalinkCreator?: RoomPermalinkCreator; + editState?: EditorStateTransfer; + + // callback which is called when the panel is scrolled. + onScroll?(event: Event): void; + + // callback which is called when the user interacts with the room timeline + onUserScroll(event: SyntheticEvent): void; + + // callback which is called when more content is needed. + onFillRequest?(backwards: boolean): Promise; + + // helper function to access relations for an event + onUnfillRequest?(backwards: boolean, scrollToken: string): void; + + getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations; +} + +interface IState { + ghostReadMarkers: string[]; + showTypingNotifications: boolean; +} + +interface IReadReceiptForUser { + lastShownEventId: string; + receipt: IReadReceiptProps; +} + /* (almost) stateless UI component which builds the event tiles in the room timeline. */ @replaceableComponent("structures.MessagePanel") -export default class MessagePanel extends React.Component { - static propTypes = { - // true to give the component a 'display: none' style. - hidden: PropTypes.bool, - - // true to show a spinner at the top of the timeline to indicate - // back-pagination in progress - backPaginating: PropTypes.bool, - - // true to show a spinner at the end of the timeline to indicate - // forward-pagination in progress - forwardPaginating: PropTypes.bool, - - // the list of MatrixEvents to display - events: PropTypes.array.isRequired, - - // ID of an event to highlight. If undefined, no event will be highlighted. - highlightedEventId: PropTypes.string, - - // The room these events are all in together, if any. - // (The notification panel won't have a room here, for example.) - room: PropTypes.object, - - // Should we show URL Previews - showUrlPreview: PropTypes.bool, - - // event after which we should show a read marker - readMarkerEventId: PropTypes.string, - - // whether the read marker should be visible - readMarkerVisible: PropTypes.bool, - - // the userid of our user. This is used to suppress the read marker - // for pending messages. - ourUserId: PropTypes.string, - - // true to suppress the date at the start of the timeline - suppressFirstDateSeparator: PropTypes.bool, - - // whether to show read receipts - showReadReceipts: PropTypes.bool, - - // true if updates to the event list should cause the scroll panel to - // scroll down when we are at the bottom of the window. See ScrollPanel - // for more details. - stickyBottom: PropTypes.bool, - - // callback which is called when the panel is scrolled. - onScroll: PropTypes.func, - - // callback which is called when the user interacts with the room timeline - onUserScroll: PropTypes.func, - - // callback which is called when more content is needed. - onFillRequest: PropTypes.func, - - // className for the panel - className: PropTypes.string.isRequired, - - // shape parameter to be passed to EventTiles - tileShape: PropTypes.string, - - // show twelve hour timestamps - isTwelveHour: PropTypes.bool, - - // show timestamps always - alwaysShowTimestamps: PropTypes.bool, - - // helper function to access relations for an event - getRelationsForEvent: PropTypes.func, - - // whether to show reactions for an event - showReactions: PropTypes.bool, - - // which layout to use - layout: LayoutPropType, - - // whether or not to show flair at all - enableFlair: PropTypes.bool, - }; - +export default class MessagePanel extends React.Component { static contextType = RoomContext; - constructor(props) { - super(props); + // opaque readreceipt info for each userId; used by ReadReceiptMarker + // to manage its animations + private readonly readReceiptMap: Record = {}; + + // Track read receipts by event ID. For each _shown_ event ID, we store + // the list of read receipts to display: + // [ + // { + // userId: string, + // member: RoomMember, + // ts: number, + // }, + // ] + // This is recomputed on each render. It's only stored on the component + // for ease of passing the data around since it's computed in one pass + // over all events. + private readReceiptsByEvent: Record = {}; + + // Track read receipts by user ID. For each user ID we've ever shown a + // a read receipt for, we store an object: + // { + // lastShownEventId: string, + // receipt: { + // userId: string, + // member: RoomMember, + // ts: number, + // }, + // } + // so that we can always keep receipts displayed by reverting back to + // the last shown event for that user ID when needed. This may feel like + // it duplicates the receipt storage in the room, but at this layer, we + // are tracking _shown_ event IDs, which the JS SDK knows nothing about. + // This is recomputed on each render, using the data from the previous + // render as our fallback for any user IDs we can't match a receipt to a + // displayed event in the current render cycle. + private readReceiptsByUserId: Record = {}; + + private readonly showHiddenEventsInTimeline: boolean; + private isMounted = false; + + private readMarkerNode = createRef(); + private whoIsTyping = createRef(); + private scrollPanel = createRef(); + + private readonly showTypingNotificationsWatcherRef: string; + private eventNodes: Record; + + constructor(props, context) { + super(props, context); this.state = { // previous positions the read marker has been in, so we can @@ -163,65 +238,21 @@ export default class MessagePanel extends React.Component { showTypingNotifications: SettingsStore.getValue("showTypingNotifications"), }; - // opaque readreceipt info for each userId; used by ReadReceiptMarker - // to manage its animations - this._readReceiptMap = {}; - - // Track read receipts by event ID. For each _shown_ event ID, we store - // the list of read receipts to display: - // [ - // { - // userId: string, - // member: RoomMember, - // ts: number, - // }, - // ] - // This is recomputed on each render. It's only stored on the component - // for ease of passing the data around since it's computed in one pass - // over all events. - this._readReceiptsByEvent = {}; - - // Track read receipts by user ID. For each user ID we've ever shown a - // a read receipt for, we store an object: - // { - // lastShownEventId: string, - // receipt: { - // userId: string, - // member: RoomMember, - // ts: number, - // }, - // } - // so that we can always keep receipts displayed by reverting back to - // the last shown event for that user ID when needed. This may feel like - // it duplicates the receipt storage in the room, but at this layer, we - // are tracking _shown_ event IDs, which the JS SDK knows nothing about. - // This is recomputed on each render, using the data from the previous - // render as our fallback for any user IDs we can't match a receipt to a - // displayed event in the current render cycle. - this._readReceiptsByUserId = {}; - // Cache hidden events setting on mount since Settings is expensive to // query, and we check this in a hot code path. - this._showHiddenEventsInTimeline = - SettingsStore.getValue("showHiddenEventsInTimeline"); + this.showHiddenEventsInTimeline = SettingsStore.getValue("showHiddenEventsInTimeline"); - this._isMounted = false; - - this._readMarkerNode = createRef(); - this._whoIsTyping = createRef(); - this._scrollPanel = createRef(); - - this._showTypingNotificationsWatcherRef = + this.showTypingNotificationsWatcherRef = SettingsStore.watchSetting("showTypingNotifications", null, this.onShowTypingNotificationsChange); } componentDidMount() { - this._isMounted = true; + this.isMounted = true; } componentWillUnmount() { - this._isMounted = false; - SettingsStore.unwatchSetting(this._showTypingNotificationsWatcherRef); + this.isMounted = false; + SettingsStore.unwatchSetting(this.showTypingNotificationsWatcherRef); } componentDidUpdate(prevProps, prevState) { @@ -234,14 +265,14 @@ export default class MessagePanel extends React.Component { } } - onShowTypingNotificationsChange = () => { + private onShowTypingNotificationsChange = (): void => { this.setState({ showTypingNotifications: SettingsStore.getValue("showTypingNotifications"), }); }; /* get the DOM node representing the given event */ - getNodeForEventId(eventId) { + public getNodeForEventId(eventId: string): HTMLElement { if (!this.eventNodes) { return undefined; } @@ -251,8 +282,8 @@ export default class MessagePanel extends React.Component { /* return true if the content is fully scrolled down right now; else false. */ - isAtBottom() { - return this._scrollPanel.current && this._scrollPanel.current.isAtBottom(); + public isAtBottom(): boolean { + return this.scrollPanel.current?.isAtBottom(); } /* get the current scroll state. See ScrollPanel.getScrollState for @@ -260,8 +291,8 @@ export default class MessagePanel extends React.Component { * * returns null if we are not mounted. */ - getScrollState() { - return this._scrollPanel.current ? this._scrollPanel.current.getScrollState() : null; + public getScrollState(): IScrollState { + return this.scrollPanel.current?.getScrollState() ?? null; } // returns one of: @@ -270,15 +301,15 @@ export default class MessagePanel extends React.Component { // -1: read marker is above the window // 0: read marker is within the window // +1: read marker is below the window - getReadMarkerPosition() { - const readMarker = this._readMarkerNode.current; - const messageWrapper = this._scrollPanel.current; + public getReadMarkerPosition(): number { + const readMarker = this.readMarkerNode.current; + const messageWrapper = this.scrollPanel.current; if (!readMarker || !messageWrapper) { return null; } - const wrapperRect = ReactDOM.findDOMNode(messageWrapper).getBoundingClientRect(); + const wrapperRect = (ReactDOM.findDOMNode(messageWrapper) as HTMLElement).getBoundingClientRect(); const readMarkerRect = readMarker.getBoundingClientRect(); // the read-marker pretends to have zero height when it is actually @@ -294,17 +325,17 @@ export default class MessagePanel extends React.Component { /* jump to the top of the content. */ - scrollToTop() { - if (this._scrollPanel.current) { - this._scrollPanel.current.scrollToTop(); + public scrollToTop(): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.scrollToTop(); } } /* jump to the bottom of the content. */ - scrollToBottom() { - if (this._scrollPanel.current) { - this._scrollPanel.current.scrollToBottom(); + public scrollToBottom(): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.scrollToBottom(); } } @@ -313,9 +344,9 @@ export default class MessagePanel extends React.Component { * * @param {number} mult: -1 to page up, +1 to page down */ - scrollRelative(mult) { - if (this._scrollPanel.current) { - this._scrollPanel.current.scrollRelative(mult); + public scrollRelative(mult: number): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.scrollRelative(mult); } } @@ -324,9 +355,9 @@ export default class MessagePanel extends React.Component { * * @param {KeyboardEvent} ev: the keyboard event to handle */ - handleScrollKey(ev) { - if (this._scrollPanel.current) { - this._scrollPanel.current.handleScrollKey(ev); + public handleScrollKey(ev: KeyboardEvent): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.handleScrollKey(ev); } } @@ -340,38 +371,41 @@ export default class MessagePanel extends React.Component { * node (specifically, the bottom of it) will be positioned. If omitted, it * defaults to 0. */ - scrollToEvent(eventId, pixelOffset, offsetBase) { - if (this._scrollPanel.current) { - this._scrollPanel.current.scrollToToken(eventId, pixelOffset, offsetBase); + public scrollToEvent(eventId: string, pixelOffset: number, offsetBase: number): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.scrollToToken(eventId, pixelOffset, offsetBase); } } - scrollToEventIfNeeded(eventId) { + public scrollToEventIfNeeded(eventId: string): void { const node = this.eventNodes[eventId]; if (node) { - node.scrollIntoView({block: "nearest", behavior: "instant"}); + node.scrollIntoView({ + block: "nearest", + behavior: "instant", + }); } } /* check the scroll state and send out pagination requests if necessary. */ - checkFillState() { - if (this._scrollPanel.current) { - this._scrollPanel.current.checkFillState(); + public checkFillState(): void { + if (this.scrollPanel.current) { + this.scrollPanel.current.checkFillState(); } } - _isUnmounting = () => { - return !this._isMounted; + private isUnmounting = (): boolean => { + return !this.isMounted; }; // TODO: Implement granular (per-room) hide options - _shouldShowEvent(mxEv) { + public shouldShowEvent(mxEv: MatrixEvent): boolean { if (mxEv.sender && MatrixClientPeg.get().isUserIgnored(mxEv.sender.userId)) { return false; // ignored = no show (only happens if the ignore happens after an event was received) } - if (this._showHiddenEventsInTimeline) { + if (this.showHiddenEventsInTimeline) { return true; } @@ -385,7 +419,7 @@ export default class MessagePanel extends React.Component { return !shouldHideEvent(mxEv, this.context); } - _readMarkerForEvent(eventId, isLastEvent) { + public readMarkerForEvent(eventId: string, isLastEvent: boolean): ReactNode { const visible = !isLastEvent && this.props.readMarkerVisible; if (this.props.readMarkerEventId === eventId) { @@ -398,13 +432,13 @@ export default class MessagePanel extends React.Component { // confused. if (visible) { hr =
; } return (
  • @@ -423,8 +457,8 @@ export default class MessagePanel extends React.Component { // transition (ie. the read markers do but the event tiles do not) // and TransitionGroup requires that all its children are Transitions. const hr =
    ; @@ -444,7 +478,7 @@ export default class MessagePanel extends React.Component { return null; } - _collectGhostReadMarker = (node) => { + private collectGhostReadMarker = (node: HTMLElement): void => { if (node) { // now the element has appeared, change the style which will trigger the CSS transition requestAnimationFrame(() => { @@ -454,15 +488,15 @@ export default class MessagePanel extends React.Component { } }; - _onGhostTransitionEnd = (ev) => { + private onGhostTransitionEnd = (ev: TransitionEvent): void => { // we can now clean up the ghost element - const finishedEventId = ev.target.dataset.eventid; + const finishedEventId = (ev.target as HTMLElement).dataset.eventid; this.setState({ ghostReadMarkers: this.state.ghostReadMarkers.filter(eid => eid !== finishedEventId), }); }; - _getNextEventInfo(arr, i) { + private getNextEventInfo(arr: MatrixEvent[], i: number): { nextEvent: MatrixEvent, nextTile: MatrixEvent } { const nextEvent = i < arr.length - 1 ? arr[i + 1] : null; @@ -471,16 +505,16 @@ export default class MessagePanel extends React.Component { // when rendering the tile. The shouldShowEvent function is pretty quick at what // it does, so this should have no significant cost even when a room is used for // not-chat purposes. - const nextTile = arr.slice(i + 1).find(e => this._shouldShowEvent(e)); + const nextTile = arr.slice(i + 1).find(e => this.shouldShowEvent(e)); - return {nextEvent, nextTile}; + return { nextEvent, nextTile }; } - get _roomHasPendingEdit() { + private get roomHasPendingEdit(): string { return this.props.room && localStorage.getItem(`mx_edit_room_${this.props.room.roomId}`); } - _getEventTiles() { + private getEventTiles(): ReactNode[] { this.eventNodes = {}; let i; @@ -496,7 +530,7 @@ export default class MessagePanel extends React.Component { let lastShownNonLocalEchoIndex = -1; for (i = this.props.events.length-1; i >= 0; i--) { const mxEv = this.props.events[i]; - if (!this._shouldShowEvent(mxEv)) { + if (!this.shouldShowEvent(mxEv)) { continue; } @@ -520,18 +554,18 @@ export default class MessagePanel extends React.Component { // Note: the EventTile might still render a "sent/sending receipt" independent of // this information. When not providing read receipt information, the tile is likely // to assume that sent receipts are to be shown more often. - this._readReceiptsByEvent = {}; + this.readReceiptsByEvent = {}; if (this.props.showReadReceipts) { - this._readReceiptsByEvent = this._getReadReceiptsByShownEvent(); + this.readReceiptsByEvent = this.getReadReceiptsByShownEvent(); } - let grouper = null; + let grouper: BaseGrouper = null; for (i = 0; i < this.props.events.length; i++) { const mxEv = this.props.events[i]; const eventId = mxEv.getId(); const last = (mxEv === lastShownEvent); - const {nextEvent, nextTile} = this._getNextEventInfo(this.props.events, i); + const { nextEvent, nextTile } = this.getNextEventInfo(this.props.events, i); if (grouper) { if (grouper.shouldGroup(mxEv)) { @@ -552,26 +586,25 @@ export default class MessagePanel extends React.Component { } } if (!grouper) { - const wantTile = this._shouldShowEvent(mxEv); + const wantTile = this.shouldShowEvent(mxEv); const isGrouped = false; if (wantTile) { - // make sure we unpack the array returned by _getTilesForEvent, + // make sure we unpack the array returned by getTilesForEvent, // otherwise react will auto-generate keys and we will end up // replacing all of the DOM elements every time we paginate. - ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, isGrouped, - nextEvent, nextTile)); + ret.push(...this.getTilesForEvent(prevEvent, mxEv, last, isGrouped, nextEvent, nextTile)); prevEvent = mxEv; } - const readMarker = this._readMarkerForEvent(eventId, i >= lastShownNonLocalEchoIndex); + const readMarker = this.readMarkerForEvent(eventId, i >= lastShownNonLocalEchoIndex); if (readMarker) ret.push(readMarker); } } - if (!this.props.editState && this._roomHasPendingEdit) { + if (!this.props.editState && this.roomHasPendingEdit) { defaultDispatcher.dispatch({ action: "edit_event", - event: this.props.room.findEventById(this._roomHasPendingEdit), + event: this.props.room.findEventById(this.roomHasPendingEdit), }); } @@ -582,10 +615,14 @@ export default class MessagePanel extends React.Component { return ret; } - _getTilesForEvent(prevEvent, mxEv, last, isGrouped=false, nextEvent, nextEventWithTile) { - const TileErrorBoundary = sdk.getComponent('messages.TileErrorBoundary'); - const EventTile = sdk.getComponent('rooms.EventTile'); - const DateSeparator = sdk.getComponent('messages.DateSeparator'); + public getTilesForEvent( + prevEvent: MatrixEvent, + mxEv: MatrixEvent, + last = false, + isGrouped = false, + nextEvent?: MatrixEvent, + nextEventWithTile?: MatrixEvent, + ): ReactNode[] { const ret = []; const isEditing = this.props.editState && @@ -600,7 +637,7 @@ export default class MessagePanel extends React.Component { } // do we need a date separator since the last event? - const wantsDateSeparator = this._wantsDateSeparator(prevEvent, eventDate); + const wantsDateSeparator = this.wantsDateSeparator(prevEvent, eventDate); if (wantsDateSeparator && !isGrouped) { const dateSeparator =
  • ; ret.push(dateSeparator); @@ -608,7 +645,7 @@ export default class MessagePanel extends React.Component { let willWantDateSeparator = false; if (nextEvent) { - willWantDateSeparator = this._wantsDateSeparator(mxEv, nextEvent.getDate() || new Date()); + willWantDateSeparator = this.wantsDateSeparator(mxEv, nextEvent.getDate() || new Date()); } // is this a continuation of the previous message? @@ -617,12 +654,12 @@ export default class MessagePanel extends React.Component { const eventId = mxEv.getId(); const highlight = (eventId === this.props.highlightedEventId); - const readReceipts = this._readReceiptsByEvent[eventId]; + const readReceipts = this.readReceiptsByEvent[eventId]; let isLastSuccessful = false; const isSentState = s => !s || s === 'sent'; const isSent = isSentState(mxEv.getAssociatedStatus()); - const hasNextEvent = nextEvent && this._shouldShowEvent(nextEvent); + const hasNextEvent = nextEvent && this.shouldShowEvent(nextEvent); if (!hasNextEvent && isSent) { isLastSuccessful = true; } else if (hasNextEvent && isSent && !isSentState(nextEvent.getAssociatedStatus())) { @@ -648,18 +685,18 @@ export default class MessagePanel extends React.Component { { if (!r.userId || r.type !== "m.read" || r.userId === myUserId) { return; // ignore non-read receipts and receipts from self. @@ -720,13 +757,13 @@ export default class MessagePanel extends React.Component { // Get an object that maps from event ID to a list of read receipts that // should be shown next to that event. If a hidden event has read receipts, // they are folded into the receipts of the last shown event. - _getReadReceiptsByShownEvent() { + private getReadReceiptsByShownEvent(): Record { const receiptsByEvent = {}; const receiptsByUserId = {}; let lastShownEventId; for (const event of this.props.events) { - if (this._shouldShowEvent(event)) { + if (this.shouldShowEvent(event)) { lastShownEventId = event.getId(); } if (!lastShownEventId) { @@ -734,7 +771,7 @@ export default class MessagePanel extends React.Component { } const existingReceipts = receiptsByEvent[lastShownEventId] || []; - const newReceipts = this._getReadReceiptsForEvent(event); + const newReceipts = this.getReadReceiptsForEvent(event); receiptsByEvent[lastShownEventId] = existingReceipts.concat(newReceipts); // Record these receipts along with their last shown event ID for @@ -753,16 +790,16 @@ export default class MessagePanel extends React.Component { // someone which had one in the last. By looking through our previous // mapping of receipts by user ID, we can cover recover any receipts // that would have been lost by using the same event ID from last time. - for (const userId in this._readReceiptsByUserId) { + for (const userId in this.readReceiptsByUserId) { if (receiptsByUserId[userId]) { continue; } - const { lastShownEventId, receipt } = this._readReceiptsByUserId[userId]; + const { lastShownEventId, receipt } = this.readReceiptsByUserId[userId]; const existingReceipts = receiptsByEvent[lastShownEventId] || []; receiptsByEvent[lastShownEventId] = existingReceipts.concat(receipt); receiptsByUserId[userId] = { lastShownEventId, receipt }; } - this._readReceiptsByUserId = receiptsByUserId; + this.readReceiptsByUserId = receiptsByUserId; // After grouping receipts by shown events, do another pass to sort each // receipt list. @@ -775,21 +812,21 @@ export default class MessagePanel extends React.Component { return receiptsByEvent; } - _collectEventNode = (eventId, node) => { + private collectEventNode = (eventId: string, node: EventTile): void => { this.eventNodes[eventId] = node?.ref?.current; - } + }; // once dynamic content in the events load, make the scrollPanel check the // scroll offsets. - _onHeightChanged = () => { - const scrollPanel = this._scrollPanel.current; + public onHeightChanged = (): void => { + const scrollPanel = this.scrollPanel.current; if (scrollPanel) { scrollPanel.checkScroll(); } }; - _onTypingShown = () => { - const scrollPanel = this._scrollPanel.current; + private onTypingShown = (): void => { + const scrollPanel = this.scrollPanel.current; // this will make the timeline grow, so checkScroll scrollPanel.checkScroll(); if (scrollPanel && scrollPanel.getScrollState().stuckAtBottom) { @@ -797,8 +834,8 @@ export default class MessagePanel extends React.Component { } }; - _onTypingHidden = () => { - const scrollPanel = this._scrollPanel.current; + private onTypingHidden = (): void => { + const scrollPanel = this.scrollPanel.current; if (scrollPanel) { // as hiding the typing notifications doesn't // update the scrollPanel, we tell it to apply @@ -810,12 +847,12 @@ export default class MessagePanel extends React.Component { } }; - updateTimelineMinHeight() { - const scrollPanel = this._scrollPanel.current; + public updateTimelineMinHeight(): void { + const scrollPanel = this.scrollPanel.current; if (scrollPanel) { const isAtBottom = scrollPanel.isAtBottom(); - const whoIsTyping = this._whoIsTyping.current; + const whoIsTyping = this.whoIsTyping.current; const isTypingVisible = whoIsTyping && whoIsTyping.isVisible(); // when messages get added to the timeline, // but somebody else is still typing, @@ -827,18 +864,14 @@ export default class MessagePanel extends React.Component { } } - onTimelineReset() { - const scrollPanel = this._scrollPanel.current; + public onTimelineReset(): void { + const scrollPanel = this.scrollPanel.current; if (scrollPanel) { scrollPanel.clearPreventShrinking(); } } render() { - const ErrorBoundary = sdk.getComponent('elements.ErrorBoundary'); - const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); - const WhoIsTypingTile = sdk.getComponent("rooms.WhoIsTypingTile"); - const Spinner = sdk.getComponent("elements.Spinner"); let topSpinner; let bottomSpinner; if (this.props.backPaginating) { @@ -854,9 +887,9 @@ export default class MessagePanel extends React.Component { if (this.props.room && !this.props.tileShape && this.state.showTypingNotifications) { whoIsTyping = ( + onShown={this.onTypingShown} + onHidden={this.onTypingHidden} + ref={this.whoIsTyping} /> ); } @@ -872,11 +905,10 @@ export default class MessagePanel extends React.Component { return ( { topSpinner } - { this._getEventTiles() } + { this.getEventTiles() } { whoIsTyping } { bottomSpinner } @@ -894,6 +926,31 @@ export default class MessagePanel extends React.Component { } } +abstract class BaseGrouper { + static canStartGroup = (panel: MessagePanel, ev: MatrixEvent): boolean => true; + + public events: MatrixEvent[] = []; + // events that we include in the group but then eject out and place above the group. + public ejectedEvents: MatrixEvent[] = []; + public readMarker: ReactNode; + + constructor( + public readonly panel: MessagePanel, + public readonly event: MatrixEvent, + public readonly prevEvent: MatrixEvent, + public readonly lastShownEvent: MatrixEvent, + public readonly nextEvent?: MatrixEvent, + public readonly nextEventTile?: MatrixEvent, + ) { + this.readMarker = panel.readMarkerForEvent(event.getId(), event === lastShownEvent); + } + + public abstract shouldGroup(ev: MatrixEvent): boolean; + public abstract add(ev: MatrixEvent): void; + public abstract getTiles(): ReactNode[]; + public abstract getNewPrevEvent(): MatrixEvent; +} + /* Grouper classes determine when events can be grouped together in a summary. * Groupers should have the following methods: * - canStartGroup (static): determines if a new group should be started with the @@ -909,36 +966,21 @@ export default class MessagePanel extends React.Component { // Wrap initial room creation events into an EventListSummary // Grouping only events sent by the same user that sent the `m.room.create` and only until // the first non-state event or membership event which is not regarding the sender of the `m.room.create` event -class CreationGrouper { - static canStartGroup = function(panel, ev) { - return ev.getType() === "m.room.create"; +class CreationGrouper extends BaseGrouper { + static canStartGroup = function(panel: MessagePanel, ev: MatrixEvent): boolean { + return ev.getType() === EventType.RoomCreate; }; - constructor(panel, createEvent, prevEvent, lastShownEvent) { - this.panel = panel; - this.createEvent = createEvent; - this.prevEvent = prevEvent; - this.lastShownEvent = lastShownEvent; - this.events = []; - // events that we include in the group but then eject out and place - // above the group. - this.ejectedEvents = []; - this.readMarker = panel._readMarkerForEvent( - createEvent.getId(), - createEvent === lastShownEvent, - ); - } - - shouldGroup(ev) { + public shouldGroup(ev: MatrixEvent): boolean { const panel = this.panel; - const createEvent = this.createEvent; - if (!panel._shouldShowEvent(ev)) { + const createEvent = this.event; + if (!panel.shouldShowEvent(ev)) { return true; } - if (panel._wantsDateSeparator(this.createEvent, ev.getDate())) { + if (panel.wantsDateSeparator(this.event, ev.getDate())) { return false; } - if (ev.getType() === "m.room.member" + if (ev.getType() === EventType.RoomMember && (ev.getStateKey() !== createEvent.getSender() || ev.getContent()["membership"] !== "join")) { return false; } @@ -948,37 +990,35 @@ class CreationGrouper { return false; } - add(ev) { + public add(ev: MatrixEvent): void { const panel = this.panel; - this.readMarker = this.readMarker || panel._readMarkerForEvent( + this.readMarker = this.readMarker || panel.readMarkerForEvent( ev.getId(), ev === this.lastShownEvent, ); - if (!panel._shouldShowEvent(ev)) { + if (!panel.shouldShowEvent(ev)) { return; } - if (ev.getType() === "m.room.encryption") { + if (ev.getType() === EventType.RoomEncryption) { this.ejectedEvents.push(ev); } else { this.events.push(ev); } } - getTiles() { + public getTiles(): ReactNode[] { // If we don't have any events to group, don't even try to group them. The logic // below assumes that we have a group of events to deal with, but we might not if // the events we were supposed to group were redacted. if (!this.events || !this.events.length) return []; - const DateSeparator = sdk.getComponent('messages.DateSeparator'); - const EventListSummary = sdk.getComponent('views.elements.EventListSummary'); const panel = this.panel; const ret = []; const isGrouped = true; - const createEvent = this.createEvent; + const createEvent = this.event; const lastShownEvent = this.lastShownEvent; - if (panel._wantsDateSeparator(this.prevEvent, createEvent.getDate())) { + if (panel.wantsDateSeparator(this.prevEvent, createEvent.getDate())) { const ts = createEvent.getTs(); ret.push(
  • , @@ -986,13 +1026,13 @@ class CreationGrouper { } // If this m.room.create event should be shown (room upgrade) then show it before the summary - if (panel._shouldShowEvent(createEvent)) { + if (panel.shouldShowEvent(createEvent)) { // pass in the createEvent as prevEvent as well so no extra DateSeparator is rendered - ret.push(...panel._getTilesForEvent(createEvent, createEvent)); + ret.push(...panel.getTilesForEvent(createEvent, createEvent)); } for (const ejected of this.ejectedEvents) { - ret.push(...panel._getTilesForEvent( + ret.push(...panel.getTilesForEvent( createEvent, ejected, createEvent === lastShownEvent, isGrouped, )); } @@ -1002,7 +1042,7 @@ class CreationGrouper { // of EventListSummary, render each member event as if the previous // one was itself. This way, the timestamp of the previous event === the // timestamp of the current event, and no DateSeparator is inserted. - return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped); + return panel.getTilesForEvent(e, e, e === lastShownEvent, isGrouped); }).reduce((a, b) => a.concat(b), []); // Get sender profile from the latest event in the summary as the m.room.create doesn't contain one const ev = this.events[this.events.length - 1]; @@ -1022,7 +1062,7 @@ class CreationGrouper { @@ -1037,62 +1077,59 @@ class CreationGrouper { return ret; } - getNewPrevEvent() { - return this.createEvent; + public getNewPrevEvent(): MatrixEvent { + return this.event; } } -class RedactionGrouper { - static canStartGroup = function(panel, ev) { - return panel._shouldShowEvent(ev) && ev.isRedacted(); - } +class RedactionGrouper extends BaseGrouper { + static canStartGroup = function(panel: MessagePanel, ev: MatrixEvent): boolean { + return panel.shouldShowEvent(ev) && ev.isRedacted(); + }; - constructor(panel, ev, prevEvent, lastShownEvent, nextEvent, nextEventTile) { - this.panel = panel; - this.readMarker = panel._readMarkerForEvent( - ev.getId(), - ev === lastShownEvent, - ); + constructor( + panel: MessagePanel, + ev: MatrixEvent, + prevEvent: MatrixEvent, + lastShownEvent: MatrixEvent, + nextEvent: MatrixEvent, + nextEventTile: MatrixEvent, + ) { + super(panel, ev, prevEvent, lastShownEvent, nextEvent, nextEventTile); this.events = [ev]; - this.prevEvent = prevEvent; - this.lastShownEvent = lastShownEvent; - this.nextEvent = nextEvent; - this.nextEventTile = nextEventTile; } - shouldGroup(ev) { + public shouldGroup(ev: MatrixEvent): boolean { // absorb hidden events so that they do not break up streams of messages & redaction events being grouped - if (!this.panel._shouldShowEvent(ev)) { + if (!this.panel.shouldShowEvent(ev)) { return true; } - if (this.panel._wantsDateSeparator(this.events[0], ev.getDate())) { + if (this.panel.wantsDateSeparator(this.events[0], ev.getDate())) { return false; } return ev.isRedacted(); } - add(ev) { - this.readMarker = this.readMarker || this.panel._readMarkerForEvent( + public add(ev: MatrixEvent): void { + this.readMarker = this.readMarker || this.panel.readMarkerForEvent( ev.getId(), ev === this.lastShownEvent, ); - if (!this.panel._shouldShowEvent(ev)) { + if (!this.panel.shouldShowEvent(ev)) { return; } this.events.push(ev); } - getTiles() { + public getTiles(): ReactNode[] { if (!this.events || !this.events.length) return []; - const DateSeparator = sdk.getComponent('messages.DateSeparator'); - const EventListSummary = sdk.getComponent('views.elements.EventListSummary'); const isGrouped = true; const panel = this.panel; const ret = []; const lastShownEvent = this.lastShownEvent; - if (panel._wantsDateSeparator(this.prevEvent, this.events[0].getDate())) { + if (panel.wantsDateSeparator(this.prevEvent, this.events[0].getDate())) { const ts = this.events[0].getTs(); ret.push(
  • , @@ -1103,11 +1140,11 @@ class RedactionGrouper { this.prevEvent ? this.events[0].getId() : "initial" ); - const senders = new Set(); + const senders = new Set(); let eventTiles = this.events.map((e, i) => { senders.add(e.sender); const prevEvent = i === 0 ? this.prevEvent : this.events[i - 1]; - return panel._getTilesForEvent( + return panel.getTilesForEvent( prevEvent, e, e === lastShownEvent, isGrouped, this.nextEvent, this.nextEventTile); }).reduce((a, b) => a.concat(b), []); @@ -1120,7 +1157,7 @@ class RedactionGrouper { key={key} threshold={2} events={this.events} - onToggle={panel._onHeightChanged} // Update scroll state + onToggle={panel.onHeightChanged} // Update scroll state summaryMembers={Array.from(senders)} summaryText={_t("%(count)s messages deleted.", { count: eventTiles.length })} > @@ -1135,61 +1172,58 @@ class RedactionGrouper { return ret; } - getNewPrevEvent() { + public getNewPrevEvent(): MatrixEvent { return this.events[this.events.length - 1]; } } // Wrap consecutive member events in a ListSummary, ignore if redacted -class MemberGrouper { - static canStartGroup = function(panel, ev) { - return panel._shouldShowEvent(ev) && membershipTypes.includes(ev.getType()); +class MemberGrouper extends BaseGrouper { + static canStartGroup = function(panel: MessagePanel, ev: MatrixEvent): boolean { + return panel.shouldShowEvent(ev) && membershipTypes.includes(ev.getType() as EventType); + }; + + constructor( + public readonly panel: MessagePanel, + public readonly event: MatrixEvent, + public readonly prevEvent: MatrixEvent, + public readonly lastShownEvent: MatrixEvent, + ) { + super(panel, event, prevEvent, lastShownEvent); + this.events = [event]; } - constructor(panel, ev, prevEvent, lastShownEvent) { - this.panel = panel; - this.readMarker = panel._readMarkerForEvent( - ev.getId(), - ev === lastShownEvent, - ); - this.events = [ev]; - this.prevEvent = prevEvent; - this.lastShownEvent = lastShownEvent; - } - - shouldGroup(ev) { - if (this.panel._wantsDateSeparator(this.events[0], ev.getDate())) { + public shouldGroup(ev: MatrixEvent): boolean { + if (this.panel.wantsDateSeparator(this.events[0], ev.getDate())) { return false; } - return membershipTypes.includes(ev.getType()); + return membershipTypes.includes(ev.getType() as EventType); } - add(ev) { - if (ev.getType() === 'm.room.member') { + public add(ev: MatrixEvent): void { + if (ev.getType() === EventType.RoomMember) { // We can ignore any events that don't actually have a message to display if (!hasText(ev)) return; } - this.readMarker = this.readMarker || this.panel._readMarkerForEvent( + this.readMarker = this.readMarker || this.panel.readMarkerForEvent( ev.getId(), ev === this.lastShownEvent, ); this.events.push(ev); } - getTiles() { + public getTiles(): ReactNode[] { // If we don't have any events to group, don't even try to group them. The logic // below assumes that we have a group of events to deal with, but we might not if // the events we were supposed to group were redacted. if (!this.events || !this.events.length) return []; - const DateSeparator = sdk.getComponent('messages.DateSeparator'); - const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary'); const isGrouped = true; const panel = this.panel; const lastShownEvent = this.lastShownEvent; const ret = []; - if (panel._wantsDateSeparator(this.prevEvent, this.events[0].getDate())) { + if (panel.wantsDateSeparator(this.prevEvent, this.events[0].getDate())) { const ts = this.events[0].getTs(); ret.push(
  • , @@ -1217,7 +1251,7 @@ class MemberGrouper { // of MemberEventListSummary, render each member event as if the previous // one was itself. This way, the timestamp of the previous event === the // timestamp of the current event, and no DateSeparator is inserted. - return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped); + return panel.getTilesForEvent(e, e, e === lastShownEvent, isGrouped); }).reduce((a, b) => a.concat(b), []); if (eventTiles.length === 0) { @@ -1225,9 +1259,10 @@ class MemberGrouper { } ret.push( - { eventTiles } @@ -1241,7 +1276,7 @@ class MemberGrouper { return ret; } - getNewPrevEvent() { + public getNewPrevEvent(): MatrixEvent { return this.events[0]; } } diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js index d0a2fbff41..87447b6aba 100644 --- a/src/components/structures/MyGroups.js +++ b/src/components/structures/MyGroups.js @@ -24,7 +24,7 @@ import dis from '../../dispatcher/dispatcher'; import AccessibleButton from '../views/elements/AccessibleButton'; import MatrixClientContext from "../../contexts/MatrixClientContext"; import AutoHideScrollbar from "./AutoHideScrollbar"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; import BetaCard from "../views/beta/BetaCard"; @replaceableComponent("structures.MyGroups") @@ -41,19 +41,19 @@ export default class MyGroups extends React.Component { } _onCreateGroupClick = () => { - dis.dispatch({action: 'view_create_group'}); + dis.dispatch({ action: 'view_create_group' }); }; _fetch() { this.context.getJoinedGroups().then((result) => { - this.setState({groups: result.groups, error: null}); + this.setState({ groups: result.groups, error: null }); }, (err) => { if (err.errcode === 'M_GUEST_ACCESS_FORBIDDEN') { // Indicate that the guest isn't in any groups (which should be true) - this.setState({groups: [], error: null}); + this.setState({ groups: [], error: null }); return; } - this.setState({groups: null, error: err}); + this.setState({ groups: null, error: err }); }); } @@ -123,7 +123,7 @@ export default class MyGroups extends React.Component {
    {/*
    - +
    diff --git a/src/components/structures/NonUrgentToastContainer.tsx b/src/components/structures/NonUrgentToastContainer.tsx index 7c193ec9d7..b1424a2974 100644 --- a/src/components/structures/NonUrgentToastContainer.tsx +++ b/src/components/structures/NonUrgentToastContainer.tsx @@ -18,7 +18,7 @@ import * as React from "react"; import { ComponentClass } from "../../@types/common"; import NonUrgentToastStore from "../../stores/NonUrgentToastStore"; import { UPDATE_EVENT } from "../../stores/AsyncStore"; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; interface IProps { } @@ -44,7 +44,7 @@ export default class NonUrgentToastContainer extends React.PureComponent { - this.setState({toasts: NonUrgentToastStore.instance.components}); + this.setState({ toasts: NonUrgentToastStore.instance.components }); }; public render() { diff --git a/src/components/structures/NotificationPanel.tsx b/src/components/structures/NotificationPanel.tsx index 6c22835447..8c8fab7ece 100644 --- a/src/components/structures/NotificationPanel.tsx +++ b/src/components/structures/NotificationPanel.tsx @@ -22,6 +22,7 @@ import BaseCard from "../views/right_panel/BaseCard"; import { replaceableComponent } from "../../utils/replaceableComponent"; import TimelinePanel from "./TimelinePanel"; import Spinner from "../views/elements/Spinner"; +import { TileShape } from "../views/rooms/EventTile"; interface IProps { onClose(): void; @@ -48,7 +49,7 @@ export default class NotificationPanel extends React.PureComponent { manageReadMarkers={false} timelineSet={timelineSet} showUrlPreview={false} - tileShape="notif" + tileShape={TileShape.Notif} empty={emptyState} alwaysShowTimestamps={true} /> diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index 294865fe08..c608f0eee9 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -104,7 +104,7 @@ export default class RightPanel extends React.Component { const userForPanel = this.getUserForPanel(); if (this.props.groupId) { if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.groupPanelPhase)) { - dis.dispatch({action: Action.SetRightPanelPhase, phase: RightPanelPhases.GroupMemberList}); + dis.dispatch({ action: Action.SetRightPanelPhase, phase: RightPanelPhases.GroupMemberList }); return RightPanelPhases.GroupMemberList; } return rps.groupPanelPhase; diff --git a/src/components/structures/RoomDirectory.tsx b/src/components/structures/RoomDirectory.tsx index 62944a9d98..2ac990436f 100644 --- a/src/components/structures/RoomDirectory.tsx +++ b/src/components/structures/RoomDirectory.tsx @@ -25,7 +25,7 @@ import { _t } from '../../languageHandler'; import SdkConfig from '../../SdkConfig'; import { instanceForInstanceId, protocolNameForInstanceId } from '../../utils/DirectoryUtils'; import Analytics from '../../Analytics'; -import {ALL_ROOMS, IFieldType, IInstance, IProtocol, Protocols} from "../views/directory/NetworkDropdown"; +import { ALL_ROOMS, IFieldType, IInstance, IProtocol, Protocols } from "../views/directory/NetworkDropdown"; import SettingsStore from "../../settings/SettingsStore"; import GroupFilterOrderStore from "../../stores/GroupFilterOrderStore"; import GroupStore from "../../stores/GroupStore"; @@ -34,7 +34,7 @@ import CountlyAnalytics from "../../CountlyAnalytics"; import { replaceableComponent } from "../../utils/replaceableComponent"; import { mediaFromMxc } from "../../customisations/Media"; import { IDialogProps } from "../views/dialogs/IDialogProps"; -import AccessibleButton, {ButtonEvent} from "../views/elements/AccessibleButton"; +import AccessibleButton, { ButtonEvent } from "../views/elements/AccessibleButton"; import BaseAvatar from "../views/avatars/BaseAvatar"; import ErrorDialog from "../views/dialogs/ErrorDialog"; import QuestionDialog from "../views/dialogs/QuestionDialog"; @@ -45,7 +45,6 @@ import ScrollPanel from "./ScrollPanel"; import Spinner from "../views/elements/Spinner"; import { ActionPayload } from "../../dispatcher/payloads"; - const MAX_NAME_LENGTH = 80; const MAX_TOPIC_LENGTH = 800; @@ -95,7 +94,7 @@ interface IPublicRoomsRequest { @replaceableComponent("structures.RoomDirectory") export default class RoomDirectory extends React.Component { private readonly startTime: number; - private unmounted = false + private unmounted = false; private nextBatch: string = null; private filterTimeout: NodeJS.Timeout; private protocols: Protocols; @@ -207,9 +206,9 @@ export default class RoomDirectory extends React.Component { this.getMoreRooms(); }; - private getMoreRooms() { - if (this.state.selectedCommunityId) return Promise.resolve(); // no more rooms - if (!MatrixClientPeg.get()) return Promise.resolve(); + private getMoreRooms(): Promise { + if (this.state.selectedCommunityId) return Promise.resolve(false); // no more rooms + if (!MatrixClientPeg.get()) return Promise.resolve(false); this.setState({ loading: true, @@ -239,12 +238,12 @@ export default class RoomDirectory extends React.Component { // if the filter or server has changed since this request was sent, // throw away the result (don't even clear the busy flag // since we must still have a request in flight) - return; + return false; } if (this.unmounted) { // if we've been unmounted, we don't care either. - return; + return false; } if (this.state.filterString) { @@ -264,14 +263,13 @@ export default class RoomDirectory extends React.Component { filterString != this.state.filterString || roomServer != this.state.roomServer || nextBatch != this.nextBatch) { - // as above: we don't care about errors for old - // requests either - return; + // as above: we don't care about errors for old requests either + return false; } if (this.unmounted) { // if we've been unmounted, we don't care either. - return; + return false; } console.error("Failed to get publicRooms: %s", JSON.stringify(err)); @@ -300,9 +298,9 @@ export default class RoomDirectory extends React.Component { let desc; if (alias) { - desc = _t('Delete the room address %(alias)s and remove %(name)s from the directory?', {alias, name}); + desc = _t('Delete the room address %(alias)s and remove %(name)s from the directory?', { alias, name }); } else { - desc = _t('Remove %(name)s from the directory?', {name: name}); + desc = _t('Remove %(name)s from the directory?', { name: name }); } Modal.createTrackedDialog('Remove from Directory', '', QuestionDialog, { @@ -312,7 +310,7 @@ export default class RoomDirectory extends React.Component { if (!shouldDelete) return; const modal = Modal.createDialog(Spinner); - let step = _t('remove %(name)s from the directory.', {name: name}); + let step = _t('remove %(name)s from the directory.', { name: name }); MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => { if (!alias) return; @@ -483,7 +481,7 @@ export default class RoomDirectory extends React.Component { // to the directory. if (MatrixClientPeg.get().isGuest()) { if (!room.world_readable && !room.guest_can_join) { - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } } @@ -782,11 +780,11 @@ export default class RoomDirectory extends React.Component { } const explanation = _t("If you can't find the room you're looking for, ask for an invite or Create a new room.", null, - {a: sub => ( + { a: sub => ( { sub } - )}, + ) }, ); const title = this.state.selectedCommunityId diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index bda46aef07..9cdd1efe7e 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -108,22 +108,22 @@ export default class RoomSearch extends React.PureComponent { }; private openSearch = () => { - defaultDispatcher.dispatch({action: "show_left_panel"}); - defaultDispatcher.dispatch({action: "focus_room_filter"}); + defaultDispatcher.dispatch({ action: "show_left_panel" }); + defaultDispatcher.dispatch({ action: "focus_room_filter" }); }; private onChange = () => { if (!this.inputRef.current) return; - this.setState({query: this.inputRef.current.value}); + this.setState({ query: this.inputRef.current.value }); }; private onFocus = (ev: React.FocusEvent) => { - this.setState({focused: true}); + this.setState({ focused: true }); ev.target.select(); }; private onBlur = (ev: React.FocusEvent) => { - this.setState({focused: false}); + this.setState({ focused: false }); }; private onKeyDown = (ev: React.KeyboardEvent) => { diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index 7d74229421..f6e42a4f9c 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -17,15 +17,15 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { _t, _td } from '../../languageHandler'; -import {MatrixClientPeg} from '../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../MatrixClientPeg'; import Resend from '../../Resend'; import dis from '../../dispatcher/dispatcher'; -import {messageForResourceLimitError} from '../../utils/ErrorUtils'; -import {Action} from "../../dispatcher/actions"; -import {replaceableComponent} from "../../utils/replaceableComponent"; -import {EventStatus} from "matrix-js-sdk/src/models/event"; +import { messageForResourceLimitError } from '../../utils/ErrorUtils'; +import { Action } from "../../dispatcher/actions"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { EventStatus } from "matrix-js-sdk/src/models/event"; import NotificationBadge from "../views/rooms/NotificationBadge"; -import {StaticNotificationState} from "../../stores/notifications/StaticNotificationState"; +import { StaticNotificationState } from "../../stores/notifications/StaticNotificationState"; import AccessibleButton from "../views/elements/AccessibleButton"; import InlineSpinner from "../views/elements/InlineSpinner"; @@ -115,9 +115,9 @@ export default class RoomStatusBar extends React.PureComponent { _onResendAllClick = () => { Resend.resendUnsentEvents(this.props.room).then(() => { - this.setState({isResending: false}); + this.setState({ isResending: false }); }); - this.setState({isResending: true}); + this.setState({ isResending: true }); dis.fire(Action.FocusComposer); }; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index aef2fbc9d4..81000a87a6 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -37,7 +37,6 @@ import Modal from '../../Modal'; import * as sdk from '../../index'; import CallHandler, { PlaceCallType } from '../../CallHandler'; import dis from '../../dispatcher/dispatcher'; -import Tinter from '../../Tinter'; import rateLimitedFunc from '../../ratelimitedfunc'; import * as Rooms from '../../Rooms'; import eventSearch, { searchPagination } from '../../Searching'; @@ -287,7 +286,7 @@ export default class RoomView extends React.Component { if (this.state.room) { this.checkWidgets(this.state.room); } - } + }; private checkWidgets = (room) => { this.setState({ @@ -530,7 +529,7 @@ export default class RoomView extends React.Component { } else if (room) { // Stop peeking because we have joined this room previously this.context.stopPeeking(); - this.setState({isPeeking: false}); + this.setState({ isPeeking: false }); } } } @@ -679,10 +678,6 @@ export default class RoomView extends React.Component { // cancel any pending calls to the rate_limited_funcs this.updateRoomMembers.cancelPendingCall(); - // no need to do this as Dir & Settings are now overlays. It just burnt CPU. - // console.log("Tinter.tint from RoomView.unmount"); - // Tinter.tint(); // reset colourscheme - for (const watcher of this.settingWatchers) { SettingsStore.unwatchSetting(watcher); } @@ -698,7 +693,7 @@ export default class RoomView extends React.Component { replyingToEvent: this.state.replyToEvent, }); } - } + }; private onRightPanelStoreUpdate = () => { this.setState({ @@ -882,7 +877,7 @@ export default class RoomView extends React.Component { // no change } else if (!shouldHideEvent(ev, this.state)) { this.setState((state, props) => { - return {numUnreadMessages: state.numUnreadMessages + 1}; + return { numUnreadMessages: state.numUnreadMessages + 1 }; }); } } @@ -907,7 +902,7 @@ export default class RoomView extends React.Component { CHAT_EFFECTS.forEach(effect => { if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) { - dis.dispatch({action: `effects.${effect.command}`}); + dis.dispatch({ action: `effects.${effect.command}` }); } }); }; @@ -960,7 +955,7 @@ export default class RoomView extends React.Component { try { await room.loadMembersIfNeeded(); if (!this.unmounted) { - this.setState({membersLoaded: true}); + this.setState({ membersLoaded: true }); } } catch (err) { const errorMessage = `Fetching room members for ${room.roomId} failed.` + @@ -988,7 +983,7 @@ export default class RoomView extends React.Component { } } - private updatePreviewUrlVisibility({roomId}: Room) { + private updatePreviewUrlVisibility({ roomId }: Room) { // URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit const key = this.context.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled'; this.setState({ @@ -1059,15 +1054,6 @@ export default class RoomView extends React.Component { }); } - private updateTint() { - const room = this.state.room; - if (!room) return; - - console.log("Tinter.tint from updateTint"); - const colorScheme = SettingsStore.getValue("roomColor", room.roomId); - Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color); - } - private onAccountData = (event: MatrixEvent) => { const type = event.getType(); if ((type === "org.matrix.preview_urls" || type === "im.vector.web.settings") && this.state.room) { @@ -1079,12 +1065,7 @@ export default class RoomView extends React.Component { private onRoomAccountData = (event: MatrixEvent, room: Room) => { if (room.roomId == this.state.roomId) { const type = event.getType(); - if (type === "org.matrix.room.color_scheme") { - const colorScheme = event.getContent(); - // XXX: we should validate the event - console.log("Tinter.tint from onRoomAccountData"); - Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color); - } else if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") { + if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") { // non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls` this.updatePreviewUrlVisibility(room); } @@ -1128,7 +1109,7 @@ export default class RoomView extends React.Component { const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me); const canReply = room.maySendMessage(); - this.setState({canReact, canReply}); + this.setState({ canReact, canReply }); } } @@ -1157,7 +1138,7 @@ export default class RoomView extends React.Component { } } - private onSearchResultsFillRequest = (backwards: boolean) => { + private onSearchResultsFillRequest = (backwards: boolean): Promise => { if (!backwards) { return Promise.resolve(false); } @@ -1192,7 +1173,7 @@ export default class RoomView extends React.Component { room_id: this.getRoomId(), }, }); - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); } else { Promise.resolve().then(() => { const signUrl = this.props.threepidInvite?.signUrl; @@ -1227,13 +1208,13 @@ export default class RoomView extends React.Component { // We always increment the counter no matter the types, because dragging is // still happening. If we didn't, the drag counter would get out of sync. - this.setState({dragCounter: this.state.dragCounter + 1}); + this.setState({ dragCounter: this.state.dragCounter + 1 }); // See: // https://docs.w3cub.com/dom/datatransfer/types // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file if (ev.dataTransfer.types.includes("Files") || ev.dataTransfer.types.includes("application/x-moz-file")) { - this.setState({draggingFile: true}); + this.setState({ draggingFile: true }); } }; @@ -1282,7 +1263,7 @@ export default class RoomView extends React.Component { private injectSticker(url, info, text) { if (this.context.isGuest()) { - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } @@ -1323,7 +1304,7 @@ export default class RoomView extends React.Component { this.handleSearchResult(searchPromise); }; - private handleSearchResult(searchPromise: Promise) { + private handleSearchResult(searchPromise: Promise): Promise { // keep a record of the current search id, so that if the search terms // change before we get a response, we can ignore the results. const localSearchId = this.searchId; @@ -1336,7 +1317,7 @@ export default class RoomView extends React.Component { debuglog("search complete"); if (this.unmounted || !this.state.searching || this.searchId != localSearchId) { console.error("Discarding stale search results"); - return; + return false; } // postgres on synapse returns us precise details of the strings @@ -1368,6 +1349,7 @@ export default class RoomView extends React.Component { description: ((error && error.message) ? error.message : _t("Server may be unavailable, overloaded, or search timed out :(")), }); + return false; }).finally(() => { this.setState({ searchInProgress: false, @@ -1609,7 +1591,7 @@ export default class RoomView extends React.Component { const showBar = this.messagePanel.canJumpToReadMarker(); if (this.state.showTopUnreadMessagesBar != showBar) { - this.setState({showTopUnreadMessagesBar: showBar}); + this.setState({ showTopUnreadMessagesBar: showBar }); } }; @@ -1718,10 +1700,6 @@ export default class RoomView extends React.Component { // otherwise react calls it with null on each update. private gatherTimelinePanelRef = r => { this.messagePanel = r; - if (r) { - console.log("updateTint from RoomView.gatherTimelinePanelRef"); - this.updateTint(); - } }; private getOldRoom() { @@ -1740,7 +1718,7 @@ export default class RoomView extends React.Component { onHiddenHighlightsClick = () => { const oldRoom = this.getOldRoom(); if (!oldRoom) return; - dis.dispatch({action: "view_room", room_id: oldRoom.roomId}); + dis.dispatch({ action: "view_room", room_id: oldRoom.roomId }); }; render() { @@ -1948,7 +1926,7 @@ export default class RoomView extends React.Component { > {_t( "You have %(count)s unread notifications in a prior version of this room.", - {count: hiddenHighlightCount}, + { count: hiddenHighlightCount }, )} ); diff --git a/src/components/structures/ScrollPanel.js b/src/components/structures/ScrollPanel.tsx similarity index 72% rename from src/components/structures/ScrollPanel.js rename to src/components/structures/ScrollPanel.tsx index f6e1530537..df885575df 100644 --- a/src/components/structures/ScrollPanel.js +++ b/src/components/structures/ScrollPanel.tsx @@ -1,5 +1,5 @@ /* -Copyright 2015, 2016 OpenMarket Ltd +Copyright 2015 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from "react"; -import PropTypes from 'prop-types'; +import React, { createRef, CSSProperties, ReactNode, SyntheticEvent, KeyboardEvent } from "react"; import Timer from '../../utils/Timer'; import AutoHideScrollbar from "./AutoHideScrollbar"; -import {replaceableComponent} from "../../utils/replaceableComponent"; -import {getKeyBindingsManager, RoomAction} from "../../KeyBindingsManager"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { getKeyBindingsManager, RoomAction } from "../../KeyBindingsManager"; +import ResizeNotifier from "../../utils/ResizeNotifier"; const DEBUG_SCROLL = false; // The amount of extra scroll distance to allow prior to unfilling. -// See _getExcessHeight. +// See getExcessHeight. const UNPAGINATION_PADDING = 6000; // The number of milliseconds to debounce calls to onUnfillRequest, to prevent // many scroll events causing many unfilling requests. @@ -43,6 +43,75 @@ if (DEBUG_SCROLL) { debuglog = function() {}; } +interface IProps { + /* stickyBottom: if set to true, then once the user hits the bottom of + * the list, any new children added to the list will cause the list to + * scroll down to show the new element, rather than preserving the + * existing view. + */ + stickyBottom?: boolean; + + /* startAtBottom: if set to true, the view is assumed to start + * scrolled to the bottom. + * XXX: It's likely this is unnecessary and can be derived from + * stickyBottom, but I'm adding an extra parameter to ensure + * behaviour stays the same for other uses of ScrollPanel. + * If so, let's remove this parameter down the line. + */ + startAtBottom?: boolean; + + /* className: classnames to add to the top-level div + */ + className?: string; + + /* style: styles to add to the top-level div + */ + style?: CSSProperties; + + /* resizeNotifier: ResizeNotifier to know when middle column has changed size + */ + resizeNotifier?: ResizeNotifier; + + /* fixedChildren: allows for children to be passed which are rendered outside + * of the wrapper + */ + fixedChildren?: ReactNode; + + /* onFillRequest(backwards): a callback which is called on scroll when + * the user nears the start (backwards = true) or end (backwards = + * false) of the list. + * + * This should return a promise; no more calls will be made until the + * promise completes. + * + * The promise should resolve to true if there is more data to be + * retrieved in this direction (in which case onFillRequest may be + * called again immediately), or false if there is no more data in this + * directon (at this time) - which will stop the pagination cycle until + * the user scrolls again. + */ + onFillRequest?(backwards: boolean): Promise; + + /* onUnfillRequest(backwards): a callback which is called on scroll when + * there are children elements that are far out of view and could be removed + * without causing pagination to occur. + * + * This function should accept a boolean, which is true to indicate the back/top + * of the panel and false otherwise, and a scroll token, which refers to the + * first element to remove if removing from the front/bottom, and last element + * to remove if removing from the back/top. + */ + onUnfillRequest?(backwards: boolean, scrollToken: string): void; + + /* onScroll: a callback which is called whenever any scroll happens. + */ + onScroll?(event: Event): void; + + /* onUserScroll: callback which is called when the user interacts with the room timeline + */ + onUserScroll?(event: SyntheticEvent): void; +} + /* This component implements an intelligent scrolling list. * * It wraps a list of
  • children; when items are added to the start or end @@ -84,97 +153,54 @@ if (DEBUG_SCROLL) { * offset as normal. */ +export interface IScrollState { + stuckAtBottom: boolean; + trackedNode?: HTMLElement; + trackedScrollToken?: string; + bottomOffset?: number; + pixelOffset?: number; +} + +interface IPreventShrinkingState { + offsetFromBottom: number; + offsetNode: HTMLElement; +} + @replaceableComponent("structures.ScrollPanel") -export default class ScrollPanel extends React.Component { - static propTypes = { - /* stickyBottom: if set to true, then once the user hits the bottom of - * the list, any new children added to the list will cause the list to - * scroll down to show the new element, rather than preserving the - * existing view. - */ - stickyBottom: PropTypes.bool, - - /* startAtBottom: if set to true, the view is assumed to start - * scrolled to the bottom. - * XXX: It's likely this is unnecessary and can be derived from - * stickyBottom, but I'm adding an extra parameter to ensure - * behaviour stays the same for other uses of ScrollPanel. - * If so, let's remove this parameter down the line. - */ - startAtBottom: PropTypes.bool, - - /* onFillRequest(backwards): a callback which is called on scroll when - * the user nears the start (backwards = true) or end (backwards = - * false) of the list. - * - * This should return a promise; no more calls will be made until the - * promise completes. - * - * The promise should resolve to true if there is more data to be - * retrieved in this direction (in which case onFillRequest may be - * called again immediately), or false if there is no more data in this - * directon (at this time) - which will stop the pagination cycle until - * the user scrolls again. - */ - onFillRequest: PropTypes.func, - - /* onUnfillRequest(backwards): a callback which is called on scroll when - * there are children elements that are far out of view and could be removed - * without causing pagination to occur. - * - * This function should accept a boolean, which is true to indicate the back/top - * of the panel and false otherwise, and a scroll token, which refers to the - * first element to remove if removing from the front/bottom, and last element - * to remove if removing from the back/top. - */ - onUnfillRequest: PropTypes.func, - - /* onScroll: a callback which is called whenever any scroll happens. - */ - onScroll: PropTypes.func, - - /* onUserScroll: callback which is called when the user interacts with the room timeline - */ - onUserScroll: PropTypes.func, - - /* className: classnames to add to the top-level div - */ - className: PropTypes.string, - - /* style: styles to add to the top-level div - */ - style: PropTypes.object, - - /* resizeNotifier: ResizeNotifier to know when middle column has changed size - */ - resizeNotifier: PropTypes.object, - - /* fixedChildren: allows for children to be passed which are rendered outside - * of the wrapper - */ - fixedChildren: PropTypes.node, - }; - +export default class ScrollPanel extends React.Component { static defaultProps = { stickyBottom: true, startAtBottom: true, - onFillRequest: function(backwards) { return Promise.resolve(false); }, - onUnfillRequest: function(backwards, scrollToken) {}, + onFillRequest: function(backwards: boolean) { return Promise.resolve(false); }, + onUnfillRequest: function(backwards: boolean, scrollToken: string) {}, onScroll: function() {}, }; - constructor(props) { - super(props); + private readonly pendingFillRequests: Record<"b" | "f", boolean> = { + b: null, + f: null, + }; + private readonly itemlist = createRef(); + private unmounted = false; + private scrollTimeout: Timer; + private isFilling: boolean; + private fillRequestWhileRunning: boolean; + private scrollState: IScrollState; + private preventShrinkingState: IPreventShrinkingState; + private unfillDebouncer: NodeJS.Timeout; + private bottomGrowth: number; + private pages: number; + private heightUpdateInProgress: boolean; + private divScroll: HTMLDivElement; - this._pendingFillRequests = {b: null, f: null}; + constructor(props, context) { + super(props, context); if (this.props.resizeNotifier) { this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize); } this.resetScrollState(); - - this._itemlist = createRef(); } componentDidMount() { @@ -203,18 +229,18 @@ export default class ScrollPanel extends React.Component { } } - onScroll = ev => { + private onScroll = ev => { // skip scroll events caused by resizing if (this.props.resizeNotifier && this.props.resizeNotifier.isResizing) return; - debuglog("onScroll", this._getScrollNode().scrollTop); - this._scrollTimeout.restart(); - this._saveScrollState(); + debuglog("onScroll", this.getScrollNode().scrollTop); + this.scrollTimeout.restart(); + this.saveScrollState(); this.updatePreventShrinking(); this.props.onScroll(ev); this.checkFillState(); }; - onResize = () => { + private onResize = () => { debuglog("onResize"); this.checkScroll(); // update preventShrinkingState if present @@ -225,11 +251,11 @@ export default class ScrollPanel extends React.Component { // after an update to the contents of the panel, check that the scroll is // where it ought to be, and set off pagination requests if necessary. - checkScroll = () => { + public checkScroll = () => { if (this.unmounted) { return; } - this._restoreSavedScrollState(); + this.restoreSavedScrollState(); this.checkFillState(); }; @@ -238,8 +264,8 @@ export default class ScrollPanel extends React.Component { // note that this is independent of the 'stuckAtBottom' state - it is simply // about whether the content is scrolled down right now, irrespective of // whether it will stay that way when the children update. - isAtBottom = () => { - const sn = this._getScrollNode(); + public isAtBottom = () => { + const sn = this.getScrollNode(); // fractional values (both too big and too small) // for scrollTop happen on certain browsers/platforms // when scrolled all the way down. E.g. Chrome 72 on debian. @@ -278,10 +304,10 @@ export default class ScrollPanel extends React.Component { // |#########| - | // |#########| | // `---------' - - _getExcessHeight(backwards) { - const sn = this._getScrollNode(); - const contentHeight = this._getMessagesHeight(); - const listHeight = this._getListHeight(); + private getExcessHeight(backwards: boolean): number { + const sn = this.getScrollNode(); + const contentHeight = this.getMessagesHeight(); + const listHeight = this.getListHeight(); const clippedHeight = contentHeight - listHeight; const unclippedScrollTop = sn.scrollTop + clippedHeight; @@ -293,13 +319,13 @@ export default class ScrollPanel extends React.Component { } // check the scroll state and send out backfill requests if necessary. - checkFillState = async (depth=0) => { + public checkFillState = async (depth = 0): Promise => { if (this.unmounted) { return; } const isFirstCall = depth === 0; - const sn = this._getScrollNode(); + const sn = this.getScrollNode(); // if there is less than a screenful of messages above or below the // viewport, try to get some more messages. @@ -330,17 +356,17 @@ export default class ScrollPanel extends React.Component { // do make a note when a new request comes in while already running one, // so we can trigger a new chain of calls once done. if (isFirstCall) { - if (this._isFilling) { - debuglog("_isFilling: not entering while request is ongoing, marking for a subsequent request"); - this._fillRequestWhileRunning = true; + if (this.isFilling) { + debuglog("isFilling: not entering while request is ongoing, marking for a subsequent request"); + this.fillRequestWhileRunning = true; return; } - debuglog("_isFilling: setting"); - this._isFilling = true; + debuglog("isFilling: setting"); + this.isFilling = true; } - const itemlist = this._itemlist.current; - const firstTile = itemlist && itemlist.firstElementChild; + const itemlist = this.itemlist.current; + const firstTile = itemlist && itemlist.firstElementChild as HTMLElement; const contentTop = firstTile && firstTile.offsetTop; const fillPromises = []; @@ -348,13 +374,13 @@ export default class ScrollPanel extends React.Component { // try backward filling if (!firstTile || (sn.scrollTop - contentTop) < sn.clientHeight) { // need to back-fill - fillPromises.push(this._maybeFill(depth, true)); + fillPromises.push(this.maybeFill(depth, true)); } // if scrollTop gets to 2 screens from the end (so 1 screen below viewport), // try forward filling if ((sn.scrollHeight - sn.scrollTop) < sn.clientHeight * 2) { // need to forward-fill - fillPromises.push(this._maybeFill(depth, false)); + fillPromises.push(this.maybeFill(depth, false)); } if (fillPromises.length) { @@ -365,26 +391,26 @@ export default class ScrollPanel extends React.Component { } } if (isFirstCall) { - debuglog("_isFilling: clearing"); - this._isFilling = false; + debuglog("isFilling: clearing"); + this.isFilling = false; } - if (this._fillRequestWhileRunning) { - this._fillRequestWhileRunning = false; + if (this.fillRequestWhileRunning) { + this.fillRequestWhileRunning = false; this.checkFillState(); } }; // check if unfilling is possible and send an unfill request if necessary - _checkUnfillState(backwards) { - let excessHeight = this._getExcessHeight(backwards); + private checkUnfillState(backwards: boolean): void { + let excessHeight = this.getExcessHeight(backwards); if (excessHeight <= 0) { return; } const origExcessHeight = excessHeight; - const tiles = this._itemlist.current.children; + const tiles = this.itemlist.current.children; // The scroll token of the first/last tile to be unpaginated let markerScrollToken = null; @@ -413,11 +439,11 @@ export default class ScrollPanel extends React.Component { if (markerScrollToken) { // Use a debouncer to prevent multiple unfill calls in quick succession // This is to make the unfilling process less aggressive - if (this._unfillDebouncer) { - clearTimeout(this._unfillDebouncer); + if (this.unfillDebouncer) { + clearTimeout(this.unfillDebouncer); } - this._unfillDebouncer = setTimeout(() => { - this._unfillDebouncer = null; + this.unfillDebouncer = setTimeout(() => { + this.unfillDebouncer = null; debuglog("unfilling now", backwards, origExcessHeight); this.props.onUnfillRequest(backwards, markerScrollToken); }, UNFILL_REQUEST_DEBOUNCE_MS); @@ -425,9 +451,9 @@ export default class ScrollPanel extends React.Component { } // check if there is already a pending fill request. If not, set one off. - _maybeFill(depth, backwards) { + private maybeFill(depth: number, backwards: boolean): Promise { const dir = backwards ? 'b' : 'f'; - if (this._pendingFillRequests[dir]) { + if (this.pendingFillRequests[dir]) { debuglog("Already a "+dir+" fill in progress - not starting another"); return; } @@ -436,7 +462,7 @@ export default class ScrollPanel extends React.Component { // onFillRequest can end up calling us recursively (via onScroll // events) so make sure we set this before firing off the call. - this._pendingFillRequests[dir] = true; + this.pendingFillRequests[dir] = true; // wait 1ms before paginating, because otherwise // this will block the scroll event handler for +700ms @@ -445,13 +471,13 @@ export default class ScrollPanel extends React.Component { return new Promise(resolve => setTimeout(resolve, 1)).then(() => { return this.props.onFillRequest(backwards); }).finally(() => { - this._pendingFillRequests[dir] = false; + this.pendingFillRequests[dir] = false; }).then((hasMoreResults) => { if (this.unmounted) { return; } // Unpaginate once filling is complete - this._checkUnfillState(!backwards); + this.checkUnfillState(!backwards); debuglog(""+dir+" fill complete; hasMoreResults:"+hasMoreResults); if (hasMoreResults) { @@ -477,7 +503,7 @@ export default class ScrollPanel extends React.Component { * the number of pixels the bottom of the tracked child is above the * bottom of the scroll panel. */ - getScrollState = () => this.scrollState; + public getScrollState = (): IScrollState => this.scrollState; /* reset the saved scroll state. * @@ -491,35 +517,35 @@ export default class ScrollPanel extends React.Component { * no use if no children exist yet, or if you are about to replace the * child list.) */ - resetScrollState = () => { + public resetScrollState = (): void => { this.scrollState = { stuckAtBottom: this.props.startAtBottom, }; - this._bottomGrowth = 0; - this._pages = 0; - this._scrollTimeout = new Timer(100); - this._heightUpdateInProgress = false; + this.bottomGrowth = 0; + this.pages = 0; + this.scrollTimeout = new Timer(100); + this.heightUpdateInProgress = false; }; /** * jump to the top of the content. */ - scrollToTop = () => { - this._getScrollNode().scrollTop = 0; - this._saveScrollState(); + public scrollToTop = (): void => { + this.getScrollNode().scrollTop = 0; + this.saveScrollState(); }; /** * jump to the bottom of the content. */ - scrollToBottom = () => { + public scrollToBottom = (): void => { // the easiest way to make sure that the scroll state is correctly // saved is to do the scroll, then save the updated state. (Calculating // it ourselves is hard, and we can't rely on an onScroll callback // happening, since there may be no user-visible change here). - const sn = this._getScrollNode(); + const sn = this.getScrollNode(); sn.scrollTop = sn.scrollHeight; - this._saveScrollState(); + this.saveScrollState(); }; /** @@ -527,18 +553,18 @@ export default class ScrollPanel extends React.Component { * * @param {number} mult: -1 to page up, +1 to page down */ - scrollRelative = mult => { - const scrollNode = this._getScrollNode(); + public scrollRelative = (mult: number): void => { + const scrollNode = this.getScrollNode(); const delta = mult * scrollNode.clientHeight * 0.9; scrollNode.scrollBy(0, delta); - this._saveScrollState(); + this.saveScrollState(); }; /** * Scroll up/down in response to a scroll key * @param {object} ev the keyboard event */ - handleScrollKey = ev => { + public handleScrollKey = (ev: KeyboardEvent) => { let isScrolling = false; const roomAction = getKeyBindingsManager().getRoomAction(ev); switch (roomAction) { @@ -575,17 +601,17 @@ export default class ScrollPanel extends React.Component { * node (specifically, the bottom of it) will be positioned. If omitted, it * defaults to 0. */ - scrollToToken = (scrollToken, pixelOffset, offsetBase) => { + public scrollToToken = (scrollToken: string, pixelOffset: number, offsetBase: number): void => { pixelOffset = pixelOffset || 0; offsetBase = offsetBase || 0; - // set the trackedScrollToken so we can get the node through _getTrackedNode + // set the trackedScrollToken so we can get the node through getTrackedNode this.scrollState = { stuckAtBottom: false, trackedScrollToken: scrollToken, }; - const trackedNode = this._getTrackedNode(); - const scrollNode = this._getScrollNode(); + const trackedNode = this.getTrackedNode(); + const scrollNode = this.getScrollNode(); if (trackedNode) { // set the scrollTop to the position we want. // note though, that this might not succeed if the combination of offsetBase and pixelOffset @@ -593,36 +619,36 @@ export default class ScrollPanel extends React.Component { // This because when setting the scrollTop only 10 or so events might be loaded, // not giving enough content below the trackedNode to scroll downwards // enough so it ends up in the top of the viewport. - debuglog("scrollToken: setting scrollTop", {offsetBase, pixelOffset, offsetTop: trackedNode.offsetTop}); + debuglog("scrollToken: setting scrollTop", { offsetBase, pixelOffset, offsetTop: trackedNode.offsetTop }); scrollNode.scrollTop = (trackedNode.offsetTop - (scrollNode.clientHeight * offsetBase)) + pixelOffset; - this._saveScrollState(); + this.saveScrollState(); } }; - _saveScrollState() { + private saveScrollState(): void { if (this.props.stickyBottom && this.isAtBottom()) { this.scrollState = { stuckAtBottom: true }; debuglog("saved stuckAtBottom state"); return; } - const scrollNode = this._getScrollNode(); + const scrollNode = this.getScrollNode(); const viewportBottom = scrollNode.scrollHeight - (scrollNode.scrollTop + scrollNode.clientHeight); - const itemlist = this._itemlist.current; + const itemlist = this.itemlist.current; const messages = itemlist.children; let node = null; // TODO: do a binary search here, as items are sorted by offsetTop // loop backwards, from bottom-most message (as that is the most common case) - for (let i = messages.length-1; i >= 0; --i) { - if (!messages[i].dataset.scrollTokens) { + for (let i = messages.length - 1; i >= 0; --i) { + if (!(messages[i] as HTMLElement).dataset.scrollTokens) { continue; } node = messages[i]; // break at the first message (coming from the bottom) // that has it's offsetTop above the bottom of the viewport. - if (this._topFromBottom(node) > viewportBottom) { + if (this.topFromBottom(node) > viewportBottom) { // Use this node as the scrollToken break; } @@ -634,7 +660,7 @@ export default class ScrollPanel extends React.Component { } const scrollToken = node.dataset.scrollTokens.split(',')[0]; debuglog("saving anchored scroll state to message", node && node.innerText, scrollToken); - const bottomOffset = this._topFromBottom(node); + const bottomOffset = this.topFromBottom(node); this.scrollState = { stuckAtBottom: false, trackedNode: node, @@ -644,35 +670,35 @@ export default class ScrollPanel extends React.Component { }; } - async _restoreSavedScrollState() { + private async restoreSavedScrollState(): Promise { const scrollState = this.scrollState; if (scrollState.stuckAtBottom) { - const sn = this._getScrollNode(); + const sn = this.getScrollNode(); if (sn.scrollTop !== sn.scrollHeight) { sn.scrollTop = sn.scrollHeight; } } else if (scrollState.trackedScrollToken) { - const itemlist = this._itemlist.current; - const trackedNode = this._getTrackedNode(); + const itemlist = this.itemlist.current; + const trackedNode = this.getTrackedNode(); if (trackedNode) { - const newBottomOffset = this._topFromBottom(trackedNode); + const newBottomOffset = this.topFromBottom(trackedNode); const bottomDiff = newBottomOffset - scrollState.bottomOffset; - this._bottomGrowth += bottomDiff; + this.bottomGrowth += bottomDiff; scrollState.bottomOffset = newBottomOffset; - const newHeight = `${this._getListHeight()}px`; + const newHeight = `${this.getListHeight()}px`; if (itemlist.style.height !== newHeight) { itemlist.style.height = newHeight; } debuglog("balancing height because messages below viewport grew by", bottomDiff); } } - if (!this._heightUpdateInProgress) { - this._heightUpdateInProgress = true; + if (!this.heightUpdateInProgress) { + this.heightUpdateInProgress = true; try { - await this._updateHeight(); + await this.updateHeight(); } finally { - this._heightUpdateInProgress = false; + this.heightUpdateInProgress = false; } } else { debuglog("not updating height because request already in progress"); @@ -680,11 +706,11 @@ export default class ScrollPanel extends React.Component { } // need a better name that also indicates this will change scrollTop? Rebalance height? Reveal content? - async _updateHeight() { + private async updateHeight(): Promise { // wait until user has stopped scrolling - if (this._scrollTimeout.isRunning()) { + if (this.scrollTimeout.isRunning()) { debuglog("updateHeight waiting for scrolling to end ... "); - await this._scrollTimeout.finished(); + await this.scrollTimeout.finished(); } else { debuglog("updateHeight getting straight to business, no scrolling going on."); } @@ -694,14 +720,14 @@ export default class ScrollPanel extends React.Component { return; } - const sn = this._getScrollNode(); - const itemlist = this._itemlist.current; - const contentHeight = this._getMessagesHeight(); + const sn = this.getScrollNode(); + const itemlist = this.itemlist.current; + const contentHeight = this.getMessagesHeight(); const minHeight = sn.clientHeight; const height = Math.max(minHeight, contentHeight); - this._pages = Math.ceil(height / PAGE_SIZE); - this._bottomGrowth = 0; - const newHeight = `${this._getListHeight()}px`; + this.pages = Math.ceil(height / PAGE_SIZE); + this.bottomGrowth = 0; + const newHeight = `${this.getListHeight()}px`; const scrollState = this.scrollState; if (scrollState.stuckAtBottom) { @@ -713,7 +739,7 @@ export default class ScrollPanel extends React.Component { } debuglog("updateHeight to", newHeight); } else if (scrollState.trackedScrollToken) { - const trackedNode = this._getTrackedNode(); + const trackedNode = this.getTrackedNode(); // if the timeline has been reloaded // this can be called before scrollToBottom or whatever has been called // so don't do anything if the node has disappeared from @@ -730,22 +756,22 @@ export default class ScrollPanel extends React.Component { // yield out of date values and cause a jump // when setting it sn.scrollBy(0, topDiff); - debuglog("updateHeight to", {newHeight, topDiff}); + debuglog("updateHeight to", { newHeight, topDiff }); } } } - _getTrackedNode() { + private getTrackedNode(): HTMLElement { const scrollState = this.scrollState; const trackedNode = scrollState.trackedNode; if (!trackedNode || !trackedNode.parentElement) { let node; - const messages = this._itemlist.current.children; + const messages = this.itemlist.current.children; const scrollToken = scrollState.trackedScrollToken; for (let i = messages.length-1; i >= 0; --i) { - const m = messages[i]; + const m = messages[i] as HTMLElement; // 'data-scroll-tokens' is a DOMString of comma-separated scroll tokens // There might only be one scroll token if (m.dataset.scrollTokens && @@ -768,45 +794,45 @@ export default class ScrollPanel extends React.Component { return scrollState.trackedNode; } - _getListHeight() { - return this._bottomGrowth + (this._pages * PAGE_SIZE); + private getListHeight(): number { + return this.bottomGrowth + (this.pages * PAGE_SIZE); } - _getMessagesHeight() { - const itemlist = this._itemlist.current; - const lastNode = itemlist.lastElementChild; + private getMessagesHeight(): number { + const itemlist = this.itemlist.current; + const lastNode = itemlist.lastElementChild as HTMLElement; const lastNodeBottom = lastNode ? lastNode.offsetTop + lastNode.clientHeight : 0; - const firstNodeTop = itemlist.firstElementChild ? itemlist.firstElementChild.offsetTop : 0; + const firstNodeTop = itemlist.firstElementChild ? (itemlist.firstElementChild as HTMLElement).offsetTop : 0; // 18 is itemlist padding return lastNodeBottom - firstNodeTop + (18 * 2); } - _topFromBottom(node) { + private topFromBottom(node: HTMLElement): number { // current capped height - distance from top = distance from bottom of container to top of tracked element - return this._itemlist.current.clientHeight - node.offsetTop; + return this.itemlist.current.clientHeight - node.offsetTop; } /* get the DOM node which has the scrollTop property we care about for our * message panel. */ - _getScrollNode() { + private getScrollNode(): HTMLDivElement { if (this.unmounted) { // this shouldn't happen, but when it does, turn the NPE into // something more meaningful. - throw new Error("ScrollPanel._getScrollNode called when unmounted"); + throw new Error("ScrollPanel.getScrollNode called when unmounted"); } - if (!this._divScroll) { + if (!this.divScroll) { // Likewise, we should have the ref by this point, but if not // turn the NPE into something meaningful. - throw new Error("ScrollPanel._getScrollNode called before AutoHideScrollbar ref collected"); + throw new Error("ScrollPanel.getScrollNode called before AutoHideScrollbar ref collected"); } - return this._divScroll; + return this.divScroll; } - _collectScroll = divScroll => { - this._divScroll = divScroll; + private collectScroll = (divScroll: HTMLDivElement) => { + this.divScroll = divScroll; }; /** @@ -814,15 +840,15 @@ export default class ScrollPanel extends React.Component { anything below it changes, by calling updatePreventShrinking, to keep the same minimum bottom offset, effectively preventing the timeline to shrink. */ - preventShrinking = () => { - const messageList = this._itemlist.current; + public preventShrinking = (): void => { + const messageList = this.itemlist.current; const tiles = messageList && messageList.children; if (!messageList) { return; } let lastTileNode; for (let i = tiles.length - 1; i >= 0; i--) { - const node = tiles[i]; + const node = tiles[i] as HTMLElement; if (node.dataset.scrollTokens) { lastTileNode = node; break; @@ -841,8 +867,8 @@ export default class ScrollPanel extends React.Component { }; /** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */ - clearPreventShrinking = () => { - const messageList = this._itemlist.current; + public clearPreventShrinking = (): void => { + const messageList = this.itemlist.current; const balanceElement = messageList && messageList.parentElement; if (balanceElement) balanceElement.style.paddingBottom = null; this.preventShrinkingState = null; @@ -857,12 +883,12 @@ export default class ScrollPanel extends React.Component { from the bottom of the marked tile grows larger than what it was when marking. */ - updatePreventShrinking = () => { + public updatePreventShrinking = (): void => { if (this.preventShrinkingState) { - const sn = this._getScrollNode(); + const sn = this.getScrollNode(); const scrollState = this.scrollState; - const messageList = this._itemlist.current; - const {offsetNode, offsetFromBottom} = this.preventShrinkingState; + const messageList = this.itemlist.current; + const { offsetNode, offsetFromBottom } = this.preventShrinkingState; // element used to set paddingBottom to balance the typing notifs disappearing const balanceElement = messageList.parentElement; // if the offsetNode got unmounted, clear @@ -898,13 +924,15 @@ export default class ScrollPanel extends React.Component { // list-style-type: none; is no longer a list return ( + className={`mx_ScrollPanel ${this.props.className}`} + style={this.props.style} + > { this.props.fixedChildren }
    -
      +
        { this.props.children }
    diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index abeb858274..5c966d2d3a 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -15,14 +15,14 @@ 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 { Key } from '../../Keyboard'; import dis from '../../dispatcher/dispatcher'; -import {throttle} from 'lodash'; +import { throttle } from 'lodash'; import AccessibleButton from '../../components/views/elements/AccessibleButton'; import classNames from 'classnames'; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; @replaceableComponent("structures.SearchBox") export default class SearchBox extends React.Component { @@ -89,7 +89,7 @@ export default class SearchBox extends React.Component { onSearch = throttle(() => { this.props.onSearch(this._search.current.value); - }, 200, {trailing: true, leading: true}); + }, 200, { trailing: true, leading: true }); _onKeyDown = ev => { switch (ev.key) { @@ -101,7 +101,7 @@ export default class SearchBox extends React.Component { }; _onFocus = ev => { - this.setState({blurred: false}); + this.setState({ blurred: false }); ev.target.select(); if (this.props.onFocus) { this.props.onFocus(ev); @@ -109,7 +109,7 @@ export default class SearchBox extends React.Component { }; _onBlur = ev => { - this.setState({blurred: true}); + this.setState({ blurred: true }); if (this.props.onBlur) { this.props.onBlur(ev); } @@ -147,7 +147,7 @@ export default class SearchBox extends React.Component { this.props.placeholder; const className = this.props.className || ""; return ( -
    +
    = ({ ev.preventDefault(); ev.stopPropagation(); onViewRoomClick(false); - } + }; const onJoinClick = (ev: ButtonEvent) => { ev.preventDefault(); ev.stopPropagation(); onViewRoomClick(true); - } + }; let button; if (joinedRoom) { @@ -137,7 +137,7 @@ const Tile: React.FC = ({ } else { checkbox = { ev.stopPropagation() }} + onClick={ev => { ev.stopPropagation(); }} > ; @@ -340,7 +340,7 @@ export const HierarchyLevel = ({ )) } - + ; }; // mutate argument refreshToken to force a reload @@ -635,9 +635,9 @@ const SpaceRoomDirectory: React.FC = ({ space, onFinished, initialText }
    { _t("If you can't find the room you're looking for, ask for an invite or create a new room.", null, - {a: sub => { + { a: sub => { return {sub}; - }}, + } }, ) } { ) : null} } -
    +
    ; }; const onBetaClick = () => { @@ -591,14 +591,14 @@ const SpaceSetupPrivateScope = ({ space, justCreatedOpts, onFinished }) => { { onFinished(false) }} + onClick={() => { onFinished(false); }} >

    { _t("Just me") }

    { _t("A private space to organise your rooms") }
    { onFinished(true) }} + onClick={() => { onFinished(true); }} >

    { _t("Me and my teammates") }

    { _t("A private space for you and your teammates") }
    @@ -685,7 +685,7 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => { let buttonLabel = _t("Skip for now"); if (emailAddresses.some(name => name.trim())) { onClick = onNextClick; - buttonLabel = busy ? _t("Inviting...") : _t("Continue") + buttonLabel = busy ? _t("Inviting...") : _t("Continue"); } return
    diff --git a/src/components/structures/TabbedView.tsx b/src/components/structures/TabbedView.tsx index 0097d55cf5..3d77eaeac1 100644 --- a/src/components/structures/TabbedView.tsx +++ b/src/components/structures/TabbedView.tsx @@ -17,10 +17,10 @@ limitations under the License. */ import * as React from "react"; -import {_t} from '../../languageHandler'; +import { _t } from '../../languageHandler'; import * as sdk from "../../index"; import AutoHideScrollbar from './AutoHideScrollbar'; -import {replaceableComponent} from "../../utils/replaceableComponent"; +import { replaceableComponent } from "../../utils/replaceableComponent"; /** * Represents a tab for the TabbedView. @@ -75,7 +75,7 @@ export default class TabbedView extends React.Component { private _setActiveTab(tab: Tab) { const idx = this.props.tabs.indexOf(tab); if (idx !== -1) { - this.setState({activeTabIndex: idx}); + this.setState({ activeTabIndex: idx }); } else { console.error("Could not find tab " + tab.label + " in tabs"); } diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.tsx similarity index 74% rename from src/components/structures/TimelinePanel.js rename to src/components/structures/TimelinePanel.tsx index ad20d38139..e4c7d15596 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.tsx @@ -1,8 +1,5 @@ /* -Copyright 2016 OpenMarket Ltd -Copyright 2017 Vector Creations Ltd -Copyright 2019 New Vector Ltd -Copyright 2019-2020 The Matrix.org Foundation C.I.C. +Copyright 2016 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import SettingsStore from "../../settings/SettingsStore"; -import { LayoutPropType } from "../../settings/Layout"; -import React, { createRef } from 'react'; +import React, { createRef, ReactNode, SyntheticEvent } from 'react'; import ReactDOM from "react-dom"; -import PropTypes from 'prop-types'; +import { Room } from "matrix-js-sdk/src/models/room"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { TimelineSet } from "matrix-js-sdk/src/models/event-timeline-set"; import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline"; import { TimelineWindow } from "matrix-js-sdk/src/timeline-window"; + +import SettingsStore from "../../settings/SettingsStore"; +import { Layout } from "../../settings/Layout"; import { _t } from '../../languageHandler'; import { MatrixClientPeg } from "../../MatrixClientPeg"; import RoomContext from "../../contexts/RoomContext"; @@ -34,10 +34,19 @@ import * as sdk from "../../index"; import { Key } from '../../Keyboard'; import Timer from '../../utils/Timer'; import shouldHideEvent from '../../shouldHideEvent'; -import { haveTileForEvent } from "../views/rooms/EventTile"; +import { haveTileForEvent, TileShape } from "../views/rooms/EventTile"; import { UIFeature } from "../../settings/UIFeature"; import { replaceableComponent } from "../../utils/replaceableComponent"; import { arrayFastClone } from "../../utils/arrays"; +import MessagePanel from "./MessagePanel"; +import { SyncState } from 'matrix-js-sdk/src/sync.api'; +import { IScrollState } from "./ScrollPanel"; +import { ActionPayload } from "../../dispatcher/payloads"; +import { EventType } from 'matrix-js-sdk/src/@types/event'; +import ResizeNotifier from "../../utils/ResizeNotifier"; +import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; +import Spinner from "../views/elements/Spinner"; +import EditorStateTransfer from '../../utils/EditorStateTransfer'; const PAGINATE_SIZE = 20; const INITIAL_SIZE = 20; @@ -45,92 +54,159 @@ const READ_RECEIPT_INTERVAL_MS = 500; const DEBUG = false; -let debuglog = function() {}; +let debuglog = function(...s: any[]) {}; if (DEBUG) { // using bind means that we get to keep useful line numbers in the console debuglog = console.log.bind(console); } +interface IProps { + // The js-sdk EventTimelineSet object for the timeline sequence we are + // representing. This may or may not have a room, depending on what it's + // a timeline representing. If it has a room, we maintain RRs etc for + // that room. + timelineSet: TimelineSet; + showReadReceipts?: boolean; + // Enable managing RRs and RMs. These require the timelineSet to have a room. + manageReadReceipts?: boolean; + sendReadReceiptOnLoad?: boolean; + manageReadMarkers?: boolean; + + // true to give the component a 'display: none' style. + hidden?: boolean; + + // ID of an event to highlight. If undefined, no event will be highlighted. + // typically this will be either 'eventId' or undefined. + highlightedEventId?: string; + + // id of an event to jump to. If not given, will go to the end of the live timeline. + eventId?: string; + + // where to position the event given by eventId, in pixels from the bottom of the viewport. + // If not given, will try to put the event half way down the viewport. + eventPixelOffset?: number; + + // Should we show URL Previews + showUrlPreview?: boolean; + + // maximum number of events to show in a timeline + timelineCap?: number; + + // classname to use for the messagepanel + className?: string; + + // shape property to be passed to EventTiles + tileShape?: TileShape; + + // placeholder to use if the timeline is empty + empty?: ReactNode; + + // whether to show reactions for an event + showReactions?: boolean; + + // which layout to use + layout?: Layout; + + // whether to always show timestamps for an event + alwaysShowTimestamps?: boolean; + + resizeNotifier?: ResizeNotifier; + editState?: EditorStateTransfer; + permalinkCreator?: RoomPermalinkCreator; + membersLoaded?: boolean; + + // callback which is called when the panel is scrolled. + onScroll?(event: Event): void; + + // callback which is called when the user interacts with the room timeline + onUserScroll?(event: SyntheticEvent): void; + + // callback which is called when the read-up-to mark is updated. + onReadMarkerUpdated?(): void; + + // callback which is called when we wish to paginate the timeline window. + onPaginationRequest?(timelineWindow: TimelineWindow, direction: string, size: number): Promise, +} + +interface IState { + events: MatrixEvent[]; + liveEvents: MatrixEvent[]; + // track whether our room timeline is loading + timelineLoading: boolean; + + // the index of the first event that is to be shown + firstVisibleEventIndex: number; + + // canBackPaginate == false may mean: + // + // * we haven't (successfully) loaded the timeline yet, or: + // + // * we have got to the point where the room was created, or: + // + // * the server indicated that there were no more visible events + // (normally implying we got to the start of the room), or: + // + // * we gave up asking the server for more events + canBackPaginate: boolean; + + // canForwardPaginate == false may mean: + // + // * we haven't (successfully) loaded the timeline yet + // + // * we have got to the end of time and are now tracking the live + // timeline, or: + // + // * the server indicated that there were no more visible events + // (not sure if this ever happens when we're not at the live + // timeline), or: + // + // * we are looking at some historical point, but gave up asking + // the server for more events + canForwardPaginate: boolean; + + // start with the read-marker visible, so that we see its animated + // disappearance when switching into the room. + readMarkerVisible: boolean; + + readMarkerEventId: string; + + backPaginating: boolean; + forwardPaginating: boolean; + + // cache of matrixClient.getSyncState() (but from the 'sync' event) + clientSyncState: SyncState; + + // should the event tiles have twelve hour times + isTwelveHour: boolean; + + // always show timestamps on event tiles? + alwaysShowTimestamps: boolean; + + // how long to show the RM for when it's visible in the window + readMarkerInViewThresholdMs: number; + + // how long to show the RM for when it's scrolled off-screen + readMarkerOutOfViewThresholdMs: number; + + editState?: EditorStateTransfer; +} + +interface IEventIndexOpts { + ignoreOwn?: boolean; + allowPartial?: boolean; +} + /* * Component which shows the event timeline in a room view. * * Also responsible for handling and sending read receipts. */ @replaceableComponent("structures.TimelinePanel") -class TimelinePanel extends React.Component { - static propTypes = { - // The js-sdk EventTimelineSet object for the timeline sequence we are - // representing. This may or may not have a room, depending on what it's - // a timeline representing. If it has a room, we maintain RRs etc for - // that room. - timelineSet: PropTypes.object.isRequired, - - showReadReceipts: PropTypes.bool, - // Enable managing RRs and RMs. These require the timelineSet to have a room. - manageReadReceipts: PropTypes.bool, - sendReadReceiptOnLoad: PropTypes.bool, - manageReadMarkers: PropTypes.bool, - // with this enabled it'll listen and react to Action.ComposerInsert and `edit_event` - manageComposerDispatches: PropTypes.bool, - - // true to give the component a 'display: none' style. - hidden: PropTypes.bool, - - // ID of an event to highlight. If undefined, no event will be highlighted. - // typically this will be either 'eventId' or undefined. - highlightedEventId: PropTypes.string, - - // id of an event to jump to. If not given, will go to the end of the - // live timeline. - eventId: PropTypes.string, - - // where to position the event given by eventId, in pixels from the - // bottom of the viewport. If not given, will try to put the event - // half way down the viewport. - eventPixelOffset: PropTypes.number, - - // Should we show URL Previews - showUrlPreview: PropTypes.bool, - - // callback which is called when the panel is scrolled. - onScroll: PropTypes.func, - - // callback which is called when the user interacts with the room timeline - onUserScroll: PropTypes.func, - - // callback which is called when the read-up-to mark is updated. - onReadMarkerUpdated: PropTypes.func, - - // callback which is called when we wish to paginate the timeline - // window. - onPaginationRequest: PropTypes.func, - - // maximum number of events to show in a timeline - timelineCap: PropTypes.number, - - // classname to use for the messagepanel - className: PropTypes.string, - - // shape property to be passed to EventTiles - tileShape: PropTypes.string, - - // placeholder to use if the timeline is empty - empty: PropTypes.node, - - // whether to show reactions for an event - showReactions: PropTypes.bool, - - // which layout to use - layout: LayoutPropType, - - // whether to always show timestamps for an event - alwaysShowTimestamps: PropTypes.bool, - } - +class TimelinePanel extends React.Component { static contextType = RoomContext; // a map from room id to read marker event timestamp - static roomReadMarkerTsMap = {}; + static roomReadMarkerTsMap: Record = {}; static defaultProps = { // By default, disable the timelineCap in favour of unpaginating based on @@ -140,16 +216,21 @@ class TimelinePanel extends React.Component { sendReadReceiptOnLoad: true, }; - constructor(props) { - super(props); + private lastRRSentEventId: string = undefined; + private lastRMSentEventId: string = undefined; + + private readonly messagePanel = createRef(); + private readonly dispatcherRef: string; + private timelineWindow?: TimelineWindow; + private unmounted = false; + private readReceiptActivityTimer: Timer; + private readMarkerActivityTimer: Timer; + + constructor(props, context) { + super(props, context); debuglog("TimelinePanel: mounting"); - this.lastRRSentEventId = undefined; - this.lastRMSentEventId = undefined; - - this._messagePanel = createRef(); - // XXX: we could track RM per TimelineSet rather than per Room. // but for now we just do it per room for simplicity. let initialReadMarker = null; @@ -158,82 +239,41 @@ class TimelinePanel extends React.Component { if (readmarker) { initialReadMarker = readmarker.getContent().event_id; } else { - initialReadMarker = this._getCurrentReadReceipt(); + initialReadMarker = this.getCurrentReadReceipt(); } } this.state = { events: [], liveEvents: [], - timelineLoading: true, // track whether our room timeline is loading - - // the index of the first event that is to be shown + timelineLoading: true, firstVisibleEventIndex: 0, - - // canBackPaginate == false may mean: - // - // * we haven't (successfully) loaded the timeline yet, or: - // - // * we have got to the point where the room was created, or: - // - // * the server indicated that there were no more visible events - // (normally implying we got to the start of the room), or: - // - // * we gave up asking the server for more events canBackPaginate: false, - - // canForwardPaginate == false may mean: - // - // * we haven't (successfully) loaded the timeline yet - // - // * we have got to the end of time and are now tracking the live - // timeline, or: - // - // * the server indicated that there were no more visible events - // (not sure if this ever happens when we're not at the live - // timeline), or: - // - // * we are looking at some historical point, but gave up asking - // the server for more events canForwardPaginate: false, - - // start with the read-marker visible, so that we see its animated - // disappearance when switching into the room. readMarkerVisible: true, - readMarkerEventId: initialReadMarker, - backPaginating: false, forwardPaginating: false, - - // cache of matrixClient.getSyncState() (but from the 'sync' event) clientSyncState: MatrixClientPeg.get().getSyncState(), - - // should the event tiles have twelve hour times isTwelveHour: SettingsStore.getValue("showTwelveHourTimestamps"), - - // always show timestamps on event tiles? alwaysShowTimestamps: SettingsStore.getValue("alwaysShowTimestamps"), - - // how long to show the RM for when it's visible in the window readMarkerInViewThresholdMs: SettingsStore.getValue("readMarkerInViewThresholdMs"), - - // how long to show the RM for when it's scrolled off-screen readMarkerOutOfViewThresholdMs: SettingsStore.getValue("readMarkerOutOfViewThresholdMs"), }; this.dispatcherRef = dis.register(this.onAction); - MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().on("Room.timelineReset", this.onRoomTimelineReset); - MatrixClientPeg.get().on("Room.redaction", this.onRoomRedaction); + const cli = MatrixClientPeg.get(); + cli.on("Room.timeline", this.onRoomTimeline); + cli.on("Room.timelineReset", this.onRoomTimelineReset); + cli.on("Room.redaction", this.onRoomRedaction); // same event handler as Room.redaction as for both we just do forceUpdate - MatrixClientPeg.get().on("Room.redactionCancelled", this.onRoomRedaction); - MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt); - MatrixClientPeg.get().on("Room.localEchoUpdated", this.onLocalEchoUpdated); - MatrixClientPeg.get().on("Room.accountData", this.onAccountData); - MatrixClientPeg.get().on("Event.decrypted", this.onEventDecrypted); - MatrixClientPeg.get().on("Event.replaced", this.onEventReplaced); - MatrixClientPeg.get().on("sync", this.onSync); + cli.on("Room.redactionCancelled", this.onRoomRedaction); + cli.on("Room.receipt", this.onRoomReceipt); + cli.on("Room.localEchoUpdated", this.onLocalEchoUpdated); + cli.on("Room.accountData", this.onAccountData); + cli.on("Event.decrypted", this.onEventDecrypted); + cli.on("Event.replaced", this.onEventReplaced); + cli.on("sync", this.onSync); } // TODO: [REACT-WARNING] Move into constructor @@ -246,7 +286,7 @@ class TimelinePanel extends React.Component { this.updateReadMarkerOnUserActivity(); } - this._initTimeline(this.props); + this.initTimeline(this.props); } // TODO: [REACT-WARNING] Replace with appropriate lifecycle event @@ -272,7 +312,7 @@ class TimelinePanel extends React.Component { if (differentEventId || differentHighlightedEventId) { console.log("TimelinePanel switching to eventId " + newProps.eventId + " (was " + this.props.eventId + ")"); - return this._initTimeline(newProps); + return this.initTimeline(newProps); } } @@ -282,13 +322,13 @@ class TimelinePanel extends React.Component { // // (We could use isMounted, but facebook have deprecated that.) this.unmounted = true; - if (this._readReceiptActivityTimer) { - this._readReceiptActivityTimer.abort(); - this._readReceiptActivityTimer = null; + if (this.readReceiptActivityTimer) { + this.readReceiptActivityTimer.abort(); + this.readReceiptActivityTimer = null; } - if (this._readMarkerActivityTimer) { - this._readMarkerActivityTimer.abort(); - this._readMarkerActivityTimer = null; + if (this.readMarkerActivityTimer) { + this.readMarkerActivityTimer.abort(); + this.readMarkerActivityTimer = null; } dis.unregister(this.dispatcherRef); @@ -308,7 +348,7 @@ class TimelinePanel extends React.Component { } } - onMessageListUnfillRequest = (backwards, scrollToken) => { + private onMessageListUnfillRequest = (backwards: boolean, scrollToken: string): void => { // If backwards, unpaginate from the back (i.e. the start of the timeline) const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS; debuglog("TimelinePanel: unpaginating events in direction", dir); @@ -327,21 +367,30 @@ class TimelinePanel extends React.Component { if (count > 0) { debuglog("TimelinePanel: Unpaginating", count, "in direction", dir); - this._timelineWindow.unpaginate(count, backwards); + this.timelineWindow.unpaginate(count, backwards); - // We can now paginate in the unpaginated direction - const canPaginateKey = (backwards) ? 'canBackPaginate' : 'canForwardPaginate'; - const { events, liveEvents, firstVisibleEventIndex } = this._getEvents(); - this.setState({ - [canPaginateKey]: true, + const { events, liveEvents, firstVisibleEventIndex } = this.getEvents(); + const newState: Partial = { events, liveEvents, firstVisibleEventIndex, - }); + }; + + // We can now paginate in the unpaginated direction + if (backwards) { + newState.canBackPaginate = true; + } else { + newState.canForwardPaginate = true; + } + this.setState(newState); } }; - onPaginationRequest = (timelineWindow, direction, size) => { + private onPaginationRequest = ( + timelineWindow: TimelineWindow, + direction: string, + size: number, + ): Promise => { if (this.props.onPaginationRequest) { return this.props.onPaginationRequest(timelineWindow, direction, size); } else { @@ -350,8 +399,8 @@ class TimelinePanel extends React.Component { }; // set off a pagination request. - onMessageListFillRequest = backwards => { - if (!this._shouldPaginate()) return Promise.resolve(false); + private onMessageListFillRequest = (backwards: boolean): Promise => { + if (!this.shouldPaginate()) return Promise.resolve(false); const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS; const canPaginateKey = backwards ? 'canBackPaginate' : 'canForwardPaginate'; @@ -362,9 +411,9 @@ class TimelinePanel extends React.Component { return Promise.resolve(false); } - if (!this._timelineWindow.canPaginate(dir)) { + if (!this.timelineWindow.canPaginate(dir)) { debuglog("TimelinePanel: can't", dir, "paginate any further"); - this.setState({[canPaginateKey]: false}); + this.setState({ [canPaginateKey]: false }); return Promise.resolve(false); } @@ -374,15 +423,15 @@ class TimelinePanel extends React.Component { } debuglog("TimelinePanel: Initiating paginate; backwards:"+backwards); - this.setState({[paginatingKey]: true}); + this.setState({ [paginatingKey]: true }); - return this.onPaginationRequest(this._timelineWindow, dir, PAGINATE_SIZE).then((r) => { + return this.onPaginationRequest(this.timelineWindow, dir, PAGINATE_SIZE).then((r) => { if (this.unmounted) { return; } debuglog("TimelinePanel: paginate complete backwards:"+backwards+"; success:"+r); - const { events, liveEvents, firstVisibleEventIndex } = this._getEvents(); - const newState = { + const { events, liveEvents, firstVisibleEventIndex } = this.getEvents(); + const newState: Partial = { [paginatingKey]: false, [canPaginateKey]: r, events, @@ -395,7 +444,7 @@ class TimelinePanel extends React.Component { const otherDirection = backwards ? EventTimeline.FORWARDS : EventTimeline.BACKWARDS; const canPaginateOtherWayKey = backwards ? 'canForwardPaginate' : 'canBackPaginate'; if (!this.state[canPaginateOtherWayKey] && - this._timelineWindow.canPaginate(otherDirection)) { + this.timelineWindow.canPaginate(otherDirection)) { debuglog('TimelinePanel: can now', otherDirection, 'paginate again'); newState[canPaginateOtherWayKey] = true; } @@ -406,9 +455,9 @@ class TimelinePanel extends React.Component { // has in memory because we never gave the component a chance to scroll // itself into the right place return new Promise((resolve) => { - this.setState(newState, () => { + this.setState(newState, () => { // we can continue paginating in the given direction if: - // - _timelineWindow.paginate says we can + // - timelineWindow.paginate says we can // - we're paginating forwards, or we won't be trying to // paginate backwards past the first visible event resolve(r && (!backwards || firstVisibleEventIndex === 0)); @@ -417,7 +466,7 @@ class TimelinePanel extends React.Component { }); }; - onMessageListScroll = e => { + private onMessageListScroll = e => { if (this.props.onScroll) { this.props.onScroll(e); } @@ -428,18 +477,18 @@ class TimelinePanel extends React.Component { // it goes back off the top of the screen (presumably because the user // clicks on the 'jump to bottom' button), we need to re-enable it. if (rmPosition < 0) { - this.setState({readMarkerVisible: true}); + this.setState({ readMarkerVisible: true }); } // if read marker position goes between 0 and -1/1, // (and user is active), switch timeout - const timeout = this._readMarkerTimeout(rmPosition); + const timeout = this.readMarkerTimeout(rmPosition); // NO-OP when timeout already has set to the given value - this._readMarkerActivityTimer.changeTimeout(timeout); + this.readMarkerActivityTimer.changeTimeout(timeout); } }; - onAction = payload => { + private onAction = (payload: ActionPayload): void => { switch (payload.action) { case "ignore_state_changed": this.forceUpdate(); @@ -447,7 +496,16 @@ class TimelinePanel extends React.Component { } }; - onRoomTimeline = (ev, room, toStartOfTimeline, removed, data) => { + private onRoomTimeline = ( + ev: MatrixEvent, + room: Room, + toStartOfTimeline: boolean, + removed: boolean, + data: { + timeline: EventTimeline; + liveEvent?: boolean; + }, + ): void => { // ignore events for other timeline sets if (data.timeline.getTimelineSet() !== this.props.timelineSet) return; @@ -455,13 +513,13 @@ class TimelinePanel extends React.Component { // updates from pagination will happen when the paginate completes. if (toStartOfTimeline || !data || !data.liveEvent) return; - if (!this._messagePanel.current) return; + if (!this.messagePanel.current) return; - if (!this._messagePanel.current.getScrollState().stuckAtBottom) { + if (!this.messagePanel.current.getScrollState().stuckAtBottom) { // we won't load this event now, because we don't want to push any // events off the other end of the timeline. But we need to note // that we can now paginate. - this.setState({canForwardPaginate: true}); + this.setState({ canForwardPaginate: true }); return; } @@ -474,13 +532,13 @@ class TimelinePanel extends React.Component { // timeline window. // // see https://github.com/vector-im/vector-web/issues/1035 - this._timelineWindow.paginate(EventTimeline.FORWARDS, 1, false).then(() => { + this.timelineWindow.paginate(EventTimeline.FORWARDS, 1, false).then(() => { if (this.unmounted) { return; } - const { events, liveEvents, firstVisibleEventIndex } = this._getEvents(); + const { events, liveEvents, firstVisibleEventIndex } = this.getEvents(); const lastLiveEvent = liveEvents[liveEvents.length - 1]; - const updatedState = { + const updatedState: Partial = { events, liveEvents, firstVisibleEventIndex, @@ -505,15 +563,15 @@ class TimelinePanel extends React.Component { // we know we're stuckAtBottom, so we can advance the RM // immediately, to save a later render cycle - this._setReadMarker(lastLiveEvent.getId(), lastLiveEvent.getTs(), true); + this.setReadMarker(lastLiveEvent.getId(), lastLiveEvent.getTs(), true); updatedState.readMarkerVisible = false; updatedState.readMarkerEventId = lastLiveEvent.getId(); callRMUpdated = true; } } - this.setState(updatedState, () => { - this._messagePanel.current.updateTimelineMinHeight(); + this.setState(updatedState, () => { + this.messagePanel.current.updateTimelineMinHeight(); if (callRMUpdated) { this.props.onReadMarkerUpdated(); } @@ -521,17 +579,17 @@ class TimelinePanel extends React.Component { }); }; - onRoomTimelineReset = (room, timelineSet) => { + private onRoomTimelineReset = (room: Room, timelineSet: TimelineSet): void => { if (timelineSet !== this.props.timelineSet) return; - if (this._messagePanel.current && this._messagePanel.current.isAtBottom()) { - this._loadTimeline(); + if (this.messagePanel.current && this.messagePanel.current.isAtBottom()) { + this.loadTimeline(); } }; - canResetTimeline = () => this._messagePanel.current && this._messagePanel.current.isAtBottom(); + public canResetTimeline = () => this.messagePanel?.current.isAtBottom(); - onRoomRedaction = (ev, room) => { + private onRoomRedaction = (ev: MatrixEvent, room: Room): void => { if (this.unmounted) return; // ignore events for other rooms @@ -542,7 +600,7 @@ class TimelinePanel extends React.Component { this.forceUpdate(); }; - onEventReplaced = (replacedEvent, room) => { + private onEventReplaced = (replacedEvent: MatrixEvent, room: Room): void => { if (this.unmounted) return; // ignore events for other rooms @@ -553,7 +611,7 @@ class TimelinePanel extends React.Component { this.forceUpdate(); }; - onRoomReceipt = (ev, room) => { + private onRoomReceipt = (ev: MatrixEvent, room: Room): void => { if (this.unmounted) return; // ignore events for other rooms @@ -562,22 +620,22 @@ class TimelinePanel extends React.Component { this.forceUpdate(); }; - onLocalEchoUpdated = (ev, room, oldEventId) => { + private onLocalEchoUpdated = (ev: MatrixEvent, room: Room, oldEventId: string): void => { if (this.unmounted) return; // ignore events for other rooms if (room !== this.props.timelineSet.room) return; - this._reloadEvents(); + this.reloadEvents(); }; - onAccountData = (ev, room) => { + private onAccountData = (ev: MatrixEvent, room: Room): void => { if (this.unmounted) return; // ignore events for other rooms if (room !== this.props.timelineSet.room) return; - if (ev.getType() !== "m.fully_read") return; + if (ev.getType() !== EventType.FullyRead) return; // XXX: roomReadMarkerTsMap not updated here so it is now inconsistent. Replace // this mechanism of determining where the RM is relative to the view-port with @@ -587,7 +645,7 @@ class TimelinePanel extends React.Component { }, this.props.onReadMarkerUpdated); }; - onEventDecrypted = ev => { + private onEventDecrypted = (ev: MatrixEvent): void => { // Can be null for the notification timeline, etc. if (!this.props.timelineSet.room) return; @@ -602,46 +660,46 @@ class TimelinePanel extends React.Component { } }; - onSync = (state, prevState, data) => { - this.setState({clientSyncState: state}); + private onSync = (clientSyncState: SyncState, prevState: SyncState, data: object): void => { + this.setState({ clientSyncState }); }; - _readMarkerTimeout(readMarkerPosition) { + private readMarkerTimeout(readMarkerPosition: number): number { return readMarkerPosition === 0 ? this.state.readMarkerInViewThresholdMs : this.state.readMarkerOutOfViewThresholdMs; } - async updateReadMarkerOnUserActivity() { - const initialTimeout = this._readMarkerTimeout(this.getReadMarkerPosition()); - this._readMarkerActivityTimer = new Timer(initialTimeout); + private async updateReadMarkerOnUserActivity(): Promise { + const initialTimeout = this.readMarkerTimeout(this.getReadMarkerPosition()); + this.readMarkerActivityTimer = new Timer(initialTimeout); - while (this._readMarkerActivityTimer) { //unset on unmount - UserActivity.sharedInstance().timeWhileActiveRecently(this._readMarkerActivityTimer); + while (this.readMarkerActivityTimer) { //unset on unmount + UserActivity.sharedInstance().timeWhileActiveRecently(this.readMarkerActivityTimer); try { - await this._readMarkerActivityTimer.finished(); + await this.readMarkerActivityTimer.finished(); } catch (e) { continue; /* aborted */ } // outside of try/catch to not swallow errors this.updateReadMarker(); } } - async updateReadReceiptOnUserActivity() { - this._readReceiptActivityTimer = new Timer(READ_RECEIPT_INTERVAL_MS); - while (this._readReceiptActivityTimer) { //unset on unmount - UserActivity.sharedInstance().timeWhileActiveNow(this._readReceiptActivityTimer); + private async updateReadReceiptOnUserActivity(): Promise { + this.readReceiptActivityTimer = new Timer(READ_RECEIPT_INTERVAL_MS); + while (this.readReceiptActivityTimer) { //unset on unmount + UserActivity.sharedInstance().timeWhileActiveNow(this.readReceiptActivityTimer); try { - await this._readReceiptActivityTimer.finished(); + await this.readReceiptActivityTimer.finished(); } catch (e) { continue; /* aborted */ } // outside of try/catch to not swallow errors this.sendReadReceipt(); } } - sendReadReceipt = () => { + private sendReadReceipt = (): void => { if (SettingsStore.getValue("lowBandwidth")) return; - if (!this._messagePanel.current) return; + if (!this.messagePanel.current) return; if (!this.props.manageReadReceipts) return; // This happens on user_activity_end which is delayed, and it's // very possible have logged out within that timeframe, so check @@ -652,8 +710,8 @@ class TimelinePanel extends React.Component { let shouldSendRR = true; - const currentRREventId = this._getCurrentReadReceipt(true); - const currentRREventIndex = this._indexForEventId(currentRREventId); + const currentRREventId = this.getCurrentReadReceipt(true); + const currentRREventIndex = this.indexForEventId(currentRREventId); // We want to avoid sending out read receipts when we are looking at // events in the past which are before the latest RR. // @@ -668,11 +726,11 @@ class TimelinePanel extends React.Component { // the user eventually hits the live timeline. // if (currentRREventId && currentRREventIndex === null && - this._timelineWindow.canPaginate(EventTimeline.FORWARDS)) { + this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) { shouldSendRR = false; } - const lastReadEventIndex = this._getLastDisplayedEventIndex({ + const lastReadEventIndex = this.getLastDisplayedEventIndex({ ignoreOwn: true, }); if (lastReadEventIndex === null) { @@ -746,7 +804,7 @@ class TimelinePanel extends React.Component { // if the read marker is on the screen, we can now assume we've caught up to the end // of the screen, so move the marker down to the bottom of the screen. - updateReadMarker = () => { + private updateReadMarker = (): void => { if (!this.props.manageReadMarkers) return; if (this.getReadMarkerPosition() === 1) { // the read marker is at an event below the viewport, @@ -756,7 +814,7 @@ class TimelinePanel extends React.Component { // move the RM to *after* the message at the bottom of the screen. This // avoids a problem whereby we never advance the RM if there is a huge // message which doesn't fit on the screen. - const lastDisplayedIndex = this._getLastDisplayedEventIndex({ + const lastDisplayedIndex = this.getLastDisplayedEventIndex({ allowPartial: true, }); @@ -764,7 +822,7 @@ class TimelinePanel extends React.Component { return; } const lastDisplayedEvent = this.state.events[lastDisplayedIndex]; - this._setReadMarker( + this.setReadMarker( lastDisplayedEvent.getId(), lastDisplayedEvent.getTs(), ); @@ -781,15 +839,14 @@ class TimelinePanel extends React.Component { this.sendReadReceipt(); }; - // advance the read marker past any events we sent ourselves. - _advanceReadMarkerPastMyEvents() { + private advanceReadMarkerPastMyEvents(): void { if (!this.props.manageReadMarkers) return; - // we call `_timelineWindow.getEvents()` rather than using + // we call `timelineWindow.getEvents()` rather than using // `this.state.liveEvents`, because React batches the update to the // latter, so it may not have been updated yet. - const events = this._timelineWindow.getEvents(); + const events = this.timelineWindow.getEvents(); // first find where the current RM is let i; @@ -814,51 +871,47 @@ class TimelinePanel extends React.Component { i--; const ev = events[i]; - this._setReadMarker(ev.getId(), ev.getTs()); + this.setReadMarker(ev.getId(), ev.getTs()); } /* jump down to the bottom of this room, where new events are arriving */ - jumpToLiveTimeline = () => { + public jumpToLiveTimeline = (): void => { // if we can't forward-paginate the existing timeline, then there // is no point reloading it - just jump straight to the bottom. // // Otherwise, reload the timeline rather than trying to paginate // through all of space-time. - if (this._timelineWindow.canPaginate(EventTimeline.FORWARDS)) { - this._loadTimeline(); + if (this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) { + this.loadTimeline(); } else { - if (this._messagePanel.current) { - this._messagePanel.current.scrollToBottom(); - } + this.messagePanel.current?.scrollToBottom(); } }; - scrollToEventIfNeeded = (eventId) => { - if (this._messagePanel.current) { - this._messagePanel.current.scrollToEventIfNeeded(eventId); - } - } + public scrollToEventIfNeeded = (eventId: string): void => { + this.messagePanel.current?.scrollToEventIfNeeded(eventId); + }; /* scroll to show the read-up-to marker. We put it 1/3 of the way down * the container. */ - jumpToReadMarker = () => { + public jumpToReadMarker = (): void => { if (!this.props.manageReadMarkers) return; - if (!this._messagePanel.current) return; + if (!this.messagePanel.current) return; if (!this.state.readMarkerEventId) return; // we may not have loaded the event corresponding to the read-marker - // into the _timelineWindow. In that case, attempts to scroll to it + // into the timelineWindow. In that case, attempts to scroll to it // will fail. // // a quick way to figure out if we've loaded the relevant event is // simply to check if the messagepanel knows where the read-marker is. - const ret = this._messagePanel.current.getReadMarkerPosition(); + const ret = this.messagePanel.current.getReadMarkerPosition(); if (ret !== null) { // The messagepanel knows where the RM is, so we must have loaded // the relevant event. - this._messagePanel.current.scrollToEvent(this.state.readMarkerEventId, + this.messagePanel.current.scrollToEvent(this.state.readMarkerEventId, 0, 1/3); return; } @@ -866,15 +919,15 @@ class TimelinePanel extends React.Component { // Looks like we haven't loaded the event corresponding to the read-marker. // As with jumpToLiveTimeline, we want to reload the timeline around the // read-marker. - this._loadTimeline(this.state.readMarkerEventId, 0, 1/3); + this.loadTimeline(this.state.readMarkerEventId, 0, 1/3); }; /* update the read-up-to marker to match the read receipt */ - forgetReadMarker = () => { + public forgetReadMarker = (): void => { if (!this.props.manageReadMarkers) return; - const rmId = this._getCurrentReadReceipt(); + const rmId = this.getCurrentReadReceipt(); // see if we know the timestamp for the rr event const tl = this.props.timelineSet.getTimelineForEvent(rmId); @@ -886,28 +939,26 @@ class TimelinePanel extends React.Component { } } - this._setReadMarker(rmId, rmTs); + this.setReadMarker(rmId, rmTs); }; /* return true if the content is fully scrolled down and we are * at the end of the live timeline. */ - isAtEndOfLiveTimeline = () => { - return this._messagePanel.current - && this._messagePanel.current.isAtBottom() - && this._timelineWindow - && !this._timelineWindow.canPaginate(EventTimeline.FORWARDS); - } - + public isAtEndOfLiveTimeline = (): boolean => { + return this.messagePanel.current?.isAtBottom() + && this.timelineWindow + && !this.timelineWindow.canPaginate(EventTimeline.FORWARDS); + }; /* get the current scroll state. See ScrollPanel.getScrollState for * details. * * returns null if we are not mounted. */ - getScrollState = () => { - if (!this._messagePanel.current) { return null; } - return this._messagePanel.current.getScrollState(); + public getScrollState = (): IScrollState => { + if (!this.messagePanel.current) { return null; } + return this.messagePanel.current.getScrollState(); }; // returns one of: @@ -916,11 +967,11 @@ class TimelinePanel extends React.Component { // -1: read marker is above the window // 0: read marker is visible // +1: read marker is below the window - getReadMarkerPosition = () => { + public getReadMarkerPosition = (): number => { if (!this.props.manageReadMarkers) return null; - if (!this._messagePanel.current) return null; + if (!this.messagePanel.current) return null; - const ret = this._messagePanel.current.getReadMarkerPosition(); + const ret = this.messagePanel.current.getReadMarkerPosition(); if (ret !== null) { return ret; } @@ -939,7 +990,7 @@ class TimelinePanel extends React.Component { return null; }; - canJumpToReadMarker = () => { + public canJumpToReadMarker = (): boolean => { // 1. Do not show jump bar if neither the RM nor the RR are set. // 3. We want to show the bar if the read-marker is off the top of the screen. // 4. Also, if pos === null, the event might not be paginated - show the unread bar @@ -954,19 +1005,19 @@ class TimelinePanel extends React.Component { * * We pass it down to the scroll panel. */ - handleScrollKey = ev => { - if (!this._messagePanel.current) { return; } + public handleScrollKey = ev => { + if (!this.messagePanel.current) { return; } // jump to the live timeline on ctrl-end, rather than the end of the // timeline window. if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.END) { this.jumpToLiveTimeline(); } else { - this._messagePanel.current.handleScrollKey(ev); + this.messagePanel.current.handleScrollKey(ev); } }; - _initTimeline(props) { + private initTimeline(props: IProps): void { const initialEvent = props.eventId; const pixelOffset = props.eventPixelOffset; @@ -977,7 +1028,7 @@ class TimelinePanel extends React.Component { offsetBase = 0.5; } - return this._loadTimeline(initialEvent, pixelOffset, offsetBase); + return this.loadTimeline(initialEvent, pixelOffset, offsetBase); } /** @@ -993,34 +1044,32 @@ class TimelinePanel extends React.Component { * @param {number?} offsetBase the reference point for the pixelOffset. 0 * means the top of the container, 1 means the bottom, and fractional * values mean somewhere in the middle. If omitted, it defaults to 0. - * - * returns a promise which will resolve when the load completes. */ - _loadTimeline(eventId, pixelOffset, offsetBase) { - this._timelineWindow = new TimelineWindow( + private loadTimeline(eventId?: string, pixelOffset?: number, offsetBase?: number): void { + this.timelineWindow = new TimelineWindow( MatrixClientPeg.get(), this.props.timelineSet, - {windowLimit: this.props.timelineCap}); + { windowLimit: this.props.timelineCap }); const onLoaded = () => { // clear the timeline min-height when // (re)loading the timeline - if (this._messagePanel.current) { - this._messagePanel.current.onTimelineReset(); + if (this.messagePanel.current) { + this.messagePanel.current.onTimelineReset(); } - this._reloadEvents(); + this.reloadEvents(); // If we switched away from the room while there were pending // outgoing events, the read-marker will be before those events. // We need to skip over any which have subsequently been sent. - this._advanceReadMarkerPastMyEvents(); + this.advanceReadMarkerPastMyEvents(); this.setState({ - canBackPaginate: this._timelineWindow.canPaginate(EventTimeline.BACKWARDS), - canForwardPaginate: this._timelineWindow.canPaginate(EventTimeline.FORWARDS), + canBackPaginate: this.timelineWindow.canPaginate(EventTimeline.BACKWARDS), + canForwardPaginate: this.timelineWindow.canPaginate(EventTimeline.FORWARDS), timelineLoading: false, }, () => { // initialise the scroll state of the message panel - if (!this._messagePanel.current) { + if (!this.messagePanel.current) { // this shouldn't happen - we know we're mounted because // we're in a setState callback, and we know // timelineLoading is now false, so render() should have @@ -1030,10 +1079,10 @@ class TimelinePanel extends React.Component { return; } if (eventId) { - this._messagePanel.current.scrollToEvent(eventId, pixelOffset, + this.messagePanel.current.scrollToEvent(eventId, pixelOffset, offsetBase); } else { - this._messagePanel.current.scrollToBottom(); + this.messagePanel.current.scrollToBottom(); } if (this.props.sendReadReceiptOnLoad) { @@ -1095,10 +1144,10 @@ class TimelinePanel extends React.Component { if (timeline) { // This is a hot-path optimization by skipping a promise tick // by repeating a no-op sync branch in TimelineSet.getTimelineForEvent & MatrixClient.getEventTimeline - this._timelineWindow.load(eventId, INITIAL_SIZE); // in this branch this method will happen in sync time + this.timelineWindow.load(eventId, INITIAL_SIZE); // in this branch this method will happen in sync time onLoaded(); } else { - const prom = this._timelineWindow.load(eventId, INITIAL_SIZE); + const prom = this.timelineWindow.load(eventId, INITIAL_SIZE); this.setState({ events: [], liveEvents: [], @@ -1113,17 +1162,17 @@ class TimelinePanel extends React.Component { // handle the completion of a timeline load or localEchoUpdate, by // reloading the events from the timelinewindow and pending event list into // the state. - _reloadEvents() { + private reloadEvents(): void { // we might have switched rooms since the load started - just bin // the results if so. if (this.unmounted) return; - this.setState(this._getEvents()); + this.setState(this.getEvents()); } // get the list of events from the timeline window and the pending event list - _getEvents() { - const events = this._timelineWindow.getEvents(); + private getEvents(): Pick { + const events: MatrixEvent[] = this.timelineWindow.getEvents(); // `arrayFastClone` performs a shallow copy of the array // we want the last event to be decrypted first but displayed last @@ -1135,14 +1184,14 @@ class TimelinePanel extends React.Component { client.decryptEventIfNeeded(event); }); - const firstVisibleEventIndex = this._checkForPreJoinUISI(events); + const firstVisibleEventIndex = this.checkForPreJoinUISI(events); // Hold onto the live events separately. The read receipt and read marker // should use this list, so that they don't advance into pending events. const liveEvents = [...events]; // if we're at the end of the live timeline, append the pending events - if (!this._timelineWindow.canPaginate(EventTimeline.FORWARDS)) { + if (!this.timelineWindow.canPaginate(EventTimeline.FORWARDS)) { events.push(...this.props.timelineSet.getPendingEvents()); } @@ -1163,7 +1212,7 @@ class TimelinePanel extends React.Component { * undecryptable event that was sent while the user was not in the room. If no * such events were found, then it returns 0. */ - _checkForPreJoinUISI(events) { + private checkForPreJoinUISI(events: MatrixEvent[]): number { const room = this.props.timelineSet.room; if (events.length === 0 || !room || @@ -1227,7 +1276,7 @@ class TimelinePanel extends React.Component { return 0; } - _indexForEventId(evId) { + private indexForEventId(evId: string): number | null { for (let i = 0; i < this.state.events.length; ++i) { if (evId == this.state.events[i].getId()) { return i; @@ -1236,15 +1285,14 @@ class TimelinePanel extends React.Component { return null; } - _getLastDisplayedEventIndex(opts) { - opts = opts || {}; + private getLastDisplayedEventIndex(opts: IEventIndexOpts = {}): number | null { const ignoreOwn = opts.ignoreOwn || false; const allowPartial = opts.allowPartial || false; - const messagePanel = this._messagePanel.current; + const messagePanel = this.messagePanel.current; if (!messagePanel) return null; - const messagePanelNode = ReactDOM.findDOMNode(messagePanel); + const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as HTMLElement; if (!messagePanelNode) return null; // sometimes this happens for fresh rooms/post-sync const wrapperRect = messagePanelNode.getBoundingClientRect(); const myUserId = MatrixClientPeg.get().credentials.userId; @@ -1321,7 +1369,7 @@ class TimelinePanel extends React.Component { * SDK. * @return {String} the event ID */ - _getCurrentReadReceipt(ignoreSynthesized) { + private getCurrentReadReceipt(ignoreSynthesized = false): string { const client = MatrixClientPeg.get(); // the client can be null on logout if (client == null) { @@ -1332,7 +1380,7 @@ class TimelinePanel extends React.Component { return this.props.timelineSet.room.getEventReadUpTo(myUserId, ignoreSynthesized); } - _setReadMarker(eventId, eventTs, inhibitSetState) { + private setReadMarker(eventId: string, eventTs: number, inhibitSetState = false): void { const roomId = this.props.timelineSet.room.roomId; // don't update the state (and cause a re-render) if there is @@ -1357,7 +1405,7 @@ class TimelinePanel extends React.Component { }, this.props.onReadMarkerUpdated); } - _shouldPaginate() { + private shouldPaginate(): boolean { // don't try to paginate while events in the timeline are // still being decrypted. We don't render events while they're // being decrypted, so they don't take up space in the timeline. @@ -1368,12 +1416,9 @@ class TimelinePanel extends React.Component { }); } - getRelationsForEvent = (...args) => this.props.timelineSet.getRelationsForEvent(...args); + private getRelationsForEvent = (...args) => this.props.timelineSet.getRelationsForEvent(...args); render() { - const MessagePanel = sdk.getComponent("structures.MessagePanel"); - const Loader = sdk.getComponent("elements.Spinner"); - // just show a spinner while the timeline loads. // // put it in a div of the right class (mx_RoomView_messagePanel) so @@ -1388,7 +1433,7 @@ class TimelinePanel extends React.Component { if (this.state.timelineLoading) { return (
    - +
    ); } @@ -1409,7 +1454,7 @@ class TimelinePanel extends React.Component { // forwards, otherwise if somebody hits the bottom of the loaded // events when viewing historical messages, we get stuck in a loop // of paginating our way through the entire history of the room. - const stickyBottom = !this._timelineWindow.canPaginate(EventTimeline.FORWARDS); + const stickyBottom = !this.timelineWindow.canPaginate(EventTimeline.FORWARDS); // If the state is PREPARED or CATCHUP, we're still waiting for the js-sdk to sync with // the HS and fetch the latest events, so we are effectively forward paginating. @@ -1422,7 +1467,7 @@ class TimelinePanel extends React.Component { : this.state.events; return (
    - ) + ); } else if (hostSignupConfig) { if (hostSignupConfig && hostSignupConfig.url) { // If hostSignup.domains is set to a non-empty array, only show @@ -509,7 +509,7 @@ export default class UserMenu extends React.Component { /> - ) + ); } else if (MatrixClientPeg.get().isGuest()) { primaryOptionList = ( diff --git a/src/components/structures/UserView.js b/src/components/structures/UserView.js index 6b472783bb..eb839be7be 100644 --- a/src/components/structures/UserView.js +++ b/src/components/structures/UserView.js @@ -17,14 +17,14 @@ 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 Modal from '../../Modal'; import { _t } from '../../languageHandler'; import HomePage from "./HomePage"; -import {replaceableComponent} from "../../utils/replaceableComponent"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {RoomMember} from "matrix-js-sdk/src/models/room-member"; +import { replaceableComponent } from "../../utils/replaceableComponent"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; @replaceableComponent("structures.UserView") export default class UserView extends React.Component { @@ -56,7 +56,7 @@ export default class UserView extends React.Component { async _loadProfileInfo() { const cli = MatrixClientPeg.get(); - this.setState({loading: true}); + this.setState({ loading: true }); let profileInfo; try { profileInfo = await cli.getProfileInfo(this.props.userId); @@ -66,13 +66,13 @@ export default class UserView extends React.Component { title: _t('Could not load user profile'), description: ((err && err.message) ? err.message : _t("Operation failed")), }); - this.setState({loading: false}); + this.setState({ loading: false }); return; } - const fakeEvent = new MatrixEvent({type: "m.room.member", content: profileInfo}); + const fakeEvent = new MatrixEvent({ type: "m.room.member", content: profileInfo }); const member = new RoomMember(null, this.props.userId); member.setMembershipEvent(fakeEvent); - this.setState({member, loading: false}); + this.setState({ member, loading: false }); } render() { diff --git a/src/components/structures/auth/CompleteSecurity.js b/src/components/structures/auth/CompleteSecurity.js index 654dd9b6c8..d691f6034b 100644 --- a/src/components/structures/auth/CompleteSecurity.js +++ b/src/components/structures/auth/CompleteSecurity.js @@ -20,7 +20,7 @@ import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore'; import SetupEncryptionBody from "./SetupEncryptionBody"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("structures.auth.CompleteSecurity") export default class CompleteSecurity extends React.Component { @@ -33,12 +33,12 @@ export default class CompleteSecurity extends React.Component { const store = SetupEncryptionStore.sharedInstance(); store.on("update", this._onStoreUpdate); store.start(); - this.state = {phase: store.phase}; + this.state = { phase: store.phase }; } _onStoreUpdate = () => { const store = SetupEncryptionStore.sharedInstance(); - this.setState({phase: store.phase}); + this.setState({ phase: store.phase }); }; componentWillUnmount() { @@ -50,7 +50,7 @@ export default class CompleteSecurity extends React.Component { render() { const AuthPage = sdk.getComponent("auth.AuthPage"); const CompleteSecurityBody = sdk.getComponent("auth.CompleteSecurityBody"); - const {phase} = this.state; + const { phase } = this.state; let icon; let title; diff --git a/src/components/structures/auth/E2eSetup.js b/src/components/structures/auth/E2eSetup.js index 4e51ae828c..9b627449bc 100644 --- a/src/components/structures/auth/E2eSetup.js +++ b/src/components/structures/auth/E2eSetup.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import AuthPage from '../../views/auth/AuthPage'; import CompleteSecurityBody from '../../views/auth/CompleteSecurityBody'; import CreateCrossSigningDialog from '../../views/dialogs/security/CreateCrossSigningDialog'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("structures.auth.E2eSetup") export default class E2eSetup extends React.Component { diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 6188fdb5e4..9f2ac9deed 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -22,13 +22,13 @@ import { _t, _td } from '../../../languageHandler'; import * as sdk from '../../../index'; import Modal from "../../../Modal"; import PasswordReset from "../../../PasswordReset"; -import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import classNames from 'classnames'; import AuthPage from "../../views/auth/AuthPage"; import CountlyAnalytics from "../../../CountlyAnalytics"; import ServerPicker from "../../views/elements/ServerPicker"; import PassphraseField from '../../views/auth/PassphraseField'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm'; // Phases diff --git a/src/components/structures/auth/Login.tsx b/src/components/structures/auth/Login.tsx index d34582b0c3..61d3759dee 100644 --- a/src/components/structures/auth/Login.tsx +++ b/src/components/structures/auth/Login.tsx @@ -14,28 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ReactNode} from 'react'; -import {MatrixError} from "matrix-js-sdk/src/http-api"; +import React, { ReactNode } from 'react'; +import { MatrixError } from "matrix-js-sdk/src/http-api"; -import {_t, _td} from '../../../languageHandler'; +import { _t, _td } from '../../../languageHandler'; import * as sdk from '../../../index'; -import Login, {ISSOFlow, LoginFlow} from '../../../Login'; +import Login, { ISSOFlow, LoginFlow } from '../../../Login'; import SdkConfig from '../../../SdkConfig'; import { messageForResourceLimitError } from '../../../utils/ErrorUtils'; -import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import classNames from "classnames"; import AuthPage from "../../views/auth/AuthPage"; import PlatformPeg from '../../../PlatformPeg'; import SettingsStore from "../../../settings/SettingsStore"; -import {UIFeature} from "../../../settings/UIFeature"; +import { UIFeature } from "../../../settings/UIFeature"; import CountlyAnalytics from "../../../CountlyAnalytics"; -import {IMatrixClientCreds} from "../../../MatrixClientPeg"; +import { IMatrixClientCreds } from "../../../MatrixClientPeg"; import PasswordLogin from "../../views/auth/PasswordLogin"; import InlineSpinner from "../../views/elements/InlineSpinner"; import Spinner from "../../views/elements/Spinner"; import SSOButtons from "../../views/elements/SSOButtons"; import ServerPicker from "../../views/elements/ServerPicker"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // These are used in several places, and come from the js-sdk's autodiscovery // stuff. We define them here so that they'll be picked up by i18n. @@ -166,7 +166,7 @@ export default class LoginComponent extends React.PureComponent onPasswordLogin = async (username, phoneCountry, phoneNumber, password) => { if (!this.state.serverIsAlive) { - this.setState({busy: true}); + this.setState({ busy: true }); // Do a quick liveliness check on the URLs let aliveAgain = true; try { @@ -174,7 +174,7 @@ export default class LoginComponent extends React.PureComponent this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl, ); - this.setState({serverIsAlive: true, errorText: ""}); + this.setState({ serverIsAlive: true, errorText: "" }); } catch (e) { const componentState = AutoDiscoveryUtils.authComponentStateForError(e); this.setState({ @@ -201,7 +201,7 @@ export default class LoginComponent extends React.PureComponent this.loginLogic.loginViaPassword( username, phoneCountry, phoneNumber, password, ).then((data) => { - this.setState({serverIsAlive: true}); // it must be, we logged in. + this.setState({ serverIsAlive: true }); // it must be, we logged in. this.props.onLoggedIn(data, password); }, (error) => { if (this.unmounted) { @@ -252,7 +252,7 @@ export default class LoginComponent extends React.PureComponent
    {_t( 'Please note you are logging into the %(hs)s server, not matrix.org.', - {hs: this.props.serverConfig.hsName}, + { hs: this.props.serverConfig.hsName }, )}
    @@ -363,7 +363,7 @@ export default class LoginComponent extends React.PureComponent } }; - private async initLoginLogic({hsUrl, isUrl}: ValidatedServerConfig) { + private async initLoginLogic({ hsUrl, isUrl }: ValidatedServerConfig) { let isDefaultServer = false; if (this.props.serverConfig.isDefault && hsUrl === this.props.serverConfig.hsUrl @@ -501,9 +501,9 @@ export default class LoginComponent extends React.PureComponent return { flows.map(flow => { const stepRenderer = this.stepRendererMap[flow.type]; - return { stepRenderer() } + return { stepRenderer() }; }) } - + ; } private renderPasswordStep = () => { diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 3a4be6f0d6..f27bed2cc3 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -14,23 +14,23 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {createClient} from 'matrix-js-sdk/src/matrix'; -import React, {ReactNode} from 'react'; -import {MatrixClient} from "matrix-js-sdk/src/client"; +import { createClient } from 'matrix-js-sdk/src/matrix'; +import React, { ReactNode } from 'react'; +import { MatrixClient } from "matrix-js-sdk/src/client"; import * as sdk from '../../../index'; import { _t, _td } from '../../../languageHandler'; import { messageForResourceLimitError } from '../../../utils/ErrorUtils'; -import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import classNames from "classnames"; import * as Lifecycle from '../../../Lifecycle'; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import AuthPage from "../../views/auth/AuthPage"; -import Login, {ISSOFlow} from "../../../Login"; +import Login, { ISSOFlow } from "../../../Login"; import dis from "../../../dispatcher/dispatcher"; import SSOButtons from "../../views/elements/SSOButtons"; import ServerPicker from '../../views/elements/ServerPicker'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { serverConfig: ValidatedServerConfig; @@ -131,7 +131,7 @@ export default class Registration extends React.Component { serverDeadError: "", }; - const {hsUrl, isUrl} = this.props.serverConfig; + const { hsUrl, isUrl } = this.props.serverConfig; this.loginLogic = new Login(hsUrl, isUrl, null, { defaultDeviceDisplayName: "Element login check", // We shouldn't ever be used }); @@ -180,7 +180,7 @@ export default class Registration extends React.Component { } } - const {hsUrl, isUrl} = serverConfig; + const { hsUrl, isUrl } = serverConfig; const cli = createClient({ baseUrl: hsUrl, idBaseUrl: isUrl, @@ -230,7 +230,7 @@ export default class Registration extends React.Component { // the user off to the login page to figure their account out. if (ssoFlow) { // Redirect to login page - server probably expects SSO only - dis.dispatch({action: 'start_login'}); + dis.dispatch({ action: 'start_login' }); } else { this.setState({ serverErrorIsFatal: true, // fatal because user cannot continue on this server @@ -267,7 +267,7 @@ export default class Registration extends React.Component { session_id: sessionId, }), ); - } + }; private onUIAuthFinished = async (success: boolean, response: any) => { if (!success) { @@ -432,7 +432,7 @@ export default class Registration extends React.Component { private onLoginClickWithCheck = async ev => { ev.preventDefault(); - const sessionLoaded = await Lifecycle.loadSession({ignoreGuest: true}); + const sessionLoaded = await Lifecycle.loadSession({ ignoreGuest: true }); if (!sessionLoaded) { // ok fine, there's still no session: really go to the login page this.props.onLoginClick(); @@ -487,7 +487,13 @@ export default class Registration extends React.Component { fragmentAfterLogin={this.props.fragmentAfterLogin} />

    - { _t("%(ssoButtons)s Or %(usernamePassword)s", { ssoButtons: "", usernamePassword: ""}).trim() } + {_t( + "%(ssoButtons)s Or %(usernamePassword)s", + { + ssoButtons: "", + usernamePassword: "", + }, + ).trim()}

    ; } @@ -563,7 +569,7 @@ export default class Registration extends React.Component {

    { const sessionLoaded = await this.onLoginClickWithCheck(event); if (sessionLoaded) { - dis.dispatch({action: "view_welcome_page"}); + dis.dispatch({ action: "view_welcome_page" }); } }}> {_t("Continue with previous account")} diff --git a/src/components/structures/auth/SetupEncryptionBody.js b/src/components/structures/auth/SetupEncryptionBody.js index 90137e084c..f0798b6d1a 100644 --- a/src/components/structures/auth/SetupEncryptionBody.js +++ b/src/components/structures/auth/SetupEncryptionBody.js @@ -22,7 +22,7 @@ import Modal from '../../../Modal'; import VerificationRequestDialog from '../../views/dialogs/VerificationRequestDialog'; import * as sdk from '../../../index'; import { SetupEncryptionStore, Phase } from '../../../stores/SetupEncryptionStore'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; function keyHasPassphrase(keyInfo) { return ( diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx index fa9207efdd..7fb60a7b5d 100644 --- a/src/components/structures/auth/SoftLogout.tsx +++ b/src/components/structures/auth/SoftLogout.tsx @@ -15,17 +15,17 @@ limitations under the License. */ import React from 'react'; -import {_t} from '../../../languageHandler'; +import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import * as Lifecycle from '../../../Lifecycle'; import Modal from '../../../Modal'; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {ISSOFlow, LoginFlow, sendLoginRequest} from "../../../Login"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { ISSOFlow, LoginFlow, sendLoginRequest } from "../../../Login"; import AuthPage from "../../views/auth/AuthPage"; -import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform"; +import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../BasePlatform"; import SSOButtons from "../../views/elements/SSOButtons"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const LOGIN_VIEW = { LOADING: 1, @@ -79,7 +79,7 @@ export default class SoftLogout extends React.Component { componentDidMount(): void { // We've ended up here when we don't need to - navigate to login if (!Lifecycle.isSoftLogout()) { - dis.dispatch({action: "start_login"}); + dis.dispatch({ action: "start_login" }); return; } @@ -109,7 +109,7 @@ export default class SoftLogout extends React.Component { const queryParams = this.props.realQueryParams; const hasAllParams = queryParams && queryParams['loginToken']; if (hasAllParams) { - this.setState({loginView: LOGIN_VIEW.LOADING}); + this.setState({ loginView: LOGIN_VIEW.LOADING }); this.trySsoLogin(); return; } @@ -125,18 +125,18 @@ export default class SoftLogout extends React.Component { } onPasswordChange = (ev) => { - this.setState({password: ev.target.value}); + this.setState({ password: ev.target.value }); }; onForgotPassword = () => { - dis.dispatch({action: 'start_password_recovery'}); + dis.dispatch({ action: 'start_password_recovery' }); }; onPasswordLogin = async (ev) => { ev.preventDefault(); ev.stopPropagation(); - this.setState({busy: true}); + this.setState({ busy: true }); const hsUrl = MatrixClientPeg.get().getHomeserverUrl(); const isUrl = MatrixClientPeg.get().getIdentityServerUrl(); @@ -168,12 +168,12 @@ export default class SoftLogout extends React.Component { Lifecycle.hydrateSession(credentials).catch((e) => { console.error(e); - this.setState({busy: false, errorText: _t("Failed to re-authenticate")}); + this.setState({ busy: false, errorText: _t("Failed to re-authenticate") }); }); }; async trySsoLogin() { - this.setState({busy: true}); + this.setState({ busy: true }); const hsUrl = localStorage.getItem(SSO_HOMESERVER_URL_KEY); const isUrl = localStorage.getItem(SSO_ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl(); @@ -188,7 +188,7 @@ export default class SoftLogout extends React.Component { credentials = await sendLoginRequest(hsUrl, isUrl, loginType, loginParams); } catch (e) { console.error(e); - this.setState({busy: false, loginView: LOGIN_VIEW.UNSUPPORTED}); + this.setState({ busy: false, loginView: LOGIN_VIEW.UNSUPPORTED }); return; } @@ -196,7 +196,7 @@ export default class SoftLogout extends React.Component { if (this.props.onTokenLoginCompleted) this.props.onTokenLoginCompleted(); }).catch((e) => { console.error(e); - this.setState({busy: false, loginView: LOGIN_VIEW.UNSUPPORTED}); + this.setState({ busy: false, loginView: LOGIN_VIEW.UNSUPPORTED }); }); } diff --git a/src/components/views/audio_messages/AudioPlayer.tsx b/src/components/views/audio_messages/AudioPlayer.tsx new file mode 100644 index 0000000000..66efa64658 --- /dev/null +++ b/src/components/views/audio_messages/AudioPlayer.tsx @@ -0,0 +1,124 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Playback, PlaybackState } from "../../../voice/Playback"; +import React, { createRef, ReactNode, RefObject } from "react"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore"; +import PlayPauseButton from "./PlayPauseButton"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { formatBytes } from "../../../utils/FormattingUtils"; +import DurationClock from "./DurationClock"; +import { Key } from "../../../Keyboard"; +import { _t } from "../../../languageHandler"; +import SeekBar from "./SeekBar"; +import PlaybackClock from "./PlaybackClock"; + +interface IProps { + // Playback instance to render. Cannot change during component lifecycle: create + // an all-new component instead. + playback: Playback; + + mediaName: string; +} + +interface IState { + playbackPhase: PlaybackState; +} + +@replaceableComponent("views.audio_messages.AudioPlayer") +export default class AudioPlayer extends React.PureComponent { + private playPauseRef: RefObject = createRef(); + private seekRef: RefObject = createRef(); + + constructor(props: IProps) { + super(props); + + this.state = { + playbackPhase: PlaybackState.Decoding, // default assumption + }; + + // We don't need to de-register: the class handles this for us internally + this.props.playback.on(UPDATE_EVENT, this.onPlaybackUpdate); + + // Don't wait for the promise to complete - it will emit a progress update when it + // is done, and it's not meant to take long anyhow. + // noinspection JSIgnoredPromiseFromCall + this.props.playback.prepare(); + } + + private onPlaybackUpdate = (ev: PlaybackState) => { + this.setState({ playbackPhase: ev }); + }; + + private onKeyDown = (ev: React.KeyboardEvent) => { + // stopPropagation() prevents the FocusComposer catch-all from triggering, + // but we need to do it on key down instead of press (even though the user + // interaction is typically on press). + if (ev.key === Key.SPACE) { + ev.stopPropagation(); + this.playPauseRef.current?.toggleState(); + } else if (ev.key === Key.ARROW_LEFT) { + ev.stopPropagation(); + this.seekRef.current?.left(); + } else if (ev.key === Key.ARROW_RIGHT) { + ev.stopPropagation(); + this.seekRef.current?.right(); + } + }; + + protected renderFileSize(): string { + const bytes = this.props.playback.sizeBytes; + if (!bytes) return null; + + // Not translated here - we're just presenting the data which should already + // be translated if needed. + return `(${formatBytes(bytes)})`; + } + + public render(): ReactNode { + // tabIndex=0 to ensure that the whole component becomes a tab stop, where we handle keyboard + // events for accessibility + return

    +
    + +
    + + {this.props.mediaName || _t("Unnamed audio")} + +
    + +   {/* easiest way to introduce a gap between the components */} + { this.renderFileSize() } +
    +
    +
    +
    + + +
    +
    ; + } +} diff --git a/src/components/views/voice_messages/Clock.tsx b/src/components/views/audio_messages/Clock.tsx similarity index 96% rename from src/components/views/voice_messages/Clock.tsx rename to src/components/views/audio_messages/Clock.tsx index 1e78cc7bbd..7f387715f8 100644 --- a/src/components/views/voice_messages/Clock.tsx +++ b/src/components/views/audio_messages/Clock.tsx @@ -28,7 +28,7 @@ interface IState { * Simply converts seconds into minutes and seconds. Note that hours will not be * displayed, making it possible to see "82:29". */ -@replaceableComponent("views.voice_messages.Clock") +@replaceableComponent("views.audio_messages.Clock") export default class Clock extends React.Component { public constructor(props) { super(props); diff --git a/src/components/views/audio_messages/DurationClock.tsx b/src/components/views/audio_messages/DurationClock.tsx new file mode 100644 index 0000000000..81852b5944 --- /dev/null +++ b/src/components/views/audio_messages/DurationClock.tsx @@ -0,0 +1,55 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import Clock from "./Clock"; +import { Playback } from "../../../voice/Playback"; + +interface IProps { + playback: Playback; +} + +interface IState { + durationSeconds: number; +} + +/** + * A clock which shows a clip's maximum duration. + */ +@replaceableComponent("views.audio_messages.DurationClock") +export default class DurationClock extends React.PureComponent { + public constructor(props) { + super(props); + + this.state = { + // we track the duration on state because we won't really know what the clip duration + // is until the first time update, and as a PureComponent we are trying to dedupe state + // updates as much as possible. This is just the easiest way to avoid a forceUpdate() or + // member property to track "did we get a duration". + durationSeconds: this.props.playback.clockInfo.durationSeconds, + }; + this.props.playback.clockInfo.liveData.onUpdate(this.onTimeUpdate); + } + + private onTimeUpdate = (time: number[]) => { + this.setState({ durationSeconds: time[1] }); + }; + + public render() { + return ; + } +} diff --git a/src/components/views/voice_messages/LiveRecordingClock.tsx b/src/components/views/audio_messages/LiveRecordingClock.tsx similarity index 90% rename from src/components/views/voice_messages/LiveRecordingClock.tsx rename to src/components/views/audio_messages/LiveRecordingClock.tsx index 2a20e9bfec..a9dbd3c52f 100644 --- a/src/components/views/voice_messages/LiveRecordingClock.tsx +++ b/src/components/views/audio_messages/LiveRecordingClock.tsx @@ -1,9 +1,12 @@ /* Copyright 2021 The Matrix.org Foundation C.I.C. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -12,16 +15,13 @@ limitations under the License. */ import React from "react"; -import Clock from "./Clock"; +import { IRecordingUpdate, VoiceRecording } from "../../../voice/VoiceRecording"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import Clock from "./Clock"; import { MarkedExecution } from "../../../utils/MarkedExecution"; -import { - IRecordingUpdate, - VoiceRecording, -} from "../../../voice/VoiceRecording"; interface IProps { - recorder?: VoiceRecording; + recorder: VoiceRecording; } interface IState { @@ -31,7 +31,7 @@ interface IState { /** * A clock for a live recording. */ -@replaceableComponent("views.voice_messages.LiveRecordingClock") +@replaceableComponent("views.audio_messages.LiveRecordingClock") export default class LiveRecordingClock extends React.PureComponent { private seconds = 0; private scheduledUpdate = new MarkedExecution( diff --git a/src/components/views/voice_messages/LiveRecordingWaveform.tsx b/src/components/views/audio_messages/LiveRecordingWaveform.tsx similarity index 66% rename from src/components/views/voice_messages/LiveRecordingWaveform.tsx rename to src/components/views/audio_messages/LiveRecordingWaveform.tsx index fdff8e87e7..b9c5f80f05 100644 --- a/src/components/views/voice_messages/LiveRecordingWaveform.tsx +++ b/src/components/views/audio_messages/LiveRecordingWaveform.tsx @@ -1,9 +1,12 @@ /* Copyright 2021 The Matrix.org Foundation C.I.C. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -12,16 +15,15 @@ limitations under the License. */ import React from "react"; -import Waveform from "./Waveform"; +import { IRecordingUpdate, RECORDING_PLAYBACK_SAMPLES, VoiceRecording } from "../../../voice/VoiceRecording"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { arrayFastResample } from "../../../utils/arrays"; +import { percentageOf } from "../../../utils/numbers"; +import Waveform from "./Waveform"; import { MarkedExecution } from "../../../utils/MarkedExecution"; -import { - IRecordingUpdate, - VoiceRecording, -} from "../../../voice/VoiceRecording"; interface IProps { - recorder?: VoiceRecording; + recorder: VoiceRecording; } interface IState { @@ -31,7 +33,7 @@ interface IState { /** * A waveform which shows the waveform of a live recording */ -@replaceableComponent("views.voice_messages.LiveRecordingWaveform") +@replaceableComponent("views.audio_messages.LiveRecordingWaveform") export default class LiveRecordingWaveform extends React.PureComponent { public static defaultProps = { progress: 1, @@ -52,15 +54,18 @@ export default class LiveRecordingWaveform extends React.PureComponent { - this.waveform = update.waveform; + const bars = arrayFastResample(Array.from(update.waveform), RECORDING_PLAYBACK_SAMPLES); + // The incoming data is between zero and one, but typically even screaming into a + // microphone won't send you over 0.6, so we artificially adjust the gain for the + // waveform. This results in a slightly more cinematic/animated waveform for the + // user. + this.waveform = bars.map(b => percentageOf(b, 0, 0.50)); this.scheduledUpdate.mark(); }); } private updateWaveform() { - this.setState({ - waveform: this.waveform, - }) + this.setState({ waveform: this.waveform }); } public render() { diff --git a/src/components/views/voice_messages/PlayPauseButton.tsx b/src/components/views/audio_messages/PlayPauseButton.tsx similarity index 67% rename from src/components/views/voice_messages/PlayPauseButton.tsx rename to src/components/views/audio_messages/PlayPauseButton.tsx index 1f87eb012d..a4f1e770f2 100644 --- a/src/components/views/voice_messages/PlayPauseButton.tsx +++ b/src/components/views/audio_messages/PlayPauseButton.tsx @@ -14,14 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ReactNode} from "react"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import React, { ReactNode } from "react"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import {_t} from "../../../languageHandler"; -import {Playback, PlaybackState} from "../../../voice/Playback"; +import { _t } from "../../../languageHandler"; +import { Playback, PlaybackState } from "../../../voice/Playback"; import classNames from "classnames"; -interface IProps { +// omitted props are handled by render function +interface IProps extends Omit, "title" | "onClick" | "disabled"> { // Playback instance to manipulate. Cannot change during the component lifecycle. playback: Playback; @@ -33,19 +34,25 @@ interface IProps { * Displays a play/pause button (activating the play/pause function of the recorder) * to be displayed in reference to a recording. */ -@replaceableComponent("views.voice_messages.PlayPauseButton") +@replaceableComponent("views.audio_messages.PlayPauseButton") export default class PlayPauseButton extends React.PureComponent { public constructor(props) { super(props); } - private onClick = async () => { - await this.props.playback.toggle(); + private onClick = () => { + // noinspection JSIgnoredPromiseFromCall + this.toggleState(); }; + public async toggleState() { + await this.props.playback.toggle(); + } + public render(): ReactNode { - const isPlaying = this.props.playback.isPlaying; - const isDisabled = this.props.playbackPhase === PlaybackState.Decoding; + const { playback, playbackPhase, ...restProps } = this.props; + const isPlaying = playback.isPlaying; + const isDisabled = playbackPhase === PlaybackState.Decoding; const classes = classNames('mx_PlayPauseButton', { 'mx_PlayPauseButton_play': !isPlaying, 'mx_PlayPauseButton_pause': isPlaying, @@ -56,6 +63,7 @@ export default class PlayPauseButton extends React.PureComponent { title={isPlaying ? _t("Pause") : _t("Play")} onClick={this.onClick} disabled={isDisabled} + {...restProps} />; } } diff --git a/src/components/views/voice_messages/PlaybackClock.tsx b/src/components/views/audio_messages/PlaybackClock.tsx similarity index 73% rename from src/components/views/voice_messages/PlaybackClock.tsx rename to src/components/views/audio_messages/PlaybackClock.tsx index 2e8ec9a3e7..374d47c31d 100644 --- a/src/components/views/voice_messages/PlaybackClock.tsx +++ b/src/components/views/audio_messages/PlaybackClock.tsx @@ -15,13 +15,18 @@ limitations under the License. */ import React from "react"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import Clock from "./Clock"; -import {Playback, PlaybackState} from "../../../voice/Playback"; -import {UPDATE_EVENT} from "../../../stores/AsyncStore"; +import { Playback, PlaybackState } from "../../../voice/Playback"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore"; interface IProps { playback: Playback; + + // The default number of seconds to show when the playback has completed or + // has not started. Not used during playback, even when paused. Defaults to + // clip duration length. + defaultDisplaySeconds?: number; } interface IState { @@ -33,7 +38,7 @@ interface IState { /** * A clock for a playback of a recording. */ -@replaceableComponent("views.voice_messages.PlaybackClock") +@replaceableComponent("views.audio_messages.PlaybackClock") export default class PlaybackClock extends React.PureComponent { public constructor(props) { super(props); @@ -54,17 +59,21 @@ export default class PlaybackClock extends React.PureComponent { private onPlaybackUpdate = (ev: PlaybackState) => { // Convert Decoding -> Stopped because we don't care about the distinction here if (ev === PlaybackState.Decoding) ev = PlaybackState.Stopped; - this.setState({playbackPhase: ev}); + this.setState({ playbackPhase: ev }); }; private onTimeUpdate = (time: number[]) => { - this.setState({seconds: time[0], durationSeconds: time[1]}); + this.setState({ seconds: time[0], durationSeconds: time[1] }); }; public render() { let seconds = this.state.seconds; if (this.state.playbackPhase === PlaybackState.Stopped) { - seconds = this.state.durationSeconds; + if (Number.isFinite(this.props.defaultDisplaySeconds)) { + seconds = this.props.defaultDisplaySeconds; + } else { + seconds = this.state.durationSeconds; + } } return ; } diff --git a/src/components/views/voice_messages/PlaybackWaveform.tsx b/src/components/views/audio_messages/PlaybackWaveform.tsx similarity index 81% rename from src/components/views/voice_messages/PlaybackWaveform.tsx rename to src/components/views/audio_messages/PlaybackWaveform.tsx index 2e9f163f5e..ea1b846c01 100644 --- a/src/components/views/voice_messages/PlaybackWaveform.tsx +++ b/src/components/views/audio_messages/PlaybackWaveform.tsx @@ -15,11 +15,11 @@ limitations under the License. */ import React from "react"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {arraySeed, arrayTrimFill} from "../../../utils/arrays"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { arraySeed, arrayTrimFill } from "../../../utils/arrays"; import Waveform from "./Waveform"; -import {Playback, PLAYBACK_WAVEFORM_SAMPLES} from "../../../voice/Playback"; -import {percentageOf} from "../../../utils/numbers"; +import { Playback, PLAYBACK_WAVEFORM_SAMPLES } from "../../../voice/Playback"; +import { percentageOf } from "../../../utils/numbers"; interface IProps { playback: Playback; @@ -33,7 +33,7 @@ interface IState { /** * A waveform which shows the waveform of a previously recorded recording */ -@replaceableComponent("views.voice_messages.PlaybackWaveform") +@replaceableComponent("views.audio_messages.PlaybackWaveform") export default class PlaybackWaveform extends React.PureComponent { public constructor(props) { super(props); @@ -53,13 +53,13 @@ export default class PlaybackWaveform extends React.PureComponent { - this.setState({heights: this.toHeights(waveform)}); + this.setState({ heights: this.toHeights(waveform) }); }; private onTimeUpdate = (time: number[]) => { // Track percentages to a general precision to avoid over-waking the component. const progress = Number(percentageOf(time[0], 0, time[1]).toFixed(3)); - this.setState({progress}); + this.setState({ progress }); }; public render() { diff --git a/src/components/views/voice_messages/RecordingPlayback.tsx b/src/components/views/audio_messages/RecordingPlayback.tsx similarity index 81% rename from src/components/views/voice_messages/RecordingPlayback.tsx rename to src/components/views/audio_messages/RecordingPlayback.tsx index 776997cec2..a0dea1c6db 100644 --- a/src/components/views/voice_messages/RecordingPlayback.tsx +++ b/src/components/views/audio_messages/RecordingPlayback.tsx @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Playback, PlaybackState} from "../../../voice/Playback"; -import React, {ReactNode} from "react"; -import {UPDATE_EVENT} from "../../../stores/AsyncStore"; +import { Playback, PlaybackState } from "../../../voice/Playback"; +import React, { ReactNode } from "react"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import PlaybackWaveform from "./PlaybackWaveform"; import PlayPauseButton from "./PlayPauseButton"; import PlaybackClock from "./PlaybackClock"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // Playback instance to render. Cannot change during component lifecycle: create @@ -31,6 +32,7 @@ interface IState { playbackPhase: PlaybackState; } +@replaceableComponent("views.audio_messages.RecordingPlayback") export default class RecordingPlayback extends React.PureComponent { constructor(props: IProps) { super(props); @@ -49,14 +51,14 @@ export default class RecordingPlayback extends React.PureComponent { - this.setState({playbackPhase: ev}); + this.setState({ playbackPhase: ev }); }; public render(): ReactNode { - return
    + return
    -
    +
    ; } } diff --git a/src/components/views/audio_messages/SeekBar.tsx b/src/components/views/audio_messages/SeekBar.tsx new file mode 100644 index 0000000000..5231a2fb79 --- /dev/null +++ b/src/components/views/audio_messages/SeekBar.tsx @@ -0,0 +1,112 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { Playback, PlaybackState } from "../../../voice/Playback"; +import React, { ChangeEvent, CSSProperties, ReactNode } from "react"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { MarkedExecution } from "../../../utils/MarkedExecution"; +import { percentageOf } from "../../../utils/numbers"; + +interface IProps { + // Playback instance to render. Cannot change during component lifecycle: create + // an all-new component instead. + playback: Playback; + + // Tab index for the underlying component. Useful if the seek bar is in a managed state. + // Defaults to zero. + tabIndex?: number; + + playbackPhase: PlaybackState; +} + +interface IState { + percentage: number; +} + +interface ISeekCSS extends CSSProperties { + '--fillTo': number; +} + +const ARROW_SKIP_SECONDS = 5; // arbitrary + +@replaceableComponent("views.audio_messages.SeekBar") +export default class SeekBar extends React.PureComponent { + // We use an animation frame request to avoid overly spamming prop updates, even if we aren't + // really using anything demanding on the CSS front. + + private animationFrameFn = new MarkedExecution( + () => this.doUpdate(), + () => requestAnimationFrame(() => this.animationFrameFn.trigger())); + + public static defaultProps = { + tabIndex: 0, + }; + + constructor(props: IProps) { + super(props); + + this.state = { + percentage: 0, + }; + + // We don't need to de-register: the class handles this for us internally + this.props.playback.clockInfo.liveData.onUpdate(() => this.animationFrameFn.mark()); + } + + private doUpdate() { + this.setState({ + percentage: percentageOf( + this.props.playback.clockInfo.timeSeconds, + 0, + this.props.playback.clockInfo.durationSeconds), + }); + } + + public left() { + // noinspection JSIgnoredPromiseFromCall + this.props.playback.skipTo(this.props.playback.clockInfo.timeSeconds - ARROW_SKIP_SECONDS); + } + + public right() { + // noinspection JSIgnoredPromiseFromCall + this.props.playback.skipTo(this.props.playback.clockInfo.timeSeconds + ARROW_SKIP_SECONDS); + } + + private onChange = (ev: ChangeEvent) => { + // Thankfully, onChange is only called when the user changes the value, not when we + // change the value on the component. We can use this as a reliable "skip to X" function. + // + // noinspection JSIgnoredPromiseFromCall + this.props.playback.skipTo(Number(ev.target.value) * this.props.playback.clockInfo.durationSeconds); + }; + + public render(): ReactNode { + // We use a range input to avoid having to re-invent accessibility handling on + // a custom set of divs. + return ; + } +} diff --git a/src/components/views/voice_messages/Waveform.tsx b/src/components/views/audio_messages/Waveform.tsx similarity index 93% rename from src/components/views/voice_messages/Waveform.tsx rename to src/components/views/audio_messages/Waveform.tsx index 5a4447065a..3b7a881754 100644 --- a/src/components/views/voice_messages/Waveform.tsx +++ b/src/components/views/audio_messages/Waveform.tsx @@ -17,8 +17,13 @@ limitations under the License. import React from "react"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import classNames from "classnames"; +import { CSSProperties } from "react"; -export interface IProps { +interface WaveformCSSProperties extends CSSProperties { + '--barHeight': number; +} + +interface IProps { relHeights: number[]; // relative heights (0-1) progress: number; // percent complete, 0-1, default 100% } @@ -34,14 +39,7 @@ interface IState { * For CSS purposes, a mx_Waveform_bar_100pct class is added when the bar should be * "filled", as a demonstration of the progress property. */ - -import { CSSProperties } from "react"; - -export interface WaveformCSSProperties extends CSSProperties { - '--barHeight': number; -} - -@replaceableComponent("views.voice_messages.Waveform") +@replaceableComponent("views.audio_messages.Waveform") export default class Waveform extends React.PureComponent { public static defaultProps = { progress: 1, diff --git a/src/components/views/auth/AuthBody.js b/src/components/views/auth/AuthBody.js index 2cb72b5e1d..abe7fd2fd3 100644 --- a/src/components/views/auth/AuthBody.js +++ b/src/components/views/auth/AuthBody.js @@ -15,7 +15,7 @@ limitations under the License. */ import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.AuthBody") export default class AuthBody extends React.PureComponent { diff --git a/src/components/views/auth/AuthFooter.js b/src/components/views/auth/AuthFooter.js index f167e16283..e81d2cd969 100644 --- a/src/components/views/auth/AuthFooter.js +++ b/src/components/views/auth/AuthFooter.js @@ -18,7 +18,7 @@ limitations under the License. import { _t } from '../../../languageHandler'; import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.AuthFooter") export default class AuthFooter extends React.Component { diff --git a/src/components/views/auth/AuthHeader.js b/src/components/views/auth/AuthHeader.js index 323299b3a8..d9bd81adcb 100644 --- a/src/components/views/auth/AuthHeader.js +++ b/src/components/views/auth/AuthHeader.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.AuthHeader") export default class AuthHeader extends React.Component { diff --git a/src/components/views/auth/AuthHeaderLogo.js b/src/components/views/auth/AuthHeaderLogo.js index b4e04799bb..0adf18dc1c 100644 --- a/src/components/views/auth/AuthHeaderLogo.js +++ b/src/components/views/auth/AuthHeaderLogo.js @@ -15,7 +15,7 @@ limitations under the License. */ import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.AuthHeaderLogo") export default class AuthHeaderLogo extends React.PureComponent { diff --git a/src/components/views/auth/AuthPage.js b/src/components/views/auth/AuthPage.js index 82f7270121..6ba47e5288 100644 --- a/src/components/views/auth/AuthPage.js +++ b/src/components/views/auth/AuthPage.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.AuthPage") export default class AuthPage extends React.PureComponent { diff --git a/src/components/views/auth/CaptchaForm.js b/src/components/views/auth/CaptchaForm.js index 50de24d403..bea4f89f53 100644 --- a/src/components/views/auth/CaptchaForm.js +++ b/src/components/views/auth/CaptchaForm.js @@ -14,11 +14,11 @@ 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 { _t } from '../../../languageHandler'; import CountlyAnalytics from "../../../CountlyAnalytics"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const DIV_ID = 'mx_recaptcha'; diff --git a/src/components/views/auth/CompleteSecurityBody.js b/src/components/views/auth/CompleteSecurityBody.js index 6647bb1200..745d7abbf2 100644 --- a/src/components/views/auth/CompleteSecurityBody.js +++ b/src/components/views/auth/CompleteSecurityBody.js @@ -15,7 +15,7 @@ limitations under the License. */ import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.auth.CompleteSecurityBody") export default class CompleteSecurityBody extends React.PureComponent { diff --git a/src/components/views/auth/CountryDropdown.js b/src/components/views/auth/CountryDropdown.js index e21f112865..cbc19e0f8d 100644 --- a/src/components/views/auth/CountryDropdown.js +++ b/src/components/views/auth/CountryDropdown.js @@ -19,10 +19,10 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; -import {COUNTRIES, getEmojiFlag} from '../../../phonenumber'; +import { COUNTRIES, getEmojiFlag } from '../../../phonenumber'; import SdkConfig from "../../../SdkConfig"; import { _t } from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const COUNTRIES_BY_ISO2 = {}; for (const c of COUNTRIES) { diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx index e819e1e59c..e002eb5717 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx +++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx @@ -24,7 +24,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import Spinner from "../elements/Spinner"; import CountlyAnalytics from "../../../CountlyAnalytics"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import { LocalisedPolicy, Policies } from '../../../Terms'; /* This file contains a collection of components which are used by the @@ -354,7 +354,6 @@ export class TermsAuthEntry extends React.Component { @@ -382,10 +381,10 @@ export class TermsAuthEntry extends React.Component { this.props.fail(e); }).finally(() => { - this.setState({requestingToken: false}); + this.setState({ requestingToken: false }); }); } @@ -710,7 +709,7 @@ export class SSOAuthEntry extends React.Component; const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index 274c244b2a..bab7e59d2a 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -14,15 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {PureComponent, RefCallback, RefObject} from "react"; +import React, { PureComponent, RefCallback, RefObject } from "react"; import classNames from "classnames"; import zxcvbn from "zxcvbn"; import SdkConfig from "../../../SdkConfig"; -import withValidation, {IFieldState, IValidationResult} from "../elements/Validation"; -import {_t, _td} from "../../../languageHandler"; -import Field, {IInputProps} from "../elements/Field"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; +import { _t, _td } from "../../../languageHandler"; +import Field, { IInputProps } from "../elements/Field"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends Omit { autoFocus?: boolean; diff --git a/src/components/views/auth/PasswordLogin.tsx b/src/components/views/auth/PasswordLogin.tsx index 2a42804a61..12f55a112c 100644 --- a/src/components/views/auth/PasswordLogin.tsx +++ b/src/components/views/auth/PasswordLogin.tsx @@ -19,14 +19,14 @@ import classNames from 'classnames'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; -import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import AccessibleButton from "../elements/AccessibleButton"; import CountlyAnalytics from "../../../CountlyAnalytics"; import withValidation from "../elements/Validation"; import * as Email from "../../../email"; import Field from "../elements/Field"; import CountryDropdown from "./CountryDropdown"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // For validating phone numbers without country codes const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/; @@ -166,7 +166,7 @@ export default class PasswordLogin extends React.PureComponent { }; private onPasswordChanged = ev => { - this.setState({password: ev.target.value}); + this.setState({ password: ev.target.value }); }; private async verifyFieldsBeforeSubmit() { @@ -322,7 +322,7 @@ export default class PasswordLogin extends React.PureComponent { const result = await this.validatePasswordRules(fieldState); this.markFieldValid(LoginField.Password, result.valid); return result; - } + }; private renderLoginField(loginType: IState["loginType"], autoFocus: boolean) { const classes = { diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx index 8f0a293a3c..be6e29a493 100644 --- a/src/components/views/auth/RegistrationForm.tsx +++ b/src/components/views/auth/RegistrationForm.tsx @@ -25,12 +25,12 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import { SAFE_LOCALPART_REGEX } from '../../../Registration'; import withValidation from '../elements/Validation'; -import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import PassphraseField from "./PassphraseField"; import CountlyAnalytics from "../../../CountlyAnalytics"; import Field from '../elements/Field'; import RegistrationEmailPromptDialog from '../dialogs/RegistrationEmailPromptDialog'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; enum RegistrationField { Email = "field_email", diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index fca66fcf9b..e3f7a601f2 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -20,11 +20,11 @@ import classNames from "classnames"; import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; -import {_td} from "../../../languageHandler"; +import { _td } from "../../../languageHandler"; import SettingsStore from "../../../settings/SettingsStore"; -import {UIFeature} from "../../../settings/UIFeature"; +import { UIFeature } from "../../../settings/UIFeature"; import CountlyAnalytics from "../../../CountlyAnalytics"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // translatable strings for Welcome pages _td("Sign in with SSO"); diff --git a/src/components/views/avatars/BaseAvatar.tsx b/src/components/views/avatars/BaseAvatar.tsx index f98f8c88a1..87cdbe7512 100644 --- a/src/components/views/avatars/BaseAvatar.tsx +++ b/src/components/views/avatars/BaseAvatar.tsx @@ -64,7 +64,7 @@ const calculateUrls = (url, urls, lowBandwidth) => { return Array.from(new Set(_urls)); }; -const useImageUrl = ({url, urls}): [string, () => void] => { +const useImageUrl = ({ url, urls }): [string, () => void] => { // Since this is a hot code path and the settings store can be slow, we // use the cached lowBandwidth value from the room context if it exists const roomContext = useContext(RoomContext); @@ -115,7 +115,7 @@ const BaseAvatar = (props: IProps) => { ...otherProps } = props; - const [imageUrl, onError] = useImageUrl({url, urls}); + const [imageUrl, onError] = useImageUrl({ url, urls }); if (!imageUrl && defaultToInitialLetter) { const initialLetter = AvatarLogic.getInitialLetter(name); diff --git a/src/components/views/avatars/DecoratedRoomAvatar.tsx b/src/components/views/avatars/DecoratedRoomAvatar.tsx index 42aef24086..950caefa02 100644 --- a/src/components/views/avatars/DecoratedRoomAvatar.tsx +++ b/src/components/views/avatars/DecoratedRoomAvatar.tsx @@ -24,12 +24,12 @@ import RoomAvatar from "./RoomAvatar"; import NotificationBadge from '../rooms/NotificationBadge'; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import { NotificationState } from "../../../stores/notifications/NotificationState"; -import {isPresenceEnabled} from "../../../utils/presence"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {_t} from "../../../languageHandler"; +import { isPresenceEnabled } from "../../../utils/presence"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { _t } from "../../../languageHandler"; import TextWithTooltip from "../elements/TextWithTooltip"; import DMRoomMap from "../../../utils/DMRoomMap"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { room: Room; @@ -121,7 +121,7 @@ export default class DecoratedRoomAvatar extends React.PureComponent { // extract the props we use from props so we can pass any others through // should consider adding this as a global rule in js-sdk? /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */ - const {groupId, groupAvatarUrl, groupName, ...otherProps} = this.props; + const { groupId, groupAvatarUrl, groupName, ...otherProps } = this.props; return ( { } render() { - let {member, fallbackUserId, onClick, viewUserOnClick, ...otherProps} = this.props; + let { member, fallbackUserId, onClick, viewUserOnClick, ...otherProps } = this.props; const userId = member ? member.userId : fallbackUserId; if (viewUserOnClick) { diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js index acf190f17f..b8b23dc33e 100644 --- a/src/components/views/avatars/MemberStatusMessageAvatar.js +++ b/src/components/views/avatars/MemberStatusMessageAvatar.js @@ -14,16 +14,16 @@ 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 {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {_t} from "../../../languageHandler"; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import { _t } from "../../../languageHandler"; import MemberAvatar from '../avatars/MemberAvatar'; import classNames from 'classnames'; import StatusMessageContextMenu from "../context_menus/StatusMessageContextMenu"; import SettingsStore from "../../../settings/SettingsStore"; -import {ContextMenu, ContextMenuButton} from "../../structures/ContextMenu"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.avatars.MemberStatusMessageAvatar") export default class MemberStatusMessageAvatar extends React.Component { diff --git a/src/components/views/avatars/RoomAvatar.tsx b/src/components/views/avatars/RoomAvatar.tsx index bd820509c5..c3f49d4a12 100644 --- a/src/components/views/avatars/RoomAvatar.tsx +++ b/src/components/views/avatars/RoomAvatar.tsx @@ -128,7 +128,7 @@ export default class RoomAvatar extends React.Component { }; public render() { - const {room, oobData, viewAvatarOnClick, onClick, ...otherProps} = this.props; + const { room, oobData, viewAvatarOnClick, onClick, ...otherProps } = this.props; const roomName = room ? room.name : oobData.name; diff --git a/src/components/views/avatars/WidgetAvatar.tsx b/src/components/views/avatars/WidgetAvatar.tsx index cca158269e..264f1f3956 100644 --- a/src/components/views/avatars/WidgetAvatar.tsx +++ b/src/components/views/avatars/WidgetAvatar.tsx @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ComponentProps} from 'react'; +import React, { ComponentProps } from 'react'; import classNames from 'classnames'; -import {IApp} from "../../../stores/WidgetStore"; -import BaseAvatar, {BaseAvatarType} from "./BaseAvatar"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { IApp } from "../../../stores/WidgetStore"; +import BaseAvatar, { BaseAvatarType } from "./BaseAvatar"; +import { mediaFromMxc } from "../../../customisations/Media"; interface IProps extends Omit, "name" | "url" | "urls"> { app: IApp; @@ -49,7 +49,7 @@ const WidgetAvatar: React.FC = ({ app, className, width = 20, height = 2 width={width} height={height} /> - ) + ); }; export default WidgetAvatar; diff --git a/src/components/views/beta/BetaCard.tsx b/src/components/views/beta/BetaCard.tsx index aa4fe49f63..3127e1a915 100644 --- a/src/components/views/beta/BetaCard.tsx +++ b/src/components/views/beta/BetaCard.tsx @@ -17,10 +17,10 @@ limitations under the License. import React from "react"; import classNames from "classnames"; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import AccessibleButton from "../elements/AccessibleButton"; import SettingsStore from "../../../settings/SettingsStore"; -import {SettingLevel} from "../../../settings/SettingLevel"; +import { SettingLevel } from "../../../settings/SettingLevel"; import TextWithTooltip from "../elements/TextWithTooltip"; import Modal from "../../../Modal"; import BetaFeedbackDialog from "../dialogs/BetaFeedbackDialog"; diff --git a/src/components/views/context_menus/CallContextMenu.tsx b/src/components/views/context_menus/CallContextMenu.tsx index 97473059a6..428e18ed30 100644 --- a/src/components/views/context_menus/CallContextMenu.tsx +++ b/src/components/views/context_menus/CallContextMenu.tsx @@ -22,7 +22,7 @@ import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import CallHandler from '../../../CallHandler'; import InviteDialog, { KIND_CALL_TRANSFER } from '../dialogs/InviteDialog'; import Modal from '../../../Modal'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; @@ -42,21 +42,21 @@ export default class CallContextMenu extends React.Component { onHoldClick = () => { this.props.call.setRemoteOnHold(true); this.props.onFinished(); - } + }; onUnholdClick = () => { CallHandler.sharedInstance().setActiveCallRoomId(this.props.call.roomId); this.props.onFinished(); - } + }; onTransferClick = () => { Modal.createTrackedDialog( - 'Transfer Call', '', InviteDialog, {kind: KIND_CALL_TRANSFER, call: this.props.call}, + 'Transfer Call', '', InviteDialog, { kind: KIND_CALL_TRANSFER, call: this.props.call }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, ); this.props.onFinished(); - } + }; render() { const holdUnholdCaption = this.props.call.isRemoteOnHold() ? _t("Resume") : _t("Hold"); diff --git a/src/components/views/context_menus/DialpadContextMenu.tsx b/src/components/views/context_menus/DialpadContextMenu.tsx index 8879629055..28a73ba8d4 100644 --- a/src/components/views/context_menus/DialpadContextMenu.tsx +++ b/src/components/views/context_menus/DialpadContextMenu.tsx @@ -20,7 +20,7 @@ import { ContextMenu, IProps as IContextMenuProps } from '../../structures/Conte import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import Field from "../elements/Field"; import Dialpad from '../voip/DialPad'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IContextMenuProps { call: MatrixCall; @@ -37,18 +37,17 @@ export default class DialpadContextMenu extends React.Component this.state = { value: '', - } + }; } onDigitPress = (digit) => { this.props.call.sendDtmfDigit(digit); - this.setState({value: this.state.value + digit}); - } + this.setState({ value: this.state.value + digit }); + }; onChange = (ev) => { - this.setState({value: ev.target.value}); - } - + this.setState({ value: ev.target.value }); + }; render() { return diff --git a/src/components/views/context_menus/GenericElementContextMenu.js b/src/components/views/context_menus/GenericElementContextMenu.js index e04e3f7695..87d44ef0d3 100644 --- a/src/components/views/context_menus/GenericElementContextMenu.js +++ b/src/components/views/context_menus/GenericElementContextMenu.js @@ -16,14 +16,13 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; /* * This component can be used to display generic HTML content in a contextual * menu. */ - @replaceableComponent("views.context_menus.GenericElementContextMenu") export default class GenericElementContextMenu extends React.Component { static propTypes = { diff --git a/src/components/views/context_menus/GenericTextContextMenu.js b/src/components/views/context_menus/GenericTextContextMenu.js index 3d3add006f..474732e88b 100644 --- a/src/components/views/context_menus/GenericTextContextMenu.js +++ b/src/components/views/context_menus/GenericTextContextMenu.js @@ -16,7 +16,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.context_menus.GenericTextContextMenu") export default class GenericTextContextMenu extends React.Component { diff --git a/src/components/views/context_menus/GroupInviteTileContextMenu.js b/src/components/views/context_menus/GroupInviteTileContextMenu.js index 15078326b3..1529723ac8 100644 --- a/src/components/views/context_menus/GroupInviteTileContextMenu.js +++ b/src/components/views/context_menus/GroupInviteTileContextMenu.js @@ -20,10 +20,10 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import {Group} from 'matrix-js-sdk/src/models/group'; +import { Group } from 'matrix-js-sdk/src/models/group'; import GroupStore from "../../../stores/GroupStore"; -import {MenuItem} from "../../structures/ContextMenu"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MenuItem } from "../../structures/ContextMenu"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.context_menus.GroupInviteTileContextMenu") export default class GroupInviteTileContextMenu extends React.Component { diff --git a/src/components/views/context_menus/IconizedContextMenu.tsx b/src/components/views/context_menus/IconizedContextMenu.tsx index a3fb00a9f4..a9c75bf3ba 100644 --- a/src/components/views/context_menus/IconizedContextMenu.tsx +++ b/src/components/views/context_menus/IconizedContextMenu.tsx @@ -90,14 +90,14 @@ export const IconizedContextMenuCheckbox: React.FC = ({ ; }; -export const IconizedContextMenuOption: React.FC = ({label, iconClassName, ...props}) => { +export const IconizedContextMenuOption: React.FC = ({ label, iconClassName, ...props }) => { return { iconClassName && } {label} ; }; -export const IconizedContextMenuOptionList: React.FC = ({first, red, className, children}) => { +export const IconizedContextMenuOptionList: React.FC = ({ first, red, className, children }) => { const classes = classNames("mx_IconizedContextMenu_optionList", className, { mx_IconizedContextMenu_optionList_notFirst: !first, mx_IconizedContextMenu_optionList_red: red, @@ -108,7 +108,7 @@ export const IconizedContextMenuOptionList: React.FC = ({first
  • ; }; -const IconizedContextMenu: React.FC = ({className, children, compact, ...props}) => { +const IconizedContextMenu: React.FC = ({ className, children, compact, ...props }) => { const classes = classNames("mx_IconizedContextMenu", className, { mx_IconizedContextMenu_compact: compact, }); diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index 5d1aad0600..a2086451cd 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -90,7 +90,7 @@ export default class MessageContextMenu extends React.Component { // HACK: Intentionally say we can't pin if the user doesn't want to use the functionality if (!SettingsStore.getValue("feature_pinning")) canPin = false; - this.setState({canRedact, canPin}); + this.setState({ canRedact, canPin }); }; _isPinned() { @@ -149,7 +149,7 @@ export default class MessageContextMenu extends React.Component { // display error message stating you couldn't delete this. Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, { title: _t('Error'), - description: _t('You cannot delete this message. (%(code)s)', {code}), + description: _t('You cannot delete this message. (%(code)s)', { code }), }); } } @@ -207,7 +207,7 @@ export default class MessageContextMenu extends React.Component { this.closeMenu(); }; - onPermalinkClick = (e: Event) => { + onPermalinkClick = (e) => { e.preventDefault(); const ShareDialog = sdk.getComponent("dialogs.ShareDialog"); Modal.createTrackedDialog('share room message dialog', '', ShareDialog, { @@ -266,7 +266,7 @@ export default class MessageContextMenu extends React.Component { resendReactionsButton = ( ); diff --git a/src/components/views/context_menus/StatusMessageContextMenu.js b/src/components/views/context_menus/StatusMessageContextMenu.js index 41f0e0ba61..23b91fe68f 100644 --- a/src/components/views/context_menus/StatusMessageContextMenu.js +++ b/src/components/views/context_menus/StatusMessageContextMenu.js @@ -17,10 +17,10 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import * as sdk from '../../../index'; import AccessibleButton from '../elements/AccessibleButton'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.context_menus.StatusMessageContextMenu") export default class StatusMessageContextMenu extends React.Component { diff --git a/src/components/views/context_menus/TagTileContextMenu.js b/src/components/views/context_menus/TagTileContextMenu.js index 4e381643ba..c40ff4207b 100644 --- a/src/components/views/context_menus/TagTileContextMenu.js +++ b/src/components/views/context_menus/TagTileContextMenu.js @@ -20,9 +20,9 @@ import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import dis from '../../../dispatcher/dispatcher'; import TagOrderActions from '../../../actions/TagOrderActions'; -import {MenuItem} from "../../structures/ContextMenu"; +import { MenuItem } from "../../structures/ContextMenu"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import GroupFilterOrderStore from "../../../stores/GroupFilterOrderStore"; @replaceableComponent("views.context_menus.TagTileContextMenu") diff --git a/src/components/views/context_menus/WidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx index 068bfd6497..b21efdceb9 100644 --- a/src/components/views/context_menus/WidgetContextMenu.tsx +++ b/src/components/views/context_menus/WidgetContextMenu.tsx @@ -14,22 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useContext} from "react"; -import {MatrixCapabilities} from "matrix-widget-api"; +import React, { useContext } from "react"; +import { MatrixCapabilities } from "matrix-widget-api"; -import IconizedContextMenu, {IconizedContextMenuOption, IconizedContextMenuOptionList} from "./IconizedContextMenu"; -import {ChevronFace} from "../../structures/ContextMenu"; -import {_t} from "../../../languageHandler"; -import {IApp} from "../../../stores/WidgetStore"; +import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from "./IconizedContextMenu"; +import { ChevronFace } from "../../structures/ContextMenu"; +import { _t } from "../../../languageHandler"; +import { IApp } from "../../../stores/WidgetStore"; import WidgetUtils from "../../../utils/WidgetUtils"; -import {WidgetMessagingStore} from "../../../stores/widgets/WidgetMessagingStore"; +import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore"; import RoomContext from "../../../contexts/RoomContext"; import dis from "../../../dispatcher/dispatcher"; import SettingsStore from "../../../settings/SettingsStore"; import Modal from "../../../Modal"; import QuestionDialog from "../dialogs/QuestionDialog"; import ErrorDialog from "../dialogs/ErrorDialog"; -import {WidgetType} from "../../../widgets/WidgetType"; +import { WidgetType } from "../../../widgets/WidgetType"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; import { getConfigLivestreamUrl, startJitsiAudioLivestream } from "../../../Livestream"; @@ -54,7 +54,7 @@ const WidgetContextMenu: React.FC = ({ ...props }) => { const cli = useContext(MatrixClientContext); - const {room, roomId} = useContext(RoomContext); + const { room, roomId } = useContext(RoomContext); const widgetMessaging = WidgetMessagingStore.instance.getMessagingForId(app.id); const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId); diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index 8997e4a5f8..c09097c4b4 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -14,29 +14,29 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ReactNode, useContext, useMemo, useState} from "react"; +import React, { ReactNode, useContext, useMemo, useState } from "react"; import classNames from "classnames"; -import {Room} from "matrix-js-sdk/src/models/room"; -import {MatrixClient} from "matrix-js-sdk/src/client"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { MatrixClient } from "matrix-js-sdk/src/client"; -import {_t} from '../../../languageHandler'; -import {IDialogProps} from "./IDialogProps"; +import { _t } from '../../../languageHandler'; +import { IDialogProps } from "./IDialogProps"; import BaseDialog from "./BaseDialog"; import Dropdown from "../elements/Dropdown"; import SearchBox from "../../structures/SearchBox"; import SpaceStore from "../../../stores/SpaceStore"; import RoomAvatar from "../avatars/RoomAvatar"; -import {getDisplayAliasForRoom} from "../../../Rooms"; +import { getDisplayAliasForRoom } from "../../../Rooms"; import AccessibleButton from "../elements/AccessibleButton"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import {sleep} from "../../../utils/promise"; +import { sleep } from "../../../utils/promise"; import DMRoomMap from "../../../utils/DMRoomMap"; -import {calculateRoomVia} from "../../../utils/permalinks/Permalinks"; +import { calculateRoomVia } from "../../../utils/permalinks/Permalinks"; import StyledCheckbox from "../elements/StyledCheckbox"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {sortRooms} from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; +import { sortRooms } from "../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; import ProgressBar from "../elements/ProgressBar"; -import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView"; +import { SpaceFeedbackPrompt } from "../../structures/SpaceRoomView"; import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar"; import QueryMatcher from "../../../autocomplete/QueryMatcher"; import TruncatedList from "../elements/TruncatedList"; diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index 77c69abc4e..ad4fc8d672 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -17,12 +17,12 @@ 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 { _t, _td } from '../../../languageHandler'; import * as sdk from '../../../index'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import dis from '../../../dispatcher/dispatcher'; import { addressTypes, getAddressType } from '../../../UserAddress'; import GroupStore from '../../../stores/GroupStore'; @@ -30,10 +30,10 @@ import * as Email from '../../../email'; import IdentityAuthClient from '../../../IdentityAuthClient'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils'; import { abbreviateUrl } from '../../../utils/UrlUtils'; -import {sleep} from "../../../utils/promise"; -import {Key} from "../../../Keyboard"; -import {Action} from "../../../dispatcher/actions"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { sleep } from "../../../utils/promise"; +import { Key } from "../../../Keyboard"; +import { Action } from "../../../dispatcher/actions"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const TRUNCATE_QUERY_LIST = 40; const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200; @@ -457,7 +457,7 @@ export default class AddressPickerDialog extends React.Component { const addrType = getAddressType(query); if (this.state.validAddressTypes.includes(addrType)) { if (addrType === 'email' && !Email.looksValid(query)) { - this.setState({searchError: _t("That doesn't look like a valid email address")}); + this.setState({ searchError: _t("That doesn't look like a valid email address") }); return; } suggestedList.unshift({ @@ -573,13 +573,13 @@ export default class AddressPickerDialog extends React.Component { _getFilteredSuggestions() { // map addressType => set of addresses to avoid O(n*m) operation const selectedAddresses = {}; - this.state.selectedList.forEach(({address, addressType}) => { + this.state.selectedList.forEach(({ address, addressType }) => { if (!selectedAddresses[addressType]) selectedAddresses[addressType] = new Set(); selectedAddresses[addressType].add(address); }); // Filter out any addresses in the above already selected addresses (matching both type and address) - return this.state.suggestedList.filter(({address, addressType}) => { + return this.state.suggestedList.filter(({ address, addressType }) => { return !(selectedAddresses[addressType] && selectedAddresses[addressType].has(address)); }); } diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.js index 0858e53e50..e92bd6315e 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.js @@ -23,10 +23,10 @@ import classNames from 'classnames'; import { Key } from '../../../Keyboard'; import AccessibleButton from '../elements/AccessibleButton'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; /* * Basic container for modal dialogs. diff --git a/src/components/views/dialogs/BetaFeedbackDialog.tsx b/src/components/views/dialogs/BetaFeedbackDialog.tsx index b8ff803627..5a2f16f169 100644 --- a/src/components/views/dialogs/BetaFeedbackDialog.tsx +++ b/src/components/views/dialogs/BetaFeedbackDialog.tsx @@ -14,28 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState} from "react"; +import React, { useState } from "react"; import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import Field from "../elements/Field"; import SdkConfig from "../../../SdkConfig"; -import {IDialogProps} from "./IDialogProps"; +import { IDialogProps } from "./IDialogProps"; import SettingsStore from "../../../settings/SettingsStore"; -import {submitFeedback} from "../../../rageshake/submit-rageshake"; +import { submitFeedback } from "../../../rageshake/submit-rageshake"; import StyledCheckbox from "../elements/StyledCheckbox"; import Modal from "../../../Modal"; import InfoDialog from "./InfoDialog"; import AccessibleButton from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; -import {Action} from "../../../dispatcher/actions"; +import { Action } from "../../../dispatcher/actions"; import { UserTab } from "./UserSettingsDialog"; interface IProps extends IDialogProps { featureId: string; } -const BetaFeedbackDialog: React.FC = ({featureId, onFinished}) => { +const BetaFeedbackDialog: React.FC = ({ featureId, onFinished }) => { const info = SettingsStore.getBetaInfo(featureId); const [comment, setComment] = useState(""); diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index f938340a50..eeb3769bf9 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -22,9 +22,9 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import sendBugReport, {downloadBugReport} from '../../../rageshake/submit-rageshake'; +import sendBugReport, { downloadBugReport } from '../../../rageshake/submit-rageshake'; import AccessibleButton from "../elements/AccessibleButton"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; @@ -68,7 +68,7 @@ export default class BugReportDialog extends React.Component { private onCancel = (): void => { this.props.onFinished(false); - } + }; private onSubmit = (): void => { if ((!this.state.text || !this.state.text.trim()) && (!this.state.issueUrl || !this.state.issueUrl.trim())) { @@ -110,7 +110,7 @@ export default class BugReportDialog extends React.Component { }); } }); - } + }; private onDownload = async (): Promise => { this.setState({ downloadBusy: true }); @@ -139,25 +139,25 @@ export default class BugReportDialog extends React.Component { private onTextChange = (ev: React.FormEvent): void => { this.setState({ text: ev.currentTarget.value }); - } + }; private onIssueUrlChange = (ev: React.FormEvent): void => { this.setState({ issueUrl: ev.currentTarget.value }); - } + }; private sendProgressCallback = (progress: string): void => { if (this.unmounted) { return; } this.setState({ progress }); - } + }; private downloadProgressCallback = (downloadProgress: string): void => { if (this.unmounted) { return; } this.setState({ downloadProgress }); - } + }; public render() { const Loader = sdk.getComponent("elements.Spinner"); diff --git a/src/components/views/dialogs/ChangelogDialog.tsx b/src/components/views/dialogs/ChangelogDialog.tsx index 0ded33cdcb..8acacd8e73 100644 --- a/src/components/views/dialogs/ChangelogDialog.tsx +++ b/src/components/views/dialogs/ChangelogDialog.tsx @@ -49,7 +49,7 @@ export default class ChangelogDialog extends React.Component { this.setState({ [REPOS[i]]: response.statusText }); return; } - this.setState({[REPOS[i]]: JSON.parse(body).commits}); + this.setState({ [REPOS[i]]: JSON.parse(body).commits }); }); } } @@ -93,7 +93,6 @@ export default class ChangelogDialog extends React.Component {
    ); - return ( { @@ -122,12 +122,12 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< if (index >= targets.length) return; // not important if (targets[index].trim() === "") { targets.splice(index, 1); - this.setState({emailTargets: targets}); + this.setState({ emailTargets: targets }); } }; private onShowPeopleClick = () => { - this.setState({showPeople: !this.state.showPeople}); + this.setState({ showPeople: !this.state.showPeople }); }; private setPersonToggle = (person: IPerson, selected: boolean) => { @@ -137,7 +137,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< } else if (!selected && targets.includes(person.userId)) { targets.splice(targets.indexOf(person.userId), 1); } - this.setState({userTargets: targets}); + this.setState({ userTargets: targets }); }; private renderPerson(person: IPerson, key: any) { @@ -165,7 +165,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< } private onShowMorePeople = () => { - this.setState({numPeople: this.state.numPeople + 5}); // arbitrary increase + this.setState({ numPeople: this.state.numPeople + 5 }); // arbitrary increase }; public render() { @@ -214,7 +214,7 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< if (this.state.people.length > 0) { peopleIntro = (
    - {_t("People you know on %(brand)s", {brand: SdkConfig.get().brand})} + {_t("People you know on %(brand)s", { brand: SdkConfig.get().brand })} {this.state.showPeople ? _t("Hide") : _t("Show")} @@ -225,14 +225,14 @@ export default class CommunityPrototypeInviteDialog extends React.PureComponent< let buttonText = _t("Skip"); const targetCount = this.state.userTargets.length + this.state.emailTargets.length; if (targetCount > 0) { - buttonText = _t("Send %(count)s invites", {count: targetCount}); + buttonText = _t("Send %(count)s invites", { count: targetCount }); } return (
    diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx index ae7b23c2c9..90b749b959 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx @@ -53,14 +53,14 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent => { if (proceed) { - this.setState({isRedacting: true}); + this.setState({ isRedacting: true }); try { await this.props.redact(); this.props.onFinished(true); } catch (error) { const code = error.errcode || error.statusCode; if (typeof code !== "undefined") { - this.setState({redactionErrorCode: code}); + this.setState({ redactionErrorCode: code }); } else { this.props.onFinished(true); } @@ -79,7 +79,7 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent ); } else { diff --git a/src/components/views/dialogs/ConfirmRedactDialog.tsx b/src/components/views/dialogs/ConfirmRedactDialog.tsx index eee05599e8..94f29a71fc 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx index d95b1fe358..2978179817 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx @@ -15,9 +15,9 @@ limitations under the License. */ import React from 'react'; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import * as sdk from "../../../index"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; diff --git a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx index 9b4484d661..29e9a2ad39 100644 --- a/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx +++ b/src/components/views/dialogs/CreateCommunityPrototypeDialog.tsx @@ -23,9 +23,9 @@ import AccessibleButton from "../elements/AccessibleButton"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import InfoTooltip from "../elements/InfoTooltip"; import dis from "../../../dispatcher/dispatcher"; -import {showCommunityRoomInviteDialog} from "../../../RoomInvite"; +import { showCommunityRoomInviteDialog } from "../../../RoomInvite"; import GroupStore from "../../../stores/GroupStore"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { } @@ -58,7 +58,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< private onNameChange = (ev: ChangeEvent) => { const localpart = (ev.target.value || "").toLowerCase().replace(/[^a-z0-9.\-_]/g, '-'); - this.setState({name: ev.target.value, localpart}); + this.setState({ name: ev.target.value, localpart }); }; private onSubmit = async (ev) => { @@ -69,7 +69,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< // We'll create the community now to see if it's taken, leaving it active in // the background for the user to look at while they invite people. - this.setState({busy: true}); + this.setState({ busy: true }); try { let avatarUrl = ''; // must be a string for synapse to accept it if (this.state.avatarFile) { @@ -85,7 +85,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< }); // Ensure the tag gets selected now that we've created it - dis.dispatch({action: 'deselect_tags'}, true); + dis.dispatch({ action: 'deselect_tags' }, true); dis.dispatch({ action: 'select_tag', tag: result.group_id, @@ -123,13 +123,13 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< private onAvatarChanged = (e: ChangeEvent) => { if (!e.target.files || !e.target.files.length) { - this.setState({avatarFile: null}); + this.setState({ avatarFile: null }); } else { - this.setState({busy: true}); + this.setState({ busy: true }); const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (ev: ProgressEvent) => { - this.setState({avatarFile: file, busy: false, avatarPreview: ev.target.result as string}); + this.setState({ avatarFile: file, busy: false, avatarPreview: ev.target.result as string }); }; reader.readAsDataURL(file); } @@ -175,7 +175,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent< let preview = ; if (!this.state.avatarPreview) { - preview =
    + preview =
    ; } return ( @@ -204,7 +204,7 @@ export default class CreateCommunityPrototypeDialog extends React.PureComponent<
    diff --git a/src/components/views/dialogs/CreateGroupDialog.tsx b/src/components/views/dialogs/CreateGroupDialog.tsx index 60e4f5efb8..f03a40ddc5 100644 --- a/src/components/views/dialogs/CreateGroupDialog.tsx +++ b/src/components/views/dialogs/CreateGroupDialog.tsx @@ -18,8 +18,8 @@ import React from 'react'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; @@ -83,7 +83,7 @@ export default class CreateGroupDialog extends React.Component { if (this.state.groupName !== '') { profile.name = this.state.groupName; } - this.setState({creating: true}); + this.setState({ creating: true }); MatrixClientPeg.get().createGroup({ localpart: this.state.groupId, profile: profile, @@ -95,9 +95,9 @@ export default class CreateGroupDialog extends React.Component { }); this.props.onFinished(true); }).catch((e) => { - this.setState({createError: e}); + this.setState({ createError: e }); }).finally(() => { - this.setState({creating: false}); + this.setState({ creating: false }); }); }; diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index 544f593708..b5c0096771 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -137,9 +137,9 @@ export default class CreateRoomDialog extends React.Component { if (activeElement) { activeElement.blur(); } - await this.nameField.current.validate({allowEmpty: false}); + await this.nameField.current.validate({ allowEmpty: false }); if (this.aliasField.current) { - await this.aliasField.current.validate({allowEmpty: false}); + await this.aliasField.current.validate({ allowEmpty: false }); } // Validation and state updates are async, so we need to wait for them to complete // first. Queue a `setState` callback and wait for it to resolve. @@ -194,7 +194,7 @@ export default class CreateRoomDialog extends React.Component { private onNameValidate = async (fieldState: IFieldState) => { const result = await CreateRoomDialog.validateRoomName(fieldState); - this.setState({nameIsValid: result.valid}); + this.setState({ nameIsValid: result.valid }); return result; }; @@ -276,7 +276,7 @@ export default class CreateRoomDialog extends React.Component { let title = this.state.isPublic ? _t('Create a public room') : _t('Create a private room'); if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { const name = CommunityPrototypeStore.instance.getSelectedCommunityName(); - title = _t("Create a room in %(communityName)s", {communityName: name}); + title = _t("Create a room in %(communityName)s", { communityName: name }); } return ( { { focus: false, onFinished: (doLogout) => { if (doLogout) { - dis.dispatch({action: 'logout'}); + dis.dispatch({ action: 'logout' }); props.onFinished(true); } }, diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index cf88802340..6df6056670 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -19,13 +19,13 @@ import React from 'react'; import * as sdk from '../../../index'; import Analytics from '../../../Analytics'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import * as Lifecycle from '../../../Lifecycle'; import { _t } from '../../../languageHandler'; -import InteractiveAuth, {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth"; -import {DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents"; +import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth"; +import { DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; import StyledCheckbox from "../elements/StyledCheckbox"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; @@ -100,7 +100,7 @@ export default class DeactivateAccountDialog extends React.Component { @@ -112,7 +112,7 @@ export default class DeactivateAccountDialog extends React.Component { @@ -123,7 +123,7 @@ export default class DeactivateAccountDialog extends React.Component { console.error(e); - this.setState({errStr: _t("There was a problem communicating with the server. Please try again.")}); + this.setState({ errStr: _t("There was a problem communicating with the server. Please try again.") }); }); }; @@ -153,13 +153,13 @@ export default class DeactivateAccountDialog extends React.Component { if (e && e.httpStatus === 401 && e.data) { // Valid UIA response - this.setState({authData: e.data, authEnabled: true}); + this.setState({ authData: e.data, authEnabled: true }); } else { - this.setState({errStr: _t("Server did not return valid authentication information.")}); + this.setState({ errStr: _t("Server did not return valid authentication information.") }); } }); } diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx index b1749b370a..de958f8e9a 100644 --- a/src/components/views/dialogs/DevtoolsDialog.tsx +++ b/src/components/views/dialogs/DevtoolsDialog.tsx @@ -62,13 +62,13 @@ abstract class GenericEditor< } else { this.props.onBack(); } - } + }; protected onChange = (e: ChangeEvent) => { // @ts-ignore: Unsure how to convince TS this is okay when the state // type can be extended. - this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value}); - } + this.setState({ [e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value }); + }; protected abstract send(); @@ -119,7 +119,7 @@ export class SendCustomEvent extends GenericEditor { !this.state.message && } - { showTglFlip &&
    + { showTglFlip &&
    { !this.state.message && } - { !this.state.message &&
    + { !this.state.message &&
    { this.setState({ editing: true }); - } + }; private onQueryEventType = (filterEventType: string) => { this.setState({ queryEventType: filterEventType }); - } + }; private onQueryStateKey = (filterStateKey: string) => { this.setState({ queryStateKey: filterStateKey }); - } + }; render() { if (this.state.event) { @@ -570,19 +570,19 @@ class AccountDataExplorer extends React.PureComponent) => { - this.setState({[e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value}); - } + this.setState({ [e.target.id]: e.target.type === 'checkbox' ? e.target.checked : e.target.value }); + }; private editEv = () => { this.setState({ editing: true }); - } + }; private onQueryEventType = (queryEventType: string) => { this.setState({ queryEventType }); - } + }; render() { if (this.state.event) { @@ -630,7 +630,7 @@ class AccountDataExplorer extends React.PureComponent
    -
    +
    { this.setState({ query }); - } + }; render() { return
    @@ -704,7 +704,7 @@ const PHASE_MAP = { const VerificationRequestExplorer: React.FC<{ txnId: string; request: VerificationRequest; -}> = ({txnId, request}) => { +}> = ({ txnId, request }) => { const [, updateState] = useState(); const [timeout, setRequestTimeout] = useState(request.timeout); @@ -739,7 +739,7 @@ const VerificationRequestExplorer: React.FC<{
    {JSON.stringify(request.observeOnly)}
    ); -} +}; class VerificationExplorer extends React.PureComponent { static getLabel() { @@ -751,7 +751,7 @@ class VerificationExplorer extends React.PureComponent { private onNewRequest = () => { this.forceUpdate(); - } + }; componentDidMount() { const cli = this.context; @@ -806,17 +806,17 @@ class WidgetExplorer extends React.Component { - this.setState({query}); + this.setState({ query }); }; private onEditWidget = (widget: IApp) => { - this.setState({editWidget: widget}); + this.setState({ editWidget: widget }); }; private onBack = () => { const widgets = WidgetStore.instance.getApps(this.props.room.roomId); if (this.state.editWidget && widgets.includes(this.state.editWidget)) { - this.setState({editWidget: null}); + this.setState({ editWidget: null }); } else { this.props.onBack(); } @@ -908,22 +908,22 @@ class SettingsExplorer extends React.PureComponent) => { - this.setState({query: ev.target.value}); + this.setState({ query: ev.target.value }); }; private onExplValuesEdit = (ev: ChangeEvent) => { - this.setState({explicitValues: ev.target.value}); + this.setState({ explicitValues: ev.target.value }); }; private onExplRoomValuesEdit = (ev: ChangeEvent) => { - this.setState({explicitRoomValues: ev.target.value}); + this.setState({ explicitRoomValues: ev.target.value }); }; private onBack = () => { if (this.state.editSetting) { - this.setState({editSetting: null}); + this.setState({ editSetting: null }); } else if (this.state.viewSetting) { - this.setState({viewSetting: null}); + this.setState({ viewSetting: null }); } else { this.props.onBack(); } @@ -931,7 +931,7 @@ class SettingsExplorer extends React.PureComponent { ev.preventDefault(); - this.setState({viewSetting: settingId}); + this.setState({ viewSetting: settingId }); }; private onEditClick = (ev: MouseEvent, settingId: string) => { @@ -1221,11 +1221,11 @@ export default class DevtoolsDialog extends React.PureComponent private onBack = () => { this.setState({ mode: null }); - } + }; private onCancel = () => { this.props.onFinished(false); - } + }; render() { let body; diff --git a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx index ee3696b427..217e4f2d37 100644 --- a/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx +++ b/src/components/views/dialogs/EditCommunityPrototypeDialog.tsx @@ -23,8 +23,8 @@ import AccessibleButton from "../elements/AccessibleButton"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; import FlairStore from "../../../stores/FlairStore"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; interface IProps extends IDialogProps { communityId: string; @@ -60,7 +60,7 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent) => { - this.setState({name: ev.target.value}); + this.setState({ name: ev.target.value }); }; private onSubmit = async (ev) => { @@ -71,7 +71,7 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent) => { if (!e.target.files || !e.target.files.length) { - this.setState({avatarFile: null}); + this.setState({ avatarFile: null }); } else { - this.setState({busy: true}); + this.setState({ busy: true }); const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (ev: ProgressEvent) => { - this.setState({avatarFile: file, busy: false, avatarPreview: ev.target.result as string}); + this.setState({ avatarFile: file, busy: false, avatarPreview: ev.target.result as string }); }; reader.readAsDataURL(file); } @@ -122,7 +122,7 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent; } else { - preview =
    + preview =
    ; } } @@ -144,7 +144,7 @@ export default class EditCommunityPrototypeDialog extends React.PureComponent
    diff --git a/src/components/views/dialogs/ErrorDialog.tsx b/src/components/views/dialogs/ErrorDialog.tsx index d50ec7bf36..0f675f0df7 100644 --- a/src/components/views/dialogs/ErrorDialog.tsx +++ b/src/components/views/dialogs/ErrorDialog.tsx @@ -28,7 +28,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { onFinished: (success: boolean) => void; diff --git a/src/components/views/dialogs/FeedbackDialog.js b/src/components/views/dialogs/FeedbackDialog.js index d80a935573..88a57cf8cb 100644 --- a/src/components/views/dialogs/FeedbackDialog.js +++ b/src/components/views/dialogs/FeedbackDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import Field from "../elements/Field"; @@ -30,7 +30,6 @@ const existingIssuesUrl = "https://github.com/vector-im/element-web/issues" + "?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc"; const newIssueUrl = "https://github.com/vector-im/element-web/issues/new"; - export default (props) => { const [rating, setRating] = useState(""); const [comment, setComment] = useState(""); diff --git a/src/components/views/dialogs/HostSignupDialog.tsx b/src/components/views/dialogs/HostSignupDialog.tsx index c8bc907136..64c080bf01 100644 --- a/src/components/views/dialogs/HostSignupDialog.tsx +++ b/src/components/views/dialogs/HostSignupDialog.tsx @@ -31,7 +31,7 @@ import { IPostmessageResponseData, PostmessageAction, } from "./HostSignupDialogTypes"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const HOST_SIGNUP_KEY = "host_signup"; @@ -86,7 +86,7 @@ export default class HostSignupDialog extends React.PureComponent { this.setState({ @@ -96,7 +96,7 @@ export default class HostSignupDialog extends React.PureComponent { this.setState({ @@ -106,7 +106,7 @@ export default class HostSignupDialog extends React.PureComponent { window.removeEventListener("message", this.messageHandler); @@ -114,7 +114,7 @@ export default class HostSignupDialog extends React.PureComponent { if (this.state.completed) { @@ -137,16 +137,16 @@ export default class HostSignupDialog extends React.PureComponent { this.iframeRef.current.contentWindow.postMessage(message, this.config.url); - } + }; private async sendAccountDetails() { const openIdToken = await MatrixClientPeg.get().getOpenIdToken(); if (!openIdToken || !openIdToken.access_token) { - console.warn("Failed to connect to homeserver for OpenID token.") + console.warn("Failed to connect to homeserver for OpenID token."); this.setState({ completed: true, error: _t("Failed to connect to your homeserver. Please close this dialog and try again."), @@ -171,7 +171,7 @@ export default class HostSignupDialog extends React.PureComponent { const textComponent = ( @@ -215,7 +215,7 @@ export default class HostSignupDialog extends React.PureComponent { - this.setState({phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM}); + this.setState({ phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM }); this.props.verifier.verify().then(() => { - this.setState({phase: PHASE_VERIFIED}); + this.setState({ phase: PHASE_VERIFIED }); }).catch((e) => { console.log("Verification failed", e); }); diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.js b/src/components/views/dialogs/IntegrationsDisabledDialog.js index dd7a51420e..1e2ff09196 100644 --- a/src/components/views/dialogs/IntegrationsDisabledDialog.js +++ b/src/components/views/dialogs/IntegrationsDisabledDialog.js @@ -16,11 +16,11 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; -import {Action} from "../../../dispatcher/actions"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Action } from "../../../dispatcher/actions"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.IntegrationsDisabledDialog") export default class IntegrationsDisabledDialog extends React.Component { diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.js b/src/components/views/dialogs/IntegrationsImpossibleDialog.js index e14d40aaef..2cf9daa7ea 100644 --- a/src/components/views/dialogs/IntegrationsImpossibleDialog.js +++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.js @@ -16,10 +16,10 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import * as sdk from "../../../index"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") export default class IntegrationsImpossibleDialog extends React.Component { diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.js index 28a9bf673a..09da72cab0 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.js +++ b/src/components/views/dialogs/InteractiveAuthDialog.js @@ -23,9 +23,9 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; -import {ERROR_USER_CANCELLED} from "../../structures/InteractiveAuth"; -import {SSOAuthEntry} from "../auth/InteractiveAuthEntryComponents"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth"; +import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.InteractiveAuthDialog") export default class InteractiveAuthDialog extends React.Component { @@ -117,7 +117,7 @@ export default class InteractiveAuthDialog extends React.Component { _onUpdateStagePhase = (newStage, newPhase) => { // We copy the stage and stage phase params into state for title selection in render() - this.setState({uiaStage: newStage, uiaStagePhase: newPhase}); + this.setState({ uiaStage: newStage, uiaStagePhase: newPhase }); }; _onDismissClick = () => { diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 553c1c544e..d9dcb8fe00 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -426,8 +426,8 @@ export default class InviteDialog extends React.PureComponent { - this.setState({consultFirst: ev.target.checked}); - } + this.setState({ consultFirst: ev.target.checked }); + }; public static buildRecents(excludedTargetIds: Set): IRecentUser[] { const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room @@ -482,7 +482,7 @@ export default class InviteDialog extends React.PureComponent ({userId: m.member.userId, user: m.member})); + return members.map(m => ({ userId: m.member.userId, user: m.member })); } private shouldAbortAfterInviteError(result: IInviteResult, room: Room): boolean { @@ -623,18 +623,18 @@ export default class InviteDialog extends React.PureComponent { - this.setState({busy: true}); + this.setState({ busy: true }); const client = MatrixClientPeg.get(); const targets = this.convertFilter(); const targetIds = targets.map(t => t.userId); @@ -657,7 +657,7 @@ export default class InviteDialog extends React.PureComponent { const startTime = CountlyAnalytics.getTimestamp(); - this.setState({busy: true}); + this.setState({ busy: true }); this.convertFilter(); const targets = this.convertFilter(); const targetIds = targets.map(t => t.userId); @@ -729,7 +729,7 @@ export default class InviteDialog extends React.PureComponent { - MatrixClientPeg.get().searchUserDirectory({term}).then(async r => { + MatrixClientPeg.get().searchUserDirectory({ term }).then(async r => { if (term !== this.state.filterText) { // Discard the results - we were probably too slow on the server-side to make // these results useful. This is a race we want to avoid because we could overwrite @@ -874,14 +874,14 @@ export default class InviteDialog extends React.PureComponent { console.error("Error searching user directory:"); console.error(e); - this.setState({serverResultsMixin: []}); // clear results because it's moderately fatal + this.setState({ serverResultsMixin: [] }); // clear results because it's moderately fatal }); // Whenever we search the directory, also try to search the identity server. It's // all debounced the same anyways. if (!this.state.canUseIdentityServer) { // The user doesn't have an identity server set - warn them of that. - this.setState({tryingIdentityServer: true}); + this.setState({ tryingIdentityServer: true }); return; } if (term.indexOf('@') > 0 && Email.looksValid(term) && SettingsStore.getValue(UIFeature.IdentityServer)) { @@ -889,7 +889,7 @@ export default class InviteDialog extends React.PureComponent { const term = e.target.value; - this.setState({filterText: term}); + this.setState({ filterText: term }); // Debounce server lookups to reduce spam. We don't clear the existing server // results because they might still be vaguely accurate, likewise for races which @@ -950,11 +950,11 @@ export default class InviteDialog extends React.PureComponent { - this.setState({numRecentsShown: this.state.numRecentsShown + INCREMENT_ROOMS_SHOWN}); + this.setState({ numRecentsShown: this.state.numRecentsShown + INCREMENT_ROOMS_SHOWN }); }; private showMoreSuggestions = () => { - this.setState({numSuggestionsShown: this.state.numSuggestionsShown + INCREMENT_ROOMS_SHOWN}); + this.setState({ numSuggestionsShown: this.state.numSuggestionsShown + INCREMENT_ROOMS_SHOWN }); }; private toggleMember = (member: Member) => { @@ -968,7 +968,7 @@ export default class InviteDialog extends React.PureComponent= 0) { targets.splice(idx, 1); - this.setState({targets}); + this.setState({ targets }); } if (this.editorRef && this.editorRef.current) { @@ -1051,13 +1051,13 @@ export default class InviteDialog extends React.PureComponent { @@ -1076,7 +1076,7 @@ export default class InviteDialog extends React.PureComponent { @@ -1100,7 +1100,7 @@ export default class InviteDialog extends React.PureComponent).", {}, - {userId: () => { + { userId: () => { return ( {userId} ); - }}, + } }, ); } else { helpText = _t( "Start a conversation with someone using their name or username (like ).", {}, - {userId: () => { + { userId: () => { return ( {userId} ); - }}, + } }, ); } @@ -1320,7 +1320,7 @@ export default class InviteDialog extends React.PureComponenthere", - {communityName}, { + { communityName }, { userId: () => { return (
    -
    +
    ; } else if (this.props.kind === KIND_INVITE) { const room = MatrixClientPeg.get()?.getRoom(this.props.roomId); const isSpace = SettingsStore.getValue("feature_spaces") && room?.isSpaceRoom(); diff --git a/src/components/views/dialogs/KeySignatureUploadFailedDialog.js b/src/components/views/dialogs/KeySignatureUploadFailedDialog.js index bcb4d4f9b9..22487af17c 100644 --- a/src/components/views/dialogs/KeySignatureUploadFailedDialog.js +++ b/src/components/views/dialogs/KeySignatureUploadFailedDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState, useCallback, useRef} from 'react'; +import React, { useState, useCallback, useRef } from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index 7bced46d43..bd9411358b 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -22,7 +22,7 @@ import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import RestoreKeyBackupDialog from './security/RestoreKeyBackupDialog'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.LogoutDialog") export default class LogoutDialog extends React.Component { @@ -85,7 +85,7 @@ export default class LogoutDialog extends React.Component { _onFinished(confirmed) { if (confirmed) { - dis.dispatch({action: 'logout'}); + dis.dispatch({ action: 'logout' }); } // close dialog this.props.onFinished(); @@ -112,7 +112,7 @@ export default class LogoutDialog extends React.Component { } _onLogoutConfirm() { - dis.dispatch({action: 'logout'}); + dis.dispatch({ action: 'logout' }); // close dialog this.props.onFinished(); diff --git a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js index 3151edd796..4387108fac 100644 --- a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js +++ b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js @@ -20,11 +20,11 @@ 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 * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.ManualDeviceKeyVerificationDialog") export default class ManualDeviceKeyVerificationDialog extends React.Component { diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.js b/src/components/views/dialogs/MessageEditHistoryDialog.js index 64d66fe833..b9225f5932 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.js +++ b/src/components/views/dialogs/MessageEditHistoryDialog.js @@ -16,12 +16,12 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; import * as sdk from "../../../index"; -import {wantsDateSeparator} from '../../../DateUtils'; +import { wantsDateSeparator } from '../../../DateUtils'; import SettingsStore from '../../../settings/SettingsStore'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.MessageEditHistoryDialog") export default class MessageEditHistoryDialog extends React.PureComponent { @@ -46,7 +46,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { // bail out on backwards as we only paginate in one direction return false; } - const opts = {from: this.state.nextBatch}; + const opts = { from: this.state.nextBatch }; const roomId = this.props.mxEvent.getRoomId(); const eventId = this.props.mxEvent.getId(); const client = MatrixClientPeg.get(); @@ -62,7 +62,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { if (error.errcode) { console.error("fetching /relations failed with error", error); } - this.setState({error}, () => reject(error)); + this.setState({ error }, () => reject(error)); return promise; } @@ -131,7 +131,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { render() { let content; if (this.state.error) { - const {error} = this.state; + const { error } = this.state; if (error.errcode === "M_UNRECOGNIZED") { content = (

    {_t("Your homeserver doesn't seem to support this feature.")} diff --git a/src/components/views/dialogs/ModalWidgetDialog.tsx b/src/components/views/dialogs/ModalWidgetDialog.tsx index df2ed6b335..6bc84b66b4 100644 --- a/src/components/views/dialogs/ModalWidgetDialog.tsx +++ b/src/components/views/dialogs/ModalWidgetDialog.tsx @@ -33,13 +33,13 @@ import { WidgetApiFromWidgetAction, WidgetKind, } from "matrix-widget-api"; -import {StopGapWidgetDriver} from "../../../stores/widgets/StopGapWidgetDriver"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {OwnProfileStore} from "../../../stores/OwnProfileStore"; +import { StopGapWidgetDriver } from "../../../stores/widgets/StopGapWidgetDriver"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { OwnProfileStore } from "../../../stores/OwnProfileStore"; import { arrayFastClone } from "../../../utils/arrays"; import { ElementWidget } from "../../../stores/widgets/StopGapWidget"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {ELEMENT_CLIENT_ID} from "../../../identifiers"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { ELEMENT_CLIENT_ID } from "../../../identifiers"; import SettingsStore from "../../../settings/SettingsStore"; interface IProps { @@ -81,7 +81,7 @@ export default class ModalWidgetDialog extends React.PureComponent) => { this.props.onFinished(true, ev.detail.data); - } + }; private onButtonEnableToggle = (ev: CustomEvent) => { ev.preventDefault(); const isClose = ev.detail.data.button === BuiltInModalButtonID.Close; if (isClose || !this.possibleButtons.includes(ev.detail.data.button)) { return this.state.messaging.transport.reply(ev.detail, { - error: {message: "Invalid button"}, + error: { message: "Invalid button" }, } as IWidgetApiErrorResponseData); } @@ -122,7 +122,7 @@ export default class ModalWidgetDialog extends React.PureComponent = ({onFinished}) => { +const RegistrationEmailPromptDialog: React.FC = ({ onFinished }) => { const [email, setEmail] = useState(""); const fieldRef = useRef(); diff --git a/src/components/views/dialogs/ReportEventDialog.tsx b/src/components/views/dialogs/ReportEventDialog.tsx index 8271239f7f..81a7d569fe 100644 --- a/src/components/views/dialogs/ReportEventDialog.tsx +++ b/src/components/views/dialogs/ReportEventDialog.tsx @@ -19,11 +19,11 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { ensureDMExists } from "../../../createRoom"; import { IDialogProps } from "./IDialogProps"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import SdkConfig from '../../../SdkConfig'; import Markdown from '../../../Markdown'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from "../../../settings/SettingsStore"; import StyledRadioButton from "../elements/StyledRadioButton"; @@ -40,7 +40,6 @@ interface IState { nature?: EXTENDED_NATURE; } - const MODERATED_BY_STATE_EVENT_TYPE = [ "org.matrix.msc3215.room.moderation.moderated_by", /** @@ -75,7 +74,7 @@ type Moderation = { moderationRoomId: string; // The id of the bot in charge of forwarding abuse reports to the moderation room. moderationBotUserId: string; -} +}; /* * A dialog for reporting an event. * @@ -162,13 +161,13 @@ export default class ReportEventDialog extends React.Component { } // The user has written down a freeform description of the abuse. - private onReasonChange = ({target: {value: reason}}): void => { + private onReasonChange = ({ target: { value: reason } }): void => { this.setState({ reason }); }; // The user has clicked on a nature. private onNatureChosen = (e: React.FormEvent): void => { - this.setState({ nature: e.currentTarget.value as EXTENDED_NATURE}); + this.setState({ nature: e.currentTarget.value as EXTENDED_NATURE }); }; // The user has clicked "cancel". diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index 303f17c342..005222a94e 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -16,8 +16,8 @@ limitations under the License. */ import React from 'react'; -import TabbedView, {Tab} from "../../structures/TabbedView"; -import {_t, _td} from "../../../languageHandler"; +import TabbedView, { Tab } from "../../structures/TabbedView"; +import { _t, _td } from "../../../languageHandler"; import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab"; import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab"; import GeneralRoomSettingsTab from "../settings/tabs/room/GeneralRoomSettingsTab"; @@ -25,11 +25,11 @@ import SecurityRoomSettingsTab from "../settings/tabs/room/SecurityRoomSettingsT import NotificationSettingsTab from "../settings/tabs/room/NotificationSettingsTab"; import BridgeSettingsTab from "../settings/tabs/room/BridgeSettingsTab"; import * as sdk from "../../../index"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; import SettingsStore from "../../../settings/SettingsStore"; -import {UIFeature} from "../../../settings/UIFeature"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { UIFeature } from "../../../settings/UIFeature"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB"; export const ROOM_SECURITY_TAB = "ROOM_SECURITY_TAB"; @@ -127,7 +127,7 @@ export default class RoomSettingsDialog extends React.Component { className='mx_RoomSettingsDialog' hasCancel={true} onFinished={this.props.onFinished} - title={_t("Room Settings - %(roomName)s", {roomName})} + title={_t("Room Settings - %(roomName)s", { roomName })} >

    { @@ -44,7 +44,7 @@ export default class RoomUpgradeDialog extends React.Component { }; _onUpgradeClick = () => { - this.setState({busy: true}); + this.setState({ busy: true }); MatrixClientPeg.get().upgradeRoom(this.props.room.roomId, this._targetVersion).then(() => { this.props.onFinished(true); }).catch((err) => { @@ -54,7 +54,7 @@ export default class RoomUpgradeDialog extends React.Component { description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")), }); }).finally(() => { - this.setState({busy: false}); + this.setState({ busy: false }); }); }; @@ -70,7 +70,7 @@ export default class RoomUpgradeDialog extends React.Component { buttons = { - this.props.onFinished({continue: true, invite: this.state.isPrivate && this.state.inviteUsersToNewRoom}); + this.props.onFinished({ continue: true, invite: this.state.isPrivate && this.state.inviteUsersToNewRoom }); }; _onCancel = () => { - this.props.onFinished({continue: false, invite: false}); + this.props.onFinished({ continue: false, invite: false }); }; _onInviteUsersToggle = (newVal) => { - this.setState({inviteUsersToNewRoom: newVal}); + this.setState({ inviteUsersToNewRoom: newVal }); }; _openBugReportDialog = (e) => { @@ -86,7 +86,7 @@ export default class RoomUpgradeWarningDialog extends React.Component {

    {_t( "This usually only affects how the room is processed on the server. If you're " + - "having problems with your %(brand)s, please report a bug.", {brand}, + "having problems with your %(brand)s, please report a bug.", { brand }, )}

    ); diff --git a/src/components/views/dialogs/ServerOfflineDialog.tsx b/src/components/views/dialogs/ServerOfflineDialog.tsx index 52ff056907..ebf32e9131 100644 --- a/src/components/views/dialogs/ServerOfflineDialog.tsx +++ b/src/components/views/dialogs/ServerOfflineDialog.tsx @@ -28,7 +28,7 @@ import AccessibleButton from "../elements/AccessibleButton"; import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { IDialogProps } from "./IDialogProps"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends IDialogProps { } @@ -85,7 +85,7 @@ export default class ServerOfflineDialog extends React.PureComponent { {entries}
    - ) + ); }); } @@ -108,7 +108,7 @@ export default class ServerOfflineDialog extends React.PureComponent { "Below are some of the most likely reasons.", )}

      -
    • {_t("The server (%(serverName)s) took too long to respond.", {serverName})}
    • +
    • {_t("The server (%(serverName)s) took too long to respond.", { serverName })}
    • {_t("Your firewall or anti-virus is blocking the request.")}
    • {_t("A browser extension is preventing the request.")}
    • {_t("The server is offline.")}
    • diff --git a/src/components/views/dialogs/ServerPickerDialog.tsx b/src/components/views/dialogs/ServerPickerDialog.tsx index 11fef9e75d..8dafd8a2bc 100644 --- a/src/components/views/dialogs/ServerPickerDialog.tsx +++ b/src/components/views/dialogs/ServerPickerDialog.tsx @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef} from "react"; -import {AutoDiscovery} from "matrix-js-sdk/src/autodiscovery"; +import React, { createRef } from "react"; +import { AutoDiscovery } from "matrix-js-sdk/src/autodiscovery"; -import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; +import AutoDiscoveryUtils, { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; import BaseDialog from './BaseDialog'; import { _t } from '../../../languageHandler'; import AccessibleButton from "../elements/AccessibleButton"; @@ -25,8 +25,8 @@ import SdkConfig from "../../../SdkConfig"; import Field from "../elements/Field"; import StyledRadioButton from "../elements/StyledRadioButton"; import TextWithTooltip from "../elements/TextWithTooltip"; -import withValidation, {IFieldState} from "../elements/Validation"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import withValidation, { IFieldState } from "../elements/Validation"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { title?: string; diff --git a/src/components/views/dialogs/SeshatResetDialog.tsx b/src/components/views/dialogs/SeshatResetDialog.tsx index 63654ca949..863157ec08 100644 --- a/src/components/views/dialogs/SeshatResetDialog.tsx +++ b/src/components/views/dialogs/SeshatResetDialog.tsx @@ -15,13 +15,13 @@ limitations under the License. */ import React from 'react'; -import {_t} from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { _t } from "../../../languageHandler"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; -import {IDialogProps} from "./IDialogProps"; +import { IDialogProps } from "./IDialogProps"; @replaceableComponent("views.dialogs.SeshatResetDialog") export default class SeshatResetDialog extends React.PureComponent { diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js index 43e73a2f83..b7037d1f4f 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js @@ -22,7 +22,7 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.SessionRestoreErrorDialog") export default class SessionRestoreErrorDialog extends React.Component { diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.js index 0f8f410a6a..3dad3821fb 100644 --- a/src/components/views/dialogs/SetEmailDialog.js +++ b/src/components/views/dialogs/SetEmailDialog.js @@ -22,8 +22,7 @@ import * as Email from '../../../email'; import AddThreepid from '../../../AddThreepid'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; - +import { replaceableComponent } from "../../../utils/replaceableComponent"; /* * Prompt the user to set an email address. @@ -71,14 +70,14 @@ export default class SetEmailDialog extends React.Component { onFinished: this.onEmailDialogFinished, }); }, (err) => { - this.setState({emailBusy: false}); + this.setState({ emailBusy: false }); console.error("Unable to add email address " + emailAddress + " " + err); Modal.createTrackedDialog('Unable to add email address', '', ErrorDialog, { title: _t("Unable to add email address"), description: ((err && err.message) ? err.message : _t("Operation failed")), }); }); - this.setState({emailBusy: true}); + this.setState({ emailBusy: true }); }; onCancelled = () => { @@ -89,7 +88,7 @@ export default class SetEmailDialog extends React.Component { if (ok) { this.verifyEmailAddress(); } else { - this.setState({emailBusy: false}); + this.setState({ emailBusy: false }); } }; @@ -97,7 +96,7 @@ export default class SetEmailDialog extends React.Component { this._addThreepid.checkEmailLinkClicked().then(() => { this.props.onFinished(true); }, (err) => { - this.setState({emailBusy: false}); + this.setState({ emailBusy: false }); if (err.errcode == 'M_THREEPID_AUTH_FAILED') { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); const message = _t("Unable to verify email address.") + " " + diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx index df1206a4f0..fb43db1a25 100644 --- a/src/components/views/dialogs/ShareDialog.tsx +++ b/src/components/views/dialogs/ShareDialog.tsx @@ -17,24 +17,24 @@ limitations under the License. import * as React from 'react'; import * as PropTypes from 'prop-types'; -import {Room} from "matrix-js-sdk/src/models/room"; -import {User} from "matrix-js-sdk/src/models/user"; -import {Group} from "matrix-js-sdk/src/models/group"; -import {RoomMember} from "matrix-js-sdk/src/models/room-member"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { User } from "matrix-js-sdk/src/models/user"; +import { Group } from "matrix-js-sdk/src/models/group"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import QRCode from "../elements/QRCode"; -import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/Permalinks"; +import { RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink } from "../../../utils/permalinks/Permalinks"; import * as ContextMenu from "../../structures/ContextMenu"; -import {toRightOf} from "../../structures/ContextMenu"; -import {copyPlaintext, selectText} from "../../../utils/strings"; +import { toRightOf } from "../../structures/ContextMenu"; +import { copyPlaintext, selectText } from "../../../utils/strings"; import StyledCheckbox from '../elements/StyledCheckbox'; import AccessibleTooltipButton from '../elements/AccessibleTooltipButton'; import { IDialogProps } from "./IDialogProps"; import SettingsStore from "../../../settings/SettingsStore"; -import {UIFeature} from "../../../settings/UIFeature"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { UIFeature } from "../../../settings/UIFeature"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const socials = [ { @@ -120,7 +120,7 @@ export default class ShareDialog extends React.PureComponent { const successful = await copyPlaintext(this.getUrl()); const buttonRect = target.getBoundingClientRect(); const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu'); - const {close} = ContextMenu.createMenu(GenericTextContextMenu, { + const { close } = ContextMenu.createMenu(GenericTextContextMenu, { ...toRightOf(buttonRect, 2), message: successful ? _t('Copied!') : _t('Failed to copy'), }); diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.js b/src/components/views/dialogs/SlashCommandHelpDialog.js index 5b4148e939..608f81a612 100644 --- a/src/components/views/dialogs/SlashCommandHelpDialog.js +++ b/src/components/views/dialogs/SlashCommandHelpDialog.js @@ -15,11 +15,11 @@ limitations under the License. */ import React from 'react'; -import {_t} from "../../../languageHandler"; -import {CommandCategories, Commands} from "../../../SlashCommands"; +import { _t } from "../../../languageHandler"; +import { CommandCategories, Commands } from "../../../SlashCommands"; import * as sdk from "../../../index"; -export default ({onFinished}) => { +export default ({ onFinished }) => { const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); const categories = {}; diff --git a/src/components/views/dialogs/SpaceSettingsDialog.tsx b/src/components/views/dialogs/SpaceSettingsDialog.tsx index 5e0cd96740..fe836ebc5c 100644 --- a/src/components/views/dialogs/SpaceSettingsDialog.tsx +++ b/src/components/views/dialogs/SpaceSettingsDialog.tsx @@ -42,7 +42,7 @@ interface IProps extends IDialogProps { } const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFinished }) => { - useDispatcher(defaultDispatcher, ({action, ...params}) => { + useDispatcher(defaultDispatcher, ({ action, ...params }) => { if (action === "after_leave_room" && params.room_id === space.roomId) { onFinished(false); } diff --git a/src/components/views/dialogs/StorageEvictedDialog.js b/src/components/views/dialogs/StorageEvictedDialog.js index 1e17ab1738..c25866b64d 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.js +++ b/src/components/views/dialogs/StorageEvictedDialog.js @@ -20,7 +20,7 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.StorageEvictedDialog") export default class StorageEvictedDialog extends React.Component { diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js b/src/components/views/dialogs/TabbedIntegrationManagerDialog.js index 618b0b4347..3a3cc31cf8 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.js @@ -16,13 +16,13 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; -import {Room} from "matrix-js-sdk/src/models/room"; +import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; +import { Room } from "matrix-js-sdk/src/models/room"; import * as sdk from '../../../index'; -import {dialogTermsInteractionCallback, TermsNotSignedError} from "../../../Terms"; +import { dialogTermsInteractionCallback, TermsNotSignedError } from "../../../Terms"; import classNames from 'classnames'; import * as ScalarMessaging from "../../../ScalarMessaging"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.TabbedIntegrationManagerDialog") export default class TabbedIntegrationManagerDialog extends React.Component { @@ -63,11 +63,11 @@ export default class TabbedIntegrationManagerDialog extends React.Component { }; } - componentDidMount(): void { + componentDidMount() { this.openManager(0, true); } - openManager = async (i: number, force = false) => { + openManager = async (i, force = false) => { if (i === this.state.currentIndex && !force) return; const manager = this.state.managers[i]; diff --git a/src/components/views/dialogs/TermsDialog.tsx b/src/components/views/dialogs/TermsDialog.tsx index ace5316323..818ac4b9e4 100644 --- a/src/components/views/dialogs/TermsDialog.tsx +++ b/src/components/views/dialogs/TermsDialog.tsx @@ -19,7 +19,7 @@ import React from 'react'; import * as sdk from '../../../index'; import { _t, pickBestLanguage } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; interface ITermsCheckboxProps { @@ -31,7 +31,7 @@ interface ITermsCheckboxProps { class TermsCheckbox extends React.PureComponent { private onChange = (ev: React.FormEvent): void => { this.props.onChange(this.props.url, ev.currentTarget.checked); - } + }; render() { return { this.props.onFinished(false); - } + }; private onNextClick = (): void => { this.props.onFinished(true, Object.keys(this.state.agreedUrls).filter((url) => this.state.agreedUrls[url])); - } + }; private nameForServiceType(serviceType: SERVICE_TYPES, host: string): JSX.Element { switch (serviceType) { @@ -114,7 +114,7 @@ export default class TermsDialog extends React.PureComponent = ({device, user, onFinished}) => { +const UntrustedDeviceDialog: React.FC = ({ device, user, onFinished }) => { let askToVerifyText; let newSessionText; @@ -39,7 +39,7 @@ const UntrustedDeviceDialog: React.FC = ({device, user, onFinished}) => askToVerifyText = _t("Verify your other session using one of the options below."); } else { newSessionText = _t("%(name)s (%(userId)s) signed in to a new session without verifying it:", - {name: user.displayName, userId: user.userId}); + { name: user.displayName, userId: user.userId }); askToVerifyText = _t("Ask this user to verify their session, or manually verify it below."); } diff --git a/src/components/views/dialogs/UploadConfirmDialog.tsx b/src/components/views/dialogs/UploadConfirmDialog.tsx index 7f6bcd27d1..5024880c1c 100644 --- a/src/components/views/dialogs/UploadConfirmDialog.tsx +++ b/src/components/views/dialogs/UploadConfirmDialog.tsx @@ -36,7 +36,7 @@ export default class UploadConfirmDialog extends React.Component { static defaultProps = { totalFiles: 1, - } + }; constructor(props) { super(props); @@ -56,15 +56,15 @@ export default class UploadConfirmDialog extends React.Component { private onCancelClick = () => { this.props.onFinished(false); - } + }; private onUploadClick = () => { this.props.onFinished(true); - } + }; private onUploadAllClick = () => { this.props.onFinished(true, true); - } + }; render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); diff --git a/src/components/views/dialogs/UploadFailureDialog.js b/src/components/views/dialogs/UploadFailureDialog.js index d220d6c684..d26b83d0d6 100644 --- a/src/components/views/dialogs/UploadFailureDialog.js +++ b/src/components/views/dialogs/UploadFailureDialog.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; /* * Tells the user about files we know cannot be uploaded before we even try uploading diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx index 1a62a4ff22..2878a07d35 100644 --- a/src/components/views/dialogs/UserSettingsDialog.tsx +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -16,8 +16,8 @@ limitations under the License. */ import React from 'react'; -import TabbedView, {Tab} from "../../structures/TabbedView"; -import {_t, _td} from "../../../languageHandler"; +import TabbedView, { Tab } from "../../structures/TabbedView"; +import { _t, _td } from "../../../languageHandler"; import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab"; import SettingsStore, { CallbackFn } from "../../../settings/SettingsStore"; import LabsUserSettingsTab from "../settings/tabs/user/LabsUserSettingsTab"; @@ -31,8 +31,8 @@ import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab"; import * as sdk from "../../../index"; import SdkConfig from "../../../SdkConfig"; import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab"; -import {UIFeature} from "../../../settings/UIFeature"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { UIFeature } from "../../../settings/UIFeature"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; export enum UserTab { General = "USER_GENERAL_TAB", @@ -78,8 +78,8 @@ export default class UserSettingsDialog extends React.Component private mjolnirChanged: CallbackFn = (settingName, roomId, atLevel, newValue) => { // We can cheat because we know what levels a feature is tracked at, and how it is tracked - this.setState({mjolnirEnabled: newValue}); - } + this.setState({ mjolnirEnabled: newValue }); + }; _getTabs() { const tabs = []; diff --git a/src/components/views/dialogs/VerificationRequestDialog.js b/src/components/views/dialogs/VerificationRequestDialog.js index 9281275e6a..bf5d63b895 100644 --- a/src/components/views/dialogs/VerificationRequestDialog.js +++ b/src/components/views/dialogs/VerificationRequestDialog.js @@ -16,10 +16,10 @@ 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 { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.VerificationRequestDialog") export default class VerificationRequestDialog extends React.Component { @@ -37,7 +37,7 @@ export default class VerificationRequestDialog extends React.Component { this.state.verificationRequest = this.props.verificationRequest; } else if (this.props.verificationRequestPromise) { this.props.verificationRequestPromise.then(r => { - this.setState({verificationRequest: r}); + this.setState({ verificationRequest: r }); }); } } diff --git a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx index 70fe7fe5e3..638d5cde93 100644 --- a/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx +++ b/src/components/views/dialogs/WidgetCapabilitiesPromptDialog.tsx @@ -29,7 +29,7 @@ import StyledCheckbox from "../elements/StyledCheckbox"; import DialogButtons from "../elements/DialogButtons"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import { CapabilityText } from "../../../widgets/CapabilityText"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; export function getRememberedCapabilitiesForWidget(widget: Widget): Capability[] { return JSON.parse(localStorage.getItem(`widget_${widget.id}_approved_caps`) || "[]"); @@ -77,11 +77,11 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent< private onToggle = (capability: Capability) => { const newStates = objectShallowClone(this.state.booleanStates); newStates[capability] = !newStates[capability]; - this.setState({booleanStates: newStates}); + this.setState({ booleanStates: newStates }); }; private onRememberSelectionChange = (newVal: boolean) => { - this.setState({rememberSelection: newVal}); + this.setState({ rememberSelection: newVal }); }; private onSubmit = async (ev) => { @@ -98,7 +98,7 @@ export default class WidgetCapabilitiesPromptDialog extends React.PureComponent< if (this.state.rememberSelection) { setRememberedCapabilitiesForWidget(this.props.widget, approved); } - this.props.onFinished({approved}); + this.props.onFinished({ approved }); } public render() { diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js index f77661c54e..2130d0e4ef 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js @@ -16,12 +16,12 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; -import {Widget} from "matrix-widget-api"; -import {OIDCState, WidgetPermissionStore} from "../../../stores/widgets/WidgetPermissionStore"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Widget } from "matrix-widget-api"; +import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.dialogs.WidgetOpenIDPermissionsDialog") export default class WidgetOpenIDPermissionsDialog extends React.Component { @@ -62,7 +62,7 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component { } _onRememberSelectionChange = (newVal) => { - this.setState({rememberSelection: newVal}); + this.setState({ rememberSelection: newVal }); }; render() { diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx index e09b39f4c7..d614cc0956 100644 --- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx +++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx @@ -14,18 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {debounce} from "lodash"; +import { debounce } from "lodash"; import classNames from 'classnames'; -import React, {ChangeEvent, FormEvent} from 'react'; -import {ISecretStorageKeyInfo} from "matrix-js-sdk/src"; +import React, { ChangeEvent, FormEvent } from 'react'; +import { ISecretStorageKeyInfo } from "matrix-js-sdk/src"; import * as sdk from '../../../../index'; -import {MatrixClientPeg} from '../../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import Field from '../../elements/Field'; import AccessibleButton from '../../elements/AccessibleButton'; -import {_t} from '../../../../languageHandler'; -import {IDialogProps} from "../IDialogProps"; -import {accessSecretStorage} from "../../../../SecurityManager"; +import { _t } from '../../../../languageHandler'; +import { IDialogProps } from "../IDialogProps"; +import { accessSecretStorage } from "../../../../SecurityManager"; import Modal from "../../../../Modal"; // Maximum acceptable size of a key file. It's 59 characters including the spaces we encode, @@ -75,7 +75,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent { if (this.state.resetting) { - this.setState({resetting: false}); + this.setState({ resetting: false }); } this.props.onFinished(false); }; @@ -169,7 +169,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent { this.fileUpload.current.click(); - } + }; private onPassPhraseNext = async (ev: FormEvent) => { ev.preventDefault(); @@ -210,7 +210,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent) => { ev.preventDefault(); - this.setState({resetting: true}); + this.setState({ resetting: true }); }; private onConfirmResetAllClick = async () => { @@ -231,7 +231,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent { // XXX: Making this an import breaks the app. const InteractiveAuthDialog = sdk.getComponent("views.dialogs.InteractiveAuthDialog"); - const {finished} = Modal.createTrackedDialog( + const { finished } = Modal.createTrackedDialog( 'Cross-signing keys dialog', '', InteractiveAuthDialog, { title: _t("Setting up keys"), diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx index 840390f6fb..84dcfede4a 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx @@ -16,6 +16,8 @@ limitations under the License. */ import React from 'react'; +import { CrossSigningKeys } from 'matrix-js-sdk/src/client'; + import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import { _t } from '../../../../languageHandler'; import Modal from '../../../../Modal'; @@ -71,7 +73,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent { try { - await MatrixClientPeg.get().uploadDeviceSigningKeys(null, {}); + await MatrixClientPeg.get().uploadDeviceSigningKeys(null, {} as CrossSigningKeys); // We should never get here: the server should always require // UI auth to upload device signing keys. If we do, we upload // no keys which would be a no-op. @@ -139,7 +141,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent => { this.setState({ @@ -163,11 +165,11 @@ export default class CreateCrossSigningDialog extends React.PureComponent { this.props.onFinished(false); - } + }; render() { let content; diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.js b/src/components/views/dialogs/security/RestoreKeyBackupDialog.js index 4ac15ab5a3..5f21033d29 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.js @@ -18,7 +18,7 @@ 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 { MatrixClient } from 'matrix-js-sdk/src/client'; import { _t } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../SecurityManager'; @@ -327,11 +327,11 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { if (this.state.recoverInfo.total > this.state.recoverInfo.imported) { failedToDecrypt =

      {_t( "Failed to decrypt %(failedCount)s sessions!", - {failedCount: this.state.recoverInfo.total - this.state.recoverInfo.imported}, + { failedCount: this.state.recoverInfo.total - this.state.recoverInfo.imported }, )}

      ; } content =
      -

      {_t("Successfully restored %(sessionCount)s keys", {sessionCount: this.state.recoverInfo.imported})}

      +

      {_t("Successfully restored %(sessionCount)s keys", { sessionCount: this.state.recoverInfo.imported })}

      {failedToDecrypt} { - this.setState({icon: iconFromPhase(this.store.phase)}); + this.setState({ icon: iconFromPhase(this.store.phase) }); }; public render() { diff --git a/src/components/views/directory/NetworkDropdown.tsx b/src/components/views/directory/NetworkDropdown.tsx index c805ee42e7..c57aa7bccc 100644 --- a/src/components/views/directory/NetworkDropdown.tsx +++ b/src/components/views/directory/NetworkDropdown.tsx @@ -186,10 +186,10 @@ const NetworkDropdown = ({ onOptionChange, protocols = {}, selectedServerName, s }); } - protocolsList.forEach(({instances=[]}) => { + protocolsList.forEach(({ instances=[] }) => { [...instances].sort((b, a) => { return compare(a.desc, b.desc); - }).forEach(({desc, instance_id: instanceId}) => { + }).forEach(({ desc, instance_id: instanceId }) => { entries.push( { closeMenu(); - const {finished} = Modal.createTrackedDialog("Network Dropdown", "Remove server", QuestionDialog, { - title: _t("Are you sure?"), - description: _t("Are you sure you want to remove %(serverName)s", { - serverName: server, - }, { - b: serverName => { serverName }, - }), - button: _t("Remove"), - fixedWidth: false, - }, "mx_NetworkDropdown_dialog"); + const { finished } = Modal.createTrackedDialog( + "Network Dropdown", "Remove server", QuestionDialog, + { + title: _t("Are you sure?"), + description: _t("Are you sure you want to remove %(serverName)s", { + serverName: server, + }, { + b: serverName => { serverName }, + }), + button: _t("Remove"), + fixedWidth: false, + }, + "mx_NetworkDropdown_dialog", + ); const [ok] = await finished; if (!ok) return; diff --git a/src/components/views/elements/AccessibleButton.tsx b/src/components/views/elements/AccessibleButton.tsx index 05bcca24b2..997bbcb9c2 100644 --- a/src/components/views/elements/AccessibleButton.tsx +++ b/src/components/views/elements/AccessibleButton.tsx @@ -16,7 +16,7 @@ import React from 'react'; -import {Key} from '../../../Keyboard'; +import { Key } from '../../../Keyboard'; import classnames from 'classnames'; export type ButtonEvent = React.MouseEvent | React.KeyboardEvent; diff --git a/src/components/views/elements/AccessibleTooltipButton.tsx b/src/components/views/elements/AccessibleTooltipButton.tsx index a1743da475..8ac41ad1a2 100644 --- a/src/components/views/elements/AccessibleTooltipButton.tsx +++ b/src/components/views/elements/AccessibleTooltipButton.tsx @@ -19,8 +19,8 @@ import React from 'react'; import classNames from 'classnames'; import AccessibleButton from "./AccessibleButton"; -import Tooltip, {Alignment} from './Tooltip'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import Tooltip, { Alignment } from './Tooltip'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface ITooltipProps extends React.ComponentProps { title: string; @@ -67,7 +67,7 @@ export default class AccessibleTooltipButton extends React.PureComponent { ev.stopPropagation(); Analytics.trackEvent('Action Button', 'click', this.props.action); - dis.dispatch({action: this.props.action}); + dis.dispatch({ action: this.props.action }); }; _onMouseEnter = () => { - if (this.props.tooltip) this.setState({showTooltip: true}); + if (this.props.tooltip) this.setState({ showTooltip: true }); if (this.props.mouseOverAction) { - dis.dispatch({action: this.props.mouseOverAction}); + dis.dispatch({ action: this.props.mouseOverAction }); } }; _onMouseLeave = () => { - this.setState({showTooltip: false}); + this.setState({ showTooltip: false }); }; render() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); - let tooltip; if (this.state.showTooltip) { const Tooltip = sdk.getComponent("elements.Tooltip"); @@ -71,7 +69,7 @@ export default class ActionButton extends React.Component { } const icon = this.props.iconPath ? - () : + () : undefined; const classNames = ["mx_RoleButton"]; diff --git a/src/components/views/elements/AddressSelector.js b/src/components/views/elements/AddressSelector.js index 33b2906870..b7c9124438 100644 --- a/src/components/views/elements/AddressSelector.js +++ b/src/components/views/elements/AddressSelector.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import classNames from 'classnames'; import { UserAddressType } from '../../../UserAddress'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.AddressSelector") export default class AddressSelector extends React.Component { diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js index f8fa294b71..ca85d73a11 100644 --- a/src/components/views/elements/AddressTile.js +++ b/src/components/views/elements/AddressTile.js @@ -53,7 +53,6 @@ export default class AddressTile extends React.Component { } const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); - const TintableSvg = sdk.getComponent("elements.TintableSvg"); const nameClasses = classNames({ "mx_AddressTile_name": true, @@ -124,7 +123,7 @@ export default class AddressTile extends React.Component { if (this.props.canDismiss) { dismiss = (
      - +
      ); } diff --git a/src/components/views/elements/AppPermission.js b/src/components/views/elements/AppPermission.js index 65e40ef19a..152d3c6b95 100644 --- a/src/components/views/elements/AppPermission.js +++ b/src/components/views/elements/AppPermission.js @@ -23,8 +23,8 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import WidgetUtils from "../../../utils/WidgetUtils"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.AppPermission") export default class AppPermission extends React.Component { @@ -115,9 +115,9 @@ export default class AppPermission extends React.Component { // Due to i18n limitations, we can't dedupe the code for variables in these two messages. const warning = this.state.isWrapped ? _t("Using this widget may share data with %(widgetDomain)s & your Integration Manager.", - {widgetDomain: this.state.widgetDomain}, {helpIcon: () => warningTooltip}) + { widgetDomain: this.state.widgetDomain }, { helpIcon: () => warningTooltip }) : _t("Using this widget may share data with %(widgetDomain)s.", - {widgetDomain: this.state.widgetDomain}, {helpIcon: () => warningTooltip}); + { widgetDomain: this.state.widgetDomain }, { helpIcon: () => warningTooltip }); const encryptionWarning = this.props.isRoomEncrypted ? _t("Widgets do not use message encryption.") : null; diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 3fa43ee9c2..f5d3aaf9eb 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -18,9 +18,9 @@ limitations under the License. */ import url from 'url'; -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import AccessibleButton from './AccessibleButton'; import { _t } from '../../../languageHandler'; import AppPermission from './AppPermission'; @@ -30,15 +30,15 @@ import dis from '../../../dispatcher/dispatcher'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; import classNames from 'classnames'; import SettingsStore from "../../../settings/SettingsStore"; -import {aboveLeftOf, ContextMenuButton} from "../../structures/ContextMenu"; -import PersistedElement, {getPersistKey} from "./PersistedElement"; -import {WidgetType} from "../../../widgets/WidgetType"; -import {StopGapWidget} from "../../../stores/widgets/StopGapWidget"; -import {ElementWidgetActions} from "../../../stores/widgets/ElementWidgetActions"; -import {MatrixCapabilities} from "matrix-widget-api"; +import { aboveLeftOf, ContextMenuButton } from "../../structures/ContextMenu"; +import PersistedElement, { getPersistKey } from "./PersistedElement"; +import { WidgetType } from "../../../widgets/WidgetType"; +import { StopGapWidget } from "../../../stores/widgets/StopGapWidget"; +import { ElementWidgetActions } from "../../../stores/widgets/ElementWidgetActions"; +import { MatrixCapabilities } from "matrix-widget-api"; import RoomWidgetContextMenu from "../context_menus/WidgetContextMenu"; import WidgetAvatar from "../avatars/WidgetAvatar"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.AppTile") export default class AppTile extends React.Component { @@ -164,7 +164,7 @@ export default class AppTile extends React.Component { _startWidget() { this._sgWidget.prepare().then(() => { - this.setState({initialising: false}); + this.setState({ initialising: false }); }); } @@ -213,17 +213,17 @@ export default class AppTile extends React.Component { } if (WidgetType.JITSI.matches(this.props.app.type)) { - dis.dispatch({action: 'hangup_conference'}); + dis.dispatch({ action: 'hangup_conference' }); } // Delete the widget from the persisted store for good measure. PersistedElement.destroyElement(this._persistKey); - if (this._sgWidget) this._sgWidget.stop({forceDestroy: true}); + if (this._sgWidget) this._sgWidget.stop({ forceDestroy: true }); } _onWidgetPrepared = () => { - this.setState({loading: false}); + this.setState({ loading: false }); }; _onWidgetReady = () => { @@ -237,7 +237,7 @@ export default class AppTile extends React.Component { switch (payload.action) { case 'm.sticker': if (this._sgWidget.widgetApi.hasCapability(MatrixCapabilities.StickerSending)) { - dis.dispatch({action: 'post_sticker_message', data: payload.data}); + dis.dispatch({ action: 'post_sticker_message', data: payload.data }); } else { console.warn('Ignoring sticker message. Invalid capability'); } @@ -253,7 +253,7 @@ export default class AppTile extends React.Component { current[this.props.app.eventId] = true; const level = SettingsStore.firstSupportedLevel("allowedWidgets"); SettingsStore.setValue("allowedWidgets", roomId, level, current).then(() => { - this.setState({hasPermissionToLoad: true}); + this.setState({ hasPermissionToLoad: true }); // Fetch a token for the integration manager, now that we're allowed to this._startWidget(); @@ -313,7 +313,7 @@ export default class AppTile extends React.Component { // Using Object.assign workaround as the following opens in a new window instead of a new tab. // window.open(this._getPopoutUrl(), '_blank', 'noopener=yes'); Object.assign(document.createElement('a'), - { target: '_blank', href: this._sgWidget.popoutUrl, rel: 'noreferrer noopener'}).click(); + { target: '_blank', href: this._sgWidget.popoutUrl, rel: 'noreferrer noopener' }).click(); }; _onContextMenuClick = () => { @@ -416,11 +416,11 @@ export default class AppTile extends React.Component { let appTileClasses; if (this.props.miniMode) { - appTileClasses = {mx_AppTile_mini: true}; + appTileClasses = { mx_AppTile_mini: true }; } else if (this.props.fullWidth) { - appTileClasses = {mx_AppTileFullWidth: true}; + appTileClasses = { mx_AppTileFullWidth: true }; } else { - appTileClasses = {mx_AppTile: true}; + appTileClasses = { mx_AppTile: true }; } appTileClasses = classNames(appTileClasses); @@ -443,7 +443,7 @@ export default class AppTile extends React.Component {
      { this.props.showMenubar &&
      - + { this.props.showTitle && this._getTileTitle() } diff --git a/src/components/views/elements/DesktopBuildsNotice.tsx b/src/components/views/elements/DesktopBuildsNotice.tsx index 426554f31e..c97a9b6cef 100644 --- a/src/components/views/elements/DesktopBuildsNotice.tsx +++ b/src/components/views/elements/DesktopBuildsNotice.tsx @@ -22,7 +22,6 @@ import dis from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; import { UserTab } from "../dialogs/UserSettingsDialog"; - export enum WarningKind { Files, Search, @@ -33,7 +32,7 @@ interface IProps { kind: WarningKind; } -export default function DesktopBuildsNotice({isRoomEncrypted, kind}: IProps) { +export default function DesktopBuildsNotice({ isRoomEncrypted, kind }: IProps) { if (!isRoomEncrypted) return null; if (EventIndexPeg.get()) return null; @@ -53,7 +52,7 @@ export default function DesktopBuildsNotice({isRoomEncrypted, kind}: IProps) { ; } - const {desktopBuilds, brand} = SdkConfig.get(); + const { desktopBuilds, brand } = SdkConfig.get(); let text = null; let logo = null; @@ -74,10 +73,10 @@ export default function DesktopBuildsNotice({isRoomEncrypted, kind}: IProps) { } else { switch (kind) { case WarningKind.Files: - text = _t("This version of %(brand)s does not support viewing some encrypted files", {brand}); + text = _t("This version of %(brand)s does not support viewing some encrypted files", { brand }); break; case WarningKind.Search: - text = _t("This version of %(brand)s does not support searching encrypted messages", {brand}); + text = _t("This version of %(brand)s does not support searching encrypted messages", { brand }); break; } } diff --git a/src/components/views/elements/DesktopCapturerSourcePicker.tsx b/src/components/views/elements/DesktopCapturerSourcePicker.tsx index 2d066a7ed7..8f9b847f4f 100644 --- a/src/components/views/elements/DesktopCapturerSourcePicker.tsx +++ b/src/components/views/elements/DesktopCapturerSourcePicker.tsx @@ -16,10 +16,10 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import BaseDialog from "..//dialogs/BaseDialog" +import BaseDialog from "..//dialogs/BaseDialog"; import AccessibleButton from './AccessibleButton'; -import {getDesktopCapturerSources} from "matrix-js-sdk/src/webrtc/call"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { getDesktopCapturerSources } from "matrix-js-sdk/src/webrtc/call"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; export interface DesktopCapturerSource { id: string; @@ -44,7 +44,7 @@ export class ExistingSource extends React.Component onClick = (ev) => { this.props.onSelect(this.props.source); - } + }; render() { return ( @@ -108,19 +108,19 @@ export default class DesktopCapturerSourcePicker extends React.Component< onSelect = (source) => { this.props.onFinished(source); - } + }; onScreensClick = (ev) => { - this.setState({selectedTab: Tabs.Screens}); - } + this.setState({ selectedTab: Tabs.Screens }); + }; onWindowsClick = (ev) => { - this.setState({selectedTab: Tabs.Windows}); - } + this.setState({ selectedTab: Tabs.Windows }); + }; onCloseClick = (ev) => { this.props.onFinished(null); - } + }; render() { let sources; diff --git a/src/components/views/elements/DialogButtons.js b/src/components/views/elements/DialogButtons.js index dcb1cee077..af68260563 100644 --- a/src/components/views/elements/DialogButtons.js +++ b/src/components/views/elements/DialogButtons.js @@ -19,7 +19,7 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; /** * Basic container for buttons in modal dialogs. diff --git a/src/components/views/elements/DirectorySearchBox.js b/src/components/views/elements/DirectorySearchBox.js index 6447bb3cd8..45270ada64 100644 --- a/src/components/views/elements/DirectorySearchBox.js +++ b/src/components/views/elements/DirectorySearchBox.js @@ -18,7 +18,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.DirectorySearchBox") export default class DirectorySearchBox extends React.Component { @@ -42,7 +42,7 @@ export default class DirectorySearchBox extends React.Component { } _onClearClick() { - this.setState({value: ''}); + this.setState({ value: '' }); if (this.input) { this.input.focus(); @@ -55,7 +55,7 @@ export default class DirectorySearchBox extends React.Component { _onChange(ev) { if (!this.input) return; - this.setState({value: ev.target.value}); + this.setState({ value: ev.target.value }); if (this.props.onChange) { this.props.onChange(ev.target.value); diff --git a/src/components/views/elements/Draggable.tsx b/src/components/views/elements/Draggable.tsx index 6032721a48..03dccadcb9 100644 --- a/src/components/views/elements/Draggable.tsx +++ b/src/components/views/elements/Draggable.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { className: string; diff --git a/src/components/views/elements/Dropdown.js b/src/components/views/elements/Dropdown.js index 981c0becc0..f95247e9ae 100644 --- a/src/components/views/elements/Dropdown.js +++ b/src/components/views/elements/Dropdown.js @@ -16,13 +16,13 @@ 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 classnames from 'classnames'; import AccessibleButton from './AccessibleButton'; import { _t } from '../../../languageHandler'; -import {Key} from "../../../Keyboard"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Key } from "../../../Keyboard"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; class MenuOption extends React.Component { constructor(props) { diff --git a/src/components/views/elements/EditableText.js b/src/components/views/elements/EditableText.js index 7c38ac1777..6dbc8b8771 100644 --- a/src/components/views/elements/EditableText.js +++ b/src/components/views/elements/EditableText.js @@ -15,10 +15,10 @@ 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 {Key} from "../../../Keyboard"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Key } from "../../../Keyboard"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.EditableText") export default class EditableText extends React.Component { @@ -209,7 +209,7 @@ export default class EditableText extends React.Component { }; render() { - const {className, editable, initialValue, label, labelClassName} = this.props; + const { className, editable, initialValue, label, labelClassName } = this.props; let editableEl; if (!editable || (this.state.phase === EditableText.Phases.Display && diff --git a/src/components/views/elements/EditableTextContainer.js b/src/components/views/elements/EditableTextContainer.js index e925220089..5778446355 100644 --- a/src/components/views/elements/EditableTextContainer.js +++ b/src/components/views/elements/EditableTextContainer.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; /** * A component which wraps an EditableText, with a spinner while updates take @@ -50,7 +50,7 @@ export default class EditableTextContainer extends React.Component { return; } - this.setState({busy: true}); + this.setState({ busy: true }); this.props.getInitialValue().then( (result) => { @@ -144,7 +144,6 @@ EditableTextContainer.propTypes = { blurToSubmit: PropTypes.bool, }; - EditableTextContainer.defaultProps = { initialValue: "", placeholder: "", diff --git a/src/components/views/elements/EffectsOverlay.tsx b/src/components/views/elements/EffectsOverlay.tsx index 00d9d147f1..9e6833696f 100644 --- a/src/components/views/elements/EffectsOverlay.tsx +++ b/src/components/views/elements/EffectsOverlay.tsx @@ -17,7 +17,7 @@ import React, { FunctionComponent, useEffect, useRef } from 'react'; import dis from '../../../dispatcher/dispatcher'; import ICanvasEffect from '../../../effects/ICanvasEffect'; -import { CHAT_EFFECTS } from '../../../effects' +import { CHAT_EFFECTS } from '../../../effects'; import UIStore, { UI_EVENTS } from "../../../stores/UIStore"; interface IProps { @@ -32,7 +32,7 @@ const EffectsOverlay: FunctionComponent = ({ roomWidth }) => { if (!name) return null; let effect: ICanvasEffect | null = effectsRef.current[name] || null; if (effect === null) { - const options = CHAT_EFFECTS.find((e) => e.command === name)?.options + const options = CHAT_EFFECTS.find((e) => e.command === name)?.options; try { const { default: Effect } = await import(`../../../effects/${name}`); effect = new Effect(options); @@ -56,7 +56,7 @@ const EffectsOverlay: FunctionComponent = ({ roomWidth }) => { const effect = payload.action.substr(actionPrefix.length); lazyLoadEffectModule(effect).then((module) => module?.start(canvasRef.current)); } - } + }; const dispatcherRef = dis.register(onAction); const canvas = canvasRef.current; canvas.height = UIStore.instance.windowHeight; @@ -89,7 +89,7 @@ const EffectsOverlay: FunctionComponent = ({ roomWidth }) => { right: 0, }} /> - ) -} + ); +}; export default EffectsOverlay; diff --git a/src/components/views/elements/ErrorBoundary.js b/src/components/views/elements/ErrorBoundary.tsx similarity index 80% rename from src/components/views/elements/ErrorBoundary.js rename to src/components/views/elements/ErrorBoundary.tsx index 9037287f49..f967b8c594 100644 --- a/src/components/views/elements/ErrorBoundary.js +++ b/src/components/views/elements/ErrorBoundary.tsx @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,21 +14,27 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import * as sdk from '../../../index'; +import React, { ErrorInfo } from 'react'; + import { _t } from '../../../languageHandler'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import PlatformPeg from '../../../PlatformPeg'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BugReportDialog from '../dialogs/BugReportDialog'; +import AccessibleButton from './AccessibleButton'; + +interface IState { + error: Error; +} /** * This error boundary component can be used to wrap large content areas and * catch exceptions during rendering in the component tree below them. */ @replaceableComponent("views.elements.ErrorBoundary") -export default class ErrorBoundary extends React.PureComponent { +export default class ErrorBoundary extends React.PureComponent<{}, IState> { constructor(props) { super(props); @@ -37,13 +43,13 @@ export default class ErrorBoundary extends React.PureComponent { }; } - static getDerivedStateFromError(error) { + static getDerivedStateFromError(error: Error): Partial { // Side effects are not permitted here, so we only update the state so // that the next render shows an error message. return { error }; } - componentDidCatch(error, { componentStack }) { + componentDidCatch(error: Error, { componentStack }: ErrorInfo): void { // Browser consoles are better at formatting output when native errors are passed // in their own `console.error` invocation. console.error(error); @@ -53,7 +59,7 @@ export default class ErrorBoundary extends React.PureComponent { ); } - _onClearCacheAndReload = () => { + private onClearCacheAndReload = (): void => { if (!PlatformPeg.get()) return; MatrixClientPeg.get().stopClient(); @@ -62,11 +68,7 @@ export default class ErrorBoundary extends React.PureComponent { }); }; - _onBugReport = () => { - const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog"); - if (!BugReportDialog) { - return; - } + private onBugReport = (): void => { Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, { label: 'react-soft-crash', }); @@ -74,7 +76,6 @@ export default class ErrorBoundary extends React.PureComponent { render() { if (this.state.error) { - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const newIssueUrl = "https://github.com/vector-im/element-web/issues/new"; let bugReportSection; @@ -95,7 +96,7 @@ export default class ErrorBoundary extends React.PureComponent { "the rooms or groups you have visited and the usernames of " + "other users. They do not contain messages.", )}

      - + {_t("Submit debug logs")} ; @@ -105,7 +106,7 @@ export default class ErrorBoundary extends React.PureComponent {

      {_t("Something went wrong!")}

      { bugReportSection } - + {_t("Clear cache and reload")}
      diff --git a/src/components/views/elements/EventListSummary.tsx b/src/components/views/elements/EventListSummary.tsx index 86d3e082ad..ab647db9ed 100644 --- a/src/components/views/elements/EventListSummary.tsx +++ b/src/components/views/elements/EventListSummary.tsx @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ReactChildren, useEffect} from 'react'; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {RoomMember} from "matrix-js-sdk/src/models/room-member"; +import React, { ReactNode, useEffect } from 'react'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import MemberAvatar from '../avatars/MemberAvatar'; import { _t } from '../../../languageHandler'; -import {useStateToggle} from "../../../hooks/useStateToggle"; +import { useStateToggle } from "../../../hooks/useStateToggle"; import AccessibleButton from "./AccessibleButton"; interface IProps { @@ -31,11 +31,11 @@ interface IProps { // Whether or not to begin with state.expanded=true startExpanded?: boolean, // The list of room members for which to show avatars next to the summary - summaryMembers?: RoomMember[], + summaryMembers?: RoomMember[]; // The text to show as the summary of this event list - summaryText?: string, + summaryText?: string; // An array of EventTiles to render when expanded - children: ReactChildren, + children: ReactNode[]; // Called when the event list expansion is toggled onToggle?(): void; } diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx index 332f3ac333..68a70133e6 100644 --- a/src/components/views/elements/EventTilePreview.tsx +++ b/src/components/views/elements/EventTilePreview.tsx @@ -73,7 +73,7 @@ export default class EventTilePreview extends React.Component { }; } - private fakeEvent({message}: IState) { + private fakeEvent({ message }: IState) { // Fake it till we make it /* eslint-disable quote-props */ const rawEvent = { diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx index 1373c2df0e..297044e422 100644 --- a/src/components/views/elements/Field.tsx +++ b/src/components/views/elements/Field.tsx @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes} from 'react'; +import React, { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react'; import classNames from 'classnames'; import * as sdk from '../../../index'; -import {debounce} from "lodash"; -import {IFieldState, IValidationResult} from "./Validation"; +import { debounce } from "lodash"; +import { IFieldState, IValidationResult } from "./Validation"; // Invoke validation from user input (when typing, etc.) at most once every N ms. const VALIDATION_THROTTLE_MS = 200; @@ -222,7 +222,7 @@ export default class Field extends React.PureComponent { /* eslint @typescript-eslint/no-unused-vars: ["error", { "ignoreRestSiblings": true }] */ const { element, prefixComponent, postfixComponent, className, onValidate, children, tooltipContent, forceValidity, tooltipClassName, list, validateOnBlur, validateOnChange, validateOnFocus, - ...inputProps} = this.props; + ...inputProps } = this.props; // Set some defaults for the element const ref = input => this.input = input; @@ -234,7 +234,7 @@ export default class Field extends React.PureComponent { inputProps.onBlur = this.onBlur; // Appease typescript's inference - const inputProps_ = {...inputProps, ref, list}; + const inputProps_ = { ...inputProps, ref, list }; const fieldInput = React.createElement(this.props.element, inputProps_, children); diff --git a/src/components/views/elements/Flair.js b/src/components/views/elements/Flair.js index 23858b860d..873d65d5bd 100644 --- a/src/components/views/elements/Flair.js +++ b/src/components/views/elements/Flair.js @@ -19,9 +19,8 @@ import PropTypes from 'prop-types'; import FlairStore from '../../../stores/FlairStore'; import dis from '../../../dispatcher/dispatcher'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; - +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; class FlairAvatar extends React.Component { constructor() { diff --git a/src/components/views/elements/IRCTimelineProfileResizer.tsx b/src/components/views/elements/IRCTimelineProfileResizer.tsx index cd1ccf2fc4..13e8ae2ae2 100644 --- a/src/components/views/elements/IRCTimelineProfileResizer.tsx +++ b/src/components/views/elements/IRCTimelineProfileResizer.tsx @@ -16,9 +16,9 @@ limitations under the License. import React from 'react'; import SettingsStore from "../../../settings/SettingsStore"; -import Draggable, {ILocationState} from './Draggable'; +import Draggable, { ILocationState } from './Draggable'; import { SettingLevel } from "../../../settings/SettingLevel"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // Current room diff --git a/src/components/views/elements/ImageView.tsx b/src/components/views/elements/ImageView.tsx index 4812817359..74538d2fa9 100644 --- a/src/components/views/elements/ImageView.tsx +++ b/src/components/views/elements/ImageView.tsx @@ -30,7 +30,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import { formatFullDate } from "../../../DateUtils"; import dis from '../../../dispatcher/dispatcher'; import { replaceableComponent } from "../../../utils/replaceableComponent"; -import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks" +import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { normalizeWheelEvent } from "../../../utils/Mouse"; @@ -116,7 +116,7 @@ export default class ImageView extends React.Component { private recalculateZoom = () => { this.setZoomAndRotation(); - } + }; private setZoomAndRotation = (inputRotation?: number) => { const image = this.image.current; @@ -158,7 +158,7 @@ export default class ImageView extends React.Component { rotation: rotation, zoom: zoom, }); - } + }; private zoom(delta: number) { const newZoom = this.state.zoom + delta; diff --git a/src/components/views/elements/InfoTooltip.tsx b/src/components/views/elements/InfoTooltip.tsx index d49090dbae..de82c5daeb 100644 --- a/src/components/views/elements/InfoTooltip.tsx +++ b/src/components/views/elements/InfoTooltip.tsx @@ -18,9 +18,9 @@ limitations under the License. import React from 'react'; import classNames from 'classnames'; -import Tooltip, {Alignment} from './Tooltip'; -import {_t} from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import Tooltip, { Alignment } from './Tooltip'; +import { _t } from "../../../languageHandler"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface ITooltipProps { tooltip?: React.ReactNode; @@ -53,7 +53,7 @@ export default class InfoTooltip extends React.PureComponent { static defaultProps = { w: 16, h: 16, - } + }; render() { return (
      {this.props.children} diff --git a/src/components/views/elements/InviteReason.tsx b/src/components/views/elements/InviteReason.tsx index ddce7552ed..d684f61859 100644 --- a/src/components/views/elements/InviteReason.tsx +++ b/src/components/views/elements/InviteReason.tsx @@ -42,7 +42,7 @@ export default class InviteReason extends React.PureComponent { this.setState({ hidden: false, }); - } + }; render() { const classes = classNames({ diff --git a/src/components/views/elements/LabelledToggleSwitch.tsx b/src/components/views/elements/LabelledToggleSwitch.tsx index d97b698fd8..14853ea117 100644 --- a/src/components/views/elements/LabelledToggleSwitch.tsx +++ b/src/components/views/elements/LabelledToggleSwitch.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from "react"; import ToggleSwitch from "./ToggleSwitch"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The value for the toggle switch diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js index 9420061a74..3f17a78629 100644 --- a/src/components/views/elements/LanguageDropdown.js +++ b/src/components/views/elements/LanguageDropdown.js @@ -22,7 +22,7 @@ import * as sdk from '../../../index'; import * as languageHandler from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; function languageMatchesSearchQuery(query, language) { if (language.label.toUpperCase().includes(query.toUpperCase())) return true; @@ -49,9 +49,9 @@ export default class LanguageDropdown extends React.Component { if (a.label > b.label) return 1; return 0; }); - this.setState({langs}); + this.setState({ langs }); }).catch(() => { - this.setState({langs: ['en']}); + this.setState({ langs: ['en'] }); }); if (!this.props.value) { diff --git a/src/components/views/elements/LazyRenderList.js b/src/components/views/elements/LazyRenderList.js index f2c8148cd2..070d9bcc8d 100644 --- a/src/components/views/elements/LazyRenderList.js +++ b/src/components/views/elements/LazyRenderList.js @@ -16,7 +16,7 @@ limitations under the License. import React from "react"; import PropTypes from 'prop-types'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; class ItemRange { constructor(topCount, renderCount, bottomCount) { @@ -72,13 +72,13 @@ export default class LazyRenderList extends React.Component { // only update render Range if the list has shrunk/grown and we need to adjust padding OR // if the new range + overflowMargin isn't contained by the old anymore if (listHasChangedSize || !state.renderRange || !state.renderRange.contains(intersectRange)) { - return {renderRange}; + return { renderRange }; } return null; } static getVisibleRangeFromProps(props) { - const {items, itemHeight, scrollTop, height} = props; + const { items, itemHeight, scrollTop, height } = props; const length = items ? items.length : 0; const topCount = Math.min(Math.max(0, Math.floor(scrollTop / itemHeight)), length); const itemsAfterTop = length - topCount; @@ -89,9 +89,9 @@ export default class LazyRenderList extends React.Component { } render() { - const {itemHeight, items, renderItem} = this.props; - const {renderRange} = this.state; - const {topCount, renderCount, bottomCount} = renderRange; + const { itemHeight, items, renderItem } = this.props; + const { renderRange } = this.state; + const { topCount, renderCount, bottomCount } = renderRange; const paddingTop = topCount * itemHeight; const paddingBottom = bottomCount * itemHeight; @@ -102,7 +102,7 @@ export default class LazyRenderList extends React.Component { const element = this.props.element || "div"; const elementProps = { - "style": {paddingTop: `${paddingTop}px`, paddingBottom: `${paddingBottom}px`}, + "style": { paddingTop: `${paddingTop}px`, paddingBottom: `${paddingBottom}px` }, "className": this.props.className, }; return React.createElement(element, elementProps, renderedItems.map(renderItem)); diff --git a/src/components/views/elements/MemberEventListSummary.tsx b/src/components/views/elements/MemberEventListSummary.tsx index bf85cee60e..d52462f629 100644 --- a/src/components/views/elements/MemberEventListSummary.tsx +++ b/src/components/views/elements/MemberEventListSummary.tsx @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { ReactChildren } from 'react'; +import React, { ComponentProps } from 'react'; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; @@ -26,21 +26,11 @@ import { isValid3pidInvite } from "../../../RoomInvite"; import EventListSummary from "./EventListSummary"; import { replaceableComponent } from "../../../utils/replaceableComponent"; -interface IProps { - // An array of member events to summarise - events: MatrixEvent[]; +interface IProps extends Omit, "summaryText" | "summaryMembers"> { // The maximum number of names to show in either each summary e.g. 2 would result "A, B and 234 others left" summaryLength?: number; // The maximum number of avatars to display in the summary avatarsMaxLength?: number; - // The minimum number of events needed to trigger summarisation - threshold?: number, - // Whether or not to begin with state.expanded=true - startExpanded?: boolean, - // An array of EventTiles to render when expanded - children: ReactChildren; - // Called when the MELS expansion is toggled - onToggle?(): void, } interface IUserEvents { diff --git a/src/components/views/elements/MiniAvatarUploader.tsx b/src/components/views/elements/MiniAvatarUploader.tsx index 32ef0d4da2..83fc1ebefd 100644 --- a/src/components/views/elements/MiniAvatarUploader.tsx +++ b/src/components/views/elements/MiniAvatarUploader.tsx @@ -14,14 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useContext, useRef, useState} from 'react'; -import {EventType} from 'matrix-js-sdk/src/@types/event'; +import React, { useContext, useRef, useState } from 'react'; +import { EventType } from 'matrix-js-sdk/src/@types/event'; import classNames from 'classnames'; import AccessibleButton from "./AccessibleButton"; import Spinner from "./Spinner"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {useTimeout} from "../../../hooks/useTimeout"; +import { useTimeout } from "../../../hooks/useTimeout"; import Analytics from "../../../Analytics"; import CountlyAnalytics from '../../../CountlyAnalytics'; import RoomContext from "../../../contexts/RoomContext"; @@ -52,7 +52,7 @@ const MiniAvatarUploader: React.FC = ({ hasAvatar, hasAvatarLabel, noAva const label = (hasAvatar || busy) ? hasAvatarLabel : noAvatarLabel; - const {room} = useContext(RoomContext); + const { room } = useContext(RoomContext); const canSetAvatar = room?.currentState.maySendStateEvent(EventType.RoomAvatar, cli.getUserId()); if (!canSetAvatar) return { children }; diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js index 701c140a19..22d4bfdd68 100644 --- a/src/components/views/elements/PersistedElement.js +++ b/src/components/views/elements/PersistedElement.js @@ -17,14 +17,14 @@ limitations under the License. import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; -import {throttle} from "lodash"; +import { throttle } from "lodash"; import ResizeObserver from 'resize-observer-polyfill'; import dis from '../../../dispatcher/dispatcher'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {isNullOrUndefined} from "matrix-js-sdk/src/utils"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and @@ -180,11 +180,11 @@ export default class PersistedElement extends React.Component { width: parentRect.width + 'px', height: parentRect.height + 'px', }); - }, 100, {trailing: true, leading: true}); + }, 100, { trailing: true, leading: true }); render() { return
      ; } } -export const getPersistKey = (appId: string) => 'widget_' + appId; +export const getPersistKey = (appId) => 'widget_' + appId; diff --git a/src/components/views/elements/PersistentApp.js b/src/components/views/elements/PersistentApp.js index 5df373e4fe..763ab63487 100644 --- a/src/components/views/elements/PersistentApp.js +++ b/src/components/views/elements/PersistentApp.js @@ -20,8 +20,8 @@ import RoomViewStore from '../../../stores/RoomViewStore'; import ActiveWidgetStore from '../../../stores/ActiveWidgetStore'; import WidgetUtils from '../../../utils/WidgetUtils'; import * as sdk from '../../../index'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.PersistentApp") export default class PersistentApp extends React.Component { diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index ace41db39d..ba166ccfc6 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -20,14 +20,14 @@ import classNames from 'classnames'; import { Room } from 'matrix-js-sdk/src/models/room'; import { RoomMember } from 'matrix-js-sdk/src/models/room-member'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import FlairStore from "../../../stores/FlairStore"; -import {getPrimaryPermalinkEntity, parseAppLocalLink} from "../../../utils/permalinks/Permalinks"; +import { getPrimaryPermalinkEntity, parseAppLocalLink } from "../../../utils/permalinks/Permalinks"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {Action} from "../../../dispatcher/actions"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { Action } from "../../../dispatcher/actions"; +import { mediaFromMxc } from "../../../customisations/Media"; import Tooltip from './Tooltip'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.Pill") class Pill extends React.Component { @@ -144,7 +144,7 @@ class Pill extends React.Component { } } } - this.setState({resourceId, pillType, member, group, room}); + this.setState({ resourceId, pillType, member, group, room }); } componentDidMount() { @@ -180,13 +180,13 @@ class Pill extends React.Component { member.rawDisplayName = resp.displayname; member.events.member = { getContent: () => { - return {avatar_url: resp.avatar_url}; + return { avatar_url: resp.avatar_url }; }, getDirectionalContent: function() { return this.getContent(); }, }; - this.setState({member}); + this.setState({ member }); }).catch((err) => { console.error('Could not retrieve profile data for ' + userId + ':', err); }); @@ -253,7 +253,7 @@ class Pill extends React.Component { break; case Pill.TYPE_GROUP_MENTION: { if (this.state.group) { - const {avatarUrl, groupId, name} = this.state.group; + const { avatarUrl, groupId, name } = this.state.group; linkText = groupId; if (this.props.shouldShowPillAvatar) { @@ -273,7 +273,7 @@ class Pill extends React.Component { }); if (this.state.pillType) { - const {yOffset} = this.props; + const { yOffset } = this.props; let tip; if (this.state.hover && resource) { diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js index a7a65425a3..ef449df295 100644 --- a/src/components/views/elements/PowerSelector.js +++ b/src/components/views/elements/PowerSelector.js @@ -19,8 +19,8 @@ import PropTypes from 'prop-types'; import * as Roles from '../../../Roles'; import { _t } from '../../../languageHandler'; import Field from "./Field"; -import {Key} from "../../../Keyboard"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Key } from "../../../Keyboard"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.PowerSelector") export default class PowerSelector extends React.Component { @@ -97,15 +97,15 @@ export default class PowerSelector extends React.Component { onSelectChange = event => { const isCustom = event.target.value === "SELECT_VALUE_CUSTOM"; if (isCustom) { - this.setState({custom: true}); + this.setState({ custom: true }); } else { this.props.onChange(event.target.value, this.props.powerLevelKey); - this.setState({selectValue: event.target.value}); + this.setState({ selectValue: event.target.value }); } }; onCustomChange = event => { - this.setState({customValue: event.target.value}); + this.setState({ customValue: event.target.value }); }; onCustomBlur = event => { diff --git a/src/components/views/elements/ProgressBar.tsx b/src/components/views/elements/ProgressBar.tsx index 90832e5006..c4ff06e04e 100644 --- a/src/components/views/elements/ProgressBar.tsx +++ b/src/components/views/elements/ProgressBar.tsx @@ -21,7 +21,7 @@ interface IProps { max: number; } -const ProgressBar: React.FC = ({value, max}) => { +const ProgressBar: React.FC = ({ value, max }) => { return ; }; diff --git a/src/components/views/elements/QRCode.tsx b/src/components/views/elements/QRCode.tsx index 9ce3dc7202..50b12ae23d 100644 --- a/src/components/views/elements/QRCode.tsx +++ b/src/components/views/elements/QRCode.tsx @@ -15,10 +15,10 @@ limitations under the License. */ import * as React from "react"; -import {toDataURL, QRCodeSegment, QRCodeToDataURLOptions} from "qrcode"; +import { toDataURL, QRCodeSegment, QRCodeToDataURLOptions } from "qrcode"; import classNames from "classnames"; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import Spinner from "./Spinner"; interface IProps extends QRCodeToDataURLOptions { @@ -30,11 +30,11 @@ const defaultOptions: QRCodeToDataURLOptions = { errorCorrectionLevel: 'L', // we want it as trivial-looking as possible }; -const QRCode: React.FC = ({data, className, ...options}) => { +const QRCode: React.FC = ({ data, className, ...options }) => { const [dataUri, setUri] = React.useState(null); React.useEffect(() => { let cancelled = false; - toDataURL(data, {...defaultOptions, ...options}).then(uri => { + toDataURL(data, { ...defaultOptions, ...options }).then(uri => { if (cancelled) return; setUri(uri); }); diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js index ebf4a18aa9..aea447c9b1 100644 --- a/src/components/views/elements/ReplyThread.js +++ b/src/components/views/elements/ReplyThread.js @@ -17,21 +17,21 @@ limitations under the License. */ import React from 'react'; import * as sdk from '../../../index'; -import {_t} from '../../../languageHandler'; +import { _t } from '../../../languageHandler'; import PropTypes from 'prop-types'; import dis from '../../../dispatcher/dispatcher'; -import {wantsDateSeparator} from '../../../DateUtils'; -import {MatrixEvent} from 'matrix-js-sdk/src/models/event'; -import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; +import { wantsDateSeparator } from '../../../DateUtils'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; +import { makeUserPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import SettingsStore from "../../../settings/SettingsStore"; -import {LayoutPropType} from "../../../settings/Layout"; +import { LayoutPropType } from "../../../settings/Layout"; import escapeHtml from "escape-html"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {Action} from "../../../dispatcher/actions"; +import { Action } from "../../../dispatcher/actions"; import sanitizeHtml from "sanitize-html"; -import {UIFeature} from "../../../settings/UIFeature"; -import {PERMITTED_URL_SCHEMES} from "../../../HtmlUtils"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { UIFeature } from "../../../settings/UIFeature"; +import { PERMITTED_URL_SCHEMES } from "../../../HtmlUtils"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // This component does no cycle detection, simply because the only way to make such a cycle would be to // craft event_id's, using a homeserver that generates predictable event IDs; even then the impact would @@ -130,7 +130,7 @@ export default class ReplyThread extends React.Component { static getNestedReplyText(ev, permalinkCreator) { if (!ev) return null; - let {body, formatted_body: html} = ev.getContent(); + let { body, formatted_body: html } = ev.getContent(); if (this.getParentEventId(ev)) { if (body) body = this.stripPlainReply(body); } @@ -200,7 +200,7 @@ export default class ReplyThread extends React.Component { return null; } - return {body, html}; + return { body, html }; } static makeReplyMixIn(ev) { @@ -269,7 +269,7 @@ export default class ReplyThread extends React.Component { }; async initialize() { - const {parentEv} = this.props; + const { parentEv } = this.props; // at time of making this component we checked that props.parentEv has a parentEventId const ev = await this.getEvent(ReplyThread.getParentEventId(parentEv)); @@ -283,7 +283,7 @@ export default class ReplyThread extends React.Component { loading: false, }); } else { - this.setState({err: true}); + this.setState({ err: true }); } } diff --git a/src/components/views/elements/RoomAliasField.tsx b/src/components/views/elements/RoomAliasField.tsx index 74af311b47..d9e081341b 100644 --- a/src/components/views/elements/RoomAliasField.tsx +++ b/src/components/views/elements/RoomAliasField.tsx @@ -80,7 +80,7 @@ export default class RoomAliasField extends React.PureComponent private onValidate = async (fieldState) => { const result = await this.validationRules(fieldState); - this.setState({isValid: result.valid}); + this.setState({ isValid: result.valid }); return result; }; @@ -105,7 +105,7 @@ export default class RoomAliasField extends React.PureComponent }, { key: "taken", final: true, - test: async ({value}) => { + test: async ({ value }) => { if (!value) { return true; } diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index fe8aa5a83d..0526c2676c 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useEffect, useState} from "react"; -import {EventType} from "matrix-js-sdk/src/@types/event"; -import {Room} from "matrix-js-sdk/src/models/room"; +import React, { useEffect, useState } from "react"; +import { EventType } from "matrix-js-sdk/src/@types/event"; +import { Room } from "matrix-js-sdk/src/models/room"; -import {useEventEmitter} from "../../../hooks/useEventEmitter"; -import {linkifyElement} from "../../../HtmlUtils"; +import { useEventEmitter } from "../../../hooks/useEventEmitter"; +import { linkifyElement } from "../../../HtmlUtils"; interface IProps { room?: Room; diff --git a/src/components/views/elements/SSOButtons.tsx b/src/components/views/elements/SSOButtons.tsx index a531abdf83..68c58a3e56 100644 --- a/src/components/views/elements/SSOButtons.tsx +++ b/src/components/views/elements/SSOButtons.tsx @@ -17,14 +17,14 @@ limitations under the License. import React from "react"; import { chunk } from "lodash"; import classNames from "classnames"; -import {MatrixClient} from "matrix-js-sdk/src/client"; +import { MatrixClient } from "matrix-js-sdk/src/client"; import PlatformPeg from "../../../PlatformPeg"; import AccessibleButton from "./AccessibleButton"; -import {_t} from "../../../languageHandler"; -import {IdentityProviderBrand, IIdentityProvider, ISSOFlow} from "../../../Login"; +import { _t } from "../../../languageHandler"; +import { IdentityProviderBrand, IIdentityProvider, ISSOFlow } from "../../../Login"; import AccessibleTooltipButton from "./AccessibleTooltipButton"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { mediaFromMxc } from "../../../customisations/Media"; interface ISSOButtonProps extends Omit { idp: IIdentityProvider; @@ -48,7 +48,7 @@ const getIcon = (brand: IdentityProviderBrand | string) => { default: return null; } -} +}; const SSOButton: React.FC = ({ matrixClient, @@ -111,7 +111,7 @@ interface IProps { const MAX_PER_ROW = 6; -const SSOButtons: React.FC = ({matrixClient, flow, loginType, fragmentAfterLogin, primary}) => { +const SSOButtons: React.FC = ({ matrixClient, flow, loginType, fragmentAfterLogin, primary }) => { const providers = flow.identity_providers || []; if (providers.length < 2) { return
      diff --git a/src/components/views/elements/ServerPicker.tsx b/src/components/views/elements/ServerPicker.tsx index 9f06e2618c..c2d1fcb275 100644 --- a/src/components/views/elements/ServerPicker.tsx +++ b/src/components/views/elements/ServerPicker.tsx @@ -17,8 +17,8 @@ limitations under the License. import React from 'react'; import AccessibleButton from "./AccessibleButton"; -import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils"; -import {_t} from "../../../languageHandler"; +import { ValidatedServerConfig } from "../../../utils/AutoDiscoveryUtils"; +import { _t } from "../../../languageHandler"; import TextWithTooltip from "./TextWithTooltip"; import SdkConfig from "../../../SdkConfig"; import Modal from "../../../Modal"; @@ -87,7 +87,7 @@ const ServerPicker = ({ title, dialogTitle, serverConfig, onServerConfigChange } {serverName} { editBtn } { desc } -
      -} +
      ; +}; export default ServerPicker; diff --git a/src/components/views/elements/SettingsFlag.tsx b/src/components/views/elements/SettingsFlag.tsx index 24a21e1a33..ccde80ff00 100644 --- a/src/components/views/elements/SettingsFlag.tsx +++ b/src/components/views/elements/SettingsFlag.tsx @@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler'; import ToggleSwitch from "./ToggleSwitch"; import StyledCheckbox from "./StyledCheckbox"; import { SettingLevel } from "../../../settings/SettingLevel"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The setting must be a boolean diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx index b513f90460..b9234d0550 100644 --- a/src/components/views/elements/Slider.tsx +++ b/src/components/views/elements/Slider.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import * as React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // A callback for the selected value @@ -86,8 +86,8 @@ export default class Slider extends React.Component { if (!this.props.disabled) { const offset = this.offset(this.props.values, this.props.value); selection =
      -
      -
      +
      +
      ; } diff --git a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx index 06e1efe415..d10a599d95 100644 --- a/src/components/views/elements/SpellCheckLanguagesDropdown.tsx +++ b/src/components/views/elements/SpellCheckLanguagesDropdown.tsx @@ -16,12 +16,12 @@ limitations under the License. import React from 'react'; -import Dropdown from "../../views/elements/Dropdown" +import Dropdown from "../../views/elements/Dropdown"; import * as sdk from '../../../index'; import PlatformPeg from "../../../PlatformPeg"; import SettingsStore from "../../../settings/SettingsStore"; import { _t } from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; function languageMatchesSearchQuery(query, language) { if (language.label.toUpperCase().includes(query.toUpperCase())) return true; @@ -67,11 +67,11 @@ export default class SpellCheckLanguagesDropdown extends React.Component { - this.setState({languages: ['en']}); + this.setState({ languages: ['en'] }); }); } } diff --git a/src/components/views/elements/Spinner.js b/src/components/views/elements/Spinner.js index 3ad8444bd6..75f85d0441 100644 --- a/src/components/views/elements/Spinner.js +++ b/src/components/views/elements/Spinner.js @@ -17,14 +17,14 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; -const Spinner = ({w = 32, h = 32, message}) => ( +const Spinner = ({ w = 32, h = 32, message }) => (
      { message &&
      { message }
       
      }
      diff --git a/src/components/views/elements/Spoiler.js b/src/components/views/elements/Spoiler.js index 33b4382a2c..56c18c6e33 100644 --- a/src/components/views/elements/Spoiler.js +++ b/src/components/views/elements/Spoiler.js @@ -15,7 +15,7 @@ */ import React from 'react'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.Spoiler") export default class Spoiler extends React.Component { diff --git a/src/components/views/elements/StyledCheckbox.tsx b/src/components/views/elements/StyledCheckbox.tsx index 2454d1336b..366cc2f1f7 100644 --- a/src/components/views/elements/StyledCheckbox.tsx +++ b/src/components/views/elements/StyledCheckbox.tsx @@ -16,7 +16,7 @@ limitations under the License. import React from "react"; import { randomString } from "matrix-js-sdk/src/randomstring"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends React.InputHTMLAttributes { } diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx index 835394e055..7ec472b639 100644 --- a/src/components/views/elements/StyledRadioButton.tsx +++ b/src/components/views/elements/StyledRadioButton.tsx @@ -16,7 +16,7 @@ limitations under the License. import React from 'react'; import classnames from 'classnames'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps extends React.InputHTMLAttributes { outlined?: boolean; diff --git a/src/components/views/elements/SyntaxHighlight.js b/src/components/views/elements/SyntaxHighlight.js index f9874c5367..2c29f7c989 100644 --- a/src/components/views/elements/SyntaxHighlight.js +++ b/src/components/views/elements/SyntaxHighlight.js @@ -16,8 +16,8 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {highlightBlock} from 'highlight.js'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { highlightBlock } from 'highlight.js'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.SyntaxHighlight") export default class SyntaxHighlight extends React.Component { diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js index 03d853babc..12c3718274 100644 --- a/src/components/views/elements/TagTile.js +++ b/src/components/views/elements/TagTile.js @@ -30,8 +30,8 @@ import GroupFilterOrderStore from '../../../stores/GroupFilterOrderStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AccessibleButton from "./AccessibleButton"; import SettingsStore from "../../../settings/SettingsStore"; -import {mediaFromMxc} from "../../../customisations/Media"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // A class for a child of GroupFilterPanel (possibly wrapped in a DNDTagTile) that represents // a thing to click on for the user to filter the visible rooms in the RoomList to: diff --git a/src/components/views/elements/TextWithTooltip.js b/src/components/views/elements/TextWithTooltip.js index a6fc00fc2e..633d182fcf 100644 --- a/src/components/views/elements/TextWithTooltip.js +++ b/src/components/views/elements/TextWithTooltip.js @@ -17,7 +17,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.elements.TextWithTooltip") export default class TextWithTooltip extends React.Component { @@ -37,17 +37,17 @@ export default class TextWithTooltip extends React.Component { } onMouseOver = () => { - this.setState({hover: true}); + this.setState({ hover: true }); }; onMouseLeave = () => { - this.setState({hover: false}); + this.setState({ hover: false }); }; render() { const Tooltip = sdk.getComponent("elements.Tooltip"); - const {class: className, children, tooltip, tooltipClass, tooltipProps, ...props} = this.props; + const { class: className, children, tooltip, tooltipClass, tooltipProps, ...props } = this.props; return ( diff --git a/src/components/views/elements/TintableSvg.js b/src/components/views/elements/TintableSvg.js deleted file mode 100644 index 670f3e9bb9..0000000000 --- a/src/components/views/elements/TintableSvg.js +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd -Copyright 2019 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import PropTypes from 'prop-types'; -import Tinter from "../../../Tinter"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; - -@replaceableComponent("views.elements.TintableSvg") -class TintableSvg extends React.Component { - static propTypes = { - src: PropTypes.string.isRequired, - width: PropTypes.string.isRequired, - height: PropTypes.string.isRequired, - className: PropTypes.string, - }; - - // list of currently mounted TintableSvgs - static mounts = {}; - static idSequence = 0; - - componentDidMount() { - this.fixups = []; - - this.id = TintableSvg.idSequence++; - TintableSvg.mounts[this.id] = this; - } - - componentWillUnmount() { - delete TintableSvg.mounts[this.id]; - } - - tint = () => { - // TODO: only bother running this if the global tint settings have changed - // since we loaded! - Tinter.applySvgFixups(this.fixups); - }; - - onLoad = event => { - // console.log("TintableSvg.onLoad for " + this.props.src); - this.fixups = Tinter.calcSvgFixups([event.target]); - Tinter.applySvgFixups(this.fixups); - }; - - render() { - return ( - - ); - } -} - -// Register with the Tinter so that we will be told if the tint changes -Tinter.registerTintable(function() { - if (TintableSvg.mounts) { - Object.keys(TintableSvg.mounts).forEach((id) => { - TintableSvg.mounts[id].tint(); - }); - } -}); - -export default TintableSvg; diff --git a/src/components/views/elements/ToggleSwitch.tsx b/src/components/views/elements/ToggleSwitch.tsx index f05c45b3db..7315cc6383 100644 --- a/src/components/views/elements/ToggleSwitch.tsx +++ b/src/components/views/elements/ToggleSwitch.tsx @@ -31,7 +31,7 @@ interface IProps { } // Controlled Toggle Switch element, written with Accessibility in mind -export default ({checked, disabled = false, onChange, ...props}: IProps) => { +export default ({ checked, disabled = false, onChange, ...props }: IProps) => { const _onClick = () => { if (disabled) return; onChange(!checked); diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index 0202c6b02f..e64819f441 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -17,11 +17,10 @@ See the License for the specific language governing permissions and limitations under the License. */ - -import React, {Component, CSSProperties} from 'react'; +import React, { Component, CSSProperties } from 'react'; import ReactDOM from 'react-dom'; import classNames from 'classnames'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import UIStore from "../../../stores/UIStore"; const MIN_TOOLTIP_HEIGHT = 25; diff --git a/src/components/views/elements/TooltipButton.tsx b/src/components/views/elements/TooltipButton.tsx index 191018cc19..87bf04c2ea 100644 --- a/src/components/views/elements/TooltipButton.tsx +++ b/src/components/views/elements/TooltipButton.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { helpText: string; diff --git a/src/components/views/elements/TruncatedList.tsx b/src/components/views/elements/TruncatedList.tsx index 395caa9222..403df4111e 100644 --- a/src/components/views/elements/TruncatedList.tsx +++ b/src/components/views/elements/TruncatedList.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { // The number of elements to show before truncating. If negative, no truncation is done. @@ -43,7 +43,7 @@ export default class TruncatedList extends React.Component { truncateAt: 2, createOverflowElement(overflowCount, totalCount) { return ( -
      { _t("And %(count)s more...", {count: overflowCount}) }
      +
      { _t("And %(count)s more...", { count: overflowCount }) }
      ); }, }; diff --git a/src/components/views/elements/UserTagTile.tsx b/src/components/views/elements/UserTagTile.tsx index d3e07a0a34..4414ff31fd 100644 --- a/src/components/views/elements/UserTagTile.tsx +++ b/src/components/views/elements/UserTagTile.tsx @@ -21,7 +21,7 @@ import GroupFilterOrderStore from "../../../stores/GroupFilterOrderStore"; import AccessibleTooltipButton from "./AccessibleTooltipButton"; import classNames from "classnames"; import { _t } from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { } @@ -52,7 +52,7 @@ export default class UserTagTile extends React.PureComponent { private onTagStoreUpdate = () => { const selected = GroupFilterOrderStore.getSelectedTags().length === 0; - this.setState({selected}); + this.setState({ selected }); }; private onTileClick = (ev) => { @@ -60,7 +60,7 @@ export default class UserTagTile extends React.PureComponent { ev.stopPropagation(); // Deselect all tags - defaultDispatcher.dispatch({action: "deselect_tags"}); + defaultDispatcher.dispatch({ action: "deselect_tags" }); }; public render() { diff --git a/src/components/views/elements/Validation.tsx b/src/components/views/elements/Validation.tsx index 1b0659ab9b..ad3571513c 100644 --- a/src/components/views/elements/Validation.tsx +++ b/src/components/views/elements/Validation.tsx @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* eslint-disable babel/no-invalid-this */ +/* eslint-disable @typescript-eslint/no-invalid-this */ import React from "react"; import classNames from "classnames"; diff --git a/src/components/views/elements/crypto/VerificationQRCode.js b/src/components/views/elements/crypto/VerificationQRCode.js index 3bbfb004c6..76cfb82d35 100644 --- a/src/components/views/elements/crypto/VerificationQRCode.js +++ b/src/components/views/elements/crypto/VerificationQRCode.js @@ -16,7 +16,7 @@ limitations under the License. import React from "react"; import PropTypes from "prop-types"; -import {replaceableComponent} from "../../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../../utils/replaceableComponent"; import QRCode from "../QRCode"; @replaceableComponent("views.elements.crypto.VerificationQRCode") @@ -28,7 +28,7 @@ export default class VerificationQRCode extends React.PureComponent { render() { return ( ); diff --git a/src/components/views/emojipicker/Category.tsx b/src/components/views/emojipicker/Category.tsx index 4c7852def3..24b4fbe3ed 100644 --- a/src/components/views/emojipicker/Category.tsx +++ b/src/components/views/emojipicker/Category.tsx @@ -15,13 +15,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {RefObject} from 'react'; +import React, { RefObject } from 'react'; import { CATEGORY_HEADER_HEIGHT, EMOJI_HEIGHT, EMOJIS_PER_ROW } from "./EmojiPicker"; import LazyRenderList from "../elements/LazyRenderList"; -import {DATA_BY_CATEGORY, IEmoji} from "../../../emoji"; +import { DATA_BY_CATEGORY, IEmoji } from "../../../emoji"; import Emoji from './Emoji'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const OVERFLOW_ROWS = 3; diff --git a/src/components/views/emojipicker/Emoji.tsx b/src/components/views/emojipicker/Emoji.tsx index 5d7665ce98..73e24f46fb 100644 --- a/src/components/views/emojipicker/Emoji.tsx +++ b/src/components/views/emojipicker/Emoji.tsx @@ -17,9 +17,9 @@ limitations under the License. import React from 'react'; -import {MenuItem} from "../../structures/ContextMenu"; -import {IEmoji} from "../../../emoji"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MenuItem } from "../../structures/ContextMenu"; +import { IEmoji } from "../../../emoji"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { emoji: IEmoji; diff --git a/src/components/views/emojipicker/EmojiPicker.tsx b/src/components/views/emojipicker/EmojiPicker.tsx index 6d7b90c8a6..47e3823116 100644 --- a/src/components/views/emojipicker/EmojiPicker.tsx +++ b/src/components/views/emojipicker/EmojiPicker.tsx @@ -19,14 +19,14 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import * as recent from '../../../emojipicker/recent'; -import {DATA_BY_CATEGORY, getEmojiFromUnicode, IEmoji} from "../../../emoji"; +import { DATA_BY_CATEGORY, getEmojiFromUnicode, IEmoji } from "../../../emoji"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import Header from "./Header"; import Search from "./Search"; import Preview from "./Preview"; import QuickReactions from "./QuickReactions"; -import Category, {ICategory, CategoryKey} from "./Category"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import Category, { ICategory, CategoryKey } from "./Category"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; export const CATEGORY_HEADER_HEIGHT = 22; export const EMOJI_HEIGHT = 37; @@ -234,7 +234,7 @@ class EmojiPicker extends React.Component { className="mx_EmojiPicker_body" wrappedRef={ref => { // @ts-ignore - AutoHideScrollbar should accept a RefObject or fall back to its own instead - this.bodyRef.current = ref + this.bodyRef.current = ref; }} onScroll={this.onScroll} > diff --git a/src/components/views/emojipicker/Header.tsx b/src/components/views/emojipicker/Header.tsx index 693f86ad73..010801141a 100644 --- a/src/components/views/emojipicker/Header.tsx +++ b/src/components/views/emojipicker/Header.tsx @@ -18,10 +18,10 @@ limitations under the License. import React from 'react'; import classNames from "classnames"; -import {_t} from "../../../languageHandler"; -import {Key} from "../../../Keyboard"; -import {CategoryKey, ICategory} from "./Category"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { _t } from "../../../languageHandler"; +import { Key } from "../../../Keyboard"; +import { CategoryKey, ICategory } from "./Category"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { categories: ICategory[]; diff --git a/src/components/views/emojipicker/Preview.tsx b/src/components/views/emojipicker/Preview.tsx index e0952ec73e..9c2dbb9cbd 100644 --- a/src/components/views/emojipicker/Preview.tsx +++ b/src/components/views/emojipicker/Preview.tsx @@ -17,8 +17,8 @@ limitations under the License. import React from 'react'; -import {IEmoji} from "../../../emoji"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { IEmoji } from "../../../emoji"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { emoji: IEmoji; diff --git a/src/components/views/emojipicker/QuickReactions.tsx b/src/components/views/emojipicker/QuickReactions.tsx index a250aca458..ffd3ce9760 100644 --- a/src/components/views/emojipicker/QuickReactions.tsx +++ b/src/components/views/emojipicker/QuickReactions.tsx @@ -18,9 +18,9 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import {getEmojiFromUnicode, IEmoji} from "../../../emoji"; +import { getEmojiFromUnicode, IEmoji } from "../../../emoji"; import Emoji from "./Emoji"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // We use the variation-selector Heart in Quick Reactions for some reason const QUICK_REACTIONS = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"].map(emoji => { diff --git a/src/components/views/emojipicker/ReactionPicker.tsx b/src/components/views/emojipicker/ReactionPicker.tsx index e86d183aba..d8f8b7f2ff 100644 --- a/src/components/views/emojipicker/ReactionPicker.tsx +++ b/src/components/views/emojipicker/ReactionPicker.tsx @@ -16,12 +16,12 @@ limitations under the License. */ import React from 'react'; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import EmojiPicker from "./EmojiPicker"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import dis from "../../../dispatcher/dispatcher"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { mxEvent: MatrixEvent; @@ -103,7 +103,7 @@ class ReactionPicker extends React.Component { "key": reaction, }, }); - dis.dispatch({action: "message_sent"}); + dis.dispatch({ action: "message_sent" }); return true; } }; diff --git a/src/components/views/emojipicker/Search.tsx b/src/components/views/emojipicker/Search.tsx index abe3e026be..c88bf8d84d 100644 --- a/src/components/views/emojipicker/Search.tsx +++ b/src/components/views/emojipicker/Search.tsx @@ -18,8 +18,8 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; -import {Key} from "../../../Keyboard"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Key } from "../../../Keyboard"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { query: string; diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js index bc0bf966f9..c12e14e024 100644 --- a/src/components/views/groups/GroupInviteTile.js +++ b/src/components/views/groups/GroupInviteTile.js @@ -20,19 +20,19 @@ import React from 'react'; import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; -import {_t} from '../../../languageHandler'; +import { _t } from '../../../languageHandler'; import classNames from 'classnames'; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextMenu"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { ContextMenu, ContextMenuButton, toRightOf } from "../../structures/ContextMenu"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {RovingTabIndexWrapper} from "../../../accessibility/RovingTabIndex"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; // XXX this class copies a lot from RoomTile.js @replaceableComponent("views.groups.GroupInviteTile") export default class GroupInviteTile extends React.Component { - static propTypes: { + static propTypes = { group: PropTypes.object.isRequired, }; @@ -57,7 +57,7 @@ export default class GroupInviteTile extends React.Component { }; onMouseEnter = () => { - const state = {hover: true}; + const state = { hover: true }; // Only allow non-guests to access the context menu if (!this.context.isGuest()) { state.badgeHover = true; @@ -165,7 +165,7 @@ export default class GroupInviteTile extends React.Component { return - {({onFocus, isActive, ref}) => + {({ onFocus, isActive, ref }) => { if (!proceed) return; - this.setState({groupRoomRemoveLoading: true}); + this.setState({ groupRoomRemoveLoading: true }); const groupId = this.props.groupId; const roomId = this.props.groupRoomId; GroupStore.removeRoomFromGroup(this.props.groupId, roomId).then(() => { @@ -108,11 +108,11 @@ export default class GroupRoomInfo extends React.Component { Modal.createTrackedDialog('Failed to remove room from group', '', ErrorDialog, { title: _t("Failed to remove room from community"), description: _t( - "Failed to remove '%(roomName)s' from %(groupId)s", {groupId, roomName}, + "Failed to remove '%(roomName)s' from %(groupId)s", { groupId, roomName }, ), }); }).finally(() => { - this.setState({groupRoomRemoveLoading: false}); + this.setState({ groupRoomRemoveLoading: false }); }); }, }); @@ -139,7 +139,7 @@ export default class GroupRoomInfo extends React.Component { title: _t("Something went wrong!"), description: _t( "The visibility of '%(roomName)s' in %(groupId)s could not be updated.", - {roomName, groupId}, + { roomName, groupId }, ), }); }).finally(() => { diff --git a/src/components/views/groups/GroupRoomList.js b/src/components/views/groups/GroupRoomList.js index 2921ac79ee..00220441e7 100644 --- a/src/components/views/groups/GroupRoomList.js +++ b/src/components/views/groups/GroupRoomList.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import { showGroupAddRoomDialog } from '../../../GroupAddressPicker'; import AccessibleButton from '../elements/AccessibleButton'; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const INITIAL_LOAD_NUM_ROOMS = 30; diff --git a/src/components/views/groups/GroupRoomTile.js b/src/components/views/groups/GroupRoomTile.js index 7edfc1a376..662359669d 100644 --- a/src/components/views/groups/GroupRoomTile.js +++ b/src/components/views/groups/GroupRoomTile.js @@ -20,8 +20,8 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { GroupRoomType } from '../../../groups'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; @replaceableComponent("views.groups.GroupRoomTile") class GroupRoomTile extends React.Component { diff --git a/src/components/views/groups/GroupTile.js b/src/components/views/groups/GroupTile.js index dd8366bbe0..21308ac056 100644 --- a/src/components/views/groups/GroupTile.js +++ b/src/components/views/groups/GroupTile.js @@ -20,8 +20,8 @@ import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import FlairStore from '../../../stores/FlairStore'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; import { _t } from "../../../languageHandler"; import TagOrderActions from "../../../actions/TagOrderActions"; import GroupFilterOrderStore from "../../../stores/GroupFilterOrderStore"; @@ -49,7 +49,7 @@ class GroupTile extends React.Component { componentDidMount() { FlairStore.getGroupProfileCached(this.context, this.props.groupId).then((profile) => { - this.setState({profile}); + this.setState({ profile }); }).catch((err) => { console.error('Error whilst getting cached profile for GroupTile', err); }); diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js index 5b537d7377..efb392c54f 100644 --- a/src/components/views/groups/GroupUserSettings.js +++ b/src/components/views/groups/GroupUserSettings.js @@ -18,7 +18,7 @@ import React from 'react'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.groups.GroupUserSettings") export default class GroupUserSettings extends React.Component { @@ -31,10 +31,10 @@ export default class GroupUserSettings extends React.Component { componentDidMount() { this.context.getJoinedGroups().then((result) => { - this.setState({groups: result.groups || [], error: null}); + this.setState({ groups: result.groups || [], error: null }); }, (err) => { console.error(err); - this.setState({groups: null, error: err}); + this.setState({ groups: null, error: err }); }); } diff --git a/src/components/views/host_signup/HostSignupContainer.tsx b/src/components/views/host_signup/HostSignupContainer.tsx index 6445454994..fc1506bf61 100644 --- a/src/components/views/host_signup/HostSignupContainer.tsx +++ b/src/components/views/host_signup/HostSignupContainer.tsx @@ -33,4 +33,4 @@ const HostSignupContainer = () => { ; }; -export default HostSignupContainer +export default HostSignupContainer; diff --git a/src/components/views/messages/DateSeparator.js b/src/components/views/messages/DateSeparator.tsx similarity index 82% rename from src/components/views/messages/DateSeparator.js rename to src/components/views/messages/DateSeparator.tsx index 82ce8dc4ae..5d43e2182d 100644 --- a/src/components/views/messages/DateSeparator.js +++ b/src/components/views/messages/DateSeparator.tsx @@ -1,6 +1,6 @@ /* -Copyright 2015, 2016 OpenMarket Ltd Copyright 2018 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2015 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import { _t } from '../../../languageHandler'; -import {formatFullDateNoTime} from '../../../DateUtils'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -function getdaysArray() { +import { _t } from '../../../languageHandler'; +import { formatFullDateNoTime } from '../../../DateUtils'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; + +function getDaysArray(): string[] { return [ _t('Sunday'), _t('Monday'), @@ -33,17 +33,17 @@ function getdaysArray() { ]; } -@replaceableComponent("views.messages.DateSeparator") -export default class DateSeparator extends React.Component { - static propTypes = { - ts: PropTypes.number.isRequired, - }; +interface IProps { + ts: number; +} - getLabel() { +@replaceableComponent("views.messages.DateSeparator") +export default class DateSeparator extends React.Component { + private getLabel() { const date = new Date(this.props.ts); const today = new Date(); const yesterday = new Date(); - const days = getdaysArray(); + const days = getDaysArray(); yesterday.setDate(today.getDate() - 1); if (date.toDateString() === today.toDateString()) { diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index dc4e0187d3..1416cfff53 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -14,20 +14,20 @@ 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 * as HtmlUtils from '../../../HtmlUtils'; import { editBodyDiffToHtml } from '../../../utils/MessageDiffUtils'; -import {formatTime} from '../../../DateUtils'; -import {MatrixEvent} from 'matrix-js-sdk/src/models/event'; -import {pillifyLinks, unmountPills} from '../../../utils/pillify'; +import { formatTime } from '../../../DateUtils'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; +import { pillifyLinks, unmountPills } from '../../../utils/pillify'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import Modal from '../../../Modal'; import classNames from 'classnames'; import RedactedBody from "./RedactedBody"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; function getReplacedContent(event) { const originalContent = event.getOriginalContent(); @@ -46,21 +46,21 @@ export default class EditHistoryMessage extends React.PureComponent { constructor(props) { super(props); const cli = MatrixClientPeg.get(); - const {userId} = cli.credentials; + const { userId } = cli.credentials; const event = this.props.mxEvent; const room = cli.getRoom(event.getRoomId()); if (event.localRedactionEvent()) { event.localRedactionEvent().on("status", this._onAssociatedStatusChanged); } const canRedact = room.currentState.maySendRedactionForEvent(event, userId); - this.state = {canRedact, sendStatus: event.getAssociatedStatus()}; + this.state = { canRedact, sendStatus: event.getAssociatedStatus() }; this._content = createRef(); this._pills = []; } _onAssociatedStatusChanged = () => { - this.setState({sendStatus: this.props.mxEvent.getAssociatedStatus()}); + this.setState({ sendStatus: this.props.mxEvent.getAssociatedStatus() }); }; _onRedactClick = async () => { @@ -129,7 +129,7 @@ export default class EditHistoryMessage extends React.PureComponent { } render() { - const {mxEvent} = this.props; + const { mxEvent } = this.props; const content = getReplacedContent(mxEvent); let contentContainer; if (mxEvent.isRedacted()) { @@ -139,7 +139,7 @@ export default class EditHistoryMessage extends React.PureComponent { if (this.props.previousEdit) { contentElements = editBodyDiffToHtml(getReplacedContent(this.props.previousEdit), content); } else { - contentElements = HtmlUtils.bodyToHtml(content, null, {stripReplyFallback: true}); + contentElements = HtmlUtils.bodyToHtml(content, null, { stripReplyFallback: true }); } if (mxEvent.getContent().msgtype === "m.emote") { const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); diff --git a/src/components/views/messages/EncryptionEvent.tsx b/src/components/views/messages/EncryptionEvent.tsx index 3af9c463c9..0f716ed010 100644 --- a/src/components/views/messages/EncryptionEvent.tsx +++ b/src/components/views/messages/EncryptionEvent.tsx @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {forwardRef, useContext} from 'react'; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import React, { forwardRef, useContext } from 'react'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; @@ -27,7 +27,7 @@ interface IProps { mxEvent: MatrixEvent; } -const EncryptionEvent = forwardRef(({mxEvent}, ref) => { +const EncryptionEvent = forwardRef(({ mxEvent }, ref) => { const cli = useContext(MatrixClientContext); const roomId = mxEvent.getRoomId(); const isRoomEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId); diff --git a/src/components/views/messages/EventTileBubble.tsx b/src/components/views/messages/EventTileBubble.tsx index 88913ac2d4..9fa3586ea5 100644 --- a/src/components/views/messages/EventTileBubble.tsx +++ b/src/components/views/messages/EventTileBubble.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {forwardRef, ReactNode, ReactChildren} from "react"; +import React, { forwardRef, ReactNode, ReactChildren } from "react"; import classNames from "classnames"; interface IProps { diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js deleted file mode 100644 index 0d5e449fc0..0000000000 --- a/src/components/views/messages/MAudioBody.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - Copyright 2016 OpenMarket Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -import React from 'react'; -import MFileBody from './MFileBody'; - -import { decryptFile } from '../../../utils/DecryptFile'; -import { _t } from '../../../languageHandler'; -import InlineSpinner from '../elements/InlineSpinner'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromContent} from "../../../customisations/Media"; - -@replaceableComponent("views.messages.MAudioBody") -export default class MAudioBody extends React.Component { - constructor(props) { - super(props); - this.state = { - playing: false, - decryptedUrl: null, - decryptedBlob: null, - error: null, - }; - } - onPlayToggle() { - this.setState({ - playing: !this.state.playing, - }); - } - - _getContentUrl() { - const media = mediaFromContent(this.props.mxEvent.getContent()); - if (media.isEncrypted) { - return this.state.decryptedUrl; - } else { - return media.srcHttp; - } - } - - componentDidMount() { - const content = this.props.mxEvent.getContent(); - if (content.file !== undefined && this.state.decryptedUrl === null) { - let decryptedBlob; - decryptFile(content.file).then(function(blob) { - decryptedBlob = blob; - return URL.createObjectURL(decryptedBlob); - }).then((url) => { - this.setState({ - decryptedUrl: url, - decryptedBlob: decryptedBlob, - }); - }, (err) => { - console.warn("Unable to decrypt attachment: ", err); - this.setState({ - error: err, - }); - }); - } - } - - componentWillUnmount() { - if (this.state.decryptedUrl) { - URL.revokeObjectURL(this.state.decryptedUrl); - } - } - - render() { - const content = this.props.mxEvent.getContent(); - - if (this.state.error !== null) { - return ( - - - { _t("Error decrypting audio") } - - ); - } - - if (content.file !== undefined && this.state.decryptedUrl === null) { - // Need to decrypt the attachment - // The attachment is decrypted in componentDidMount. - // For now add an img tag with a 16x16 spinner. - // Not sure how tall the audio player is so not sure how tall it should actually be. - return ( - - - - ); - } - - const contentUrl = this._getContentUrl(); - - return ( - - - ); - } -} diff --git a/src/components/views/messages/MAudioBody.tsx b/src/components/views/messages/MAudioBody.tsx new file mode 100644 index 0000000000..bc7216f42c --- /dev/null +++ b/src/components/views/messages/MAudioBody.tsx @@ -0,0 +1,110 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { Playback } from "../../../voice/Playback"; +import MFileBody from "./MFileBody"; +import InlineSpinner from '../elements/InlineSpinner'; +import { _t } from "../../../languageHandler"; +import { mediaFromContent } from "../../../customisations/Media"; +import { decryptFile } from "../../../utils/DecryptFile"; +import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; +import AudioPlayer from "../audio_messages/AudioPlayer"; + +interface IProps { + mxEvent: MatrixEvent; +} + +interface IState { + error?: Error; + playback?: Playback; + decryptedBlob?: Blob; +} + +@replaceableComponent("views.messages.MAudioBody") +export default class MAudioBody extends React.PureComponent { + constructor(props: IProps) { + super(props); + + this.state = {}; + } + + public async componentDidMount() { + let buffer: ArrayBuffer; + const content: IMediaEventContent = this.props.mxEvent.getContent(); + const media = mediaFromContent(content); + if (media.isEncrypted) { + try { + const blob = await decryptFile(content.file); + buffer = await blob.arrayBuffer(); + this.setState({ decryptedBlob: blob }); + } catch (e) { + this.setState({ error: e }); + console.warn("Unable to decrypt audio message", e); + return; // stop processing the audio file + } + } else { + try { + buffer = await media.downloadSource().then(r => r.blob()).then(r => r.arrayBuffer()); + } catch (e) { + this.setState({ error: e }); + console.warn("Unable to download audio message", e); + return; // stop processing the audio file + } + } + + // We should have a buffer to work with now: let's set it up + const playback = new Playback(buffer); + playback.clockInfo.populatePlaceholdersFrom(this.props.mxEvent); + this.setState({ playback }); + // Note: the RecordingPlayback component will handle preparing the Playback class for us. + } + + public componentWillUnmount() { + this.state.playback?.destroy(); + } + + public render() { + if (this.state.error) { + // TODO: @@TR: Verify error state + return ( + + + { _t("Error processing audio message") } + + ); + } + + if (!this.state.playback) { + // TODO: @@TR: Verify loading/decrypting state + return ( + + + + ); + } + + // At this point we should have a playable state + return ( + + + + + ); + } +} diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 8f464e08bd..d8d832d15d 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -14,15 +14,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 PropTypes from 'prop-types'; import filesize from 'filesize'; import { _t } from '../../../languageHandler'; -import {decryptFile} from '../../../utils/DecryptFile'; +import { decryptFile } from '../../../utils/DecryptFile'; import Modal from '../../../Modal'; import AccessibleButton from "../elements/AccessibleButton"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromContent} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromContent } from "../../../customisations/Media"; import ErrorDialog from "../dialogs/ErrorDialog"; let downloadIconUrl; // cached copy of the download.svg asset for the sandboxed iframe later on @@ -242,7 +242,7 @@ export default class MFileBody extends React.Component { {placeholder}
      -
      +
      { /* * Add dummy copy of the "a" tag * We'll use it to learn how the download link diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 6505b1d66a..7e85f15898 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -16,7 +16,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 MFileBody from './MFileBody'; @@ -27,8 +27,8 @@ import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import InlineSpinner from '../elements/InlineSpinner'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromContent} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromContent } from "../../../customisations/Media"; @replaceableComponent("views.messages.MImageBody") export default class MImageBody extends React.Component { @@ -90,7 +90,7 @@ export default class MImageBody extends React.Component { showImage() { localStorage.setItem("mx_ShowImage_" + this.props.mxEvent.getId(), "true"); - this.setState({showImage: true}); + this.setState({ showImage: true }); this._downloadImage(); } @@ -296,7 +296,7 @@ export default class MImageBody extends React.Component { if (showImage) { // Don't download anything becaue we don't want to display anything. this._downloadImage(); - this.setState({showImage: true}); + this.setState({ showImage: true }); } this._afterComponentDidMount(); @@ -345,7 +345,7 @@ export default class MImageBody extends React.Component { imageElement = ; } else { imageElement = ( - {content.body} } -
      +
      { img } { gifLabel }
      diff --git a/src/components/views/messages/MJitsiWidgetEvent.tsx b/src/components/views/messages/MJitsiWidgetEvent.tsx index 626efe1f36..aaf659d6d9 100644 --- a/src/components/views/messages/MJitsiWidgetEvent.tsx +++ b/src/components/views/messages/MJitsiWidgetEvent.tsx @@ -21,7 +21,7 @@ import WidgetStore from "../../../stores/WidgetStore"; import EventTileBubble from "./EventTileBubble"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { mxEvent: MatrixEvent; @@ -52,20 +52,20 @@ export default class MJitsiWidgetEvent extends React.PureComponent { // removed return ; } else if (prevUrl) { // modified return ; } else { // assume added return ; } diff --git a/src/components/views/messages/MKeyVerificationConclusion.js b/src/components/views/messages/MKeyVerificationConclusion.js index c9489711aa..a5f12df47d 100644 --- a/src/components/views/messages/MKeyVerificationConclusion.js +++ b/src/components/views/messages/MKeyVerificationConclusion.js @@ -17,12 +17,12 @@ limitations under the License. import React from 'react'; import classNames from 'classnames'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; -import {getNameForEventRoom, userLabelForEventRoom} +import { getNameForEventRoom, userLabelForEventRoom } from '../../../utils/KeyVerificationStateObserver'; import EventTileBubble from "./EventTileBubble"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.MKeyVerificationConclusion") export default class MKeyVerificationConclusion extends React.Component { @@ -90,7 +90,7 @@ export default class MKeyVerificationConclusion extends React.Component { } render() { - const {mxEvent} = this.props; + const { mxEvent } = this.props; const request = mxEvent.verificationRequest; if (!this._shouldRender(mxEvent, request)) { @@ -103,15 +103,15 @@ export default class MKeyVerificationConclusion extends React.Component { let title; if (request.done) { - title = _t("You verified %(name)s", {name: getNameForEventRoom(request.otherUserId, mxEvent)}); + title = _t("You verified %(name)s", { name: getNameForEventRoom(request.otherUserId, mxEvent) }); } else if (request.cancelled) { const userId = request.cancellingUserId; if (userId === myUserId) { title = _t("You cancelled verifying %(name)s", - {name: getNameForEventRoom(request.otherUserId, mxEvent)}); + { name: getNameForEventRoom(request.otherUserId, mxEvent) }); } else { title = _t("%(name)s cancelled verifying", - {name: getNameForEventRoom(userId, mxEvent)}); + { name: getNameForEventRoom(userId, mxEvent) }); } } diff --git a/src/components/views/messages/MKeyVerificationRequest.tsx b/src/components/views/messages/MKeyVerificationRequest.tsx index 69467cfa50..d690513d55 100644 --- a/src/components/views/messages/MKeyVerificationRequest.tsx +++ b/src/components/views/messages/MKeyVerificationRequest.tsx @@ -53,7 +53,7 @@ export default class MKeyVerificationRequest extends React.Component { dis.dispatch({ action: Action.SetRightPanelPhase, phase: RightPanelPhases.EncryptionPanel, - refireParams: {verificationRequest, member}, + refireParams: { verificationRequest, member }, }); }; @@ -90,14 +90,14 @@ export default class MKeyVerificationRequest extends React.Component { if (userId === myUserId) { return _t("You accepted"); } else { - return _t("%(name)s accepted", {name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId())}); + return _t("%(name)s accepted", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()) }); } } private cancelledLabel(userId: string) { const client = MatrixClientPeg.get(); const myUserId = client.getUserId(); - const {cancellationCode} = this.props.mxEvent.verificationRequest; + const { cancellationCode } = this.props.mxEvent.verificationRequest; const declined = cancellationCode === "m.user"; if (userId === myUserId) { if (declined) { @@ -107,9 +107,9 @@ export default class MKeyVerificationRequest extends React.Component { } } else { if (declined) { - return _t("%(name)s declined", {name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId())}); + return _t("%(name)s declined", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()) }); } else { - return _t("%(name)s cancelled", {name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId())}); + return _t("%(name)s cancelled", { name: getNameForEventRoom(userId, this.props.mxEvent.getRoomId()) }); } } } @@ -117,7 +117,7 @@ export default class MKeyVerificationRequest extends React.Component { public render() { const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); - const {mxEvent} = this.props; + const { mxEvent } = this.props; const request = mxEvent.verificationRequest; if (!request || request.invalid) { @@ -147,7 +147,7 @@ export default class MKeyVerificationRequest extends React.Component { if (!request.initiatedByMe) { const name = getNameForEventRoom(request.requestingUserId, mxEvent.getRoomId()); - title = _t("%(name)s wants to verify", {name}); + title = _t("%(name)s wants to verify", { name }); subtitle = userLabelForEventRoom(request.requestingUserId, mxEvent.getRoomId()); if (request.canAccept) { stateNode = (
      diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index 54eb7649b4..eb3635b0c0 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import MImageBody from './MImageBody'; import * as sdk from '../../../index'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.MStickerBody") export default class MStickerBody extends MImageBody { @@ -42,8 +42,7 @@ export default class MStickerBody extends MImageBody { // Placeholder to show in place of the sticker image if // img onLoad hasn't fired yet. getPlaceholder() { - const TintableSVG = sdk.getComponent('elements.TintableSvg'); - return ; + return ; } // Tooltip to show on mouse over @@ -53,7 +52,7 @@ export default class MStickerBody extends MImageBody { if (!content || !content.body || !content.info || !content.info.w) return null; const Tooltip = sdk.getComponent('elements.Tooltip'); - return
      + return
      ; } diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index 2efdce506e..ef79e96370 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -21,8 +21,8 @@ import { decryptFile } from '../../../utils/DecryptFile'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import InlineSpinner from '../elements/InlineSpinner'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromContent} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromContent } from "../../../customisations/Media"; interface IProps { /* the MatrixEvent to show */ @@ -51,7 +51,7 @@ export default class MVideoBody extends React.PureComponent { decryptedThumbnailUrl: null, decryptedBlob: null, error: null, - } + }; } thumbScale(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number) { @@ -182,7 +182,7 @@ export default class MVideoBody extends React.PureComponent { this.videoRef.current.play(); }); this.props.onHeightChanged(); - } + }; render() { const content = this.props.mxEvent.getContent(); diff --git a/src/components/views/messages/MVoiceMessageBody.tsx b/src/components/views/messages/MVoiceMessageBody.tsx index a7e3b1cd86..2edd42f2e4 100644 --- a/src/components/views/messages/MVoiceMessageBody.tsx +++ b/src/components/views/messages/MVoiceMessageBody.tsx @@ -15,16 +15,16 @@ limitations under the License. */ import React from "react"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {Playback} from "../../../voice/Playback"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { Playback } from "../../../voice/Playback"; import MFileBody from "./MFileBody"; import InlineSpinner from '../elements/InlineSpinner'; -import {_t} from "../../../languageHandler"; -import {mediaFromContent} from "../../../customisations/Media"; -import {decryptFile} from "../../../utils/DecryptFile"; -import RecordingPlayback from "../voice_messages/RecordingPlayback"; -import {IMediaEventContent} from "../../../customisations/models/IMediaEventContent"; +import { _t } from "../../../languageHandler"; +import { mediaFromContent } from "../../../customisations/Media"; +import { decryptFile } from "../../../utils/DecryptFile"; +import RecordingPlayback from "../audio_messages/RecordingPlayback"; +import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent"; interface IProps { mxEvent: MatrixEvent; @@ -52,9 +52,9 @@ export default class MVoiceMessageBody extends React.PureComponent r.blob()).then(r => r.arrayBuffer()); } catch (e) { - this.setState({error: e}); + this.setState({ error: e }); console.warn("Unable to download voice message", e); return; // stop processing the audio file } @@ -106,6 +106,6 @@ export default class MVoiceMessageBody extends React.PureComponent - ) + ); } } diff --git a/src/components/views/messages/MVoiceOrAudioBody.tsx b/src/components/views/messages/MVoiceOrAudioBody.tsx index 6d26ef3dcb..676b5a2c47 100644 --- a/src/components/views/messages/MVoiceOrAudioBody.tsx +++ b/src/components/views/messages/MVoiceOrAudioBody.tsx @@ -15,9 +15,9 @@ limitations under the License. */ import React from "react"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import MAudioBody from "./MAudioBody"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import SettingsStore from "../../../settings/SettingsStore"; import MVoiceMessageBody from "./MVoiceMessageBody"; diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 3d434e0ee2..7532554666 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -16,24 +16,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useEffect} from 'react'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import { EventStatus } from 'matrix-js-sdk/src/models/event'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; -import {aboveLeftOf, ContextMenu, ContextMenuTooltipButton, useContextMenu} from '../../structures/ContextMenu'; +import { aboveLeftOf, ContextMenu, ContextMenuTooltipButton, useContextMenu } from '../../structures/ContextMenu'; import { isContentActionable, canEditContent } from '../../../utils/EventUtils'; import RoomContext from "../../../contexts/RoomContext"; import Toolbar from "../../../accessibility/Toolbar"; -import {RovingAccessibleTooltipButton, useRovingTabIndex} from "../../../accessibility/RovingTabIndex"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {canCancel} from "../context_menus/MessageContextMenu"; +import { RovingAccessibleTooltipButton, useRovingTabIndex } from "../../../accessibility/RovingTabIndex"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { canCancel } from "../context_menus/MessageContextMenu"; import Resend from "../../../Resend"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange}) => { +const OptionsButton = ({ mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange }) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); const [onFocus, isActive, ref] = useRovingTabIndex(button); useEffect(() => { @@ -73,7 +73,7 @@ const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFo ; }; -const ReactButton = ({mxEvent, reactions, onFocusChange}) => { +const ReactButton = ({ mxEvent, reactions, onFocusChange }) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); const [onFocus, isActive, ref] = useRovingTabIndex(button); useEffect(() => { diff --git a/src/components/views/messages/MessageEvent.js b/src/components/views/messages/MessageEvent.js index 78e0dc422d..52a0b9ad08 100644 --- a/src/components/views/messages/MessageEvent.js +++ b/src/components/views/messages/MessageEvent.js @@ -14,14 +14,14 @@ 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 * as sdk from '../../../index'; import SettingsStore from "../../../settings/SettingsStore"; -import {Mjolnir} from "../../../mjolnir/Mjolnir"; +import { Mjolnir } from "../../../mjolnir/Mjolnir"; import RedactedBody from "./RedactedBody"; import UnknownBody from "./UnknownBody"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.MessageEvent") export default class MessageEvent extends React.Component { diff --git a/src/components/views/messages/MjolnirBody.js b/src/components/views/messages/MjolnirBody.js index 4368fd936c..67484a6d9c 100644 --- a/src/components/views/messages/MjolnirBody.js +++ b/src/components/views/messages/MjolnirBody.js @@ -16,8 +16,8 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {_t} from '../../../languageHandler'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { _t } from '../../../languageHandler'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.MjolnirBody") export default class MjolnirBody extends React.Component { @@ -43,7 +43,7 @@ export default class MjolnirBody extends React.Component { return (
      {_t( "You have ignored this user, so their message is hidden. Show anyways.", - {}, {a: (sub) => {sub}}, + {}, { a: (sub) => {sub} }, )}
      ); } diff --git a/src/components/views/messages/ReactionsRow.tsx b/src/components/views/messages/ReactionsRow.tsx index 0180baa466..55ffb8deac 100644 --- a/src/components/views/messages/ReactionsRow.tsx +++ b/src/components/views/messages/ReactionsRow.tsx @@ -125,7 +125,7 @@ export default class ReactionsRow extends React.PureComponent { private onDecrypted = () => { // Decryption changes whether the event is actionable this.forceUpdate(); - } + }; private onReactionsChange = () => { // TODO: Call `onHeightChanged` as needed @@ -136,7 +136,7 @@ export default class ReactionsRow extends React.PureComponent { // has changed (this is triggered by events for that purpose only) and // `PureComponent`s shallow state / props compare would otherwise filter this out. this.forceUpdate(); - } + }; private getMyReactions() { const reactions = this.props.reactions; @@ -155,7 +155,7 @@ export default class ReactionsRow extends React.PureComponent { this.setState({ showAll: true, }); - } + }; render() { const { mxEvent, reactions } = this.props; diff --git a/src/components/views/messages/ReactionsRowButton.tsx b/src/components/views/messages/ReactionsRowButton.tsx index d163f1ad30..53e27b882e 100644 --- a/src/components/views/messages/ReactionsRowButton.tsx +++ b/src/components/views/messages/ReactionsRowButton.tsx @@ -68,7 +68,7 @@ export default class ReactionsRowButton extends React.PureComponent { this.setState({ tooltipVisible: false, }); - } + }; render() { const { mxEvent, content, count, reactionEvents, myReactionEvent } = this.props; diff --git a/src/components/views/messages/RedactedBody.tsx b/src/components/views/messages/RedactedBody.tsx index 5f80460d03..3e5da1dd43 100644 --- a/src/components/views/messages/RedactedBody.tsx +++ b/src/components/views/messages/RedactedBody.tsx @@ -14,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useContext} from "react"; -import {MatrixClient} from "matrix-js-sdk/src/client"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import React, { useContext } from "react"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {formatFullDate} from "../../../DateUtils"; +import { formatFullDate } from "../../../DateUtils"; import SettingsStore from "../../../settings/SettingsStore"; interface IProps { mxEvent: MatrixEvent; } -const RedactedBody = React.forwardRef(({mxEvent}, ref) => { +const RedactedBody = React.forwardRef(({ mxEvent }, ref) => { const cli: MatrixClient = useContext(MatrixClientContext); let text = _t("Message deleted"); diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js index 41eada3193..d68d794ee6 100644 --- a/src/components/views/messages/RoomAvatarEvent.js +++ b/src/components/views/messages/RoomAvatarEvent.js @@ -18,13 +18,13 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import Modal from '../../../Modal'; import AccessibleButton from '../elements/AccessibleButton'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; @replaceableComponent("views.messages.RoomAvatarEvent") export default class RoomAvatarEvent extends React.Component { @@ -60,7 +60,7 @@ export default class RoomAvatarEvent extends React.Component { if (!ev.getContent().url || ev.getContent().url.trim().length === 0) { return (
      - { _t('%(senderDisplayName)s removed the room avatar.', {senderDisplayName}) } + { _t('%(senderDisplayName)s removed the room avatar.', { senderDisplayName }) }
      ); } diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js index 3e02884c02..56bd25cbac 100644 --- a/src/components/views/messages/RoomCreate.js +++ b/src/components/views/messages/RoomCreate.js @@ -21,9 +21,9 @@ import PropTypes from 'prop-types'; import dis from '../../../dispatcher/dispatcher'; import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import { _t } from '../../../languageHandler'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import EventTileBubble from "./EventTileBubble"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.RoomCreate") export default class RoomCreate extends React.Component { diff --git a/src/components/views/messages/SenderProfile.tsx b/src/components/views/messages/SenderProfile.tsx index d6b802beff..11c3ca4e3c 100644 --- a/src/components/views/messages/SenderProfile.tsx +++ b/src/components/views/messages/SenderProfile.tsx @@ -39,7 +39,7 @@ export default class SenderProfile extends React.Component { private unmounted: boolean; constructor(props: IProps) { - super(props) + super(props); const senderId = this.props.mxEvent.getSender(); this.state = { @@ -56,7 +56,6 @@ export default class SenderProfile extends React.Component { this.getPublicisedGroups(); } - this.context.on('RoomState.events', this.onRoomStateEvents); } @@ -70,7 +69,7 @@ export default class SenderProfile extends React.Component { const userGroups = await FlairStore.getPublicisedGroupsCached( this.context, this.props.mxEvent.getSender(), ); - this.setState({userGroups}); + this.setState({ userGroups }); } } @@ -106,9 +105,9 @@ export default class SenderProfile extends React.Component { } render() { - const {mxEvent} = this.props; + const { mxEvent } = this.props; const colorClass = getUserNameColorClass(mxEvent.getSender()); - const {msgtype} = mxEvent.getContent(); + const { msgtype } = mxEvent.getContent(); const disambiguate = mxEvent.sender?.disambiguate; const displayName = mxEvent.sender?.rawDisplayName || mxEvent.getSender() || ""; diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index ebc4ce7ce8..ffaaaada4d 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -190,7 +190,7 @@ export default class TextualBody extends React.Component { const buttonRect = button.getBoundingClientRect(); const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu'); - const {close} = ContextMenu.createMenu(GenericTextContextMenu, { + const { close } = ContextMenu.createMenu(GenericTextContextMenu, { ...toRightOf(buttonRect, 2), message: successful ? _t('Copied!') : _t('Failed to copy'), }); @@ -404,7 +404,7 @@ export default class TextualBody extends React.Component { }, unhideWidget: () => { - this.setState({widgetHidden: false}); + this.setState({ widgetHidden: false }); if (global.localStorage) { global.localStorage.removeItem("hide_preview_" + this.props.mxEvent.getId()); } @@ -460,7 +460,7 @@ export default class TextualBody extends React.Component { _openHistoryDialog = async () => { const MessageEditHistoryDialog = sdk.getComponent("views.dialogs.MessageEditHistoryDialog"); - Modal.createDialog(MessageEditHistoryDialog, {mxEvent: this.props.mxEvent}); + Modal.createDialog(MessageEditHistoryDialog, { mxEvent: this.props.mxEvent }); }; _renderEditedMarker() { @@ -469,7 +469,7 @@ export default class TextualBody extends React.Component { const tooltip =
      - {_t("Edited at %(date)s", {date: dateString})} + {_t("Edited at %(date)s", { date: dateString })}
      {_t("Click to view edits")} @@ -480,7 +480,7 @@ export default class TextualBody extends React.Component { {`(${_t("edited")})`} diff --git a/src/components/views/messages/TextualEvent.js b/src/components/views/messages/TextualEvent.js index 25da18da0d..663f47dd2a 100644 --- a/src/components/views/messages/TextualEvent.js +++ b/src/components/views/messages/TextualEvent.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import * as TextForEvent from "../../../TextForEvent"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.messages.TextualEvent") export default class TextualEvent extends React.Component { diff --git a/src/components/views/messages/TileErrorBoundary.js b/src/components/views/messages/TileErrorBoundary.tsx similarity index 77% rename from src/components/views/messages/TileErrorBoundary.js rename to src/components/views/messages/TileErrorBoundary.tsx index 0e9a7b6128..967127d275 100644 --- a/src/components/views/messages/TileErrorBoundary.js +++ b/src/components/views/messages/TileErrorBoundary.tsx @@ -1,5 +1,5 @@ /* -Copyright 2020 The Matrix.org Foundation C.I.C. +Copyright 2020 - 2021 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,14 +16,24 @@ limitations under the License. import React from 'react'; import classNames from 'classnames'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; + import { _t } from '../../../languageHandler'; -import * as sdk from '../../../index'; import Modal from '../../../Modal'; import SdkConfig from "../../../SdkConfig"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BugReportDialog from '../dialogs/BugReportDialog'; + +interface IProps { + mxEvent: MatrixEvent; +} + +interface IState { + error: Error; +} @replaceableComponent("views.messages.TileErrorBoundary") -export default class TileErrorBoundary extends React.Component { +export default class TileErrorBoundary extends React.Component { constructor(props) { super(props); @@ -32,17 +42,13 @@ export default class TileErrorBoundary extends React.Component { }; } - static getDerivedStateFromError(error) { + static getDerivedStateFromError(error: Error): Partial { // Side effects are not permitted here, so we only update the state so // that the next render shows an error message. return { error }; } - _onBugReport = () => { - const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog"); - if (!BugReportDialog) { - return; - } + private onBugReport = (): void => { Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, { label: 'react-soft-crash-tile', }); @@ -60,7 +66,7 @@ export default class TileErrorBoundary extends React.Component { let submitLogsButton; if (SdkConfig.get().bug_report_endpoint_url) { - submitLogsButton = + submitLogsButton = {_t("Submit logs")} ; } diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.js index 786facc340..0f866216fc 100644 --- a/src/components/views/messages/UnknownBody.js +++ b/src/components/views/messages/UnknownBody.js @@ -15,9 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {forwardRef} from "react"; +import React, { forwardRef } from "react"; -export default forwardRef(({mxEvent}, ref) => { +export default forwardRef(({ mxEvent }, ref) => { const text = mxEvent.getContent().body; return ( diff --git a/src/components/views/messages/ViewSourceEvent.js b/src/components/views/messages/ViewSourceEvent.js index 2ec567c5ad..62454fef1a 100644 --- a/src/components/views/messages/ViewSourceEvent.js +++ b/src/components/views/messages/ViewSourceEvent.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; @replaceableComponent("views.messages.ViewSourceEvent") @@ -36,7 +36,7 @@ export default class ViewSourceEvent extends React.PureComponent { } componentDidMount() { - const {mxEvent} = this.props; + const { mxEvent } = this.props; const client = MatrixClientPeg.get(); client.decryptEventIfNeeded(mxEvent); diff --git a/src/components/views/right_panel/BaseCard.tsx b/src/components/views/right_panel/BaseCard.tsx index 09973809de..2528139a2b 100644 --- a/src/components/views/right_panel/BaseCard.tsx +++ b/src/components/views/right_panel/BaseCard.tsx @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {ReactNode} from 'react'; +import React, { ReactNode } from 'react'; import classNames from 'classnames'; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import AccessibleButton from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; -import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; -import {Action} from "../../../dispatcher/actions"; -import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; +import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; +import { Action } from "../../../dispatcher/actions"; +import { RightPanelPhases } from "../../../stores/RightPanelStorePhases"; interface IProps { header?: ReactNode; diff --git a/src/components/views/right_panel/EncryptionInfo.tsx b/src/components/views/right_panel/EncryptionInfo.tsx index db59a88967..c34cf18710 100644 --- a/src/components/views/right_panel/EncryptionInfo.tsx +++ b/src/components/views/right_panel/EncryptionInfo.tsx @@ -21,7 +21,7 @@ import { _t } from "../../../languageHandler"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { User } from "matrix-js-sdk/src/models/user"; -export const PendingActionSpinner = ({text}) => { +export const PendingActionSpinner = ({ text }) => { const Spinner = sdk.getComponent('elements.Spinner'); return
      diff --git a/src/components/views/right_panel/GroupHeaderButtons.tsx b/src/components/views/right_panel/GroupHeaderButtons.tsx index 3c93cf6470..132a76e891 100644 --- a/src/components/views/right_panel/GroupHeaderButtons.tsx +++ b/src/components/views/right_panel/GroupHeaderButtons.tsx @@ -48,7 +48,7 @@ export default class GroupHeaderButtons extends HeaderButtons { protected onAction(payload: ActionPayload) { if (payload.action === Action.ViewUser) { if ((payload as ViewUserPayload).member) { - this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member}); + this.setPhase(RightPanelPhases.RoomMemberInfo, { member: payload.member }); } else { this.setPhase(RightPanelPhases.GroupMemberList); } @@ -57,14 +57,14 @@ export default class GroupHeaderButtons extends HeaderButtons { } else if (payload.action === "view_group_room") { this.setPhase( RightPanelPhases.GroupRoomInfo, - {groupRoomId: payload.groupRoomId, groupId: payload.groupId}, + { groupRoomId: payload.groupRoomId, groupId: payload.groupId }, ); } else if (payload.action === "view_group_room_list") { this.setPhase(RightPanelPhases.GroupRoomList); } else if (payload.action === "view_group_member_list") { this.setPhase(RightPanelPhases.GroupMemberList); } else if (payload.action === "view_group_user") { - this.setPhase(RightPanelPhases.GroupMemberInfo, {member: payload.member}); + this.setPhase(RightPanelPhases.GroupMemberInfo, { member: payload.member }); } } diff --git a/src/components/views/right_panel/HeaderButton.tsx b/src/components/views/right_panel/HeaderButton.tsx index cdf4f44e06..1625db3f55 100644 --- a/src/components/views/right_panel/HeaderButton.tsx +++ b/src/components/views/right_panel/HeaderButton.tsx @@ -48,7 +48,7 @@ export default class HeaderButton extends React.Component { public render() { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const {isHighlighted, onClick, analytics, name, title, ...props} = this.props; + const { isHighlighted, onClick, analytics, name, title, ...props } = this.props; const classes = classNames({ mx_RightPanel_headerButton: true, diff --git a/src/components/views/right_panel/HeaderButtons.tsx b/src/components/views/right_panel/HeaderButtons.tsx index 6d44a081d9..c30ad60771 100644 --- a/src/components/views/right_panel/HeaderButtons.tsx +++ b/src/components/views/right_panel/HeaderButtons.tsx @@ -88,9 +88,9 @@ export default abstract class HeaderButtons

      extends React.Component { protected onAction(payload: ActionPayload) { if (payload.action === Action.ViewUser) { if (payload.member) { - this.setPhase(RightPanelPhases.RoomMemberInfo, {member: payload.member}); + this.setPhase(RightPanelPhases.RoomMemberInfo, { member: payload.member }); } else { this.setPhase(RightPanelPhases.RoomMemberList); } } else if (payload.action === "view_3pid_invite") { if (payload.event) { - this.setPhase(RightPanelPhases.Room3pidMemberInfo, {event: payload.event}); + this.setPhase(RightPanelPhases.Room3pidMemberInfo, { event: payload.event }); } else { this.setPhase(RightPanelPhases.RoomMemberList); } diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index 937037f644..21c1c39827 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useCallback, useState, useEffect, useContext} from "react"; +import React, { useCallback, useState, useEffect, useContext } from "react"; import classNames from "classnames"; -import {Room} from "matrix-js-sdk/src/models/room"; +import { Room } from "matrix-js-sdk/src/models/room"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { useIsEncrypted } from '../../../hooks/useIsEncrypted'; @@ -25,25 +25,25 @@ import { _t } from '../../../languageHandler'; import RoomAvatar from "../avatars/RoomAvatar"; import AccessibleButton from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; -import {Action} from "../../../dispatcher/actions"; -import {RightPanelPhases} from "../../../stores/RightPanelStorePhases"; -import {SetRightPanelPhasePayload} from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; +import { Action } from "../../../dispatcher/actions"; +import { RightPanelPhases } from "../../../stores/RightPanelStorePhases"; +import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload"; import Modal from "../../../Modal"; import ShareDialog from '../dialogs/ShareDialog'; -import {useEventEmitter} from "../../../hooks/useEventEmitter"; +import { useEventEmitter } from "../../../hooks/useEventEmitter"; import WidgetUtils from "../../../utils/WidgetUtils"; -import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; +import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import SettingsStore from "../../../settings/SettingsStore"; import TextWithTooltip from "../elements/TextWithTooltip"; import WidgetAvatar from "../avatars/WidgetAvatar"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import WidgetStore, {IApp} from "../../../stores/WidgetStore"; +import WidgetStore, { IApp } from "../../../stores/WidgetStore"; import { E2EStatus } from "../../../utils/ShieldUtils"; import RoomContext from "../../../contexts/RoomContext"; -import {UIFeature} from "../../../settings/UIFeature"; -import {ChevronFace, ContextMenuTooltipButton, useContextMenu} from "../../structures/ContextMenu"; +import { UIFeature } from "../../../settings/UIFeature"; +import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu"; import WidgetContextMenu from "../context_menus/WidgetContextMenu"; -import {useRoomMemberCount} from "../../../hooks/useRoomMembers"; +import { useRoomMemberCount } from "../../../hooks/useRoomMembers"; import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; import RoomName from "../elements/RoomName"; import UIStore from "../../../stores/UIStore"; diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 111e9dbf38..e9d80d49c5 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -164,7 +164,7 @@ function useHasCrossSigningKeys(cli: MatrixClient, member: User, canVerify: bool }, [cli, member, canVerify], undefined); } -function DeviceItem({userId, device}: {userId: string, device: IDevice}) { +function DeviceItem({ userId, device }: {userId: string, device: IDevice}) { const cli = useContext(MatrixClientContext); const isMe = userId === cli.getUserId(); const deviceTrust = cli.checkDeviceTrust(userId, device.deviceId); @@ -202,7 +202,6 @@ function DeviceItem({userId, device}: {userId: string, device: IDevice}) { let trustedLabel = null; if (userTrust.isVerified()) trustedLabel = isVerified ? _t("Trusted") : _t("Not trusted"); - if (isVerified) { return (

      @@ -226,7 +225,7 @@ function DeviceItem({userId, device}: {userId: string, device: IDevice}) { } } -function DevicesSection({devices, userId, loading}: {devices: IDevice[], userId: string, loading: boolean}) { +function DevicesSection({ devices, userId, loading }: {devices: IDevice[], userId: string, loading: boolean}) { const cli = useContext(MatrixClientContext); const userTrust = cli.checkUserTrust(userId); @@ -266,12 +265,12 @@ function DevicesSection({devices, userId, loading}: {devices: IDevice[], userId: unverifiedDevices.push(device); } } - expandCountCaption = _t("%(count)s verified sessions", {count: expandSectionDevices.length}); + expandCountCaption = _t("%(count)s verified sessions", { count: expandSectionDevices.length }); expandHideCaption = _t("Hide verified sessions"); expandIconClasses += " mx_E2EIcon_verified"; } else { expandSectionDevices = devices; - expandCountCaption = _t("%(count)s sessions", {count: devices.length}); + expandCountCaption = _t("%(count)s sessions", { count: devices.length }); expandHideCaption = _t("Hide sessions"); expandIconClasses += " mx_E2EIcon_normal"; } @@ -317,7 +316,7 @@ const UserOptionsSection: React.FC<{ isIgnored: boolean; canInvite: boolean; isSpace?: boolean; -}> = ({member, isIgnored, canInvite, isSpace}) => { +}> = ({ member, isIgnored, canInvite, isSpace }) => { const cli = useContext(MatrixClientContext); let ignoreButton = null; @@ -351,7 +350,7 @@ const UserOptionsSection: React.FC<{ ignoreButton = ( { isIgnored ? _t("Unignore") : _t("Ignore") } @@ -450,7 +449,7 @@ const UserOptionsSection: React.FC<{ }; const warnSelfDemote = async (isSpace: boolean) => { - const {finished} = Modal.createTrackedDialog('Demoting Self', '', QuestionDialog, { + const { finished } = Modal.createTrackedDialog('Demoting Self', '', QuestionDialog, { title: _t("Demote yourself?"), description:
      @@ -469,7 +468,7 @@ const warnSelfDemote = async (isSpace: boolean) => { return confirmed; }; -const GenericAdminToolsContainer: React.FC<{}> = ({children}) => { +const GenericAdminToolsContainer: React.FC<{}> = ({ children }) => { return (

      { _t("Admin Tools") }

      @@ -530,14 +529,14 @@ interface IBaseProps { stopUpdating(): void; } -const RoomKickButton: React.FC = ({member, startUpdating, stopUpdating}) => { +const RoomKickButton: React.FC = ({ member, startUpdating, stopUpdating }) => { const cli = useContext(MatrixClientContext); // check if user can be kicked/disinvited if (member.membership !== "invite" && member.membership !== "join") return null; const onKick = async () => { - const {finished} = Modal.createTrackedDialog( + const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onKick', ConfirmUserActionDialog, @@ -575,11 +574,11 @@ const RoomKickButton: React.FC = ({member, startUpdating, stopUpdati ; }; -const RedactMessagesButton: React.FC = ({member}) => { +const RedactMessagesButton: React.FC = ({ member }) => { const cli = useContext(MatrixClientContext); const onRedactAllMessages = async () => { - const {roomId, userId} = member; + const { roomId, userId } = member; const room = cli.getRoom(roomId); if (!room) { return; @@ -607,23 +606,23 @@ const RedactMessagesButton: React.FC = ({member}) => { if (count === 0) { Modal.createTrackedDialog('No user messages found to remove', '', InfoDialog, { - title: _t("No recent messages by %(user)s found", {user}), + title: _t("No recent messages by %(user)s found", { user }), description:

      { _t("Try scrolling up in the timeline to see if there are any earlier ones.") }

      , }); } else { - const {finished} = Modal.createTrackedDialog('Remove recent messages by user', '', QuestionDialog, { - title: _t("Remove recent messages by %(user)s", {user}), + const { finished } = Modal.createTrackedDialog('Remove recent messages by user', '', QuestionDialog, { + title: _t("Remove recent messages by %(user)s", { user }), description:

      { _t("You are about to remove %(count)s messages by %(user)s. " + - "This cannot be undone. Do you wish to continue?", {count, user}) }

      + "This cannot be undone. Do you wish to continue?", { count, user }) }

      { _t("For a large amount of messages, this might take some time. " + "Please don't refresh your client in the meantime.") }

      , - button: _t("Remove %(count)s messages", {count}), + button: _t("Remove %(count)s messages", { count }), }); const [confirmed] = await finished; @@ -654,11 +653,11 @@ const RedactMessagesButton: React.FC = ({member}) => { ; }; -const BanToggleButton: React.FC = ({member, startUpdating, stopUpdating}) => { +const BanToggleButton: React.FC = ({ member, startUpdating, stopUpdating }) => { const cli = useContext(MatrixClientContext); const onBanOrUnban = async () => { - const {finished} = Modal.createTrackedDialog( + const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onBanOrUnban', ConfirmUserActionDialog, @@ -715,7 +714,7 @@ interface IBaseRoomProps extends IBaseProps { powerLevels: IPowerLevelsContent; } -const MuteToggleButton: React.FC = ({member, room, powerLevels, startUpdating, stopUpdating}) => { +const MuteToggleButton: React.FC = ({ member, room, powerLevels, startUpdating, stopUpdating }) => { const cli = useContext(MatrixClientContext); // Don't show the mute/unmute option if the user is not in the room @@ -862,7 +861,7 @@ const GroupAdminToolsSection: React.FC<{ groupMember: GroupMember; startUpdating(): void; stopUpdating(): void; -}> = ({children, groupId, groupMember, startUpdating, stopUpdating}) => { +}> = ({ children, groupId, groupMember, startUpdating, stopUpdating }) => { const cli = useContext(MatrixClientContext); const [isPrivileged, setIsPrivileged] = useState(false); @@ -891,7 +890,7 @@ const GroupAdminToolsSection: React.FC<{ if (isPrivileged) { const onKick = async () => { - const {finished} = Modal.createDialog(ConfirmUserActionDialog, { + const { finished } = Modal.createDialog(ConfirmUserActionDialog, { matrixClient: cli, groupMember, action: isInvited ? _t('Disinvite') : _t('Remove from community'), @@ -1029,7 +1028,7 @@ const PowerLevelSection: React.FC<{ room: Room; roomPermissions: IRoomPermissions; powerLevels: IPowerLevelsContent; -}> = ({user, room, roomPermissions, powerLevels}) => { +}> = ({ user, room, roomPermissions, powerLevels }) => { if (roomPermissions.canEdit) { return (); } else { @@ -1048,7 +1047,7 @@ const PowerLevelEditor: React.FC<{ user: RoomMember; room: Room; roomPermissions: IRoomPermissions; -}> = ({user, room, roomPermissions}) => { +}> = ({ user, room, roomPermissions }) => { const cli = useContext(MatrixClientContext); const [selectedPowerLevel, setSelectedPowerLevel] = useState(user.powerLevel); @@ -1081,7 +1080,7 @@ const PowerLevelEditor: React.FC<{ const myUserId = cli.getUserId(); const myPower = powerLevelEvent.getContent().users[myUserId]; if (myPower && parseInt(myPower) === powerLevel) { - const {finished} = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, { + const { finished } = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, { title: _t("Warning!"), description:
      @@ -1198,7 +1197,7 @@ const BasicUserInfo: React.FC<{ groupId: string; devices: IDevice[]; isRoomEncrypted: boolean; -}> = ({room, member, groupId, devices, isRoomEncrypted}) => { +}> = ({ room, member, groupId, devices, isRoomEncrypted }) => { const cli = useContext(MatrixClientContext); const powerLevels = useRoomPowerLevels(cli, room); @@ -1231,7 +1230,7 @@ const BasicUserInfo: React.FC<{ const roomPermissions = useRoomPermissions(cli, room, member as RoomMember); const onSynapseDeactivate = useCallback(async () => { - const {finished} = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, { + const { finished } = Modal.createTrackedDialog('Synapse User Deactivation', '', QuestionDialog, { title: _t("Deactivate user?"), description:
      { _t( @@ -1382,7 +1381,7 @@ const BasicUserInfo: React.FC<{ }}> { _t("Edit devices") } -

      ) +

      ); } const securitySection = ( @@ -1420,7 +1419,7 @@ type Member = User | RoomMember | GroupMember; const UserInfoHeader: React.FC<{ member: Member; e2eStatus: E2EStatus; -}> = ({member, e2eStatus}) => { +}> = ({ member, e2eStatus }) => { const cli = useContext(MatrixClientContext); const onMemberAvatarClick = useCallback(() => { @@ -1567,7 +1566,7 @@ const UserInfo: React.FC = ({ // We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time if (room && phase === RightPanelPhases.EncryptionPanel) { previousPhase = RightPanelPhases.RoomMemberInfo; - refireParams = {member: member}; + refireParams = { member: member }; } else if (room) { previousPhase = previousPhase = SettingsStore.getValue("feature_spaces") && room.isSpaceRoom() ? RightPanelPhases.SpaceMemberList @@ -1580,7 +1579,7 @@ const UserInfo: React.FC = ({ phase: previousPhase, refireParams: refireParams, }); - } + }; let content; switch (phase) { diff --git a/src/components/views/right_panel/VerificationPanel.tsx b/src/components/views/right_panel/VerificationPanel.tsx index d3f2ba8cbf..6087923057 100644 --- a/src/components/views/right_panel/VerificationPanel.tsx +++ b/src/components/views/right_panel/VerificationPanel.tsx @@ -16,18 +16,18 @@ limitations under the License. import React from "react"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import * as sdk from '../../../index'; -import {verificationMethods} from 'matrix-js-sdk/src/crypto'; -import {SCAN_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode"; -import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; -import {RoomMember} from "matrix-js-sdk/src/models/room-member"; +import { verificationMethods } from 'matrix-js-sdk/src/crypto'; +import { SCAN_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode"; +import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { User } from "matrix-js-sdk/src/models/user"; -import {ReciprocateQRCode} from "matrix-js-sdk/src/crypto/verification/QRCode"; -import {SAS} from "matrix-js-sdk/src/crypto/verification/SAS"; +import { ReciprocateQRCode } from "matrix-js-sdk/src/crypto/verification/QRCode"; +import { SAS } from "matrix-js-sdk/src/crypto/verification/SAS"; import VerificationQRCode from "../elements/crypto/VerificationQRCode"; -import {_t} from "../../../languageHandler"; +import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import E2EIcon from "../rooms/E2EIcon"; import { @@ -37,7 +37,7 @@ import { PHASE_CANCELLED, } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import Spinner from "../elements/Spinner"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; // XXX: Should be defined in matrix-js-sdk enum VerificationPhase { @@ -78,7 +78,7 @@ export default class VerificationPanel extends React.PureComponent { - this.setState({reciprocateButtonClicked: true}); + this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent.confirm(); }; private onReciprocateNoClick = () => { - this.setState({reciprocateButtonClicked: true}); + this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent.cancel(); }; @@ -194,7 +194,7 @@ export default class VerificationPanel extends React.PureComponent { - this.setState({emojiButtonClicked: true}); + this.setState({ emojiButtonClicked: true }); const verifier = this.props.request.beginKeyVerification(verificationMethods.SAS); try { await verifier.verify(); @@ -379,15 +379,15 @@ export default class VerificationPanel extends React.PureComponent { - const {request} = this.props; - const {sasEvent, reciprocateQREvent} = request.verifier; + const { request } = this.props; + const { sasEvent, reciprocateQREvent } = request.verifier; request.verifier.off('show_sas', this.updateVerifierState); request.verifier.off('show_reciprocate_qr', this.updateVerifierState); - this.setState({sasEvent, reciprocateQREvent}); + this.setState({ sasEvent, reciprocateQREvent }); }; private onRequestChange = async () => { - const {request} = this.props; + const { request } = this.props; const hadVerifier = this.hasVerifier; this.hasVerifier = !!request.verifier; if (!hadVerifier && this.hasVerifier) { @@ -404,17 +404,17 @@ export default class VerificationPanel extends React.PureComponent { if (!this.props.domain) { return super.renderNewItemField(); } - const onChange = (alias) => this.onNewItemChanged({target: {value: alias}}); + const onChange = (alias) => this.onNewItemChanged({ target: { value: alias } }); return ( { "or a temporary failure occurred.", ), }); - this.setState({canonicalAlias: oldAlias}); + this.setState({ canonicalAlias: oldAlias }); }).finally(() => { - this.setState({updatingCanonicalAlias: false}); + this.setState({ updatingCanonicalAlias: false }); }); } @@ -213,7 +213,7 @@ export default class AliasSettings extends React.Component { ), }); }).finally(() => { - this.setState({updatingCanonicalAlias: false}); + this.setState({ updatingCanonicalAlias: false }); }); } @@ -253,7 +253,7 @@ export default class AliasSettings extends React.Component { // to this room. See https://github.com/vector-im/element-web/issues/7353 MatrixClientPeg.get().deleteAlias(alias).then(() => { const localAliases = this.state.localAliases.filter(a => a !== alias); - this.setState({localAliases}); + this.setState({ localAliases }); if (this.state.canonicalAlias === alias) { this.changeCanonicalAlias(null); @@ -293,7 +293,7 @@ export default class AliasSettings extends React.Component { private onNewAltAliasChanged = (value: string) => { this.setState({ newAltAlias: value }); - } + }; private onAltAliasAdded = (alias: string) => { const altAliases = this.state.altAliases.slice(); @@ -302,20 +302,20 @@ export default class AliasSettings extends React.Component { this.changeAltAliases(altAliases); this.setState({ newAltAlias: "" }); } - } + }; private onAltAliasDeleted = (index: number) => { const altAliases = this.state.altAliases.slice(); altAliases.splice(index, 1); this.changeAltAliases(altAliases); - } + }; private getAliases() { return this.state.altAliases.concat(this.getLocalNonAltAliases()); } private getLocalNonAltAliases() { - const {altAliases} = this.state; + const { altAliases } = this.state; return this.state.localAliases.filter(alias => !altAliases.includes(alias)); } diff --git a/src/components/views/room_settings/RelatedGroupSettings.js b/src/components/views/room_settings/RelatedGroupSettings.js index 272ecd1228..f2533bc11e 100644 --- a/src/components/views/room_settings/RelatedGroupSettings.js +++ b/src/components/views/room_settings/RelatedGroupSettings.js @@ -16,13 +16,13 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import {MatrixEvent} from 'matrix-js-sdk/src/models/event'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import ErrorDialog from "../dialogs/ErrorDialog"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const GROUP_ID_REGEX = /\+\S+:\S+/; @@ -116,7 +116,7 @@ export default class RelatedGroupSettings extends React.Component { itemsLabel={_t('Showing flair for these communities:')} noItemsLabel={_t('This room is not showing flair for any communities')} placeholder={_t( - 'New community ID (e.g. +foo:%(localDomain)s)', {localDomain}, + 'New community ID (e.g. +foo:%(localDomain)s)', { localDomain }, )} />
      ; diff --git a/src/components/views/room_settings/RoomProfileSettings.js b/src/components/views/room_settings/RoomProfileSettings.js index b6885887b1..ded186af9c 100644 --- a/src/components/views/room_settings/RoomProfileSettings.js +++ b/src/components/views/room_settings/RoomProfileSettings.js @@ -14,14 +14,14 @@ 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 {_t} from "../../../languageHandler"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { _t } from "../../../languageHandler"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import Field from "../elements/Field"; import * as sdk from "../../../index"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; // TODO: Merge with ProfileSettings? @replaceableComponent("views.room_settings.RoomProfileSettings") @@ -97,7 +97,7 @@ export default class RoomProfileSettings extends React.Component { e.preventDefault(); if (!this.state.enableProfileSave) return; - this.setState({enableProfileSave: false}); + this.setState({ enableProfileSave: false }); const client = MatrixClientPeg.get(); const newState = {}; @@ -112,7 +112,7 @@ export default class RoomProfileSettings extends React.Component { if (this.state.avatarFile) { const uri = await client.uploadContent(this.state.avatarFile); - await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {url: uri}, ''); + await client.sendStateEvent(this.props.roomId, 'm.room.avatar', { url: uri }, ''); newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96); newState.originalAvatarUrl = newState.avatarUrl; newState.avatarFile = null; @@ -129,20 +129,20 @@ export default class RoomProfileSettings extends React.Component { }; _onDisplayNameChanged = (e) => { - this.setState({displayName: e.target.value}); + this.setState({ displayName: e.target.value }); if (this.state.originalDisplayName === e.target.value) { - this.setState({enableProfileSave: false}); + this.setState({ enableProfileSave: false }); } else { - this.setState({enableProfileSave: true}); + this.setState({ enableProfileSave: true }); } }; _onTopicChanged = (e) => { - this.setState({topic: e.target.value}); + this.setState({ topic: e.target.value }); if (this.state.originalTopic === e.target.value) { - this.setState({enableProfileSave: false}); + this.setState({ enableProfileSave: false }); } else { - this.setState({enableProfileSave: true}); + this.setState({ enableProfileSave: true }); } }; diff --git a/src/components/views/room_settings/RoomPublishSetting.tsx b/src/components/views/room_settings/RoomPublishSetting.tsx index 95b0ac100d..bc1d6f9e2c 100644 --- a/src/components/views/room_settings/RoomPublishSetting.tsx +++ b/src/components/views/room_settings/RoomPublishSetting.tsx @@ -44,7 +44,7 @@ export default class RoomPublishSetting extends React.PureComponent { const valueBefore = this.state.isRoomPublished; const newValue = !valueBefore; - this.setState({isRoomPublished: newValue}); + this.setState({ isRoomPublished: newValue }); const client = MatrixClientPeg.get(); client.setRoomDirectoryVisibility( @@ -52,14 +52,14 @@ export default class RoomPublishSetting extends React.PureComponent { // Roll back the local echo on the change - this.setState({isRoomPublished: valueBefore}); + this.setState({ isRoomPublished: valueBefore }); }); }; componentDidMount() { const client = MatrixClientPeg.get(); client.getRoomDirectoryVisibility(this.props.roomId).then((result => { - this.setState({isRoomPublished: result.visibility === 'public'}); + this.setState({ isRoomPublished: result.visibility === 'public' }); })); } diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index f797ffeb96..0ff3b051d6 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -23,10 +23,10 @@ import * as sdk from "../../../index"; import { _t, _td } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; import dis from "../../../dispatcher/dispatcher"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; -import {Action} from "../../../dispatcher/actions"; -import {SettingLevel} from "../../../settings/SettingLevel"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { Action } from "../../../dispatcher/actions"; +import { SettingLevel } from "../../../settings/SettingLevel"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.room_settings.UrlPreviewSettings") export default class UrlPreviewSettings extends React.Component { diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index 0b32d5d1bb..2866780255 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import {Resizable} from "re-resizable"; +import { Resizable } from "re-resizable"; import AppTile from '../elements/AppTile'; import dis from '../../../dispatcher/dispatcher'; @@ -26,16 +26,16 @@ import * as sdk from '../../../index'; import * as ScalarMessaging from '../../../ScalarMessaging'; import WidgetUtils from '../../../utils/WidgetUtils'; import WidgetEchoStore from "../../../stores/WidgetEchoStore"; -import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; +import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import SettingsStore from "../../../settings/SettingsStore"; import ResizeNotifier from "../../../utils/ResizeNotifier"; import ResizeHandle from "../elements/ResizeHandle"; import Resizer from "../../../resizer/resizer"; import PercentageDistributor from "../../../resizer/distributors/percentage"; -import {Container, WidgetLayoutStore} from "../../../stores/widgets/WidgetLayoutStore"; -import {clamp, percentageOf, percentageWithin} from "../../../utils/numbers"; -import {useStateCallback} from "../../../hooks/useStateCallback"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; +import { clamp, percentageOf, percentageWithin } from "../../../utils/numbers"; +import { useStateCallback } from "../../../hooks/useStateCallback"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import UIStore from "../../../stores/UIStore"; @replaceableComponent("views.rooms.AppsDrawer") @@ -303,7 +303,7 @@ const PersistentVResizer = ({ }); return { @@ -317,9 +317,9 @@ const PersistentVResizer = ({ resizeNotifier.stopResizing(); }} handleWrapperClass={handleWrapperClass} - handleClasses={{bottom: handleClass}} + handleClasses={{ bottom: handleClass }} className={className} - enable={{bottom: true}} + enable={{ bottom: true }} > { children } ; diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index 7054741da4..8fbecbe722 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -15,15 +15,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {createRef, KeyboardEvent} from 'react'; +import React, { createRef, KeyboardEvent } from 'react'; import classNames from 'classnames'; -import {flatMap} from "lodash"; -import {ICompletion, ISelectionRange, IProviderCompletions} from '../../../autocomplete/Autocompleter'; -import {Room} from 'matrix-js-sdk/src/models/room'; +import { flatMap } from "lodash"; +import { ICompletion, ISelectionRange, IProviderCompletions } from '../../../autocomplete/Autocompleter'; +import { Room } from 'matrix-js-sdk/src/models/room'; import SettingsStore from "../../../settings/SettingsStore"; import Autocompleter from '../../../autocomplete/Autocompleter'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const COMPOSER_SELECTED = 0; const MAX_PROVIDER_MATCHES = 20; @@ -247,7 +247,7 @@ export default class Autocomplete extends React.PureComponent { }; setSelection(selectionOffset: number) { - this.setState({selectionOffset, hide: false}); + this.setState({ selectionOffset, hide: false }); if (this.props.onSelectionChange) { this.props.onSelectionChange(this.state.completionList[selectionOffset - 1], selectionOffset - 1); } @@ -273,7 +273,7 @@ export default class Autocomplete extends React.PureComponent { const renderedCompletions = this.state.completions.map((completionResult, i) => { const completions = completionResult.completions.map((completion, j) => { const selected = position === this.state.selectionOffset; - const className = classNames('mx_Autocomplete_Completion', {selected}); + const className = classNames('mx_Autocomplete_Completion', { selected }); const componentPosition = position; position++; @@ -291,7 +291,6 @@ export default class Autocomplete extends React.PureComponent { }); }); - return completions.length > 0 ? (
      { completionResult.provider.getName() }
      diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 04c7a57048..1c817140fa 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import classNames from 'classnames'; import { lexicographicCompare } from 'matrix-js-sdk/src/utils'; -import { Room } from 'matrix-js-sdk/src/models/room' +import { Room } from 'matrix-js-sdk/src/models/room'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import AppsDrawer from './AppsDrawer'; @@ -126,7 +126,7 @@ export default class AuxPanel extends React.Component { link, severity, stateKey, - }) + }); } } } diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 981ff1b4ae..94a292afe7 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -147,7 +147,7 @@ export default class BasicMessageEditor extends React.Component const enabledChange = this.props.disabled !== prevProps.disabled; const placeholderChanged = this.props.placeholder !== prevProps.placeholder; if (this.props.placeholder && (placeholderChanged || enabledChange)) { - const {isEmpty} = this.props.model; + const { isEmpty } = this.props.model; if (isEmpty) { this.showPlaceholder(); } else { @@ -157,7 +157,7 @@ export default class BasicMessageEditor extends React.Component } private replaceEmoticon = (caretPosition: DocumentPosition) => { - const {model} = this.props; + const { model } = this.props; const range = model.startRange(caretPosition); // expand range max 8 characters backwards from caretPosition, // as a space to look for an emoticon @@ -174,7 +174,7 @@ export default class BasicMessageEditor extends React.Component const data = EMOTICON_TO_EMOJI.get(query) || EMOTICON_TO_EMOJI.get(query.toLowerCase()); if (data) { - const {partCreator} = model; + const { partCreator } = model; const hasPrecedingSpace = emoticonMatch[0][0] === " "; // we need the range to only comprise of the emoticon // because we'll replace the whole range with an emoji, @@ -200,7 +200,7 @@ export default class BasicMessageEditor extends React.Component const position = selection instanceof Range ? selection.end : selection; this.setLastCaretFromPosition(position); } - const {isEmpty} = this.props.model; + const { isEmpty } = this.props.model; if (this.props.placeholder) { if (isEmpty) { this.showPlaceholder(); @@ -211,13 +211,13 @@ export default class BasicMessageEditor extends React.Component if (isEmpty) { this.formatBarRef.current.hide(); } - this.setState({autoComplete: this.props.model.autoComplete}); + this.setState({ autoComplete: this.props.model.autoComplete }); this.historyManager.tryPush(this.props.model, selection, inputType, diff); let isTyping = !this.props.model.isEmpty; // If the user is entering a command, only consider them typing if it is one which sends a message into the room if (isTyping && this.props.model.parts[0].type === "command") { - const {cmd} = parseCommandString(this.props.model.parts[0].text); + const { cmd } = parseCommandString(this.props.model.parts[0].text); const command = CommandMap.get(cmd); if (!command || !command.isEnabled() || command.category !== CommandCategories.messages) { isTyping = false; @@ -263,10 +263,10 @@ export default class BasicMessageEditor extends React.Component const isSafari = ua.includes('safari/') && !ua.includes('chrome/'); if (isSafari) { - this.onInput({inputType: "insertCompositionText"}); + this.onInput({ inputType: "insertCompositionText" }); } else { Promise.resolve().then(() => { - this.onInput({inputType: "insertCompositionText"}); + this.onInput({ inputType: "insertCompositionText" }); }); } }; @@ -282,7 +282,7 @@ export default class BasicMessageEditor extends React.Component const selection = document.getSelection(); const text = selection.toString(); if (text) { - const {model} = this.props; + const { model } = this.props; const range = getRangeForSelection(this.editorRef.current, model, selection); const selectedParts = range.parts.map(p => p.serialize()); event.clipboardData.setData("application/x-element-composer", JSON.stringify(selectedParts)); @@ -311,8 +311,8 @@ export default class BasicMessageEditor extends React.Component return true; } - const {model} = this.props; - const {partCreator} = model; + const { model } = this.props; + const { partCreator } = model; const partsText = event.clipboardData.getData("application/x-element-composer"); let parts; if (partsText) { @@ -335,13 +335,13 @@ export default class BasicMessageEditor extends React.Component } this.modifiedFlag = true; const sel = document.getSelection(); - const {caret, text} = getCaretOffsetAndText(this.editorRef.current, sel); + const { caret, text } = getCaretOffsetAndText(this.editorRef.current, sel); this.props.model.update(text, event.inputType, caret); }; private insertText(textToInsert: string, inputType = "insertText") { const sel = document.getSelection(); - const {caret, text} = getCaretOffsetAndText(this.editorRef.current, sel); + const { caret, text } = getCaretOffsetAndText(this.editorRef.current, sel); const newText = text.substr(0, caret.offset) + textToInsert + text.substr(caret.offset); caret.offset += textToInsert.length; this.modifiedFlag = true; @@ -354,7 +354,7 @@ export default class BasicMessageEditor extends React.Component // we need to recalculate it, to be able to know where to insert content after // losing focus private setLastCaretFromPosition(position: DocumentPosition) { - const {model} = this.props; + const { model } = this.props; this._isCaretAtEnd = position.isAtEnd(model); this.lastCaret = position.asOffset(model); this.lastSelection = cloneSelection(document.getSelection()); @@ -370,7 +370,7 @@ export default class BasicMessageEditor extends React.Component const selection = document.getSelection(); if (!this.lastSelection || !selectionEquals(this.lastSelection, selection)) { this.lastSelection = cloneSelection(selection); - const {caret, text} = getCaretOffsetAndText(this.editorRef.current, selection); + const { caret, text } = getCaretOffsetAndText(this.editorRef.current, selection); this.lastCaret = caret; this._isCaretAtEnd = caret.offset === text.length; } @@ -409,7 +409,7 @@ export default class BasicMessageEditor extends React.Component }; private onSelectionChange = () => { - const {isEmpty} = this.props.model; + const { isEmpty } = this.props.model; this.refreshLastCaretIfNeeded(); const selection = document.getSelection(); @@ -446,7 +446,7 @@ export default class BasicMessageEditor extends React.Component break; case MessageComposerAction.EditRedo: if (this.historyManager.canRedo()) { - const {parts, caret} = this.historyManager.redo(); + const { parts, caret } = this.historyManager.redo(); // pass matching inputType so historyManager doesn't push echo // when invoked from rerender callback. model.reset(parts, caret, "historyRedo"); @@ -455,7 +455,7 @@ export default class BasicMessageEditor extends React.Component break; case MessageComposerAction.EditUndo: if (this.historyManager.canUndo()) { - const {parts, caret} = this.historyManager.undo(this.props.model); + const { parts, caret } = this.historyManager.undo(this.props.model); // pass matching inputType so historyManager doesn't push echo // when invoked from rerender callback. model.reset(parts, caret, "historyUndo"); @@ -525,8 +525,8 @@ export default class BasicMessageEditor extends React.Component private async tabCompleteName() { try { - await new Promise(resolve => this.setState({showVisualBell: false}, resolve)); - const {model} = this.props; + await new Promise(resolve => this.setState({ showVisualBell: false }, resolve)); + const { model } = this.props; const caret = this.getCaret(); const position = model.positionForOffset(caret.offset, caret.atNodeEnd); const range = model.startRange(position); @@ -537,7 +537,7 @@ export default class BasicMessageEditor extends React.Component part.type === "command" ); }); - const {partCreator} = model; + const { partCreator } = model; // await for auto-complete to be open await model.transform(() => { const addedLen = range.replace([partCreator.pillCandidate(range.text)]); @@ -548,7 +548,7 @@ export default class BasicMessageEditor extends React.Component if (model.autoComplete) { await model.autoComplete.startSelection(); if (!model.autoComplete.hasSelection()) { - this.setState({showVisualBell: true}); + this.setState({ showVisualBell: true }); model.autoComplete.close(); } } @@ -569,7 +569,7 @@ export default class BasicMessageEditor extends React.Component private onAutoCompleteSelectionChange = (completion: ICompletion, completionIndex: number) => { this.modifiedFlag = true; this.props.model.autoComplete.onComponentSelectionChange(completion); - this.setState({completionIndex}); + this.setState({ completionIndex }); }; private configureEmoticonAutoReplace = () => { @@ -599,7 +599,7 @@ export default class BasicMessageEditor extends React.Component // not really, but we could not serialize the parts, and just change the autoCompleter partCreator.setAutoCompleteCreator(getAutoCompleteCreator( () => this.autocompleteRef.current, - query => new Promise(resolve => this.setState({query}, resolve)), + query => new Promise(resolve => this.setState({ query }, resolve)), )); // initial render of model this.updateEditorState(this.getInitialCaretPosition()); @@ -666,7 +666,7 @@ export default class BasicMessageEditor extends React.Component query={query} onConfirm={this.onAutoCompleteConfirm} onSelectionChange={this.onAutoCompleteSelectionChange} - selection={{beginning: true, end: queryLen, start: queryLen}} + selection={{ beginning: true, end: queryLen, start: queryLen }} room={this.props.room} />
      ); @@ -685,7 +685,7 @@ export default class BasicMessageEditor extends React.Component quote: ctrlShortcutLabel(">"), }; - const {completionIndex} = this.state; + const { completionIndex } = this.state; return (
      { autoComplete } @@ -719,8 +719,8 @@ export default class BasicMessageEditor extends React.Component } public insertMention(userId: string) { - const {model} = this.props; - const {partCreator} = model; + const { model } = this.props; + const { partCreator } = model; const member = this.props.room.getMember(userId); const displayName = member ? member.rawDisplayName : userId; @@ -737,9 +737,9 @@ export default class BasicMessageEditor extends React.Component } public insertQuotedMessage(event: MatrixEvent) { - const {model} = this.props; - const {partCreator} = model; - const quoteParts = parseEvent(event, partCreator, {isQuotedMessage: true}); + const { model } = this.props; + const { partCreator } = model; + const quoteParts = parseEvent(event, partCreator, { isQuotedMessage: true }); // add two newlines quoteParts.push(partCreator.newline()); quoteParts.push(partCreator.newline()); @@ -752,8 +752,8 @@ export default class BasicMessageEditor extends React.Component } public insertPlaintext(text: string) { - const {model} = this.props; - const {partCreator} = model; + const { model } = this.props; + const { partCreator } = model; const caret = this.getCaret(); const position = model.positionForOffset(caret.offset, caret.atNodeEnd); model.transform(() => { diff --git a/src/components/views/rooms/E2EIcon.js b/src/components/views/rooms/E2EIcon.js index d7316f198d..7425af6060 100644 --- a/src/components/views/rooms/E2EIcon.js +++ b/src/components/views/rooms/E2EIcon.js @@ -15,11 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, {useState} from "react"; +import React, { useState } from "react"; import PropTypes from "prop-types"; import classNames from 'classnames'; -import {_t, _td} from '../../../languageHandler'; +import { _t, _td } from '../../../languageHandler'; import AccessibleButton from "../elements/AccessibleButton"; import Tooltip from "../elements/Tooltip"; @@ -42,7 +42,7 @@ const crossSigningRoomTitles = { [E2E_STATE.VERIFIED]: _td("Everyone in this room is verified"), }; -const E2EIcon = ({isUser, status, className, size, onClick, hideTooltip, bordered}) => { +const E2EIcon = ({ isUser, status, className, size, onClick, hideTooltip, bordered }) => { const [hover, setHover] = useState(false); const classes = classNames({ @@ -62,7 +62,7 @@ const E2EIcon = ({isUser, status, className, size, onClick, hideTooltip, bordere let style; if (size) { - style = {width: `${size}px`, height: `${size}px`}; + style = { width: `${size}px`, height: `${size}px` }; } const onMouseOver = () => setHover(true); diff --git a/src/components/views/rooms/EditMessageComposer.js b/src/components/views/rooms/EditMessageComposer.js index 914f08eac7..0ab972b5f1 100644 --- a/src/components/views/rooms/EditMessageComposer.js +++ b/src/components/views/rooms/EditMessageComposer.js @@ -88,7 +88,7 @@ function createEditContent(model, editedEvent) { body: `${plainPrefix} * ${body}`, }; - const formattedBody = htmlSerializeIfNeeded(model, {forceHTML: isReply}); + const formattedBody = htmlSerializeIfNeeded(model, { forceHTML: isReply }); if (formattedBody) { newContent.format = "org.matrix.custom.html"; newContent.formatted_body = formattedBody; @@ -156,7 +156,7 @@ export default class EditMessageComposer extends React.Component { const previousEvent = findEditableEvent(this._getRoom(), false, this.props.editState.getEvent().getId()); if (previousEvent) { - dis.dispatch({action: 'edit_event', event: previousEvent}); + dis.dispatch({ action: 'edit_event', event: previousEvent }); event.preventDefault(); } break; @@ -167,10 +167,10 @@ export default class EditMessageComposer extends React.Component { } const nextEvent = findEditableEvent(this._getRoom(), true, this.props.editState.getEvent().getId()); if (nextEvent) { - dis.dispatch({action: 'edit_event', event: nextEvent}); + dis.dispatch({ action: 'edit_event', event: nextEvent }); } else { this._clearStoredEditorState(); - dis.dispatch({action: 'edit_event', event: null}); + dis.dispatch({ action: 'edit_event', event: null }); dis.fire(Action.FocusComposer); } event.preventDefault(); @@ -189,7 +189,7 @@ export default class EditMessageComposer extends React.Component { _cancelEdit = () => { this._clearStoredEditorState(); - dis.dispatch({action: "edit_event", event: null}); + dis.dispatch({ action: "edit_event", event: null }); dis.fire(Action.FocusComposer); } @@ -201,7 +201,7 @@ export default class EditMessageComposer extends React.Component { const json = localStorage.getItem(this._editorStateKey); if (json) { try { - const {parts: serializedParts} = JSON.parse(json); + const { parts: serializedParts } = JSON.parse(json); const parts = serializedParts.map(p => partCreator.deserializePart(p)); return parts; } catch (e) { @@ -264,7 +264,7 @@ export default class EditMessageComposer extends React.Component { } return text + part.text; }, ""); - const {cmd, args} = getCommand(commandText); + const { cmd, args } = getCommand(commandText); return [cmd, args, commandText]; } @@ -332,11 +332,11 @@ export default class EditMessageComposer extends React.Component { } else { // ask the user if their unknown command should be sent as a message const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - const {finished} = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, { + const { finished } = Modal.createTrackedDialog("Unknown command", "", QuestionDialog, { title: _t("Unknown Command"), description:

      - { _t("Unrecognised command: %(commandText)s", {commandText}) } + { _t("Unrecognised command: %(commandText)s", { commandText }) }

      { _t("You can use /help to list available commands. " + @@ -361,13 +361,13 @@ export default class EditMessageComposer extends React.Component { this._cancelPreviousPendingEdit(); const prom = this.context.sendMessage(roomId, editContent); this._clearStoredEditorState(); - dis.dispatch({action: "message_sent"}); + dis.dispatch({ action: "message_sent" }); CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent); } } // close the event editing and focus composer - dis.dispatch({action: "edit_event", event: null}); + dis.dispatch({ action: "edit_event", event: null }); dis.fire(Action.FocusComposer); }; @@ -404,7 +404,7 @@ export default class EditMessageComposer extends React.Component { } _createEditorModel() { - const {editState} = this.props; + const { editState } = this.props; const room = this._getRoom(); const partCreator = new CommandPartCreator(room, this.context); let parts; @@ -421,7 +421,7 @@ export default class EditMessageComposer extends React.Component { } _getInitialCaretPosition() { - const {editState} = this.props; + const { editState } = this.props; let caretPosition; if (editState.hasEditorState() && editState.getCaret()) { // if restoring state from a previous editor, diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx index 2032856500..74738c3683 100644 --- a/src/components/views/rooms/EntityTile.tsx +++ b/src/components/views/rooms/EntityTile.tsx @@ -33,7 +33,7 @@ export enum PowerStatus { const PowerLabel: Record = { [PowerStatus.Admin]: _td("Admin"), [PowerStatus.Moderator]: _td("Mod"), -} +}; const PRESENCE_CLASS = { "offline": "mx_EntityTile_offline", @@ -116,7 +116,7 @@ export default class EntityTile extends React.PureComponent { mainClassNames[presenceClass] = true; let nameEl; - const {name} = this.props; + const { name } = this.props; if (!this.props.suppressOnHover) { const activeAgo = this.props.presenceLastActiveAgo ? diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index c1c6bd4600..277f3ccb7c 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { createRef } from 'react'; import classNames from "classnames"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event"; @@ -176,12 +176,19 @@ const MAX_READ_AVATARS = 5; // | '--------------------------------------' | // '----------------------------------------------------------' -interface IReadReceiptProps { +export interface IReadReceiptProps { userId: string; roomMember: RoomMember; ts: number; } +export enum TileShape { + Notif = "notif", + FileGrid = "file_grid", + Reply = "reply", + ReplyPreview = "reply_preview", +} + interface IProps { // the MatrixEvent to show mxEvent: MatrixEvent; @@ -248,7 +255,7 @@ interface IProps { // It could also be done by subclassing EventTile, but that'd be quite // boiilerplatey. So just make the necessary render decisions conditional // for now. - tileShape?: 'notif' | 'file_grid' | 'reply' | 'reply_preview'; + tileShape?: TileShape; // show twelve hour timestamps isTwelveHour?: boolean; @@ -306,10 +313,11 @@ interface IState { export default class EventTile extends React.Component { private suppressReadReceiptAnimation: boolean; private isListeningForReceipts: boolean; - private ref: React.RefObject; private tile = React.createRef(); private replyThread = React.createRef(); + public readonly ref = createRef(); + static defaultProps = { // no-op function because onHeightChanged is optional yet some sub-components assume its existence onHeightChanged: function() {}, @@ -345,8 +353,6 @@ export default class EventTile extends React.Component { // to determine if we've already subscribed and use a combination of other flags to find // out if we should even be subscribed at all. this.isListeningForReceipts = false; - - this.ref = React.createRef(); } /** @@ -723,7 +729,7 @@ export default class EventTile extends React.Component { { avatars }

      - ) + ); } onSenderProfileClick = event => { @@ -870,7 +876,7 @@ export default class EventTile extends React.Component { // This shouldn't happen: the caller should check we support this type // before trying to instantiate us if (!tileHandler) { - const {mxEvent} = this.props; + const { mxEvent } = this.props; console.warn(`Event type not supported: type:${mxEvent.getType()} isState:${mxEvent.isState()}`); return
      @@ -1017,7 +1023,7 @@ export default class EventTile extends React.Component { _t( 'Re-request encryption keys from your other sessions.', {}, - {'requestLink': (sub) => { sub }}, + { 'requestLink': (sub) => { sub } }, ); const TooltipButton = sdk.getComponent('elements.TooltipButton'); @@ -1207,7 +1213,7 @@ export default class EventTile extends React.Component { avatar, ]) - ) + ); } } } @@ -1290,11 +1296,11 @@ class E2ePadlock extends React.Component { } onHoverStart = () => { - this.setState({hover: true}); + this.setState({ hover: true }); }; onHoverEnd = () => { - this.setState({hover: false}); + this.setState({ hover: false }); }; render() { @@ -1332,11 +1338,11 @@ class SentReceipt extends React.PureComponent { - this.setState({hover: true}); + this.setState({ hover: true }); }; onHoverEnd = () => { - this.setState({hover: false}); + this.setState({ hover: false }); }; render() { diff --git a/src/components/views/rooms/ExtraTile.tsx b/src/components/views/rooms/ExtraTile.tsx index 20d12955d5..18c5d50ae8 100644 --- a/src/components/views/rooms/ExtraTile.tsx +++ b/src/components/views/rooms/ExtraTile.tsx @@ -46,11 +46,11 @@ export default class ExtraTile extends React.Component { } private onTileMouseEnter = () => { - this.setState({hover: true}); + this.setState({ hover: true }); }; private onTileMouseLeave = () => { - this.setState({hover: false}); + this.setState({ hover: false }); }; public render(): React.ReactElement { diff --git a/src/components/views/rooms/LinkPreviewWidget.js b/src/components/views/rooms/LinkPreviewWidget.js index 904040a067..360ca41d55 100644 --- a/src/components/views/rooms/LinkPreviewWidget.js +++ b/src/components/views/rooms/LinkPreviewWidget.js @@ -15,18 +15,18 @@ 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 { AllHtmlEntities } from 'html-entities'; -import {linkifyElement} from '../../../HtmlUtils'; +import { linkifyElement } from '../../../HtmlUtils'; import SettingsStore from "../../../settings/SettingsStore"; -import {MatrixClientPeg} from "../../../MatrixClientPeg"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; import * as sdk from "../../../index"; import Modal from "../../../Modal"; import * as ImageUtils from "../../../ImageUtils"; import { _t } from "../../../languageHandler"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; @replaceableComponent("views.rooms.LinkPreviewWidget") export default class LinkPreviewWidget extends React.Component { diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx index 5ebe5bea59..68f87580df 100644 --- a/src/components/views/rooms/MemberList.tsx +++ b/src/components/views/rooms/MemberList.tsx @@ -148,7 +148,7 @@ export default class MemberList extends React.Component { const room = cli.getRoom(this.props.roomId); const membership = room && room.getMyMembership(); if (membership === "join") { - this.setState({loading: true}); + this.setState({ loading: true }); try { await room.loadMembersIfNeeded(); } catch (ex) {/* already logged in RoomView */} @@ -242,7 +242,7 @@ export default class MemberList extends React.Component { }, 500); private updateListNow(): void { - const members = this.roomMembers() + const members = this.roomMembers(); this.setState({ loading: false, @@ -471,7 +471,7 @@ export default class MemberList extends React.Component { } private getChildrenJoined = (start: number, end: number): Array => { - return this.makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end)) + return this.makeMemberTiles(this.state.filteredJoinedMembers.slice(start, end)); }; private getChildCountJoined = (): number => this.state.filteredJoinedMembers.length; @@ -487,7 +487,7 @@ export default class MemberList extends React.Component { private getChildCountInvited = (): number => { return this.state.filteredInvitedMembers.length + (this.getPending3PidInvites() || []).length; - } + }; render() { if (this.state.loading) { @@ -582,7 +582,7 @@ export default class MemberList extends React.Component { onInviteButtonClick = (): void => { if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } diff --git a/src/components/views/rooms/MemberTile.tsx b/src/components/views/rooms/MemberTile.tsx index 2f9927a756..ce571f78ad 100644 --- a/src/components/views/rooms/MemberTile.tsx +++ b/src/components/views/rooms/MemberTile.tsx @@ -20,7 +20,7 @@ import React from 'react'; import dis from "../../../dispatcher/dispatcher"; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import {Action} from "../../../dispatcher/actions"; +import { Action } from "../../../dispatcher/actions"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index f7d562fca0..db57f98025 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -69,7 +69,7 @@ function SendButton(props: ISendButtonProps) { ); } -const EmojiButton = ({addEmoji}) => { +const EmojiButton = ({ addEmoji }) => { const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu(); let contextMenu; @@ -132,11 +132,11 @@ class UploadButton extends React.Component { private onUploadClick = () => { if (MatrixClientPeg.get().isGuest()) { - dis.dispatch({action: 'require_registration'}); + dis.dispatch({ action: 'require_registration' }); return; } this.uploadInput.current.click(); - } + }; private onUploadFileInputChange = (ev: React.ChangeEvent) => { if (ev.target.files.length === 0) return; @@ -157,10 +157,10 @@ class UploadButton extends React.Component { // to empty. // NB. we need to set 'value': the 'files' property is immutable. ev.target.value = ''; - } + }; render() { - const uploadInputStyle = {display: 'none'}; + const uploadInputStyle = { display: 'none' }; return ( { // if we have the member already, do that const me = this.props.room.getMember(MatrixClientPeg.get().getUserId()); if (me) { - this.setState({me}); + this.setState({ me }); return; } // Otherwise, wait for member loading to finish and then update the member for the avatar. @@ -245,7 +245,7 @@ export default class MessageComposer extends React.Component { // will return the promise for the existing operation this.props.room.loadMembersIfNeeded().then(() => { const me = this.props.room.getMember(MatrixClientPeg.get().getUserId()); - this.setState({me}); + this.setState({ me }); }); } @@ -261,12 +261,12 @@ export default class MessageComposer extends React.Component { if (ev.getRoomId() !== this.props.room.roomId) return; if (ev.getType() === 'm.room.tombstone') { - this.setState({tombstone: this.getRoomTombstone()}); + this.setState({ tombstone: this.getRoomTombstone() }); } if (ev.getType() === 'm.room.power_levels') { - this.setState({canSendMessages: this.props.room.maySendMessage()}); + this.setState({ canSendMessages: this.props.room.maySendMessage() }); } - } + }; private getRoomTombstone() { return this.props.room.currentState.getStateEvents('m.room.tombstone', ''); @@ -300,7 +300,7 @@ export default class MessageComposer extends React.Component { viaServers: viaServers, }, }); - } + }; private renderPlaceholderText = () => { if (this.props.replyToEvent) { @@ -316,7 +316,7 @@ export default class MessageComposer extends React.Component { return _t('Send a message…'); } } - } + }; addEmoji(emoji: string) { dis.dispatch({ @@ -335,24 +335,24 @@ export default class MessageComposer extends React.Component { // XXX: Private function access this.messageComposerInput._sendMessage(); - } + }; onChange = (model) => { this.setState({ isComposerEmpty: model.isEmpty, }); - } + }; private onVoiceStoreUpdate = () => { const recording = VoiceRecordingStore.instance.activeRecording; - this.setState({haveRecording: !!recording}); + this.setState({ haveRecording: !!recording }); if (recording) { // We show a little heads up that the recording is about to automatically end soon. The 3s // display time is completely arbitrary. Note that we don't need to deregister the listener // because the recording instance will clean that up for us. - recording.on(RecordingState.EndingSoon, ({secondsLeft}) => { - this.setState({recordingTimeLeftSeconds: secondsLeft}); - setTimeout(() => this.setState({recordingTimeLeftSeconds: null}), 3000); + recording.on(RecordingState.EndingSoon, ({ secondsLeft }) => { + this.setState({ recordingTimeLeftSeconds: secondsLeft }); + setTimeout(() => this.setState({ recordingTimeLeftSeconds: null }), 3000); }); } }; @@ -442,7 +442,7 @@ export default class MessageComposer extends React.Component { const secondsLeft = Math.round(this.state.recordingTimeLeftSeconds); if (secondsLeft) { recordingTooltip = ; } diff --git a/src/components/views/rooms/MessageComposerFormatBar.js b/src/components/views/rooms/MessageComposerFormatBar.js index fc0f785b08..c31538c6cd 100644 --- a/src/components/views/rooms/MessageComposerFormatBar.js +++ b/src/components/views/rooms/MessageComposerFormatBar.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import classNames from 'classnames'; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.rooms.MessageComposerFormatBar") export default class MessageComposerFormatBar extends React.PureComponent { @@ -30,7 +30,7 @@ export default class MessageComposerFormatBar extends React.PureComponent { constructor(props) { super(props); - this.state = {visible: false}; + this.state = { visible: false }; } render() { @@ -47,7 +47,7 @@ export default class MessageComposerFormatBar extends React.PureComponent { } showAt(selectionRect) { - this.setState({visible: true}); + this.setState({ visible: true }); const parentRect = this._formatBarRef.parentElement.getBoundingClientRect(); this._formatBarRef.style.left = `${selectionRect.left - parentRect.left}px`; // 12 is half the height of the bar (e.g. to center it) and 16 is an offset that felt ok. @@ -55,7 +55,7 @@ export default class MessageComposerFormatBar extends React.PureComponent { } hide() { - this.setState({visible: false}); + this.setState({ visible: false }); } } diff --git a/src/components/views/rooms/NewRoomIntro.tsx b/src/components/views/rooms/NewRoomIntro.tsx index cae86846d9..8961bcc253 100644 --- a/src/components/views/rooms/NewRoomIntro.tsx +++ b/src/components/views/rooms/NewRoomIntro.tsx @@ -45,7 +45,7 @@ function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room): const NewRoomIntro = () => { const cli = useContext(MatrixClientContext); - const {room, roomId} = useContext(RoomContext); + const { room, roomId } = useContext(RoomContext); const dmPartner = DMRoomMap.shared().getUserIdForRoomId(roomId); let body; diff --git a/src/components/views/rooms/NotificationBadge.tsx b/src/components/views/rooms/NotificationBadge.tsx index 4b843bfc29..778a8a7215 100644 --- a/src/components/views/rooms/NotificationBadge.tsx +++ b/src/components/views/rooms/NotificationBadge.tsx @@ -21,7 +21,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import { XOR } from "../../../@types/common"; import { NOTIFICATION_STATE_UPDATE, NotificationState } from "../../../stores/notifications/NotificationState"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; interface IProps { notification: NotificationState; @@ -86,7 +86,7 @@ export default class NotificationBadge extends React.PureComponent { - this.setState({showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId)}); + this.setState({ showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId) }); }; private onNotificationUpdate = () => { @@ -95,7 +95,7 @@ export default class NotificationBadge extends React.PureComponent // The second update, on the next available tick, causes the "enter" animation to start // again and this time we want to show the newest breadcrumb because it'll be hidden // off screen for the animation. - this.setState({doAnimation: false, skipFirst: true}); - setTimeout(() => this.setState({doAnimation: true, skipFirst: false}), 0); + this.setState({ doAnimation: false, skipFirst: true }); + setTimeout(() => this.setState({ doAnimation: true, skipFirst: false }), 0); }; private viewRoom = (room: Room, index: number) => { Analytics.trackEvent("Breadcrumbs", "click_node", String(index)); - defaultDispatcher.dispatch({action: "view_room", room_id: room.roomId}); + defaultDispatcher.dispatch({ action: "view_room", room_id: room.roomId }); }; public render(): React.ReactElement { @@ -87,7 +87,7 @@ export default class RoomBreadcrumbs extends React.PureComponent className="mx_RoomBreadcrumbs_crumb" key={r.roomId} onClick={() => this.viewRoom(r, i)} - aria-label={_t("Room %(name)s", {name: r.name})} + aria-label={_t("Room %(name)s", { name: r.name })} title={r.name} tooltipClassName="mx_RoomBreadcrumbs_Tooltip" > diff --git a/src/components/views/rooms/RoomDetailList.js b/src/components/views/rooms/RoomDetailList.js index be22cda199..bf2f5418c9 100644 --- a/src/components/views/rooms/RoomDetailList.js +++ b/src/components/views/rooms/RoomDetailList.js @@ -21,8 +21,8 @@ import { _t } from '../../../languageHandler'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import {roomShape} from './RoomDetailRow'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { roomShape } from './RoomDetailRow'; +import { replaceableComponent } from "../../../utils/replaceableComponent"; @replaceableComponent("views.rooms.RoomDetailList") export default class RoomDetailList extends React.Component { diff --git a/src/components/views/rooms/RoomDetailRow.js b/src/components/views/rooms/RoomDetailRow.js index ad073f3278..6cee691dfa 100644 --- a/src/components/views/rooms/RoomDetailRow.js +++ b/src/components/views/rooms/RoomDetailRow.js @@ -15,12 +15,12 @@ limitations under the License. */ import * as sdk from '../../../index'; -import React, {createRef} from 'react'; +import React, { createRef } from 'react'; import { _t } from '../../../languageHandler'; import { linkifyElement } from '../../../HtmlUtils'; import PropTypes from 'prop-types'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; export function getDisplayAliasForRoom(room) { return room.canonicalAlias || (room.aliases ? room.aliases[0] : ""); diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index dc179532af..886317f2bf 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -74,7 +74,7 @@ export default class RoomHeader extends React.Component { }; _rateLimitedUpdate = new RateLimitedFunc(function() { - /* eslint-disable babel/no-invalid-this */ + /* eslint-disable @babel/no-invalid-this */ this.forceUpdate(); }, 500); diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index eb50224a60..c94256800d 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -45,9 +45,9 @@ import { objectShallowClone, objectWithOnly } from "../../../utils/objects"; import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../context_menus/IconizedContextMenu"; import AccessibleButton from "../elements/AccessibleButton"; import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; -import SpaceStore, {ISuggestedRoom, SUGGESTED_ROOMS} from "../../../stores/SpaceStore"; -import {showAddExistingRooms, showCreateNewRoom, showSpaceInvite} from "../../../utils/space"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import SpaceStore, { ISuggestedRoom, SUGGESTED_ROOMS } from "../../../stores/SpaceStore"; +import { showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; import RoomAvatar from "../avatars/RoomAvatar"; interface IProps { @@ -119,7 +119,7 @@ const TAG_AESTHETICS: ITagAestheticsMap = { defaultHidden: false, addRoomLabel: _td("Start chat"), onAddRoom: (dispatcher?: Dispatcher) => { - (dispatcher || defaultDispatcher).dispatch({action: 'view_create_chat'}); + (dispatcher || defaultDispatcher).dispatch({ action: 'view_create_chat' }); }, }, [DefaultTagID.Untagged]: { @@ -180,7 +180,7 @@ const TAG_AESTHETICS: ITagAestheticsMap = { e.preventDefault(); e.stopPropagation(); onFinished(); - defaultDispatcher.dispatch({action: "view_create_room"}); + defaultDispatcher.dispatch({ action: "view_create_room" }); }} /> { const newSublists = objectWithOnly(newLists, newListIds); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); - this.setState({sublists, isNameFiltering}, () => { + this.setState({ sublists, isNameFiltering }, () => { this.props.onResize(); }); } @@ -495,7 +495,7 @@ export default class RoomList extends React.PureComponent { resizeNotifier={this.props.resizeNotifier} alwaysVisible={ALWAYS_VISIBLE_TAGS.includes(orderedTagId)} onListCollapse={this.props.onListCollapse} - /> + />; }); } @@ -542,7 +542,7 @@ export default class RoomList extends React.PureComponent { }
      ; } else if (Object.values(this.state.sublists).some(list => list.length > 0)) { - const unfilteredLists = RoomListStore.instance.unfilteredLists + const unfilteredLists = RoomListStore.instance.unfilteredLists; const unfilteredRooms = unfilteredLists[DefaultTagID.Untagged] || []; const unfilteredHistorical = unfilteredLists[DefaultTagID.Archived] || []; const unfilteredFavourite = unfilteredLists[DefaultTagID.Favourite] || []; @@ -572,7 +572,7 @@ export default class RoomList extends React.PureComponent { const sublists = this.renderSublists(); return ( - {({onKeyDownHandler}) => ( + {({ onKeyDownHandler }) => (
      wants to chat", {}, {userName: () => inviterElement}), + _t(" wants to chat", {}, { userName: () => inviterElement }), ]; primaryActionLabel = _t("Start chatting"); } else { @@ -486,7 +486,7 @@ export default class RoomPreviewBar extends React.Component { { roomName: this._roomName() }); subTitle = [ avatar, - _t(" invited you", {}, {userName: () => inviterElement}), + _t(" invited you", {}, { userName: () => inviterElement }), ]; primaryActionLabel = _t("Accept"); } @@ -513,22 +513,22 @@ export default class RoomPreviewBar extends React.Component { case MessageCase.ViewingRoom: { if (this.props.canPreview) { title = _t("You're previewing %(roomName)s. Want to join it?", - {roomName: this._roomName()}); + { roomName: this._roomName() }); } else { title = _t("%(roomName)s can't be previewed. Do you want to join it?", - {roomName: this._roomName(true)}); + { roomName: this._roomName(true) }); } primaryActionLabel = _t("Join the discussion"); primaryActionHandler = this.props.onJoinClick; break; } case MessageCase.RoomNotFound: { - title = _t("%(roomName)s does not exist.", {roomName: this._roomName(true)}); + title = _t("%(roomName)s does not exist.", { roomName: this._roomName(true) }); subTitle = _t("This room doesn't exist. Are you sure you're at the right place?"); break; } case MessageCase.OtherError: { - title = _t("%(roomName)s is not accessible at this time.", {roomName: this._roomName(true)}); + title = _t("%(roomName)s is not accessible at this time.", { roomName: this._roomName(true) }); subTitle = [ _t("Try again later, or ask a room admin to check if you have access."), _t( diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index 61166b4230..fce9e297a1 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -54,7 +54,7 @@ import ExtraTile from "./ExtraTile"; import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; import IconizedContextMenu from "../context_menus/IconizedContextMenu"; import { getKeyBindingsManager, RoomListAction } from "../../../KeyBindingsManager"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS @@ -128,7 +128,7 @@ export default class RoomSublist extends React.Component { rooms: arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []), }; // Why Object.assign() and not this.state.height? Because TypeScript says no. - this.state = Object.assign(this.state, {height: this.calculateInitialHeight()}); + this.state = Object.assign(this.state, { height: this.calculateInitialHeight() }); } private calculateInitialHeight() { @@ -184,7 +184,7 @@ export default class RoomSublist extends React.Component { // as the rooms can come in one by one we need to reevaluate // the amount of available rooms to cap the amount of requested visible rooms by the layout if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) { - this.setState({height: this.calculateInitialHeight()}); + this.setState({ height: this.calculateInitialHeight() }); } } @@ -329,12 +329,12 @@ export default class RoomSublist extends React.Component { ) => { const newHeight = this.heightAtStart + delta.height; this.applyHeightChange(newHeight); - this.setState({height: newHeight}); + this.setState({ height: newHeight }); }; private onResizeStart = () => { this.heightAtStart = this.state.height; - this.setState({isResizing: true}); + this.setState({ isResizing: true }); }; private onResizeStop = ( @@ -345,7 +345,7 @@ export default class RoomSublist extends React.Component { ) => { const newHeight = this.heightAtStart + delta.height; this.applyHeightChange(newHeight); - this.setState({isResizing: false, height: newHeight}); + this.setState({ isResizing: false, height: newHeight }); }; private onShowAllClick = () => { @@ -353,7 +353,7 @@ export default class RoomSublist extends React.Component { const numVisibleTiles = this.numVisibleTiles; const newHeight = this.layout.tilesToPixelsWithPadding(this.numTiles, this.padding); this.applyHeightChange(newHeight); - this.setState({height: newHeight}, () => { + this.setState({ height: newHeight }, () => { // focus the top-most new room this.focusRoomTile(numVisibleTiles); }); @@ -362,7 +362,7 @@ export default class RoomSublist extends React.Component { private onShowLessClick = () => { const newHeight = this.layout.tilesToPixelsWithPadding(this.layout.defaultVisibleTiles, this.padding); this.applyHeightChange(newHeight); - this.setState({height: newHeight}); + this.setState({ height: newHeight }); }; private focusRoomTile = (index: number) => { @@ -378,7 +378,7 @@ export default class RoomSublist extends React.Component { ev.preventDefault(); ev.stopPropagation(); const target = ev.target as HTMLButtonElement; - this.setState({contextMenuPosition: target.getBoundingClientRect()}); + this.setState({ contextMenuPosition: target.getBoundingClientRect() }); }; private onContextMenu = (ev: React.MouseEvent) => { @@ -397,15 +397,15 @@ export default class RoomSublist extends React.Component { ev.preventDefault(); ev.stopPropagation(); const target = ev.target as HTMLButtonElement; - this.setState({addRoomContextMenuPosition: target.getBoundingClientRect()}); + this.setState({ addRoomContextMenuPosition: target.getBoundingClientRect() }); }; private onCloseMenu = () => { - this.setState({contextMenuPosition: null}); + this.setState({ contextMenuPosition: null }); }; private onCloseAddRoomMenu = () => { - this.setState({addRoomContextMenuPosition: null}); + this.setState({ addRoomContextMenuPosition: null }); }; private onUnreadFirstChanged = async () => { @@ -462,7 +462,7 @@ export default class RoomSublist extends React.Component { if ((isStickyBottom && !isAtBottom) || (isStickyTop && !isAtTop)) { // is sticky - jump to list - sublist.scrollIntoView({behavior: 'smooth'}); + sublist.scrollIntoView({ behavior: 'smooth' }); } else { // on screen - toggle collapse const isExpanded = this.state.isExpanded; @@ -470,7 +470,7 @@ export default class RoomSublist extends React.Component { // if the bottom list is collapsed then scroll it in so it doesn't expand off screen if (!isExpanded && isStickyBottom) { setImmediate(() => { - sublist.scrollIntoView({behavior: 'smooth'}); + sublist.scrollIntoView({ behavior: 'smooth' }); }); } } @@ -478,9 +478,9 @@ export default class RoomSublist extends React.Component { private toggleCollapsed = () => { this.layout.isCollapsed = this.state.isExpanded; - this.setState({isExpanded: !this.layout.isCollapsed}); + this.setState({ isExpanded: !this.layout.isCollapsed }); if (this.props.onListCollapse) { - this.props.onListCollapse(!this.layout.isCollapsed) + this.props.onListCollapse(!this.layout.isCollapsed); } }; @@ -655,7 +655,7 @@ export default class RoomSublist extends React.Component { private renderHeader(): React.ReactElement { return ( - {({onFocus, isActive, ref}) => { + {({ onFocus, isActive, ref }) => { const tabIndex = isActive ? 0 : -1; let ariaLabel = _t("Jump to first unread room."); @@ -801,7 +801,7 @@ export default class RoomSublist extends React.Component { const nonPaddedHeight = this.state.height - RESIZE_HANDLE_HEIGHT - SHOW_N_BUTTON_HEIGHT; const amountFullyShown = Math.floor(nonPaddedHeight / this.layout.tileHeight); const numMissing = this.numTiles - amountFullyShown; - const label = _t("Show %(count)s more", {count: numMissing}); + const label = _t("Show %(count)s more", { count: numMissing }); let showMoreText = ( {label} @@ -879,14 +879,14 @@ export default class RoomSublist extends React.Component { content = ( diff --git a/src/components/views/rooms/RoomTile.tsx b/src/components/views/rooms/RoomTile.tsx index 310ff29010..9be0274dd5 100644 --- a/src/components/views/rooms/RoomTile.tsx +++ b/src/components/views/rooms/RoomTile.tsx @@ -78,7 +78,7 @@ const contextMenuBelow = (elementRect: PartialDOMRect) => { const left = elementRect.left + window.pageXOffset - 9; const top = elementRect.bottom + window.pageYOffset + 17; const chevronFace = ChevronFace.None; - return {left, top, chevronFace}; + return { left, top, chevronFace }; }; @replaceableComponent("views.rooms.RoomTile") @@ -112,7 +112,7 @@ export default class RoomTile extends React.PureComponent { private onRoomNameUpdate = (room) => { this.forceUpdate(); - } + }; private onNotificationUpdate = () => { this.forceUpdate(); // notification state changed - update @@ -120,7 +120,7 @@ export default class RoomTile extends React.PureComponent { private onLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { if (room?.roomId !== this.props.room.roomId) return; - this.setState({hasUnsentEvents: this.countUnsentEvents() > 0}); + this.setState({ hasUnsentEvents: this.countUnsentEvents() > 0 }); }; private onRoomPropertyUpdate = (property: CachedRoomKey) => { @@ -259,25 +259,25 @@ export default class RoomTile extends React.PureComponent { }; private onActiveRoomUpdate = (isActive: boolean) => { - this.setState({selected: isActive}); + this.setState({ selected: isActive }); }; private onNotificationsMenuOpenClick = (ev: React.MouseEvent) => { ev.preventDefault(); ev.stopPropagation(); const target = ev.target as HTMLButtonElement; - this.setState({notificationsMenuPosition: target.getBoundingClientRect()}); + this.setState({ notificationsMenuPosition: target.getBoundingClientRect() }); }; private onCloseNotificationsMenu = () => { - this.setState({notificationsMenuPosition: null}); + this.setState({ notificationsMenuPosition: null }); }; private onGeneralMenuOpenClick = (ev: React.MouseEvent) => { ev.preventDefault(); ev.stopPropagation(); const target = ev.target as HTMLButtonElement; - this.setState({generalMenuPosition: target.getBoundingClientRect()}); + this.setState({ generalMenuPosition: target.getBoundingClientRect() }); }; private onContextMenu = (ev: React.MouseEvent) => { @@ -295,7 +295,7 @@ export default class RoomTile extends React.PureComponent { }; private onCloseGeneralMenu = () => { - this.setState({generalMenuPosition: null}); + this.setState({ generalMenuPosition: null }); }; private onTagRoom = (ev: ButtonEvent, tagId: TagID) => { @@ -321,7 +321,7 @@ export default class RoomTile extends React.PureComponent { if ((ev as React.KeyboardEvent).key === Key.ENTER) { // Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12 - this.setState({generalMenuPosition: null}); // hide the menu + this.setState({ generalMenuPosition: null }); // hide the menu } }; @@ -333,7 +333,7 @@ export default class RoomTile extends React.PureComponent { action: 'leave_room', room_id: this.props.room.roomId, }); - this.setState({generalMenuPosition: null}); // hide the menu + this.setState({ generalMenuPosition: null }); // hide the menu }; private onForgetRoomClick = (ev: ButtonEvent) => { @@ -344,7 +344,7 @@ export default class RoomTile extends React.PureComponent { action: 'forget_room', room_id: this.props.room.roomId, }); - this.setState({generalMenuPosition: null}); // hide the menu + this.setState({ generalMenuPosition: null }); // hide the menu }; private onOpenRoomSettings = (ev: ButtonEvent) => { @@ -355,7 +355,7 @@ export default class RoomTile extends React.PureComponent { action: 'open_room_settings', room_id: this.props.room.roomId, }); - this.setState({generalMenuPosition: null}); // hide the menu + this.setState({ generalMenuPosition: null }); // hide the menu }; private onInviteClick = (ev: ButtonEvent) => { @@ -366,7 +366,7 @@ export default class RoomTile extends React.PureComponent { action: 'view_invite', roomId: this.props.room.roomId, }); - this.setState({generalMenuPosition: null}); // hide the menu + this.setState({ generalMenuPosition: null }); // hide the menu }; private async saveNotifState(ev: ButtonEvent, newState: Volume) { @@ -379,7 +379,7 @@ export default class RoomTile extends React.PureComponent { const key = (ev as React.KeyboardEvent).key; if (key === Key.ENTER) { // Implements https://www.w3.org/TR/wai-aria-practices/#keyboard-interaction-12 - this.setState({notificationsMenuPosition: null}); // hide the menu + this.setState({ notificationsMenuPosition: null }); // hide the menu } } @@ -554,7 +554,7 @@ export default class RoomTile extends React.PureComponent { 'mx_RoomTile_minimized': this.props.isMinimized, }); - let roomProfile: IRoomProfile = {displayName: null, avatarMxc: null}; + let roomProfile: IRoomProfile = { displayName: null, avatarMxc: null }; if (this.props.tag === DefaultTagID.Invite) { roomProfile = CommunityPrototypeStore.instance.getInviteProfile(this.props.room.roomId); } @@ -567,7 +567,7 @@ export default class RoomTile extends React.PureComponent { room={this.props.room} avatarSize={32} displayBadge={this.props.isMinimized} - oobData={({avatarUrl: roomProfile.avatarMxc})} + oobData={({ avatarUrl: roomProfile.avatarMxc })} />; let badge: React.ReactNode; @@ -659,7 +659,7 @@ export default class RoomTile extends React.PureComponent { return ( - {({onFocus, isActive, ref}) => + {({ onFocus, isActive, ref }) => } @@ -119,4 +119,3 @@ describe("RovingTabIndex", () => { }); }); - diff --git a/test/autocomplete/QueryMatcher-test.js b/test/autocomplete/QueryMatcher-test.js index cae71841d4..72f894c678 100644 --- a/test/autocomplete/QueryMatcher-test.js +++ b/test/autocomplete/QueryMatcher-test.js @@ -31,7 +31,7 @@ const NONWORDOBJECTS = [ describe('QueryMatcher', function() { it('Returns results by key', function() { - const qm = new QueryMatcher(OBJECTS, {keys: ["name"]}); + const qm = new QueryMatcher(OBJECTS, { keys: ["name"] }); const results = qm.match('Geri'); expect(results.length).toBe(1); @@ -39,7 +39,7 @@ describe('QueryMatcher', function() { }); it('Returns results by prefix', function() { - const qm = new QueryMatcher(OBJECTS, {keys: ["name"]}); + const qm = new QueryMatcher(OBJECTS, { keys: ["name"] }); const results = qm.match('Ge'); expect(results.length).toBe(1); @@ -47,7 +47,7 @@ describe('QueryMatcher', function() { }); it('Matches case-insensitive', function() { - const qm = new QueryMatcher(OBJECTS, {keys: ["name"]}); + const qm = new QueryMatcher(OBJECTS, { keys: ["name"] }); const results = qm.match('geri'); expect(results.length).toBe(1); @@ -55,7 +55,7 @@ describe('QueryMatcher', function() { }); it('Matches ignoring accents', function() { - const qm = new QueryMatcher([{name: "Gëri", foo: 46}], {keys: ["name"]}); + const qm = new QueryMatcher([{ name: "Gëri", foo: 46 }], { keys: ["name"] }); const results = qm.match('geri'); expect(results.length).toBe(1); @@ -63,14 +63,13 @@ describe('QueryMatcher', function() { }); it('Returns multiple results in order of search string appearance', function() { - const qm = new QueryMatcher(OBJECTS, {keys: ["name", "nick"]}); + const qm = new QueryMatcher(OBJECTS, { keys: ["name", "nick"] }); const results = qm.match('or'); expect(results.length).toBe(2); expect(results[0].name).toBe('Mel C'); expect(results[1].name).toBe('Victoria'); - qm.setObjects(OBJECTS.slice().reverse()); const reverseResults = qm.match('or'); @@ -87,7 +86,7 @@ describe('QueryMatcher', function() { { name: "b", first: "miss", second: "hit", third: "miss" }, { name: "c", first: "miss", second: "miss", third: "hit" }, ]; - const qm = new QueryMatcher(objects, {keys: ["second", "first", "third"]}); + const qm = new QueryMatcher(objects, { keys: ["second", "first", "third"] }); const results = qm.match('hit'); expect(results.length).toBe(3); @@ -95,7 +94,6 @@ describe('QueryMatcher', function() { expect(results[1].name).toBe('a'); expect(results[2].name).toBe('c'); - qm.setObjects(objects.slice().reverse()); const reverseResults = qm.match('hit'); @@ -109,14 +107,13 @@ describe('QueryMatcher', function() { }); it('Returns results with search string in same place and key in same place in insertion order', function() { - const qm = new QueryMatcher(OBJECTS, {keys: ["name"]}); + const qm = new QueryMatcher(OBJECTS, { keys: ["name"] }); const results = qm.match('Mel'); expect(results.length).toBe(2); expect(results[0].name).toBe('Mel B'); expect(results[1].name).toBe('Mel C'); - qm.setObjects(OBJECTS.slice().reverse()); const reverseResults = qm.match('Mel'); @@ -129,9 +126,9 @@ describe('QueryMatcher', function() { it('Returns numeric results in correct order (input pos)', function() { // regression test for depending on object iteration order const qm = new QueryMatcher([ - {name: "123456badger"}, - {name: "123456"}, - ], {keys: ["name"]}); + { name: "123456badger" }, + { name: "123456" }, + ], { keys: ["name"] }); const results = qm.match('123456'); expect(results.length).toBe(2); @@ -141,9 +138,9 @@ describe('QueryMatcher', function() { it('Returns numeric results in correct order (query pos)', function() { const qm = new QueryMatcher([ - {name: "999999123456"}, - {name: "123456badger"}, - ], {keys: ["name"]}); + { name: "999999123456" }, + { name: "123456badger" }, + ], { keys: ["name"] }); const results = qm.match('123456'); expect(results.length).toBe(2); diff --git a/test/components/structures/GroupView-test.js b/test/components/structures/GroupView-test.js index ee5d1b6912..2ff1257d32 100644 --- a/test/components/structures/GroupView-test.js +++ b/test/components/structures/GroupView-test.js @@ -19,7 +19,7 @@ import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-dom/test-utils'; import MockHttpBackend from 'matrix-mock-request'; -import {MatrixClientPeg} from '../../../src/MatrixClientPeg'; +import { MatrixClientPeg } from '../../../src/MatrixClientPeg'; import sdk from '../../skinned-sdk'; import Matrix from 'matrix-js-sdk'; diff --git a/test/components/structures/auth/Login-test.js b/test/components/structures/auth/Login-test.js index f39802464f..9def0c8d95 100644 --- a/test/components/structures/auth/Login-test.js +++ b/test/components/structures/auth/Login-test.js @@ -19,7 +19,7 @@ import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-dom/test-utils'; import sdk from '../../../skinned-sdk'; import SdkConfig from '../../../../src/SdkConfig'; -import {mkServerConfig} from "../../../test-utils"; +import { mkServerConfig } from "../../../test-utils"; const Login = sdk.getComponent( 'structures.auth.Login', diff --git a/test/components/structures/auth/Registration-test.js b/test/components/structures/auth/Registration-test.js index 3e8e887329..e09304962f 100644 --- a/test/components/structures/auth/Registration-test.js +++ b/test/components/structures/auth/Registration-test.js @@ -19,7 +19,7 @@ import ReactDOM from 'react-dom'; import ReactTestUtils from 'react-dom/test-utils'; import sdk from '../../../skinned-sdk'; import SdkConfig from '../../../../src/SdkConfig'; -import {mkServerConfig} from "../../../test-utils"; +import { mkServerConfig } from "../../../test-utils"; const Registration = sdk.getComponent( 'structures.auth.Registration', diff --git a/test/components/stub-component.js b/test/components/stub-component.js index e242c06707..f98959a573 100644 --- a/test/components/stub-component.js +++ b/test/components/stub-component.js @@ -3,7 +3,7 @@ import React from 'react'; -export default function({displayName = "StubComponent", render} = {}) { +export default function({ displayName = "StubComponent", render } = {}) { if (!render) { render = function() { return
      { displayName }
      ; diff --git a/test/components/views/dialogs/AccessSecretStorageDialog-test.js b/test/components/views/dialogs/AccessSecretStorageDialog-test.js index d9e07a2d74..8c16e7f104 100644 --- a/test/components/views/dialogs/AccessSecretStorageDialog-test.js +++ b/test/components/views/dialogs/AccessSecretStorageDialog-test.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import TestRenderer from 'react-test-renderer'; import sdk from '../../../skinned-sdk'; -import {MatrixClientPeg} from '../../../../src/MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import { stubClient } from '../../../test-utils'; const AccessSecretStorageDialog = sdk.getComponent("dialogs.security.AccessSecretStorageDialog"); diff --git a/test/components/views/dialogs/ForwardDialog-test.js b/test/components/views/dialogs/ForwardDialog-test.js index dbd50612bb..c5ce330fec 100644 --- a/test/components/views/dialogs/ForwardDialog-test.js +++ b/test/components/views/dialogs/ForwardDialog-test.js @@ -17,14 +17,14 @@ limitations under the License. import "../../../skinned-sdk"; import React from "react"; -import {configure, mount} from "enzyme"; +import { configure, mount } from "enzyme"; import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; -import {act} from "react-dom/test-utils"; +import { act } from "react-dom/test-utils"; import * as TestUtils from "../../../test-utils"; -import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import DMRoomMap from "../../../../src/utils/DMRoomMap"; -import {RoomPermalinkCreator} from "../../../../src/utils/permalinks/Permalinks"; +import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks"; import ForwardDialog from "../../../../src/components/views/dialogs/ForwardDialog"; configure({ adapter: new Adapter() }); diff --git a/test/components/views/elements/MemberEventListSummary-test.js b/test/components/views/elements/MemberEventListSummary-test.js index 95bf206d02..e2d51f13a4 100644 --- a/test/components/views/elements/MemberEventListSummary-test.js +++ b/test/components/views/elements/MemberEventListSummary-test.js @@ -90,7 +90,7 @@ describe('MemberEventListSummary', function() { it('renders expanded events if there are less than props.threshold', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, ]); const props = { events: events, @@ -112,8 +112,8 @@ describe('MemberEventListSummary', function() { it('renders expanded events if there are less than props.threshold', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, ]); const props = { events: events, @@ -136,9 +136,9 @@ describe('MemberEventListSummary', function() { it('renders collapsed events if events.length = props.threshold', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, ]); const props = { events: events, @@ -161,20 +161,20 @@ describe('MemberEventListSummary', function() { it('truncates long join,leave repetitions', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, ]); const props = { events: events, @@ -203,20 +203,20 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_1:some.domain", prevMembership: "leave", @@ -253,22 +253,22 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_1:some.domain", prevMembership: "leave", membership: "ban", senderId: "@some_other_user:some.domain", }, - {userId: "@user_1:some.domain", prevMembership: "ban", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "ban", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_1:some.domain", prevMembership: "leave", @@ -307,10 +307,10 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_1:some.domain", prevMembership: "leave", @@ -324,10 +324,10 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {userId: "@user_2:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_2:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_2:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_2:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_2:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_2:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_2:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_2:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_2:some.domain", prevMembership: "leave", @@ -363,10 +363,10 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {prevMembership: "leave", membership: "join"}, - {prevMembership: "join", membership: "leave"}, - {prevMembership: "leave", membership: "join"}, - {prevMembership: "join", membership: "leave"}, + { prevMembership: "leave", membership: "join" }, + { prevMembership: "join", membership: "leave" }, + { prevMembership: "leave", membership: "join" }, + { prevMembership: "join", membership: "leave" }, { prevMembership: "leave", membership: "ban", @@ -408,20 +408,20 @@ describe('MemberEventListSummary', function() { membership: "leave", senderId: "@some_other_user:some.domain", }, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_1:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_1:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, { userId: "@user_1:some.domain", prevMembership: "leave", membership: "ban", senderId: "@some_other_user:some.domain", }, - {userId: "@user_2:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_2:some.domain", prevMembership: "join", membership: "leave"}, - {userId: "@user_2:some.domain", prevMembership: "leave", membership: "join"}, - {userId: "@user_2:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_2:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_2:some.domain", prevMembership: "join", membership: "leave" }, + { userId: "@user_2:some.domain", prevMembership: "leave", membership: "join" }, + { userId: "@user_2:some.domain", prevMembership: "join", membership: "leave" }, ]); const props = { events: events, @@ -448,11 +448,11 @@ describe('MemberEventListSummary', function() { it('correctly identifies transitions', function() { const events = generateEvents([ // invited - {userId: "@user_1:some.domain", membership: "invite"}, + { userId: "@user_1:some.domain", membership: "invite" }, // banned - {userId: "@user_1:some.domain", membership: "ban"}, + { userId: "@user_1:some.domain", membership: "ban" }, // joined - {userId: "@user_1:some.domain", membership: "join"}, + { userId: "@user_1:some.domain", membership: "join" }, // invite_reject { userId: "@user_1:some.domain", @@ -460,7 +460,7 @@ describe('MemberEventListSummary', function() { membership: "leave", }, // left - {userId: "@user_1:some.domain", prevMembership: "join", membership: "leave"}, + { userId: "@user_1:some.domain", prevMembership: "join", membership: "leave" }, // invite_withdrawal { userId: "@user_1:some.domain", @@ -602,10 +602,10 @@ describe('MemberEventListSummary', function() { it('handles a summary length = 2, with no "others"', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", membership: "join"}, - {userId: "@user_1:some.domain", membership: "join"}, - {userId: "@user_2:some.domain", membership: "join"}, - {userId: "@user_2:some.domain", membership: "join"}, + { userId: "@user_1:some.domain", membership: "join" }, + { userId: "@user_1:some.domain", membership: "join" }, + { userId: "@user_2:some.domain", membership: "join" }, + { userId: "@user_2:some.domain", membership: "join" }, ]); const props = { events: events, @@ -630,9 +630,9 @@ describe('MemberEventListSummary', function() { it('handles a summary length = 2, with 1 "other"', function() { const events = generateEvents([ - {userId: "@user_1:some.domain", membership: "join"}, - {userId: "@user_2:some.domain", membership: "join"}, - {userId: "@user_3:some.domain", membership: "join"}, + { userId: "@user_1:some.domain", membership: "join" }, + { userId: "@user_2:some.domain", membership: "join" }, + { userId: "@user_3:some.domain", membership: "join" }, ]); const props = { events: events, @@ -657,7 +657,7 @@ describe('MemberEventListSummary', function() { it('handles a summary length = 2, with many "others"', function() { const events = generateEventsForUsers("@user_$:some.domain", 20, [ - {membership: "join"}, + { membership: "join" }, ]); const props = { events: events, diff --git a/test/components/views/groups/GroupMemberList-test.js b/test/components/views/groups/GroupMemberList-test.js index 39720177cc..7e01540d38 100644 --- a/test/components/views/groups/GroupMemberList-test.js +++ b/test/components/views/groups/GroupMemberList-test.js @@ -19,7 +19,7 @@ import ReactDOM from "react-dom"; import ReactTestUtils from "react-dom/test-utils"; import MockHttpBackend from "matrix-mock-request"; -import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import sdk from "../../../skinned-sdk"; import Matrix from "matrix-js-sdk"; diff --git a/test/components/views/messages/TextualBody-test.js b/test/components/views/messages/TextualBody-test.js index b81486b293..c9418fc557 100644 --- a/test/components/views/messages/TextualBody-test.js +++ b/test/components/views/messages/TextualBody-test.js @@ -19,8 +19,8 @@ import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { configure, mount } from "enzyme"; import sdk from "../../../skinned-sdk"; -import {mkEvent, mkStubRoom} from "../../../test-utils"; -import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; +import { mkEvent, mkStubRoom } from "../../../test-utils"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import * as languageHandler from "../../../../src/languageHandler"; const TextualBody = sdk.getComponent("views.messages.TextualBody"); @@ -343,4 +343,3 @@ describe("", () => { }); }); - diff --git a/test/components/views/rooms/MemberList-test.tsx b/test/components/views/rooms/MemberList-test.tsx index 8012c43c4b..a169cd08e6 100644 --- a/test/components/views/rooms/MemberList-test.tsx +++ b/test/components/views/rooms/MemberList-test.tsx @@ -312,4 +312,3 @@ describe('MemberList', () => { }); }); - diff --git a/test/components/views/rooms/RoomList-test.js b/test/components/views/rooms/RoomList-test.js index 6aad6a90fd..cee0fe5a47 100644 --- a/test/components/views/rooms/RoomList-test.js +++ b/test/components/views/rooms/RoomList-test.js @@ -4,7 +4,7 @@ import ReactDOM from 'react-dom'; import * as TestUtils from '../../../test-utils'; -import {MatrixClientPeg} from '../../../../src/MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import sdk from '../../../skinned-sdk'; import dis from '../../../../src/dispatcher/dispatcher'; @@ -12,7 +12,7 @@ import DMRoomMap from '../../../../src/utils/DMRoomMap'; import GroupStore from '../../../../src/stores/GroupStore'; import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk'; -import {DefaultTagID} from "../../../../src/stores/room-list/models"; +import { DefaultTagID } from "../../../../src/stores/room-list/models"; import RoomListStore, { LISTS_UPDATE_EVENT, RoomListStoreClass } from "../../../../src/stores/room-list/RoomListStore"; import RoomListLayoutStore from "../../../../src/stores/room-list/RoomListLayoutStore"; @@ -55,7 +55,7 @@ describe('RoomList', () => { TestUtils.stubClient(); client = MatrixClientPeg.get(); - client.credentials = {userId: myUserId}; + client.credentials = { userId: myUserId }; //revert this to prototype method as the test-utils monkey-patches this to return a hardcoded value client.getUserId = MatrixClient.prototype.getUserId; @@ -72,7 +72,7 @@ describe('RoomList', () => { ); ReactTestUtils.findRenderedComponentWithType(root, RoomList); - movingRoom = createRoom({name: 'Moving room'}); + movingRoom = createRoom({ name: 'Moving room' }); expect(movingRoom.roomId).not.toBe(null); // Mock joined member @@ -83,7 +83,7 @@ describe('RoomList', () => { [client.credentials.userId]: myMember, }[userId]); - otherRoom = createRoom({name: 'Other room'}); + otherRoom = createRoom({ name: 'Other room' }); myOtherMember = new RoomMember(otherRoom.roomId, myUserId); myOtherMember.membership = 'join'; otherRoom.updateMyMembership('join'); @@ -95,10 +95,10 @@ describe('RoomList', () => { client.getRooms = () => [ movingRoom, otherRoom, - createRoom({tags: {'m.favourite': {order: 0.1}}, name: 'Some other room'}), - createRoom({tags: {'m.favourite': {order: 0.2}}, name: 'Some other room 2'}), - createRoom({tags: {'m.lowpriority': {}}, name: 'Some unimportant room'}), - createRoom({tags: {'custom.tag': {}}, name: 'Some room customly tagged'}), + createRoom({ tags: { 'm.favourite': { order: 0.1 } }, name: 'Some other room' }), + createRoom({ tags: { 'm.favourite': { order: 0.2 } }, name: 'Some other room 2' }), + createRoom({ tags: { 'm.lowpriority': {} }, name: 'Some unimportant room' }), + createRoom({ tags: { 'custom.tag': {} }, name: 'Some room customly tagged' }), ]; client.getVisibleRooms = client.getRooms; @@ -138,7 +138,7 @@ describe('RoomList', () => { let expectedRoomTile; try { const roomTiles = ReactTestUtils.scryRenderedComponentsWithType(containingSubList, RoomTile); - console.info({roomTiles: roomTiles.length}); + console.info({ roomTiles: roomTiles.length }); expectedRoomTile = roomTiles.find((tile) => tile.props.room === room); } catch (err) { // truncate the error message because it's spammy @@ -164,7 +164,7 @@ describe('RoomList', () => { // Set up the room that will be moved such that it has the correct state for a room in // the section for oldTagId if (oldTagId === DefaultTagID.Favourite || oldTagId === DefaultTagID.LowPriority) { - movingRoom.tags = {[oldTagId]: {}}; + movingRoom.tags = { [oldTagId]: {} }; } else if (oldTagId === DefaultTagID.DM) { // Mock inverse m.direct DMRoomMap.shared().roomToUser = { @@ -172,13 +172,13 @@ describe('RoomList', () => { }; } - dis.dispatch({action: 'MatrixActions.sync', prevState: null, state: 'PREPARED', matrixClient: client}); + dis.dispatch({ action: 'MatrixActions.sync', prevState: null, state: 'PREPARED', matrixClient: client }); expectRoomInSubList(movingRoom, srcSubListTest); - dis.dispatch({action: 'RoomListActions.tagRoom.pending', request: { + dis.dispatch({ action: 'RoomListActions.tagRoom.pending', request: { oldTagId, newTagId, room: movingRoom, - }}); + } }); expectRoomInSubList(movingRoom, destSubListTest); } @@ -279,11 +279,11 @@ describe('RoomList', () => { // We also have to mock the client's getGroup function for the room list to filter it. // It's not smart enough to tell the difference between a real group and a template though. client.getGroup = (groupId) => { - return {groupId}; + return { groupId }; }; // Select tag - dis.dispatch({action: 'select_tag', tag: '+group:domain'}, true); + dis.dispatch({ action: 'select_tag', tag: '+group:domain' }, true); } beforeEach(() => { @@ -309,4 +309,3 @@ describe('RoomList', () => { }); }); - diff --git a/test/components/views/rooms/RoomSettings-test.js b/test/components/views/rooms/RoomSettings-test.js index 3b4989ccab..cd70b81cd7 100644 --- a/test/components/views/rooms/RoomSettings-test.js +++ b/test/components/views/rooms/RoomSettings-test.js @@ -3,10 +3,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import * as testUtils from '../../../test-utils'; import sdk from '../../../skinned-sdk'; -import {MatrixClientPeg} from '../../../../src/MatrixClientPeg'; +import { MatrixClientPeg } from '../../../../src/MatrixClientPeg'; import SettingsStore from '../../../../src/settings/SettingsStore'; - describe.skip('RoomSettings', () => { const WrappedRoomSettings = testUtils.wrapInMatrixClientContext(sdk.getComponent('views.rooms.RoomSettings')); @@ -36,7 +35,7 @@ describe.skip('RoomSettings', () => { beforeEach(function(done) { testUtils.stubClient(); client = MatrixClientPeg.get(); - client.credentials = {userId: '@me:domain.com'}; + client.credentials = { userId: '@me:domain.com' }; client.setRoomName = jest.fn().mockReturnValue(Promise.resolve()); client.setRoomTopic = jest.fn().mockReturnValue(Promise.resolve()); @@ -128,7 +127,7 @@ describe.skip('RoomSettings', () => { roomSettings.save().then(() => { expectSentStateEvent( "!DdJkzRliezrwpNebLk:matrix.org", - "m.room.history_visibility", {history_visibility: historyVisibility}, + "m.room.history_visibility", { history_visibility: historyVisibility }, ); done(); }); diff --git a/test/components/views/rooms/SendMessageComposer-test.js b/test/components/views/rooms/SendMessageComposer-test.js index eb7b2ffeff..2fddf8b691 100644 --- a/test/components/views/rooms/SendMessageComposer-test.js +++ b/test/components/views/rooms/SendMessageComposer-test.js @@ -18,18 +18,18 @@ import '../../../skinned-sdk'; // Must be first for skinning to work import Adapter from "@wojtekmaj/enzyme-adapter-react-17"; import { configure, mount } from "enzyme"; import React from "react"; -import {act} from "react-dom/test-utils"; +import { act } from "react-dom/test-utils"; import SendMessageComposer, { createMessageContent, isQuickReaction, } from "../../../../src/components/views/rooms/SendMessageComposer"; import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; import EditorModel from "../../../../src/editor/model"; -import {createPartCreator, createRenderer} from "../../../editor/mock"; -import {createTestClient, mkEvent, mkStubRoom} from "../../../test-utils"; +import { createPartCreator, createRenderer } from "../../../editor/mock"; +import { createTestClient, mkEvent, mkStubRoom } from "../../../test-utils"; import BasicMessageComposer from "../../../../src/components/views/rooms/BasicMessageComposer"; -import {MatrixClientPeg} from "../../../../src/MatrixClientPeg"; -import {sleep} from "../../../../src/utils/promise"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; +import { sleep } from "../../../../src/utils/promise"; import SpecPermalinkConstructor from "../../../../src/utils/permalinks/SpecPermalinkConstructor"; import defaultDispatcher from "../../../../src/dispatcher/dispatcher"; @@ -43,7 +43,7 @@ describe('', () => { it("sends plaintext messages correctly", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("hello world", "insertText", {offset: 11, atNodeEnd: true}); + model.update("hello world", "insertText", { offset: 11, atNodeEnd: true }); const content = createMessageContent(model, permalinkCreator); @@ -55,7 +55,7 @@ describe('', () => { it("sends markdown messages correctly", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("hello *world*", "insertText", {offset: 13, atNodeEnd: true}); + model.update("hello *world*", "insertText", { offset: 13, atNodeEnd: true }); const content = createMessageContent(model, permalinkCreator); @@ -69,7 +69,7 @@ describe('', () => { it("strips /me from messages and marks them as m.emote accordingly", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("/me blinks __quickly__", "insertText", {offset: 22, atNodeEnd: true}); + model.update("/me blinks __quickly__", "insertText", { offset: 22, atNodeEnd: true }); const content = createMessageContent(model, permalinkCreator); @@ -83,7 +83,7 @@ describe('', () => { it("allows sending double-slash escaped slash commands correctly", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("//dev/null is my favourite place", "insertText", {offset: 32, atNodeEnd: true}); + model.update("//dev/null is my favourite place", "insertText", { offset: 32, atNodeEnd: true }); const content = createMessageContent(model, permalinkCreator); @@ -155,7 +155,7 @@ describe('', () => { // ensure the right state was persisted to localStorage wrapper.unmount(); expect(JSON.parse(localStorage.getItem(key))).toStrictEqual({ - parts: [{"type": "plain", "text": "Test Text"}], + parts: [{ "type": "plain", "text": "Test Text" }], replyEventId: mockEvent.getId(), }); @@ -196,7 +196,7 @@ describe('', () => { // ensure the right state was persisted to localStorage window.dispatchEvent(new Event('beforeunload')); expect(JSON.parse(localStorage.getItem(key))).toStrictEqual({ - parts: [{"type": "plain", "text": "Hello World"}], + parts: [{ "type": "plain", "text": "Hello World" }], }); }); @@ -225,7 +225,7 @@ describe('', () => { expect(wrapper.text()).toBe(""); const str = sessionStorage.getItem(`mx_cider_history_${mockRoom.roomId}[0]`); expect(JSON.parse(str)).toStrictEqual({ - parts: [{"type": "plain", "text": "This is a message"}], + parts: [{ "type": "plain", "text": "This is a message" }], replyEventId: mockEvent.getId(), }); }); @@ -234,7 +234,7 @@ describe('', () => { describe("isQuickReaction", () => { it("correctly detects quick reaction", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("+😊", "insertText", {offset: 3, atNodeEnd: true}); + model.update("+😊", "insertText", { offset: 3, atNodeEnd: true }); const isReaction = isQuickReaction(model); @@ -243,7 +243,7 @@ describe('', () => { it("correctly detects quick reaction with space", () => { const model = new EditorModel([], createPartCreator(), createRenderer()); - model.update("+ 😊", "insertText", {offset: 4, atNodeEnd: true}); + model.update("+ 😊", "insertText", { offset: 4, atNodeEnd: true }); const isReaction = isQuickReaction(model); @@ -255,10 +255,10 @@ describe('', () => { const model2 = new EditorModel([], createPartCreator(), createRenderer()); const model3 = new EditorModel([], createPartCreator(), createRenderer()); const model4 = new EditorModel([], createPartCreator(), createRenderer()); - model.update("+😊hello", "insertText", {offset: 8, atNodeEnd: true}); - model2.update(" +😊", "insertText", {offset: 4, atNodeEnd: true}); - model3.update("+ 😊😊", "insertText", {offset: 6, atNodeEnd: true}); - model4.update("+smiley", "insertText", {offset: 7, atNodeEnd: true}); + model.update("+😊hello", "insertText", { offset: 8, atNodeEnd: true }); + model2.update(" +😊", "insertText", { offset: 4, atNodeEnd: true }); + model3.update("+ 😊😊", "insertText", { offset: 6, atNodeEnd: true }); + model4.update("+smiley", "insertText", { offset: 7, atNodeEnd: true }); expect(isQuickReaction(model)).toBeFalsy(); expect(isQuickReaction(model2)).toBeFalsy(); @@ -268,4 +268,3 @@ describe('', () => { }); }); - diff --git a/test/createRoom-test.js b/test/createRoom-test.js index ed8f9779f7..b9b7e7df01 100644 --- a/test/createRoom-test.js +++ b/test/createRoom-test.js @@ -1,6 +1,6 @@ import './skinned-sdk'; // Must be first for skinning to work -import {_waitForMember, canEncryptToAllUsers} from '../src/createRoom'; -import {EventEmitter} from 'events'; +import { _waitForMember, canEncryptToAllUsers } from '../src/createRoom'; +import { EventEmitter } from 'events'; /* Shorter timeout, we've got tests to run */ const timeout = 30; @@ -61,10 +61,9 @@ describe("canEncryptToAllUsers", () => { done(); }); - it("returns false if not all users have crypto", async (done) => { const client = { - downloadKeys: async function(userIds) { return {...trueUser, ...falseUser}; }, + downloadKeys: async function(userIds) { return { ...trueUser, ...falseUser }; }, }; const response = await canEncryptToAllUsers(client, ["@goodUser:localhost", "@badUser:localhost"]); expect(response).toBe(false); diff --git a/test/editor/caret-test.js b/test/editor/caret-test.js index f0c171c7c9..e1a66a4431 100644 --- a/test/editor/caret-test.js +++ b/test/editor/caret-test.js @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {getLineAndNodePosition} from "../../src/editor/caret"; +import { getLineAndNodePosition } from "../../src/editor/caret"; import EditorModel from "../../src/editor/model"; -import {createPartCreator} from "./mock"; +import { createPartCreator } from "./mock"; describe('editor/caret: DOM position for caret', function() { describe('basic text handling', function() { @@ -25,8 +25,8 @@ describe('editor/caret: DOM position for caret', function() { const model = new EditorModel([ pc.plain("hello"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 5}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 5 }); expect(lineIndex).toBe(0); expect(nodeIndex).toBe(0); expect(offset).toBe(5); @@ -36,8 +36,8 @@ describe('editor/caret: DOM position for caret', function() { const model = new EditorModel([ pc.plain("hello"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 0 }); expect(lineIndex).toBe(0); expect(nodeIndex).toBe(0); expect(offset).toBe(0); @@ -47,8 +47,8 @@ describe('editor/caret: DOM position for caret', function() { const model = new EditorModel([ pc.plain("hello"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 2}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 2 }); expect(lineIndex).toBe(0); expect(nodeIndex).toBe(0); expect(offset).toBe(2); @@ -62,8 +62,8 @@ describe('editor/caret: DOM position for caret', function() { pc.newline(), pc.plain("world"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 2, offset: 5}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 2, offset: 5 }); expect(lineIndex).toBe(1); expect(nodeIndex).toBe(0); expect(offset).toBe(5); @@ -75,8 +75,8 @@ describe('editor/caret: DOM position for caret', function() { pc.newline(), pc.plain("world"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 2, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 2, offset: 0 }); expect(lineIndex).toBe(1); expect(nodeIndex).toBe(0); expect(offset).toBe(0); @@ -89,8 +89,8 @@ describe('editor/caret: DOM position for caret', function() { pc.newline(), pc.plain("world"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 1, offset: 1}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 1, offset: 1 }); expect(lineIndex).toBe(1); expect(nodeIndex).toBe(-1); expect(offset).toBe(0); @@ -103,8 +103,8 @@ describe('editor/caret: DOM position for caret', function() { pc.newline(), pc.plain("world"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 3, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 3, offset: 0 }); expect(lineIndex).toBe(2); expect(nodeIndex).toBe(0); expect(offset).toBe(0); @@ -118,8 +118,8 @@ describe('editor/caret: DOM position for caret', function() { pc.userPill("Alice", "@alice:hs.tld"), pc.plain("!"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 1, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 1, offset: 0 }); expect(lineIndex).toBe(0); expect(nodeIndex).toBe(0); expect(offset).toBe(5); @@ -131,8 +131,8 @@ describe('editor/caret: DOM position for caret', function() { pc.userPill("Alice", "@alice:hs.tld"), pc.plain("!"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 1, offset: 2}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 1, offset: 2 }); expect(lineIndex).toBe(0); expect(nodeIndex).toBe(2); expect(offset).toBe(0); @@ -142,8 +142,8 @@ describe('editor/caret: DOM position for caret', function() { const model = new EditorModel([ pc.userPill("Alice", "@alice:hs.tld"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 0 }); expect(lineIndex).toBe(0); //presumed nodes on line are (caret, pill, caret) expect(nodeIndex).toBe(0); @@ -154,8 +154,8 @@ describe('editor/caret: DOM position for caret', function() { const model = new EditorModel([ pc.userPill("Alice", "@alice:hs.tld"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 1}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 1 }); expect(lineIndex).toBe(0); //presumed nodes on line are (caret, pill, caret) expect(nodeIndex).toBe(2); @@ -167,8 +167,8 @@ describe('editor/caret: DOM position for caret', function() { pc.userPill("Alice", "@alice:hs.tld"), pc.userPill("Bob", "@bob:hs.tld"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 0, offset: 1}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 0, offset: 1 }); expect(lineIndex).toBe(0); //presumed nodes on line are (caret, pill, caret, pill, caret) expect(nodeIndex).toBe(2); @@ -180,8 +180,8 @@ describe('editor/caret: DOM position for caret', function() { pc.userPill("Alice", "@alice:hs.tld"), pc.userPill("Bob", "@bob:hs.tld"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 1, offset: 0}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 1, offset: 0 }); expect(lineIndex).toBe(0); //presumed nodes on line are (caret, pill, caret, pill, caret) expect(nodeIndex).toBe(2); @@ -193,8 +193,8 @@ describe('editor/caret: DOM position for caret', function() { pc.userPill("Alice", "@alice:hs.tld"), pc.userPill("Bob", "@bob:hs.tld"), ]); - const {offset, lineIndex, nodeIndex} = - getLineAndNodePosition(model, {index: 1, offset: 1}); + const { offset, lineIndex, nodeIndex } = + getLineAndNodePosition(model, { index: 1, offset: 1 }); expect(lineIndex).toBe(0); //presumed nodes on line are (caret, pill, caret, pill, caret) expect(nodeIndex).toBe(4); diff --git a/test/editor/deserialize-test.js b/test/editor/deserialize-test.js index 7c7a2f84fb..17e8a31780 100644 --- a/test/editor/deserialize-test.js +++ b/test/editor/deserialize-test.js @@ -15,8 +15,8 @@ limitations under the License. */ import '../skinned-sdk'; // Must be first for skinning to work -import {parseEvent} from "../../src/editor/deserialize"; -import {createPartCreator} from "./mock"; +import { parseEvent } from "../../src/editor/deserialize"; +import { createPartCreator } from "./mock"; function htmlMessage(formattedBody, msgtype = "m.text") { return { @@ -71,22 +71,22 @@ describe('editor/deserialize', function() { describe('text messages', function() { it('test with newlines', function() { const parts = normalize(parseEvent(textMessage("hello\nworld"), createPartCreator())); - expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "world"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "hello" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "world" }); expect(parts.length).toBe(3); }); it('@room pill', function() { const parts = normalize(parseEvent(textMessage("text message for @room"), createPartCreator())); expect(parts.length).toBe(2); - expect(parts[0]).toStrictEqual({type: "plain", text: "text message for "}); - expect(parts[1]).toStrictEqual({type: "at-room-pill", text: "@room"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "text message for " }); + expect(parts[1]).toStrictEqual({ type: "at-room-pill", text: "@room" }); }); it('emote', function() { const text = "says DON'T SHOUT!"; const parts = normalize(parseEvent(textMessage(text, "m.emote"), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "/me says DON'T SHOUT!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "/me says DON'T SHOUT!" }); }); }); describe('html messages', function() { @@ -94,159 +94,159 @@ describe('editor/deserialize', function() { const html = "bold and emphasized text"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "**bold** and _emphasized_ text"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "**bold** and _emphasized_ text" }); }); it('hyperlink', function() { const html = 'click this!'; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "click [this](http://example.com/)!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "click [this](http://example.com/)!" }); }); it('multiple lines with paragraphs', function() { const html = '

      hello

      world

      '; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(4); - expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[3]).toStrictEqual({type: "plain", text: "world"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "hello" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[3]).toStrictEqual({ type: "plain", text: "world" }); }); it('multiple lines with line breaks', function() { const html = 'hello
      world'; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "world"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "hello" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "world" }); }); it('multiple lines mixing paragraphs and line breaks', function() { const html = '

      hello
      warm

      world

      '; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(6); - expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "warm"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[5]).toStrictEqual({type: "plain", text: "world"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "hello" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "warm" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[5]).toStrictEqual({ type: "plain", text: "world" }); }); it('quote', function() { const html = '

      wise
      words

      indeed

      '; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(6); - expect(parts[0]).toStrictEqual({type: "plain", text: "> _wise_"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "> **words**"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[5]).toStrictEqual({type: "plain", text: "indeed"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "> _wise_" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "> **words**" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[5]).toStrictEqual({ type: "plain", text: "indeed" }); }); it('user pill', function() { const html = "Hi Alice!"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "Hi "}); - expect(parts[1]).toStrictEqual({type: "user-pill", text: "Alice", resourceId: "@alice:hs.tld"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "Hi " }); + expect(parts[1]).toStrictEqual({ type: "user-pill", text: "Alice", resourceId: "@alice:hs.tld" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "!" }); }); it('user pill with displayname containing backslash', function() { const html = "Hi Alice\\!"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "Hi "}); - expect(parts[1]).toStrictEqual({type: "user-pill", text: "Alice\\", resourceId: "@alice:hs.tld"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "Hi " }); + expect(parts[1]).toStrictEqual({ type: "user-pill", text: "Alice\\", resourceId: "@alice:hs.tld" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "!" }); }); it('user pill with displayname containing opening square bracket', function() { const html = "Hi Alice[[!"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "Hi "}); - expect(parts[1]).toStrictEqual({type: "user-pill", text: "Alice[[", resourceId: "@alice:hs.tld"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "Hi " }); + expect(parts[1]).toStrictEqual({ type: "user-pill", text: "Alice[[", resourceId: "@alice:hs.tld" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "!" }); }); it('user pill with displayname containing closing square bracket', function() { const html = "Hi Alice]!"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "Hi "}); - expect(parts[1]).toStrictEqual({type: "user-pill", text: "Alice]", resourceId: "@alice:hs.tld"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "Hi " }); + expect(parts[1]).toStrictEqual({ type: "user-pill", text: "Alice]", resourceId: "@alice:hs.tld" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "!" }); }); it('room pill', function() { const html = "Try #room:hs.tld?"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(3); - expect(parts[0]).toStrictEqual({type: "plain", text: "Try "}); - expect(parts[1]).toStrictEqual({type: "room-pill", text: "#room:hs.tld", resourceId: "#room:hs.tld"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "?"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "Try " }); + expect(parts[1]).toStrictEqual({ type: "room-pill", text: "#room:hs.tld", resourceId: "#room:hs.tld" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "?" }); }); it('@room pill', function() { const html = "formatted message for @room"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(2); - expect(parts[0]).toStrictEqual({type: "plain", text: "_formatted_ message for "}); - expect(parts[1]).toStrictEqual({type: "at-room-pill", text: "@room"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "_formatted_ message for " }); + expect(parts[1]).toStrictEqual({ type: "at-room-pill", text: "@room" }); }); it('inline code', function() { const html = "there is no place like 127.0.0.1!"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "there is no place like `127.0.0.1`!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "there is no place like `127.0.0.1`!" }); }); it('code block with no trailing text', function() { const html = "
      0xDEADBEEF\n
      \n"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); console.log(parts); expect(parts.length).toBe(5); - expect(parts[0]).toStrictEqual({type: "plain", text: "```"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "0xDEADBEEF"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "plain", text: "```"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "```" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "0xDEADBEEF" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: "```" }); }); // failing likely because of https://github.com/vector-im/element-web/issues/10316 xit('code block with no trailing text and no newlines', function() { const html = "
      0xDEADBEEF
      "; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(5); - expect(parts[0]).toStrictEqual({type: "plain", text: "```"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "0xDEADBEEF"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "plain", text: "```"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "```" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "0xDEADBEEF" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: "```" }); }); it('unordered lists', function() { const html = "
      • Oak
      • Spruce
      • Birch
      "; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(5); - expect(parts[0]).toStrictEqual({type: "plain", text: "- Oak"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "- Spruce"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "plain", text: "- Birch"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "- Oak" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "- Spruce" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: "- Birch" }); }); it('ordered lists', function() { const html = "
      1. Start
      2. Continue
      3. Finish
      "; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(5); - expect(parts[0]).toStrictEqual({type: "plain", text: "1. Start"}); - expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[2]).toStrictEqual({type: "plain", text: "2. Continue"}); - expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); - expect(parts[4]).toStrictEqual({type: "plain", text: "3. Finish"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "1. Start" }); + expect(parts[1]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[2]).toStrictEqual({ type: "plain", text: "2. Continue" }); + expect(parts[3]).toStrictEqual({ type: "newline", text: "\n" }); + expect(parts[4]).toStrictEqual({ type: "plain", text: "3. Finish" }); }); it('mx-reply is stripped', function() { const html = "foobar"; const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "bar"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "bar" }); }); it('emote', function() { const html = "says DON'T SHOUT!"; const parts = normalize(parseEvent(htmlMessage(html, "m.emote"), createPartCreator())); expect(parts.length).toBe(1); - expect(parts[0]).toStrictEqual({type: "plain", text: "/me says _DON'T SHOUT_!"}); + expect(parts[0]).toStrictEqual({ type: "plain", text: "/me says _DON'T SHOUT_!" }); }); }); }); diff --git a/test/editor/diff-test.js b/test/editor/diff-test.js index 4637206b27..e525731340 100644 --- a/test/editor/diff-test.js +++ b/test/editor/diff-test.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {diffDeletion, diffAtCaret} from "../../src/editor/diff"; +import { diffDeletion, diffAtCaret } from "../../src/editor/diff"; describe('editor/diff', function() { describe('diffDeletion', function() { diff --git a/test/editor/history-test.js b/test/editor/history-test.js index e54c1e7ea9..e3ae3e16f6 100644 --- a/test/editor/history-test.js +++ b/test/editor/history-test.js @@ -14,13 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import HistoryManager, {MAX_STEP_LENGTH} from "../../src/editor/history"; +import HistoryManager, { MAX_STEP_LENGTH } from "../../src/editor/history"; describe('editor/history', function() { it('push, then undo', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; const caret1 = {}; const result1 = history.tryPush(model, caret1); expect(result1).toEqual(true); @@ -35,7 +35,7 @@ describe('editor/history', function() { it('push, undo, then redo', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; history.tryPush(model, {}); parts[0] = "hello world"; const caret2 = {}; @@ -51,7 +51,7 @@ describe('editor/history', function() { it('push, undo, push, ensure you can`t redo', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; history.tryPush(model, {}); parts[0] = "hello world"; history.tryPush(model, {}); @@ -63,10 +63,10 @@ describe('editor/history', function() { it('not every keystroke stores a history step', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; const firstCaret = {}; history.tryPush(model, firstCaret); - const diff = {added: "o"}; + const diff = { added: "o" }; let keystrokeCount = 0; do { parts[0] = parts[0] + diff.added; @@ -80,24 +80,24 @@ describe('editor/history', function() { }); it('history step is added at word boundary', function() { const history = new HistoryManager(); - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; const parts = ["h"]; - let diff = {added: "h"}; + let diff = { added: "h" }; expect(history.tryPush(model, {}, "insertText", diff)).toEqual(false); - diff = {added: "i"}; + diff = { added: "i" }; parts[0] = "hi"; expect(history.tryPush(model, {}, "insertText", diff)).toEqual(false); - diff = {added: " "}; + diff = { added: " " }; parts[0] = "hi "; const spaceCaret = {}; expect(history.tryPush(model, spaceCaret, "insertText", diff)).toEqual(true); - diff = {added: "y"}; + diff = { added: "y" }; parts[0] = "hi y"; expect(history.tryPush(model, {}, "insertText", diff)).toEqual(false); - diff = {added: "o"}; + diff = { added: "o" }; parts[0] = "hi yo"; expect(history.tryPush(model, {}, "insertText", diff)).toEqual(false); - diff = {added: "u"}; + diff = { added: "u" }; parts[0] = "hi you"; expect(history.canUndo()).toEqual(true); @@ -108,11 +108,11 @@ describe('editor/history', function() { it('keystroke that didn\'t add a step can undo', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; const firstCaret = {}; history.tryPush(model, {}); parts[0] = "helloo"; - const result = history.tryPush(model, {}, "insertText", {added: "o"}); + const result = history.tryPush(model, {}, "insertText", { added: "o" }); expect(result).toEqual(false); expect(history.canUndo()).toEqual(true); const undoState = history.undo(model); @@ -122,11 +122,11 @@ describe('editor/history', function() { it('undo after keystroke that didn\'t add a step is able to redo', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; history.tryPush(model, {}); parts[0] = "helloo"; - const caret = {last: true}; - history.tryPush(model, caret, "insertText", {added: "o"}); + const caret = { last: true }; + history.tryPush(model, caret, "insertText", { added: "o" }); history.undo(model); expect(history.canRedo()).toEqual(true); const redoState = history.redo(); @@ -136,10 +136,10 @@ describe('editor/history', function() { it('overwriting text always stores a step', function() { const history = new HistoryManager(); const parts = ["hello"]; - const model = {serializeParts: () => parts.slice()}; + const model = { serializeParts: () => parts.slice() }; const firstCaret = {}; history.tryPush(model, firstCaret); - const diff = {at: 1, added: "a", removed: "e"}; + const diff = { at: 1, added: "a", removed: "e" }; const result = history.tryPush(model, {}, "insertText", diff); expect(result).toEqual(true); }); diff --git a/test/editor/mock.js b/test/editor/mock.js index 6de65cf23d..2d82d22033 100644 --- a/test/editor/mock.js +++ b/test/editor/mock.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {PartCreator} from "../../src/editor/parts"; +import { PartCreator } from "../../src/editor/parts"; class MockAutoComplete { constructor(updateCallback, partCreator, completions) { @@ -25,7 +25,7 @@ class MockAutoComplete { } close() { - this._updateCallback({close: true}); + this._updateCallback({ close: true }); } tryComplete(close = true) { @@ -40,7 +40,7 @@ class MockAutoComplete { } else { pill = this._partCreator.roomPill(match.resourceId); } - this._updateCallback({replaceParts: [pill], close}); + this._updateCallback({ replaceParts: [pill], close }); } } diff --git a/test/editor/model-test.js b/test/editor/model-test.js index 2df9fdd573..35bd4143a7 100644 --- a/test/editor/model-test.js +++ b/test/editor/model-test.js @@ -15,14 +15,14 @@ limitations under the License. */ import EditorModel from "../../src/editor/model"; -import {createPartCreator, createRenderer} from "./mock"; +import { createPartCreator, createRenderer } from "./mock"; describe('editor/model', function() { describe('plain text manipulation', function() { it('insert text into empty document', function() { const renderer = createRenderer(); const model = new EditorModel([], createPartCreator(), renderer); - model.update("hello", "insertText", {offset: 5, atNodeEnd: true}); + model.update("hello", "insertText", { offset: 5, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(0); expect(renderer.caret.offset).toBe(5); @@ -34,7 +34,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.plain("hello")], pc, renderer); - model.update("hello world", "insertText", {offset: 11, atNodeEnd: true}); + model.update("hello world", "insertText", { offset: 11, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(0); expect(renderer.caret.offset).toBe(11); @@ -46,7 +46,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.plain("world")], pc, renderer); - model.update("hello world", "insertText", {offset: 6, atNodeEnd: false}); + model.update("hello world", "insertText", { offset: 6, atNodeEnd: false }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(0); expect(renderer.caret.offset).toBe(6); @@ -60,7 +60,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.plain("hello")], pc, renderer); - model.update("hello\n", "insertText", {offset: 6, atNodeEnd: true}); + model.update("hello\n", "insertText", { offset: 6, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(1); expect(renderer.caret.offset).toBe(1); @@ -74,7 +74,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.plain("hello")], pc, renderer); - model.update("hello\n\n\nworld!", "insertText", {offset: 14, atNodeEnd: true}); + model.update("hello\n\n\nworld!", "insertText", { offset: 14, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(4); expect(renderer.caret.offset).toBe(6); @@ -99,7 +99,7 @@ describe('editor/model', function() { pc.newline(), pc.plain("world"), ], pc, renderer); - model.update("hello\nwarm\nworld", "insertText", {offset: 10, atNodeEnd: true}); + model.update("hello\nwarm\nworld", "insertText", { offset: 10, atNodeEnd: true }); console.log(model.serializeParts()); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(2); @@ -125,7 +125,7 @@ describe('editor/model', function() { pc.plain("try "), pc.roomPill("#someroom"), ], pc, renderer); - model.update("try foo#someroom", "insertText", {offset: 7, atNodeEnd: false}); + model.update("try foo#someroom", "insertText", { offset: 7, atNodeEnd: false }); expect(renderer.caret.index).toBe(0); expect(renderer.caret.offset).toBe(7); expect(model.parts.length).toBe(2); @@ -142,7 +142,7 @@ describe('editor/model', function() { pc.roomPill("#someroom"), pc.plain("?"), ], pc, renderer); - model.update("try #some perhapsroom?", "insertText", {offset: 17, atNodeEnd: false}); + model.update("try #some perhapsroom?", "insertText", { offset: 17, atNodeEnd: false }); expect(renderer.caret.index).toBe(2); expect(renderer.caret.offset).toBe(8); expect(model.parts.length).toBe(3); @@ -157,7 +157,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.roomPill("#someroom")], pc, renderer); - model.update("#someroo", "deleteContentBackward", {offset: 8, atNodeEnd: true}); + model.update("#someroo", "deleteContentBackward", { offset: 8, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(-1); expect(renderer.caret.offset).toBe(0); @@ -167,7 +167,7 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([pc.roomPill("#someroom")], pc, renderer); - model.update("someroom", "deleteContentForward", {offset: 0, atNodeEnd: false}); + model.update("someroom", "deleteContentForward", { offset: 0, atNodeEnd: false }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(-1); expect(renderer.caret.offset).toBe(0); @@ -177,10 +177,10 @@ describe('editor/model', function() { describe('auto-complete', function() { it('insert user pill', function() { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "@alice", label: "Alice"}]); + const pc = createPartCreator([{ resourceId: "@alice", label: "Alice" }]); const model = new EditorModel([pc.plain("hello ")], pc, renderer); - model.update("hello @a", "insertText", {offset: 8, atNodeEnd: true}); + model.update("hello @a", "insertText", { offset: 8, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(1); @@ -205,10 +205,10 @@ describe('editor/model', function() { it('insert room pill', function() { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "#riot-dev"}]); + const pc = createPartCreator([{ resourceId: "#riot-dev" }]); const model = new EditorModel([pc.plain("hello ")], pc, renderer); - model.update("hello #r", "insertText", {offset: 8, atNodeEnd: true}); + model.update("hello #r", "insertText", { offset: 8, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(renderer.caret.index).toBe(1); @@ -233,12 +233,12 @@ describe('editor/model', function() { it('type after inserting pill', function() { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "#riot-dev"}]); + const pc = createPartCreator([{ resourceId: "#riot-dev" }]); const model = new EditorModel([pc.plain("hello ")], pc, renderer); - model.update("hello #r", "insertText", {offset: 8, atNodeEnd: true}); + model.update("hello #r", "insertText", { offset: 8, atNodeEnd: true }); model.autoComplete.tryComplete(); // see MockAutoComplete - model.update("hello #riot-dev!!", "insertText", {offset: 17, atNodeEnd: true}); + model.update("hello #riot-dev!!", "insertText", { offset: 17, atNodeEnd: true }); expect(renderer.count).toBe(3); expect(renderer.caret.index).toBe(2); @@ -254,10 +254,10 @@ describe('editor/model', function() { it('pasting text does not trigger auto-complete', function() { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "#define-room"}]); + const pc = createPartCreator([{ resourceId: "#define-room" }]); const model = new EditorModel([pc.plain("try ")], pc, renderer); - model.update("try #define", "insertFromPaste", {offset: 11, atNodeEnd: true}); + model.update("try #define", "insertFromPaste", { offset: 11, atNodeEnd: true }); expect(model.autoComplete).toBeFalsy(); expect(renderer.caret.index).toBe(0); @@ -269,10 +269,10 @@ describe('editor/model', function() { it('dropping text does not trigger auto-complete', function() { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "#define-room"}]); + const pc = createPartCreator([{ resourceId: "#define-room" }]); const model = new EditorModel([pc.plain("try ")], pc, renderer); - model.update("try #define", "insertFromDrop", {offset: 11, atNodeEnd: true}); + model.update("try #define", "insertFromDrop", { offset: 11, atNodeEnd: true }); expect(model.autoComplete).toBeFalsy(); expect(renderer.caret.index).toBe(0); @@ -284,17 +284,17 @@ describe('editor/model', function() { it('insert room pill without splitting at the colon', () => { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "#room:server"}]); + const pc = createPartCreator([{ resourceId: "#room:server" }]); const model = new EditorModel([], pc, renderer); - model.update("#roo", "insertText", {offset: 4, atNodeEnd: true}); + model.update("#roo", "insertText", { offset: 4, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(model.parts.length).toBe(1); expect(model.parts[0].type).toBe("pill-candidate"); expect(model.parts[0].text).toBe("#roo"); - model.update("#room:s", "insertText", {offset: 7, atNodeEnd: true}); + model.update("#room:s", "insertText", { offset: 7, atNodeEnd: true }); expect(renderer.count).toBe(2); expect(model.parts.length).toBe(1); @@ -304,10 +304,10 @@ describe('editor/model', function() { it('allow typing e-mail addresses without splitting at the @', () => { const renderer = createRenderer(); - const pc = createPartCreator([{resourceId: "@alice", label: "Alice"}]); + const pc = createPartCreator([{ resourceId: "@alice", label: "Alice" }]); const model = new EditorModel([], pc, renderer); - model.update("foo@a", "insertText", {offset: 5, atNodeEnd: true}); + model.update("foo@a", "insertText", { offset: 5, atNodeEnd: true }); expect(renderer.count).toBe(1); expect(model.parts.length).toBe(1); diff --git a/test/editor/operations-test.js b/test/editor/operations-test.js index 90a9812306..32ccaa5440 100644 --- a/test/editor/operations-test.js +++ b/test/editor/operations-test.js @@ -15,10 +15,10 @@ limitations under the License. */ import EditorModel from "../../src/editor/model"; -import {createPartCreator, createRenderer} from "./mock"; -import {toggleInlineFormat} from "../../src/editor/operations"; +import { createPartCreator, createRenderer } from "./mock"; +import { toggleInlineFormat } from "../../src/editor/operations"; -const SERIALIZED_NEWLINE = {"text": "\n", "type": "newline"}; +const SERIALIZED_NEWLINE = { "text": "\n", "type": "newline" }; describe('editor/operations: formatting operations', () => { describe('toggleInlineFormat', () => { @@ -33,9 +33,9 @@ describe('editor/operations: formatting operations', () => { model.positionForOffset(11, false)); // around "world" expect(range.parts[0].text).toBe("world"); - expect(model.serializeParts()).toEqual([{"text": "hello world!", "type": "plain"}]); + expect(model.serializeParts()).toEqual([{ "text": "hello world!", "type": "plain" }]); toggleInlineFormat(range, "_"); - expect(model.serializeParts()).toEqual([{"text": "hello _world_!", "type": "plain"}]); + expect(model.serializeParts()).toEqual([{ "text": "hello _world_!", "type": "plain" }]); }); it('works for parts of words', () => { @@ -49,9 +49,9 @@ describe('editor/operations: formatting operations', () => { model.positionForOffset(10, false)); // around "orl" expect(range.parts[0].text).toBe("orl"); - expect(model.serializeParts()).toEqual([{"text": "hello world!", "type": "plain"}]); + expect(model.serializeParts()).toEqual([{ "text": "hello world!", "type": "plain" }]); toggleInlineFormat(range, "*"); - expect(model.serializeParts()).toEqual([{"text": "hello w*orl*d!", "type": "plain"}]); + expect(model.serializeParts()).toEqual([{ "text": "hello w*orl*d!", "type": "plain" }]); }); it('works for around pills', () => { @@ -68,15 +68,15 @@ describe('editor/operations: formatting operations', () => { expect(range.parts.map(p => p.text).join("")).toBe("there @room, how are you"); expect(model.serializeParts()).toEqual([ - {"text": "hello there ", "type": "plain"}, - {"text": "@room", "type": "at-room-pill"}, - {"text": ", how are you doing?", "type": "plain"}, + { "text": "hello there ", "type": "plain" }, + { "text": "@room", "type": "at-room-pill" }, + { "text": ", how are you doing?", "type": "plain" }, ]); toggleInlineFormat(range, "_"); expect(model.serializeParts()).toEqual([ - {"text": "hello _there ", "type": "plain"}, - {"text": "@room", "type": "at-room-pill"}, - {"text": ", how are you_ doing?", "type": "plain"}, + { "text": "hello _there ", "type": "plain" }, + { "text": "@room", "type": "at-room-pill" }, + { "text": ", how are you_ doing?", "type": "plain" }, ]); }); @@ -94,15 +94,15 @@ describe('editor/operations: formatting operations', () => { expect(range.parts.map(p => p.text).join("")).toBe("world,\nhow"); expect(model.serializeParts()).toEqual([ - {"text": "hello world,", "type": "plain"}, + { "text": "hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?", "type": "plain"}, + { "text": "how are you doing?", "type": "plain" }, ]); toggleInlineFormat(range, "**"); expect(model.serializeParts()).toEqual([ - {"text": "hello **world,", "type": "plain"}, + { "text": "hello **world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how** are you doing?", "type": "plain"}, + { "text": "how** are you doing?", "type": "plain" }, ]); }); @@ -125,9 +125,9 @@ describe('editor/operations: formatting operations', () => { expect(model.serializeParts()).toEqual([ SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, - {"text": "hello world,", "type": "plain"}, + { "text": "hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?", "type": "plain"}, + { "text": "how are you doing?", "type": "plain" }, SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, ]); @@ -135,9 +135,9 @@ describe('editor/operations: formatting operations', () => { expect(model.serializeParts()).toEqual([ SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, - {"text": "**hello world,", "type": "plain"}, + { "text": "**hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?**", "type": "plain"}, + { "text": "how are you doing?**", "type": "plain" }, SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, ]); @@ -158,32 +158,32 @@ describe('editor/operations: formatting operations', () => { let range = model.startRange(model.positionForOffset(0, true), model.getPositionAtEnd()); // select-all expect(model.serializeParts()).toEqual([ - {"text": "hello world,", "type": "plain"}, + { "text": "hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?", "type": "plain"}, + { "text": "how are you doing?", "type": "plain" }, SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, - {"text": "new paragraph", "type": "plain"}, + { "text": "new paragraph", "type": "plain" }, ]); toggleInlineFormat(range, "__"); expect(model.serializeParts()).toEqual([ - {"text": "__hello world,", "type": "plain"}, + { "text": "__hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?__", "type": "plain"}, + { "text": "how are you doing?__", "type": "plain" }, SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, - {"text": "__new paragraph__", "type": "plain"}, + { "text": "__new paragraph__", "type": "plain" }, ]); range = model.startRange(model.positionForOffset(0, true), model.getPositionAtEnd()); // select-all console.log("RANGE", range.parts); toggleInlineFormat(range, "__"); expect(model.serializeParts()).toEqual([ - {"text": "hello world,", "type": "plain"}, + { "text": "hello world,", "type": "plain" }, SERIALIZED_NEWLINE, - {"text": "how are you doing?", "type": "plain"}, + { "text": "how are you doing?", "type": "plain" }, SERIALIZED_NEWLINE, SERIALIZED_NEWLINE, - {"text": "new paragraph", "type": "plain"}, + { "text": "new paragraph", "type": "plain" }, ]); }); }); diff --git a/test/editor/position-test.js b/test/editor/position-test.js index 90f40c21a7..813a8e9f7f 100644 --- a/test/editor/position-test.js +++ b/test/editor/position-test.js @@ -15,7 +15,7 @@ limitations under the License. */ import EditorModel from "../../src/editor/model"; -import {createPartCreator} from "./mock"; +import { createPartCreator } from "./mock"; function createRenderer() { const render = (c) => { diff --git a/test/editor/range-test.js b/test/editor/range-test.js index 60055af824..d411a0d911 100644 --- a/test/editor/range-test.js +++ b/test/editor/range-test.js @@ -15,7 +15,7 @@ limitations under the License. */ import EditorModel from "../../src/editor/model"; -import {createPartCreator, createRenderer} from "./mock"; +import { createPartCreator, createRenderer } from "./mock"; const pillChannel = "#riot-dev:matrix.org"; diff --git a/test/editor/serialize-test.js b/test/editor/serialize-test.js index f0d577ea21..691130bd34 100644 --- a/test/editor/serialize-test.js +++ b/test/editor/serialize-test.js @@ -15,8 +15,8 @@ limitations under the License. */ import EditorModel from "../../src/editor/model"; -import {htmlSerializeIfNeeded} from "../../src/editor/serialize"; -import {createPartCreator} from "./mock"; +import { htmlSerializeIfNeeded } from "../../src/editor/serialize"; +import { createPartCreator } from "./mock"; describe('editor/serialize', function() { it('user pill turns message into html', function() { diff --git a/test/end-to-end-tests/src/rest/consent.js b/test/end-to-end-tests/src/rest/consent.js index 956441571b..8be27258d0 100644 --- a/test/end-to-end-tests/src/rest/consent.js +++ b/test/end-to-end-tests/src/rest/consent.js @@ -27,5 +27,5 @@ module.exports.approveConsent = async function(consentUrl) { const h = doc("input[name=h]").val(); const formAction = doc("form").attr("action"); const absAction = url.resolve(consentUrl, formAction); - await request.post(absAction).form({v, u, h}); + await request.post(absAction).form({ v, u, h }); }; diff --git a/test/end-to-end-tests/src/rest/creator.js b/test/end-to-end-tests/src/rest/creator.js index 03b2e099bc..f01a325a71 100644 --- a/test/end-to-end-tests/src/rest/creator.js +++ b/test/end-to-end-tests/src/rest/creator.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {exec} = require('child_process'); +const { exec } = require('child_process'); const request = require('request-promise-native'); const RestSession = require('./session'); const RestMultiSession = require('./multi'); @@ -26,7 +26,7 @@ function execAsync(command, options) { if (error) { reject(error); } else { - resolve({stdout, stderr}); + resolve({ stdout, stderr }); } }); }); @@ -67,7 +67,7 @@ module.exports = class RestSessionCreator { registerCmd, ].join(' && '); - await execAsync(allCmds, {cwd: this.cwd, encoding: 'utf-8'}); + await execAsync(allCmds, { cwd: this.cwd, encoding: 'utf-8' }); } async _authenticate(username, password) { @@ -80,7 +80,7 @@ module.exports = class RestSessionCreator { "password": password, }; const url = `${this.hsUrl}/_matrix/client/r0/login`; - const responseBody = await request.post({url, json: true, body: requestBody}); + const responseBody = await request.post({ url, json: true, body: requestBody }); return { accessToken: responseBody.access_token, homeServer: responseBody.home_server, diff --git a/test/end-to-end-tests/src/rest/session.js b/test/end-to-end-tests/src/rest/session.js index 5b97824f5c..3c04592d02 100644 --- a/test/end-to-end-tests/src/rest/session.js +++ b/test/end-to-end-tests/src/rest/session.js @@ -17,7 +17,7 @@ limitations under the License. const request = require('request-promise-native'); const Logger = require('../logger'); const RestRoom = require('./room'); -const {approveConsent} = require('./consent'); +const { approveConsent } = require('./consent'); module.exports = class RestSession { constructor(credentials) { diff --git a/test/end-to-end-tests/src/scenario.js b/test/end-to-end-tests/src/scenario.js index 2191d630ac..c44f209bf3 100644 --- a/test/end-to-end-tests/src/scenario.js +++ b/test/end-to-end-tests/src/scenario.js @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ - -const {range} = require('./util'); +const { range } = require('./util'); const signup = require('./usecases/signup'); const toastScenarios = require('./scenarios/toast'); const roomDirectoryScenarios = require('./scenarios/directory'); diff --git a/test/end-to-end-tests/src/scenarios/directory.js b/test/end-to-end-tests/src/scenarios/directory.js index b5be9ed4f4..53b790c174 100644 --- a/test/end-to-end-tests/src/scenarios/directory.js +++ b/test/end-to-end-tests/src/scenarios/directory.js @@ -15,23 +15,22 @@ See the License for the specific language governing permissions and limitations under the License. */ - const join = require('../usecases/join'); const sendMessage = require('../usecases/send-message'); -const {receiveMessage} = require('../usecases/timeline'); -const {createRoom} = require('../usecases/create-room'); -const {changeRoomSettings} = require('../usecases/room-settings'); +const { receiveMessage } = require('../usecases/timeline'); +const { createRoom } = require('../usecases/create-room'); +const { changeRoomSettings } = require('../usecases/room-settings'); module.exports = async function roomDirectoryScenarios(alice, bob) { console.log(" creating a public room and join through directory:"); const room = 'test'; await createRoom(alice, room); - await changeRoomSettings(alice, {directory: true, visibility: "public_no_guests", alias: "#test"}); + await changeRoomSettings(alice, { directory: true, visibility: "public_no_guests", alias: "#test" }); await join(bob, room); //looks up room in directory const bobMessage = "hi Alice!"; await sendMessage(bob, bobMessage); - await receiveMessage(alice, {sender: "bob", body: bobMessage}); + await receiveMessage(alice, { sender: "bob", body: bobMessage }); const aliceMessage = "hi Bob, welcome!"; await sendMessage(alice, aliceMessage); - await receiveMessage(bob, {sender: "alice", body: aliceMessage}); + await receiveMessage(bob, { sender: "alice", body: aliceMessage }); }; diff --git a/test/end-to-end-tests/src/scenarios/e2e-encryption.js b/test/end-to-end-tests/src/scenarios/e2e-encryption.js index b20874fdaf..23234b85ce 100644 --- a/test/end-to-end-tests/src/scenarios/e2e-encryption.js +++ b/test/end-to-end-tests/src/scenarios/e2e-encryption.js @@ -17,19 +17,18 @@ limitations under the License. const sendMessage = require('../usecases/send-message'); const acceptInvite = require('../usecases/accept-invite'); -const {receiveMessage} = require('../usecases/timeline'); -const {createDm} = require('../usecases/create-room'); -const {checkRoomSettings} = require('../usecases/room-settings'); -const {startSasVerification, acceptSasVerification} = require('../usecases/verify'); +const { receiveMessage } = require('../usecases/timeline'); +const { createDm } = require('../usecases/create-room'); +const { checkRoomSettings } = require('../usecases/room-settings'); +const { startSasVerification, acceptSasVerification } = require('../usecases/verify'); const { setupSecureBackup } = require('../usecases/security'); const assert = require('assert'); const { measureStart, measureStop } = require('../util'); - module.exports = async function e2eEncryptionScenarios(alice, bob) { console.log(" creating an e2e encrypted DM and join through invite:"); await createDm(bob, ['@alice:localhost']); - await checkRoomSettings(bob, {encryption: true}); // for sanity, should be e2e-by-default + await checkRoomSettings(bob, { encryption: true }); // for sanity, should be e2e-by-default await acceptInvite(alice, 'bob'); // do sas verifcation bob.log.step(`starts SAS verification with ${alice.username}`); @@ -44,9 +43,9 @@ module.exports = async function e2eEncryptionScenarios(alice, bob) { bob.log.done(`done (match for ${bobSas.join(", ")})`); const aliceMessage = "Guess what I just heard?!"; await sendMessage(alice, aliceMessage); - await receiveMessage(bob, {sender: "alice", body: aliceMessage, encrypted: true}); + await receiveMessage(bob, { sender: "alice", body: aliceMessage, encrypted: true }); const bobMessage = "You've got to tell me!"; await sendMessage(bob, bobMessage); - await receiveMessage(alice, {sender: "bob", body: bobMessage, encrypted: true}); + await receiveMessage(alice, { sender: "bob", body: bobMessage, encrypted: true }); await setupSecureBackup(alice); }; diff --git a/test/end-to-end-tests/src/scenarios/lazy-loading.js b/test/end-to-end-tests/src/scenarios/lazy-loading.js index 6d321dc737..1b5d449af9 100644 --- a/test/end-to-end-tests/src/scenarios/lazy-loading.js +++ b/test/end-to-end-tests/src/scenarios/lazy-loading.js @@ -15,17 +15,16 @@ See the License for the specific language governing permissions and limitations under the License. */ - -const {delay} = require('../util'); +const { delay } = require('../util'); const join = require('../usecases/join'); const sendMessage = require('../usecases/send-message'); const { checkTimelineContains, scrollToTimelineTop, } = require('../usecases/timeline'); -const {createRoom} = require('../usecases/create-room'); -const {getMembersInMemberlist} = require('../usecases/memberlist'); -const {changeRoomSettings} = require('../usecases/room-settings'); +const { createRoom } = require('../usecases/create-room'); +const { getMembersInMemberlist } = require('../usecases/memberlist'); +const { changeRoomSettings } = require('../usecases/room-settings'); const assert = require('assert'); module.exports = async function lazyLoadingScenarios(alice, bob, charlies) { @@ -52,7 +51,7 @@ const charlyMsg2 = "how's it going??"; async function setupRoomWithBobAliceAndCharlies(alice, bob, charlies) { await createRoom(bob, room); - await changeRoomSettings(bob, {directory: true, visibility: "public_no_guests", alias}); + await changeRoomSettings(bob, { directory: true, visibility: "public_no_guests", alias }); // wait for alias to be set by server after clicking "save" // so the charlies can join it. await bob.delay(500); diff --git a/test/end-to-end-tests/src/scenarios/toast.js b/test/end-to-end-tests/src/scenarios/toast.js index 8b23dbcabc..40b480c3fa 100644 --- a/test/end-to-end-tests/src/scenarios/toast.js +++ b/test/end-to-end-tests/src/scenarios/toast.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {assertNoToasts, acceptToast, rejectToast} = require("../usecases/toasts"); +const { assertNoToasts, acceptToast, rejectToast } = require("../usecases/toasts"); module.exports = async function toastScenarios(alice, bob) { console.log(" checking and clearing toasts:"); diff --git a/test/end-to-end-tests/src/session.js b/test/end-to-end-tests/src/session.js index 6c68929a0b..f5d20fde28 100644 --- a/test/end-to-end-tests/src/session.js +++ b/test/end-to-end-tests/src/session.js @@ -18,7 +18,7 @@ limitations under the License. const puppeteer = require('puppeteer'); const Logger = require('./logger'); const LogBuffer = require('./logbuffer'); -const {delay} = require('./util'); +const { delay } = require('./util'); const DEFAULT_TIMEOUT = 20000; @@ -112,7 +112,7 @@ module.exports = class ElementSession { async replaceInputText(input, text) { // click 3 times to select all text - await input.click({clickCount: 3}); + await input.click({ clickCount: 3 }); // waiting here solves not having selected all the text by the 3x click above, // presumably because of the Field label animation. await this.delay(300); @@ -123,7 +123,7 @@ module.exports = class ElementSession { } query(selector, timeout = DEFAULT_TIMEOUT, hidden = false) { - return this.page.waitForSelector(selector, {visible: true, timeout, hidden}); + return this.page.waitForSelector(selector, { visible: true, timeout, hidden }); } async queryAll(selector) { diff --git a/test/end-to-end-tests/src/usecases/accept-invite.js b/test/end-to-end-tests/src/usecases/accept-invite.js index d7c024ac4b..50d685dc74 100644 --- a/test/end-to-end-tests/src/usecases/accept-invite.js +++ b/test/end-to-end-tests/src/usecases/accept-invite.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {findSublist} = require("./create-room"); +const { findSublist } = require("./create-room"); module.exports = async function acceptInvite(session, name) { session.log.step(`accepts "${name}" invite`); @@ -23,9 +23,9 @@ module.exports = async function acceptInvite(session, name) { const invitesHandles = await inviteSublist.$$(".mx_RoomTile_name"); const invitesWithText = await Promise.all(invitesHandles.map(async (inviteHandle) => { const text = await session.innerText(inviteHandle); - return {inviteHandle, text}; + return { inviteHandle, text }; })); - const inviteHandle = invitesWithText.find(({inviteHandle, text}) => { + const inviteHandle = invitesWithText.find(({ inviteHandle, text }) => { return text.trim() === name; }).inviteHandle; diff --git a/test/end-to-end-tests/src/usecases/create-room.js b/test/end-to-end-tests/src/usecases/create-room.js index 36b9ed21ec..b644ad0309 100644 --- a/test/end-to-end-tests/src/usecases/create-room.js +++ b/test/end-to-end-tests/src/usecases/create-room.js @@ -84,4 +84,4 @@ async function createDm(session, invitees) { await measureStop(session, "mx_CreateDM"); } -module.exports = {openRoomDirectory, findSublist, createRoom, createDm}; +module.exports = { openRoomDirectory, findSublist, createRoom, createDm }; diff --git a/test/end-to-end-tests/src/usecases/join.js b/test/end-to-end-tests/src/usecases/join.js index cf0f67be44..1dff5fc45b 100644 --- a/test/end-to-end-tests/src/usecases/join.js +++ b/test/end-to-end-tests/src/usecases/join.js @@ -15,10 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -const {openRoomDirectory} = require('./create-room'); +const { openRoomDirectory } = require('./create-room'); const { measureStart, measureStop } = require('../util'); - module.exports = async function join(session, roomName) { session.log.step(`joins room "${roomName}"`); await measureStart(session, "mx_JoinRoom"); diff --git a/test/end-to-end-tests/src/usecases/memberlist.js b/test/end-to-end-tests/src/usecases/memberlist.js index ed7f0e389b..26c0c39755 100644 --- a/test/end-to-end-tests/src/usecases/memberlist.js +++ b/test/end-to-end-tests/src/usecases/memberlist.js @@ -16,7 +16,7 @@ limitations under the License. */ const assert = require('assert'); -const {openRoomSummaryCard} = require("./rightpanel"); +const { openRoomSummaryCard } = require("./rightpanel"); async function openMemberInfo(session, name) { const membersAndNames = await getMembersInMemberlist(session); @@ -49,7 +49,6 @@ module.exports.verifyDeviceForUser = async function(session, name, expectedDevic const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e))); console.log("my sas labels", sasLabels); - const dialogCodeFields = await session.queryAll(".mx_QuestionDialog code"); assert.equal(dialogCodeFields.length, 2); const deviceId = await session.innerText(dialogCodeFields[0]); @@ -71,7 +70,7 @@ async function getMembersInMemberlist(session) { const memberNameElements = await session.queryAll(".mx_MemberList .mx_EntityTile_name"); return Promise.all(memberNameElements.map(async (el) => { - return {label: el, displayName: await session.innerText(el)}; + return { label: el, displayName: await session.innerText(el) }; })); } diff --git a/test/end-to-end-tests/src/usecases/room-settings.js b/test/end-to-end-tests/src/usecases/room-settings.js index 654c461296..b40afe76bf 100644 --- a/test/end-to-end-tests/src/usecases/room-settings.js +++ b/test/end-to-end-tests/src/usecases/room-settings.js @@ -16,8 +16,8 @@ limitations under the License. */ const assert = require('assert'); -const {openRoomSummaryCard} = require("./rightpanel"); -const {acceptDialog} = require('./dialog'); +const { openRoomSummaryCard } = require("./rightpanel"); +const { acceptDialog } = require('./dialog'); async function setSettingsToggle(session, toggle, enabled) { const className = await session.getElementProperty(toggle, "className"); @@ -57,13 +57,13 @@ async function findTabs(session) { const tabLabels = await Promise.all(tabButtons.map(t => session.innerText(t))); const securityTabButton = tabButtons[tabLabels.findIndex(l => l.toLowerCase().includes("security"))]; - return {securityTabButton}; + return { securityTabButton }; } async function checkRoomSettings(session, expectedSettings) { session.log.startGroup(`checks the room settings`); - const {securityTabButton} = await findTabs(session); + const { securityTabButton } = await findTabs(session); const generalSwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch"); const isDirectory = generalSwitches[0]; @@ -129,7 +129,7 @@ async function checkRoomSettings(session, expectedSettings) { async function changeRoomSettings(session, settings) { session.log.startGroup(`changes the room settings`); - const {securityTabButton} = await findTabs(session); + const { securityTabButton } = await findTabs(session); const generalSwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch"); const isDirectory = generalSwitches[0]; @@ -188,4 +188,4 @@ async function changeRoomSettings(session, settings) { session.log.endGroup(); } -module.exports = {checkRoomSettings, changeRoomSettings}; +module.exports = { checkRoomSettings, changeRoomSettings }; diff --git a/test/end-to-end-tests/src/usecases/settings.js b/test/end-to-end-tests/src/usecases/settings.js index 52e4bb7e0a..509e0b4a07 100644 --- a/test/end-to-end-tests/src/usecases/settings.js +++ b/test/end-to-end-tests/src/usecases/settings.js @@ -51,5 +51,5 @@ module.exports.getE2EDeviceFromSettings = async function(session) { const closeButton = await session.query(".mx_UserSettingsDialog .mx_Dialog_cancelButton"); await closeButton.click(); session.log.done(); - return {id, key}; + return { id, key }; }; diff --git a/test/end-to-end-tests/src/usecases/timeline.js b/test/end-to-end-tests/src/usecases/timeline.js index 01dc618571..f9d7300ff1 100644 --- a/test/end-to-end-tests/src/usecases/timeline.js +++ b/test/end-to-end-tests/src/usecases/timeline.js @@ -69,7 +69,6 @@ module.exports.receiveMessage = async function(session, expectedMessage) { session.log.done(); }; - module.exports.checkTimelineContains = async function(session, expectedMessages, sendersDescription) { session.log.step(`checks timeline contains ${expectedMessages.length} ` + `given messages${sendersDescription ? ` from ${sendersDescription}`:""}`); diff --git a/test/end-to-end-tests/src/usecases/toasts.js b/test/end-to-end-tests/src/usecases/toasts.js index d739f3b4ea..8650ff1400 100644 --- a/test/end-to-end-tests/src/usecases/toasts.js +++ b/test/end-to-end-tests/src/usecases/toasts.js @@ -44,4 +44,4 @@ async function rejectToast(session, expectedTitle) { await btn.click(); } -module.exports = {assertNoToasts, assertToast, acceptToast, rejectToast}; +module.exports = { assertNoToasts, assertToast, acceptToast, rejectToast }; diff --git a/test/end-to-end-tests/src/usecases/verify.js b/test/end-to-end-tests/src/usecases/verify.js index a66c8c1b1c..a1f600833d 100644 --- a/test/end-to-end-tests/src/usecases/verify.js +++ b/test/end-to-end-tests/src/usecases/verify.js @@ -16,7 +16,7 @@ limitations under the License. */ const assert = require('assert'); -const {openMemberInfo} = require("./memberlist"); +const { openMemberInfo } = require("./memberlist"); async function startVerification(session, name) { session.log.step("opens their opponent's profile and starts verification"); diff --git a/test/end-to-end-tests/start.js b/test/end-to-end-tests/start.js index 04df0c51c0..f65d6137f4 100644 --- a/test/end-to-end-tests/start.js +++ b/test/end-to-end-tests/start.js @@ -133,7 +133,7 @@ async function writeLogs(sessions, dir) { fs.writeFileSync(appHtmlName, documentHtml); fs.writeFileSync(networkLogName, session.networkLogs()); fs.writeFileSync(consoleLogName, session.consoleLogs()); - await session.page.screenshot({path: `${userLogDir}/screenshot.png`}); + await session.page.screenshot({ path: `${userLogDir}/screenshot.png` }); } return logs; } diff --git a/test/notifications/ContentRules-test.js b/test/notifications/ContentRules-test.js index ca25edf5b1..9c21c05da7 100644 --- a/test/notifications/ContentRules-test.js +++ b/test/notifications/ContentRules-test.js @@ -52,13 +52,12 @@ const USERNAME_RULE = { rule_id: ".m.rule.contains_user_name", }; - describe("ContentRules", function() { describe("parseContentRules", function() { it("should handle there being no keyword rules", function() { const rules = { 'global': { 'content': [ USERNAME_RULE, - ]}}; + ] } }; const parsed = ContentRules.parseContentRules(rules); expect(parsed.rules).toEqual([]); expect(parsed.vectorState).toEqual(PushRuleVectorState.ON); @@ -69,7 +68,7 @@ describe("ContentRules", function() { const rules = { 'global': { 'content': [ NORMAL_RULE, USERNAME_RULE, - ]}}; + ] } }; const parsed = ContentRules.parseContentRules(rules); expect(parsed.rules.length).toEqual(1); @@ -82,7 +81,7 @@ describe("ContentRules", function() { const rules = { 'global': { 'content': [ LOUD_RULE, USERNAME_RULE, - ]}}; + ] } }; const parsed = ContentRules.parseContentRules(rules); expect(parsed.rules.length).toEqual(1); @@ -96,7 +95,7 @@ describe("ContentRules", function() { LOUD_RULE, NORMAL_RULE, USERNAME_RULE, - ]}}; + ] } }; const parsed = ContentRules.parseContentRules(rules); expect(parsed.rules.length).toEqual(1); diff --git a/test/skinned-sdk.js b/test/skinned-sdk.js index 876a188cc0..9de13d20a1 100644 --- a/test/skinned-sdk.js +++ b/test/skinned-sdk.js @@ -18,12 +18,12 @@ components['structures.RightPanel'] = stubComponent(); components['structures.RoomDirectory'] = stubComponent(); components['views.globals.GuestWarningBar'] = stubComponent(); components['views.globals.NewVersionBar'] = stubComponent(); -components['views.elements.Spinner'] = stubComponent({displayName: 'Spinner'}); -components['views.messages.DateSeparator'] = stubComponent({displayName: 'DateSeparator'}); -components['views.messages.MessageTimestamp'] = stubComponent({displayName: 'MessageTimestamp'}); -components['views.messages.SenderProfile'] = stubComponent({displayName: 'SenderProfile'}); +components['views.elements.Spinner'] = stubComponent({ displayName: 'Spinner' }); +components['views.messages.DateSeparator'] = stubComponent({ displayName: 'DateSeparator' }); +components['views.messages.MessageTimestamp'] = stubComponent({ displayName: 'MessageTimestamp' }); +components['views.messages.SenderProfile'] = stubComponent({ displayName: 'SenderProfile' }); components['views.rooms.SearchBar'] = stubComponent(); -sdk.loadSkin({components}); +sdk.loadSkin({ components }); export default sdk; diff --git a/test/stores/RoomViewStore-test.js b/test/stores/RoomViewStore-test.js index 41252103e7..cb5d7d21f0 100644 --- a/test/stores/RoomViewStore-test.js +++ b/test/stores/RoomViewStore-test.js @@ -1,6 +1,6 @@ import RoomViewStore from '../../src/stores/RoomViewStore'; -import {MatrixClientPeg as peg} from '../../src/MatrixClientPeg'; +import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; import * as testUtils from '../test-utils'; @@ -36,7 +36,7 @@ describe('RoomViewStore', function() { } }); - peg.get().getRoomIdForAlias.mockResolvedValue({room_id: "!randomcharacters:aser.ver"}); + peg.get().getRoomIdForAlias.mockResolvedValue({ room_id: "!randomcharacters:aser.ver" }); peg.get().joinRoom = async (roomAddress) => { token.remove(); // stop RVS listener expect(roomAddress).toBe("#somealias2:aser.ver"); diff --git a/test/test-utils.js b/test/test-utils.js index e4c051cce2..ad56522965 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -1,11 +1,11 @@ import React from 'react'; -import {MatrixClientPeg as peg} from '../src/MatrixClientPeg'; +import { MatrixClientPeg as peg } from '../src/MatrixClientPeg'; import dis from '../src/dispatcher/dispatcher'; -import {makeType} from "../src/utils/TypeUtils"; -import {ValidatedServerConfig} from "../src/utils/AutoDiscoveryUtils"; +import { makeType } from "../src/utils/TypeUtils"; +import { ValidatedServerConfig } from "../src/utils/AutoDiscoveryUtils"; import ShallowRenderer from 'react-test-renderer/shallow'; import MatrixClientContext from "../src/contexts/MatrixClientContext"; -import {MatrixEvent} from "matrix-js-sdk/src/models/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; export function getRenderer() { // Old: ReactTestUtils.createRenderer(); diff --git a/test/utils/MegolmExportEncryption-test.js b/test/utils/MegolmExportEncryption-test.js index 07ec03860b..39ffed25f1 100644 --- a/test/utils/MegolmExportEncryption-test.js +++ b/test/utils/MegolmExportEncryption-test.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {TextEncoder} from "util"; +import { TextEncoder } from "util"; import nodeCrypto from "crypto"; import { Crypto } from "@peculiar/webcrypto"; @@ -144,7 +144,7 @@ cissyYBxjsfsAn const password = 'my super secret passphrase'; return MegolmExportEncryption.encryptMegolmKeyFile( - input, password, {kdf_rounds: 1000}, + input, password, { kdf_rounds: 1000 }, ).then((ciphertext) => { return MegolmExportEncryption.decryptMegolmKeyFile( ciphertext, password, diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js index fdf4f527ee..b70031dc21 100644 --- a/test/utils/ShieldUtils-test.js +++ b/test/utils/ShieldUtils-test.js @@ -54,7 +54,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@FF1:h", "@FF2:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@FF1:h", "@FF2:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual("normal"); @@ -67,7 +67,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@TT2:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@TT2:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -80,7 +80,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@FF2:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@FF2:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -93,7 +93,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -106,7 +106,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TT:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TT:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -119,7 +119,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -139,7 +139,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -151,7 +151,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -163,7 +163,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -175,7 +175,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@WF:h", "@FT:h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@WF:h", "@FT:h"].map((userId) => ({ userId })), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); diff --git a/test/utils/Singleflight-test.ts b/test/utils/Singleflight-test.ts index 80258701bb..148388dc71 100644 --- a/test/utils/Singleflight-test.ts +++ b/test/utils/Singleflight-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Singleflight} from "../../src/utils/Singleflight"; +import { Singleflight } from "../../src/utils/Singleflight"; describe('Singleflight', () => { afterEach(() => { diff --git a/test/utils/arrays-test.ts b/test/utils/arrays-test.ts index 5974915965..cf9a5f0089 100644 --- a/test/utils/arrays-test.ts +++ b/test/utils/arrays-test.ts @@ -29,7 +29,7 @@ import { ArrayUtil, GroupedArray, } from "../../src/utils/arrays"; -import {objectFromEntries} from "../../src/utils/objects"; +import { objectFromEntries } from "../../src/utils/objects"; function expectSample(i: number, input: number[], expected: number[], smooth = false) { console.log(`Resample case index: ${i}`); // for debugging test failures @@ -43,26 +43,26 @@ describe('arrays', () => { describe('arrayFastResample', () => { it('should downsample', () => { [ - {input: [1, 2, 3, 4, 5], output: [1, 4]}, // Odd -> Even - {input: [1, 2, 3, 4, 5], output: [1, 3, 5]}, // Odd -> Odd - {input: [1, 2, 3, 4], output: [1, 2, 3]}, // Even -> Odd - {input: [1, 2, 3, 4], output: [1, 3]}, // Even -> Even + { input: [1, 2, 3, 4, 5], output: [1, 4] }, // Odd -> Even + { input: [1, 2, 3, 4, 5], output: [1, 3, 5] }, // Odd -> Odd + { input: [1, 2, 3, 4], output: [1, 2, 3] }, // Even -> Odd + { input: [1, 2, 3, 4], output: [1, 3] }, // Even -> Even ].forEach((c, i) => expectSample(i, c.input, c.output)); }); it('should upsample', () => { [ - {input: [1, 2, 3], output: [1, 1, 2, 2, 3, 3]}, // Odd -> Even - {input: [1, 2, 3], output: [1, 1, 2, 2, 3]}, // Odd -> Odd - {input: [1, 2], output: [1, 1, 1, 2, 2]}, // Even -> Odd - {input: [1, 2], output: [1, 1, 1, 2, 2, 2]}, // Even -> Even + { input: [1, 2, 3], output: [1, 1, 2, 2, 3, 3] }, // Odd -> Even + { input: [1, 2, 3], output: [1, 1, 2, 2, 3] }, // Odd -> Odd + { input: [1, 2], output: [1, 1, 1, 2, 2] }, // Even -> Odd + { input: [1, 2], output: [1, 1, 1, 2, 2, 2] }, // Even -> Even ].forEach((c, i) => expectSample(i, c.input, c.output)); }); it('should maintain sample', () => { [ - {input: [1, 2, 3], output: [1, 2, 3]}, // Odd - {input: [1, 2], output: [1, 2]}, // Even + { input: [1, 2, 3], output: [1, 2, 3] }, // Odd + { input: [1, 2], output: [1, 2] }, // Even ].forEach((c, i) => expectSample(i, c.input, c.output)); }); }); @@ -73,26 +73,26 @@ describe('arrays', () => { // we'd be feeding a thousand values in and seeing what a curve of 250 values looks like, // but that's not really feasible to manually verify accuracy. [ - {input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3, 3]}, // Odd -> Even - {input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3]}, // Odd -> Odd - {input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3, 3]}, // Even -> Odd - {input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3]}, // Even -> Even + { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3, 3] }, // Odd -> Even + { input: [4, 4, 1, 4, 4, 1, 4, 4, 1], output: [3, 3, 3] }, // Odd -> Odd + { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3, 3] }, // Even -> Odd + { input: [4, 4, 1, 4, 4, 1, 4, 4], output: [3, 3] }, // Even -> Even ].forEach((c, i) => expectSample(i, c.input, c.output, true)); }); it('should upsample', () => { [ - {input: [2, 0, 2], output: [2, 2, 0, 0, 2, 2]}, // Odd -> Even - {input: [2, 0, 2], output: [2, 2, 0, 0, 2]}, // Odd -> Odd - {input: [2, 0], output: [2, 2, 2, 0, 0]}, // Even -> Odd - {input: [2, 0], output: [2, 2, 2, 0, 0, 0]}, // Even -> Even + { input: [2, 0, 2], output: [2, 2, 0, 0, 2, 2] }, // Odd -> Even + { input: [2, 0, 2], output: [2, 2, 0, 0, 2] }, // Odd -> Odd + { input: [2, 0], output: [2, 2, 2, 0, 0] }, // Even -> Odd + { input: [2, 0], output: [2, 2, 2, 0, 0, 0] }, // Even -> Even ].forEach((c, i) => expectSample(i, c.input, c.output, true)); }); it('should maintain sample', () => { [ - {input: [2, 0, 2], output: [2, 0, 2]}, // Odd - {input: [2, 0], output: [2, 0]}, // Even + { input: [2, 0, 2], output: [2, 0, 2] }, // Odd + { input: [2, 0], output: [2, 0] }, // Even ].forEach((c, i) => expectSample(i, c.input, c.output, true)); }); }); diff --git a/test/utils/enums-test.ts b/test/utils/enums-test.ts index 423b135f77..e1d34ee688 100644 --- a/test/utils/enums-test.ts +++ b/test/utils/enums-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {getEnumValues, isEnumValue} from "../../src/utils/enums"; +import { getEnumValues, isEnumValue } from "../../src/utils/enums"; enum TestStringEnum { First = "__first__", diff --git a/test/utils/iterables-test.ts b/test/utils/iterables-test.ts index 9b30b6241c..5c1e2241f4 100644 --- a/test/utils/iterables-test.ts +++ b/test/utils/iterables-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {iterableDiff, iterableUnion} from "../../src/utils/iterables"; +import { iterableDiff, iterableUnion } from "../../src/utils/iterables"; describe('iterables', () => { describe('iterableUnion', () => { diff --git a/test/utils/maps-test.ts b/test/utils/maps-test.ts index 8764a8f2cf..097f3ef9c9 100644 --- a/test/utils/maps-test.ts +++ b/test/utils/maps-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {EnhancedMap, mapDiff, mapKeyChanges} from "../../src/utils/maps"; +import { EnhancedMap, mapDiff, mapKeyChanges } from "../../src/utils/maps"; describe('maps', () => { describe('mapDiff', () => { @@ -187,7 +187,7 @@ describe('maps', () => { }); it('should use the provided entries', () => { - const obj = {a: 1, b: 2}; + const obj = { a: 1, b: 2 }; const result = new EnhancedMap(Object.entries(obj)); expect(result.size).toBe(2); expect(result.get('a')).toBe(1); diff --git a/test/utils/numbers-test.ts b/test/utils/numbers-test.ts index 36e7d4f7e7..340ffe3302 100644 --- a/test/utils/numbers-test.ts +++ b/test/utils/numbers-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {clamp, defaultNumber, percentageOf, percentageWithin, sum} from "../../src/utils/numbers"; +import { clamp, defaultNumber, percentageOf, percentageWithin, sum } from "../../src/utils/numbers"; describe('numbers', () => { describe('defaultNumber', () => { diff --git a/test/utils/objects-test.ts b/test/utils/objects-test.ts index b7a80e6761..154fa3604f 100644 --- a/test/utils/objects-test.ts +++ b/test/utils/objects-test.ts @@ -28,8 +28,8 @@ import { describe('objects', () => { describe('objectExcluding', () => { it('should exclude the given properties', () => { - const input = {hello: "world", test: true}; - const output = {hello: "world"}; + const input = { hello: "world", test: true }; + const output = { hello: "world" }; const props = ["test", "doesnotexist"]; // we also make sure it doesn't explode on missing props const result = objectExcluding(input, props); // any is to test the missing prop expect(result).toBeDefined(); @@ -39,8 +39,8 @@ describe('objects', () => { describe('objectWithOnly', () => { it('should exclusively use the given properties', () => { - const input = {hello: "world", test: true}; - const output = {hello: "world"}; + const input = { hello: "world", test: true }; + const output = { hello: "world" }; const props = ["hello", "doesnotexist"]; // we also make sure it doesn't explode on missing props const result = objectWithOnly(input, props); // any is to test the missing prop expect(result).toBeDefined(); @@ -50,7 +50,7 @@ describe('objects', () => { describe('objectShallowClone', () => { it('should create a new object', () => { - const input = {test: 1}; + const input = { test: 1 }; const result = objectShallowClone(input); expect(result).toBeDefined(); expect(result).not.toBe(input); @@ -58,7 +58,7 @@ describe('objects', () => { }); it('should only clone the top level properties', () => { - const input = {a: 1, b: {c: 2}}; + const input = { a: 1, b: { c: 2 } }; const result = objectShallowClone(input); expect(result).toBeDefined(); expect(result).toMatchObject(input); @@ -66,8 +66,8 @@ describe('objects', () => { }); it('should support custom clone functions', () => { - const input = {a: 1, b: 2}; - const output = {a: 4, b: 8}; + const input = { a: 1, b: 2 }; + const output = { a: 4, b: 8 }; const result = objectShallowClone(input, (k, v) => { // XXX: inverted expectation for ease of assertion expect(Object.keys(input)).toContain(k); @@ -87,29 +87,29 @@ describe('objects', () => { }); it('should return true if keys for A > keys for B', () => { - const a = {a: 1, b: 2}; - const b = {a: 1}; + const a = { a: 1, b: 2 }; + const b = { a: 1 }; const result = objectHasDiff(a, b); expect(result).toBe(true); }); it('should return true if keys for A < keys for B', () => { - const a = {a: 1}; - const b = {a: 1, b: 2}; + const a = { a: 1 }; + const b = { a: 1, b: 2 }; const result = objectHasDiff(a, b); expect(result).toBe(true); }); it('should return false if the objects are the same but different pointers', () => { - const a = {a: 1, b: 2}; - const b = {a: 1, b: 2}; + const a = { a: 1, b: 2 }; + const b = { a: 1, b: 2 }; const result = objectHasDiff(a, b); expect(result).toBe(false); }); it('should consider pointers when testing values', () => { - const a = {a: {}, b: 2}; // `{}` is shorthand for `new Object()` - const b = {a: {}, b: 2}; + const a = { a: {}, b: 2 }; // `{}` is shorthand for `new Object()` + const b = { a: {}, b: 2 }; const result = objectHasDiff(a, b); expect(result).toBe(true); // even though the keys are the same, the value pointers vary }); @@ -117,8 +117,8 @@ describe('objects', () => { describe('objectDiff', () => { it('should return empty sets for the same object', () => { - const a = {a: 1, b: 2}; - const b = {a: 1, b: 2}; + const a = { a: 1, b: 2 }; + const b = { a: 1, b: 2 }; const result = objectDiff(a, b); expect(result).toBeDefined(); expect(result.changed).toBeDefined(); @@ -130,7 +130,7 @@ describe('objects', () => { }); it('should return empty sets for the same object pointer', () => { - const a = {a: 1, b: 2}; + const a = { a: 1, b: 2 }; const result = objectDiff(a, a); expect(result).toBeDefined(); expect(result.changed).toBeDefined(); @@ -142,8 +142,8 @@ describe('objects', () => { }); it('should indicate when property changes are made', () => { - const a = {a: 1, b: 2}; - const b = {a: 11, b: 2}; + const a = { a: 1, b: 2 }; + const b = { a: 11, b: 2 }; const result = objectDiff(a, b); expect(result.changed).toBeDefined(); expect(result.added).toBeDefined(); @@ -155,8 +155,8 @@ describe('objects', () => { }); it('should indicate when properties are added', () => { - const a = {a: 1, b: 2}; - const b = {a: 1, b: 2, c: 3}; + const a = { a: 1, b: 2 }; + const b = { a: 1, b: 2, c: 3 }; const result = objectDiff(a, b); expect(result.changed).toBeDefined(); expect(result.added).toBeDefined(); @@ -168,8 +168,8 @@ describe('objects', () => { }); it('should indicate when properties are removed', () => { - const a = {a: 1, b: 2}; - const b = {a: 1}; + const a = { a: 1, b: 2 }; + const b = { a: 1 }; const result = objectDiff(a, b); expect(result.changed).toBeDefined(); expect(result.added).toBeDefined(); @@ -181,8 +181,8 @@ describe('objects', () => { }); it('should indicate when multiple aspects change', () => { - const a = {a: 1, b: 2, c: 3}; - const b: (typeof a | {d: number}) = {a: 1, b: 22, d: 4}; + const a = { a: 1, b: 2, c: 3 }; + const b: (typeof a | {d: number}) = { a: 1, b: 22, d: 4 }; const result = objectDiff(a, b); expect(result.changed).toBeDefined(); expect(result.added).toBeDefined(); @@ -198,23 +198,23 @@ describe('objects', () => { describe('objectKeyChanges', () => { it('should return an empty set if no properties changed', () => { - const a = {a: 1, b: 2}; - const b = {a: 1, b: 2}; + const a = { a: 1, b: 2 }; + const b = { a: 1, b: 2 }; const result = objectKeyChanges(a, b); expect(result).toBeDefined(); expect(result).toHaveLength(0); }); it('should return an empty set if no properties changed for the same pointer', () => { - const a = {a: 1, b: 2}; + const a = { a: 1, b: 2 }; const result = objectKeyChanges(a, a); expect(result).toBeDefined(); expect(result).toHaveLength(0); }); it('should return properties which were changed, added, or removed', () => { - const a = {a: 1, b: 2, c: 3}; - const b: (typeof a | {d: number}) = {a: 1, b: 22, d: 4}; + const a = { a: 1, b: 2, c: 3 }; + const b: (typeof a | {d: number}) = { a: 1, b: 22, d: 4 }; const result = objectKeyChanges(a, b); expect(result).toBeDefined(); expect(result).toHaveLength(3); @@ -245,14 +245,14 @@ describe('objects', () => { describe('objectFromEntries', () => { it('should create an object from an array of entries', () => { - const output = {a: 1, b: 2, c: 3}; + const output = { a: 1, b: 2, c: 3 }; const result = objectFromEntries(Object.entries(output)); expect(result).toBeDefined(); expect(result).toMatchObject(output); }); it('should maintain pointers in values', () => { - const output = {a: {}, b: 2, c: 3}; + const output = { a: {}, b: 2, c: 3 }; const result = objectFromEntries(Object.entries(output)); expect(result).toBeDefined(); expect(result).toMatchObject(output); diff --git a/test/utils/permalinks/Permalinks-test.js b/test/utils/permalinks/Permalinks-test.js index 3c4982b465..41cce7f98d 100644 --- a/test/utils/permalinks/Permalinks-test.js +++ b/test/utils/permalinks/Permalinks-test.js @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {MatrixClientPeg as peg} from '../../../src/MatrixClientPeg'; +import { MatrixClientPeg as peg } from '../../../src/MatrixClientPeg'; import { makeGroupPermalink, makeRoomPermalink, @@ -48,7 +48,7 @@ function mockRoom(roomId, members, serverACL) { content = serverACL; break; case "m.room.power_levels": - content = {users: powerLevelsUsers, users_default: 0}; + content = { users: powerLevelsUsers, users_default: 0 }; break; } if (content) { diff --git a/test/utils/sets-test.ts b/test/utils/sets-test.ts index 98dc218309..fec6cab0f3 100644 --- a/test/utils/sets-test.ts +++ b/test/utils/sets-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {setHasDiff} from "../../src/utils/sets"; +import { setHasDiff } from "../../src/utils/sets"; describe('sets', () => { describe('setHasDiff', () => { diff --git a/yarn.lock b/yarn.lock index 3bcb8de404..89e11fcea5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,12 +26,12 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== +"@babel/code-frame@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== dependencies: - "@babel/highlight" "^7.12.13" + "@babel/highlight" "^7.14.5" "@babel/compat-data@^7.12.5", "@babel/compat-data@^7.12.7": version "7.12.7" @@ -59,7 +59,23 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.12.1", "@babel/generator@^7.12.10", "@babel/generator@^7.12.11": +"@babel/eslint-parser@^7.12.10": + version "7.13.14" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.14.tgz#f80fd23bdd839537221914cb5d17720a5ea6ba3a" + integrity sha512-I0HweR36D73Ibn/FfrRDMKlMqJHFwidIUgYdMpH+aXYuQC+waq59YaJ6t9e9N36axJ82v1jR041wwqDrDXEwRA== + dependencies: + eslint-scope "^5.1.0" + eslint-visitor-keys "^1.3.0" + semver "^6.3.0" + +"@babel/eslint-plugin@^7.12.10": + version "7.13.10" + resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.13.10.tgz#6720c32d52a4fef817796c7bb55a87b80320bbe7" + integrity sha512-xsNxo099fKnJ2rArkuuMOTPxxTLZSXwbFXdH4GjqQRKTOr6S1odQlE+R3Leid56VFQ3KVAR295vVNG9fqNQVvQ== + dependencies: + eslint-rule-composer "^0.3.0" + +"@babel/generator@^7.12.10", "@babel/generator@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== @@ -68,12 +84,12 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.16.tgz#0befc287031a201d84cdfc173b46b320ae472d14" - integrity sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg== +"@babel/generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785" + integrity sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA== dependencies: - "@babel/types" "^7.13.16" + "@babel/types" "^7.14.5" jsesc "^2.5.1" source-map "^0.5.0" @@ -146,14 +162,14 @@ "@babel/template" "^7.12.7" "@babel/types" "^7.12.11" -"@babel/helper-function-name@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a" - integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA== +"@babel/helper-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4" + integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ== dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/helper-get-function-arity" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/types" "^7.14.5" "@babel/helper-get-function-arity@^7.12.10": version "7.12.10" @@ -162,12 +178,12 @@ dependencies: "@babel/types" "^7.12.10" -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== +"@babel/helper-get-function-arity@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" + integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.14.5" "@babel/helper-hoist-variables@^7.10.4": version "7.10.4" @@ -176,6 +192,13 @@ dependencies: "@babel/types" "^7.10.4" +"@babel/helper-hoist-variables@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" + integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ== + dependencies: + "@babel/types" "^7.14.5" + "@babel/helper-member-expression-to-functions@^7.12.1", "@babel/helper-member-expression-to-functions@^7.12.7": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" @@ -257,18 +280,23 @@ dependencies: "@babel/types" "^7.12.11" -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== +"@babel/helper-split-export-declaration@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" + integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.14.5" "@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" + integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== + "@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f" @@ -302,24 +330,24 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.12.13": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" - integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.5" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.7.0": +"@babel/parser@^7.1.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== -"@babel/parser@^7.12.13", "@babel/parser@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.16.tgz#0f18179b0448e6939b1f3f5c4c355a3a9bcdfd37" - integrity sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw== +"@babel/parser@^7.13.16", "@babel/parser@^7.14.5", "@babel/parser@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.7.tgz#6099720c8839ca865a2637e6c85852ead0bdb595" + integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA== "@babel/plugin-proposal-async-generator-functions@^7.12.1": version "7.12.12" @@ -494,13 +522,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.12.1.tgz#a77670d9abe6d63e8acadf4c31bb1eb5a506bbdd" - integrity sha512-1lBLLmtxrwpm4VKmtVFselI/P3pX+G63fAtUUt6b2Nzgao77KNDwyuRt90Mj2/9pKobtt68FdvjfqohZjg/FCA== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -659,23 +680,6 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-flow-comments@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-comments/-/plugin-transform-flow-comments-7.12.1.tgz#92fe5a27e635bd6d2e46f616094d60edff895a0b" - integrity sha512-jQd0UQUg98j95JJVQL74mOrzES7dYyd8hy+ZDiMj1wjHw1Nj0Pzkk7tKZdqqAoSZV/yTYLp0lJ0/PTozy2cNDg== - dependencies: - "@babel/generator" "^7.12.1" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-flow" "^7.12.1" - -"@babel/plugin-transform-flow-strip-types@^7.12.1": - version "7.12.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.10.tgz#d85e30ecfa68093825773b7b857e5085bbd32c95" - integrity sha512-0ti12wLTLeUIzu9U7kjqIn4MyOL7+Wibc7avsHhj4o1l5C0ATs8p2IMHrVYjm9t9wzhfEO6S3kxax0Rpdo8LTg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-flow" "^7.12.1" - "@babel/plugin-transform-for-of@^7.12.1": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz#07640f28867ed16f9511c99c888291f560921cfa" @@ -967,14 +971,6 @@ core-js-compat "^3.8.0" semver "^5.5.0" -"@babel/preset-flow@^7.12.1": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.12.1.tgz#1a81d376c5a9549e75352a3888f8c273455ae940" - integrity sha512-UAoyMdioAhM6H99qPoKvpHMzxmNVXno8GYU/7vZmGaHk6/KqfDYL1W0NxszVbJ2EP271b7e6Ox+Vk2A9QsB3Sw== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-transform-flow-strip-types" "^7.12.1" - "@babel/preset-modules@^0.1.3": version "0.1.4" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" @@ -1040,16 +1036,16 @@ "@babel/parser" "^7.12.7" "@babel/types" "^7.12.7" -"@babel/template@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== +"@babel/template@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/parser" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.12", "@babel/traverse@^7.12.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.4": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.12", "@babel/traverse@^7.12.5": version "7.12.12" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376" integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w== @@ -1065,20 +1061,21 @@ lodash "^4.17.19" "@babel/traverse@^7.13.17": - version "7.13.17" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.17.tgz#c85415e0c7d50ac053d758baec98b28b2ecfeea3" - integrity sha512-BMnZn0R+X6ayqm3C3To7o1j7Q020gWdqdyP50KEoVqaCO2c/Im7sYZSmVgvefp8TTMQ+9CtwuBp0Z1CZ8V3Pvg== + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.7.tgz#64007c9774cfdc3abd23b0780bc18a3ce3631753" + integrity sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.16" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.16" - "@babel/types" "^7.13.17" + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.14.5" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-hoist-variables" "^7.14.5" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/parser" "^7.14.7" + "@babel/types" "^7.14.5" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.12.12" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== @@ -1087,12 +1084,12 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@babel/types@^7.12.13", "@babel/types@^7.13.16", "@babel/types@^7.13.17": - version "7.13.17" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.17.tgz#48010a115c9fba7588b4437dd68c9469012b38b4" - integrity sha512-RawydLgxbOPDlTLJNtoIypwdmAy//uQIzlKt2+iBiJaRlVuI6QLUxVAyWGNfOzp8Yu4L4lLIacoCyTNtpb4wiA== +"@babel/types@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff" + integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.14.5" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -1334,7 +1331,6 @@ "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz": version "3.2.3" - uid cc332fdd25c08ef0e40f4d33fc3f822a0f98b6f4 resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz#cc332fdd25c08ef0e40f4d33fc3f822a0f98b6f4" "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents": @@ -1565,11 +1561,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - "@types/linkifyjs@^2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@types/linkifyjs/-/linkifyjs-2.1.3.tgz#80195c3c88c5e75d9f660e3046ce4a42be2c2fa4" @@ -1725,13 +1716,13 @@ resolved "https://registry.yarnpkg.com/@types/zxcvbn/-/zxcvbn-4.4.0.tgz#fbc1d941cc6d9d37d18405c513ba6b294f89b609" integrity sha512-GQLOT+SN20a+AI51y3fAimhyTF4Y0RG+YP3gf91OibIZ7CJmPFgoZi+ZR5a+vRbS01LbQosITWum4ATmJ1Z6Pg== -"@typescript-eslint/eslint-plugin@^4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.0.tgz#92db8e7c357ed7d69632d6843ca70b71be3a721d" - integrity sha512-IJ5e2W7uFNfg4qh9eHkHRUCbgZ8VKtGwD07kannJvM5t/GU8P8+24NX8gi3Hf5jST5oWPY8kyV1s/WtfiZ4+Ww== +"@typescript-eslint/eslint-plugin@^4.17.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.20.0.tgz#9d8794bd99aad9153092ad13c96164e3082e9a92" + integrity sha512-sw+3HO5aehYqn5w177z2D82ZQlqHCwcKSMboueo7oE4KU9QiC0SAgfS/D4z9xXvpTc8Bt41Raa9fBR8T2tIhoQ== dependencies: - "@typescript-eslint/experimental-utils" "4.14.0" - "@typescript-eslint/scope-manager" "4.14.0" + "@typescript-eslint/experimental-utils" "4.20.0" + "@typescript-eslint/scope-manager" "4.20.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -1739,61 +1730,60 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.0.tgz#5aa7b006736634f588a69ee343ca959cd09988df" - integrity sha512-6i6eAoiPlXMKRbXzvoQD5Yn9L7k9ezzGRvzC/x1V3650rUk3c3AOjQyGYyF9BDxQQDK2ElmKOZRD0CbtdkMzQQ== +"@typescript-eslint/experimental-utils@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.20.0.tgz#a8ab2d7b61924f99042b7d77372996d5f41dc44b" + integrity sha512-sQNlf6rjLq2yB5lELl3gOE7OuoA/6IVXJUJ+Vs7emrQMva14CkOwyQwD7CW+TkmOJ4Q/YGmoDLmbfFrpGmbKng== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.14.0" - "@typescript-eslint/types" "4.14.0" - "@typescript-eslint/typescript-estree" "4.14.0" + "@typescript-eslint/scope-manager" "4.20.0" + "@typescript-eslint/types" "4.20.0" + "@typescript-eslint/typescript-estree" "4.20.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.14.0.tgz#62d4cd2079d5c06683e9bfb200c758f292c4dee7" - integrity sha512-sUDeuCjBU+ZF3Lzw0hphTyScmDDJ5QVkyE21pRoBo8iDl7WBtVFS+WDN3blY1CH3SBt7EmYCw6wfmJjF0l/uYg== +"@typescript-eslint/parser@^4.17.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.20.0.tgz#8dd403c8b4258b99194972d9799e201b8d083bdd" + integrity sha512-m6vDtgL9EABdjMtKVw5rr6DdeMCH3OA1vFb0dAyuZSa3e5yw1YRzlwFnm9knma9Lz6b2GPvoNSa8vOXrqsaglA== dependencies: - "@typescript-eslint/scope-manager" "4.14.0" - "@typescript-eslint/types" "4.14.0" - "@typescript-eslint/typescript-estree" "4.14.0" + "@typescript-eslint/scope-manager" "4.20.0" + "@typescript-eslint/types" "4.20.0" + "@typescript-eslint/typescript-estree" "4.20.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.14.0.tgz#55a4743095d684e1f7b7180c4bac2a0a3727f517" - integrity sha512-/J+LlRMdbPh4RdL4hfP1eCwHN5bAhFAGOTsvE6SxsrM/47XQiPSgF5MDgLyp/i9kbZV9Lx80DW0OpPkzL+uf8Q== +"@typescript-eslint/scope-manager@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.20.0.tgz#953ecbf3b00845ece7be66246608be9d126d05ca" + integrity sha512-/zm6WR6iclD5HhGpcwl/GOYDTzrTHmvf8LLLkwKqqPKG6+KZt/CfSgPCiybshmck66M2L5fWSF/MKNuCwtKQSQ== dependencies: - "@typescript-eslint/types" "4.14.0" - "@typescript-eslint/visitor-keys" "4.14.0" + "@typescript-eslint/types" "4.20.0" + "@typescript-eslint/visitor-keys" "4.20.0" -"@typescript-eslint/types@4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.14.0.tgz#d8a8202d9b58831d6fd9cee2ba12f8a5a5dd44b6" - integrity sha512-VsQE4VvpldHrTFuVPY1ZnHn/Txw6cZGjL48e+iBxTi2ksa9DmebKjAeFmTVAYoSkTk7gjA7UqJ7pIsyifTsI4A== +"@typescript-eslint/types@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.20.0.tgz#c6cf5ef3c9b1c8f699a9bbdafb7a1da1ca781225" + integrity sha512-cYY+1PIjei1nk49JAPnH1VEnu7OYdWRdJhYI5wiKOUMhLTG1qsx5cQxCUTuwWCmQoyriadz3Ni8HZmGSofeC+w== -"@typescript-eslint/typescript-estree@4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.0.tgz#4bcd67486e9acafc3d0c982b23a9ab8ac8911ed7" - integrity sha512-wRjZ5qLao+bvS2F7pX4qi2oLcOONIB+ru8RGBieDptq/SudYwshveORwCVU4/yMAd4GK7Fsf8Uq1tjV838erag== +"@typescript-eslint/typescript-estree@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.20.0.tgz#8b3b08f85f18a8da5d88f65cb400f013e88ab7be" + integrity sha512-Knpp0reOd4ZsyoEJdW8i/sK3mtZ47Ls7ZHvD8WVABNx5Xnn7KhenMTRGegoyMTx6TiXlOVgMz9r0pDgXTEEIHA== dependencies: - "@typescript-eslint/types" "4.14.0" - "@typescript-eslint/visitor-keys" "4.14.0" + "@typescript-eslint/types" "4.20.0" + "@typescript-eslint/visitor-keys" "4.20.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" - lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.14.0": - version "4.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.0.tgz#b1090d9d2955b044b2ea2904a22496849acbdf54" - integrity sha512-MeHHzUyRI50DuiPgV9+LxcM52FCJFYjJiWHtXlbyC27b80mfOwKeiKI+MHOTEpcpfmoPFm/vvQS88bYIx6PZTA== +"@typescript-eslint/visitor-keys@4.20.0": + version "4.20.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.20.0.tgz#1e84db034da13f208325e6bfc995c3b75f7dbd62" + integrity sha512-NXKRM3oOVQL8yNFDNCZuieRIwZ5UtjNLYtmMx2PacEAGmbaEYtGgVHUHVyZvU/0rYZcizdrWjDo+WBtRPSgq+A== dependencies: - "@typescript-eslint/types" "4.14.0" + "@typescript-eslint/types" "4.20.0" eslint-visitor-keys "^2.0.0" "@wojtekmaj/enzyme-adapter-react-17@^0.6.1": @@ -1834,7 +1824,7 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: +acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== @@ -1849,7 +1839,7 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2027,11 +2017,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -2080,18 +2065,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -babel-eslint@^10.0.1, babel-eslint@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - babel-jest@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" @@ -2388,7 +2361,7 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2433,11 +2406,6 @@ character-reference-invalid@^1.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - cheerio-select@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.4.0.tgz#3a16f21e37a2ef0f211d6d1aa4eff054bb22cdc9" @@ -2502,18 +2470,6 @@ classnames@^2.2.6: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -2643,11 +2599,6 @@ concurrently@^5.3.0: tree-kill "^1.2.2" yargs "^13.3.0" -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - content-type@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -2717,7 +2668,7 @@ cross-fetch@^3.0.4: dependencies: node-fetch "2.6.1" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2818,7 +2769,7 @@ date-names@^0.1.11: resolved "https://registry.yarnpkg.com/date-names/-/date-names-0.1.13.tgz#c4358f6f77c8056e2f5ea68fdbb05f0bf1e53bd0" integrity sha512-IxxoeD9tdx8pXVcmqaRlPvrXIsSrSrIZzfzlOkm9u+hyzKp5Wk/odt9O/gd7Ockzy8n/WHeEpTVJ2bF3mMV4LA== -debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2941,14 +2892,6 @@ discontinuous-range@1.0.0: resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo= -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -3146,7 +3089,7 @@ enzyme@^3.11.0: rst-selector-parser "^2.2.3" string.prototype.trim "^1.2.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== @@ -3272,131 +3215,21 @@ escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" -eslint-config-esnext@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz#8695b858fcf40d28c1aedca181f700528c7b60c6" - integrity sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA== - dependencies: - babel-eslint "^10.0.1" - eslint "^6.8.0" - eslint-plugin-babel "^5.2.1" - eslint-plugin-import "^2.14.0" - eslint-config-google@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a" integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw== -eslint-config-matrix-org@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-matrix-org/-/eslint-config-matrix-org-0.2.0.tgz#27571c7c3a9ab6cc1e9d0f3d53a3739d1b004a7f" - integrity sha512-Hwgm1Qk0atjWgj5SWxpFPvxy6k6bDlPb9Pqjvb1i59nx8Zm6jDPy1C5vKQpkFpc0ntr+gJHa+ejYhuhaofu6Mw== - dependencies: - "@typescript-eslint/eslint-plugin" "^4.14.0" - "@typescript-eslint/parser" "^4.14.0" - babel-eslint "^10.1.0" - eslint-config-google "^0.14.0" - eslint-config-recommended "^4.1.0" - eslint-plugin-babel "^5.3.1" - typescript "^4.1.3" - -eslint-config-node@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-node/-/eslint-config-node-4.1.0.tgz#fc1f13946d83766d6b83b0e67699e2071a56f417" - integrity sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ== - dependencies: - eslint "^6.8.0" - eslint-config-esnext "^4.1.0" - -eslint-config-react-native@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-react-native/-/eslint-config-react-native-4.1.0.tgz#63e9401c7fac146804785f609e7df8f15b3e04eb" - integrity sha512-kNND+cs+ztawH7wgajf/K6FfNshjlDsFDAkkFZF9HAXDgH1w1sNMIfTfwzufg0hOcSK7rbiL4qbG/gg/oR507Q== - dependencies: - eslint "^6.8.0" - eslint-config-esnext "^4.1.0" - eslint-plugin-react "^7.19.0" - eslint-plugin-react-native "^3.8.1" - -eslint-config-recommended@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-recommended/-/eslint-config-recommended-4.1.0.tgz#1adff90e0716d439be471d192977f233de171a46" - integrity sha512-2evA0SX1VqtyFiExmBI2WAO4XQCKlr7wmNELE8rcT5PyZY2ixsY881ofVZWKuI/dywpgLiES1gR/XUQcnVLRzQ== - dependencies: - eslint "^6.8.0" - eslint-config-esnext "^4.1.0" - eslint-config-node "^4.1.0" - eslint-config-react-native "^4.1.0" - -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== - dependencies: - debug "^2.6.9" - resolve "^1.13.1" - -eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== - dependencies: - debug "^2.6.9" - pkg-dir "^2.0.0" - -eslint-plugin-babel@^5.2.1, eslint-plugin-babel@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz#75a2413ffbf17e7be57458301c60291f2cfbf560" - integrity sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g== - dependencies: - eslint-rule-composer "^0.3.0" - -eslint-plugin-flowtype@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz#a4bef5dc18f9b2bdb41569a4ab05d73805a3d261" - integrity sha512-z7ULdTxuhlRJcEe1MVljePXricuPOrsWfScRXFhNzVD5dmTHWjIF57AxD0e7AbEoLSbjSsaA5S+hCg43WvpXJQ== - dependencies: - lodash "^4.17.15" - string-natural-compare "^3.0.1" - -eslint-plugin-import@^2.14.0: - version "2.22.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" - integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== - dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" - debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.0" - has "^1.0.3" - minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" +"eslint-plugin-matrix-org@github:matrix-org/eslint-plugin-matrix-org#main": + version "0.3.2" + resolved "https://codeload.github.com/matrix-org/eslint-plugin-matrix-org/tar.gz/28d392822533a7468be0dd806d0a4ba573a45d74" eslint-plugin-react-hooks@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== -eslint-plugin-react-native-globals@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2" - integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g== - -eslint-plugin-react-native@^3.8.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-3.10.0.tgz#240f7e6979a908af3dfd9ba9652434c33f4d64cd" - integrity sha512-4f5+hHYYq5wFhB5eptkPEAR7FfvqbS7AzScUOANfAMZtYw5qgnCxRq45bpfBaQF+iyPMim5Q8pubcpvLv75NAg== - dependencies: - "@babel/traverse" "^7.7.4" - eslint-plugin-react-native-globals "^0.1.1" - -eslint-plugin-react@^7.19.0, eslint-plugin-react@^7.22.0: +eslint-plugin-react@^7.22.0: version "7.22.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz#3d1c542d1d3169c45421c1215d9470e341707269" integrity sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA== @@ -3418,7 +3251,7 @@ eslint-rule-composer@^0.3.0: resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== -eslint-scope@^5.0.0, eslint-scope@^5.1.1: +eslint-scope@^5.0.0, eslint-scope@^5.1.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3426,13 +3259,6 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" @@ -3440,7 +3266,7 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -3493,58 +3319,6 @@ eslint@7.18.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - espree@^7.3.0, espree@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" @@ -3559,7 +3333,7 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1, esquery@^1.2.0: +esquery@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== @@ -3703,15 +3477,6 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -3816,20 +3581,6 @@ fbjs@^0.8.4: setimmediate "^1.0.5" ua-parser-js "^0.7.18" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - file-entry-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" @@ -3873,13 +3624,6 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -3895,15 +3639,6 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -3912,11 +3647,6 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - flatted@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" @@ -4153,7 +3883,19 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -globby@^11.0.1, globby@^11.0.2: +globby@^11.0.1: + version "11.0.3" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" + integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^11.0.2: version "11.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== @@ -4177,7 +3919,7 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -4367,7 +4109,7 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4460,25 +4202,6 @@ ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - internal-slot@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3" @@ -4876,7 +4599,7 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -5483,13 +5206,6 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - json5@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" @@ -5566,14 +5282,6 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -5582,6 +5290,14 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -5592,24 +5308,6 @@ linkifyjs@^2.1.9: resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.9.tgz#af06e45a2866ff06c4766582590d098a4d584702" integrity sha512-74ivurkK6WHvHFozVaGtQWV38FzBwSTGNmJolEgFp7QgR2bl6ArUWlvT4GcHKbPe1z3nWYi+VUdDZk16zDOVug== -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -5645,7 +5343,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5933,13 +5631,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - moo-color@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.2.tgz#837c40758d2d58763825d1359a84e330531eca64" @@ -5962,11 +5653,6 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - nanoid@^3.1.20: version "3.1.20" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" @@ -6251,7 +5937,7 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -6280,11 +5966,6 @@ opus-recorder@^8.0.3: resolved "https://registry.yarnpkg.com/opus-recorder/-/opus-recorder-8.0.3.tgz#f7b44f8f68500c9b96a15042a69f915fd9c1716d" integrity sha512-8vXGiRwlJAavT9D3yYzukNVXQ8vEcKHcsQL/zXO24DQtJ0PLXvoPHNQPJrbMCdB4ypJgWDExvHF4JitQDL7dng== -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - p-each-series@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" @@ -6295,13 +5976,6 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -6309,13 +5983,6 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -6330,11 +5997,6 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -6364,13 +6026,6 @@ parse-entities@^2.0.0: is-decimal "^1.0.0" is-hexadecimal "^1.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -6451,13 +6106,6 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -6473,11 +6121,6 @@ picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" @@ -6495,13 +6138,6 @@ pirates@^4.0.0, pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -6885,14 +6521,6 @@ react@^17.0.2: loose-envify "^1.1.0" object-assign "^4.1.1" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -6902,15 +6530,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" @@ -7023,11 +6642,6 @@ regexp.prototype.flags@^1.3.0: call-bind "^1.0.2" define-properties "^1.1.3" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - regexpp@^3.0.0, regexpp@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" @@ -7179,7 +6793,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.18.1: +resolve@^1.10.0, resolve@^1.17.0, resolve@^1.18.1: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== @@ -7187,14 +6801,6 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.1 is-core-module "^2.1.0" path-parse "^1.0.6" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -7210,13 +6816,6 @@ rfc4648@^1.4.0: resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.4.0.tgz#c75b2856ad2e2d588b6ddb985d556f1f7f2a2abd" integrity sha512-3qIzGhHlMHA6PoT6+cdPKZ+ZqtxkIvg8DZGKA5z6PQ33/uuhoJ+Ws/D/J9rXW6gXodgH8QYlz2UCl+sdUDmNIg== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -7237,17 +6836,12 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.1.10" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== -rxjs@^6.5.2, rxjs@^6.6.0: +rxjs@^6.5.2: version "6.6.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== @@ -7329,7 +6923,7 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -7419,15 +7013,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -7609,11 +7194,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-natural-compare@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" - integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== - string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -7719,11 +7299,6 @@ strip-ansi@^6.0.0: dependencies: ansi-regex "^5.0.0" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -7746,7 +7321,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.0.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -7879,16 +7454,6 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - table@^6.0.4, table@^6.0.7: version "6.0.7" resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" @@ -7931,11 +7496,6 @@ throat@^5.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - tiny-invariant@^1.0.6: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" @@ -7946,13 +7506,6 @@ tmatch@^2.0.1: resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf" integrity sha1-DFYkbzPzDaG409colauvFmYPOM8= -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -8034,16 +7587,6 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -8060,9 +7603,9 @@ tslib@^2.2.0: integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== tsutils@^3.17.1: - version "3.19.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.19.1.tgz#d8566e0c51c82f32f9c25a4d367cd62409a547a9" - integrity sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw== + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" @@ -8501,13 +8044,6 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - ws@^7.2.3: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"