From 6b746b5d1d1893eadb7300ed49fa237823da152e Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 20:15:05 +0100 Subject: [PATCH 01/22] Migrate ConfirmDestroyCrossSigningDialog to TypeScript --- ...s => ConfirmDestroyCrossSigningDialog.tsx} | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) rename src/components/views/dialogs/security/{ConfirmDestroyCrossSigningDialog.js => ConfirmDestroyCrossSigningDialog.tsx} (83%) diff --git a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx similarity index 83% rename from src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js rename to src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx index e71983b074..6272302a76 100644 --- a/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.js +++ b/src/components/views/dialogs/security/ConfirmDestroyCrossSigningDialog.tsx @@ -15,22 +15,21 @@ 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 {replaceableComponent} from "../../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../../utils/replaceableComponent"; + +interface IProps { + onFinished: (success: boolean) => void; +} @replaceableComponent("views.dialogs.security.ConfirmDestroyCrossSigningDialog") -export default class ConfirmDestroyCrossSigningDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; - - _onConfirm = () => { +export default class ConfirmDestroyCrossSigningDialog extends React.Component { + private onConfirm = (): void => { this.props.onFinished(true); }; - _onDecline = () => { + private onDecline = (): void => { this.props.onFinished(false); }; @@ -57,10 +56,10 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component { ); From 0909112fa973a38ce871152ccd7d95aeb4a9cf96 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 20:21:11 +0100 Subject: [PATCH 02/22] Migrate CreateCrossSigningDialog to TypeScript --- ...Dialog.js => CreateCrossSigningDialog.tsx} | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) rename src/components/views/dialogs/security/{CreateCrossSigningDialog.js => CreateCrossSigningDialog.tsx} (85%) diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.js b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx similarity index 85% rename from src/components/views/dialogs/security/CreateCrossSigningDialog.js rename to src/components/views/dialogs/security/CreateCrossSigningDialog.tsx index fedcc02f89..7770da3049 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.js +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx @@ -16,7 +16,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import { _t } from '../../../../languageHandler'; import Modal from '../../../../Modal'; @@ -25,7 +24,19 @@ import DialogButtons from '../../elements/DialogButtons'; import BaseDialog from '../BaseDialog'; import Spinner from '../../elements/Spinner'; import InteractiveAuthDialog from '../InteractiveAuthDialog'; -import {replaceableComponent} from "../../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../../utils/replaceableComponent"; + +interface IProps { + accountPassword?: string; + tokenLogin?: boolean; + onFinished?: (success: boolean) => void; +} + +interface IState { + error: Error | null; + canUploadKeysWithPasswordOnly: boolean | null; + accountPassword: string; +} /* * Walks the user through the process of creating a cross-signing keys. In most @@ -33,12 +44,7 @@ import {replaceableComponent} from "../../../../utils/replaceableComponent"; * may need to complete some steps to proceed. */ @replaceableComponent("views.dialogs.security.CreateCrossSigningDialog") -export default class CreateCrossSigningDialog extends React.PureComponent { - static propTypes = { - accountPassword: PropTypes.string, - tokenLogin: PropTypes.bool, - }; - +export default class CreateCrossSigningDialog extends React.PureComponent { constructor(props) { super(props); @@ -46,26 +52,24 @@ export default class CreateCrossSigningDialog extends React.PureComponent { error: null, // Does the server offer a UI auth flow with just m.login.password // for /keys/device_signing/upload? - canUploadKeysWithPasswordOnly: null, - accountPassword: props.accountPassword || "", - }; - - if (this.state.accountPassword) { // If we have an account password in memory, let's simplify and // assume it means password auth is also supported for device // signing key upload as well. This avoids hitting the server to // test auth flows, which may be slow under high load. - this.state.canUploadKeysWithPasswordOnly = true; - } else { - this._queryKeyUploadAuth(); + canUploadKeysWithPasswordOnly: props.accountPassword ? true : null, + accountPassword: props.accountPassword || "", + }; + + if (!this.state.accountPassword) { + this.queryKeyUploadAuth(); } } - componentDidMount() { - this._bootstrapCrossSigning(); + public componentDidMount(): void { + this.bootstrapCrossSigning(); } - async _queryKeyUploadAuth() { + private async queryKeyUploadAuth(): Promise { try { await MatrixClientPeg.get().uploadDeviceSigningKeys(null, {}); // We should never get here: the server should always require @@ -86,7 +90,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent { } } - _doBootstrapUIAuth = async (makeRequest) => { + private doBootstrapUIAuth = async (makeRequest): Promise => { if (this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) { await makeRequest({ type: 'm.login.password', @@ -137,7 +141,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent { } } - _bootstrapCrossSigning = async () => { + private bootstrapCrossSigning = async (): Promise => { this.setState({ error: null, }); @@ -146,13 +150,13 @@ export default class CreateCrossSigningDialog extends React.PureComponent { try { await cli.bootstrapCrossSigning({ - authUploadDeviceSigningKeys: this._doBootstrapUIAuth, + authUploadDeviceSigningKeys: this.doBootstrapUIAuth, }); this.props.onFinished(true); } catch (e) { if (this.props.tokenLogin) { // ignore any failures, we are relying on grace period here - this.props.onFinished(); + this.props.onFinished(false); return; } @@ -161,7 +165,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent { } } - _onCancel = () => { + private onCancel = (): void => { this.props.onFinished(false); } @@ -172,8 +176,8 @@ export default class CreateCrossSigningDialog extends React.PureComponent {

{_t("Unable to set up keys")}

; From 68db2438ea84940086d8a05b960aeadd3e9de071 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 20:41:26 +0100 Subject: [PATCH 03/22] Migrate SetupEncryptionDialog to TypeScript --- ...ionDialog.js => SetupEncryptionDialog.tsx} | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) rename src/components/views/dialogs/security/{SetupEncryptionDialog.js => SetupEncryptionDialog.tsx} (77%) diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.js b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx similarity index 77% rename from src/components/views/dialogs/security/SetupEncryptionDialog.js rename to src/components/views/dialogs/security/SetupEncryptionDialog.tsx index 3c15ea9f1d..01ed3e0771 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.js +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx @@ -15,14 +15,13 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; import { SetupEncryptionStore, PHASE_DONE } from '../../../../stores/SetupEncryptionStore'; import {replaceableComponent} from "../../../../utils/replaceableComponent"; -function iconFromPhase(phase) { +function iconFromPhase(phase: string) { if (phase === PHASE_DONE) { return require("../../../../../res/img/e2e/verified.svg"); } else { @@ -30,32 +29,38 @@ function iconFromPhase(phase) { } } -@replaceableComponent("views.dialogs.security.SetupEncryptionDialog") -export default class SetupEncryptionDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; +interface IProps { + onFinished: (success: boolean) => void; +} - constructor() { - super(); +interface IState { + icon: any; +} + +@replaceableComponent("views.dialogs.security.SetupEncryptionDialog") +export default class SetupEncryptionDialog extends React.Component { + private store: SetupEncryptionStore; + + constructor(props) { + super(props); this.store = SetupEncryptionStore.sharedInstance(); this.state = {icon: iconFromPhase(this.store.phase)}; } - componentDidMount() { - this.store.on("update", this._onStoreUpdate); + public componentDidMount() { + this.store.on("update", this.onStoreUpdate); } - componentWillUnmount() { - this.store.removeListener("update", this._onStoreUpdate); + public componentWillUnmount() { + this.store.removeListener("update", this.onStoreUpdate); } - _onStoreUpdate = () => { + private onStoreUpdate = (): void => { this.setState({icon: iconFromPhase(this.store.phase)}); }; - render() { + public render() { return Date: Mon, 14 Jun 2021 20:58:20 +0100 Subject: [PATCH 04/22] migrate SetupEncryptionStore to TypeScript --- src/@types/global.d.ts | 2 + .../security/SetupEncryptionDialog.tsx | 8 +- ...yptionStore.js => SetupEncryptionStore.ts} | 97 +++++++++++-------- 3 files changed, 61 insertions(+), 46 deletions(-) rename src/stores/{SetupEncryptionStore.js => SetupEncryptionStore.ts} (73%) diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 22280b8a28..0c6b63dd33 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -44,6 +44,7 @@ import { EventIndexPeg } from "../indexing/EventIndexPeg"; import {VoiceRecordingStore} from "../stores/VoiceRecordingStore"; import PerformanceMonitor from "../performance"; import UIStore from "../stores/UIStore"; +import { SetupEncryptionStore } from "../stores/SetupEncryptionStore"; declare global { interface Window { @@ -84,6 +85,7 @@ declare global { mxPerformanceMonitor: PerformanceMonitor; mxPerformanceEntryNames: any; mxUIStore: UIStore; + mxSetupEncryptionStore?: SetupEncryptionStore; } interface Document { diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx index 01ed3e0771..b86b89cede 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx @@ -18,11 +18,11 @@ import React from 'react'; import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; -import { SetupEncryptionStore, PHASE_DONE } from '../../../../stores/SetupEncryptionStore'; +import { SetupEncryptionStore, PHASE } from '../../../../stores/SetupEncryptionStore'; import {replaceableComponent} from "../../../../utils/replaceableComponent"; -function iconFromPhase(phase: string) { - if (phase === PHASE_DONE) { +function iconFromPhase(phase: PHASE) { + if (phase === PHASE.DONE) { return require("../../../../../res/img/e2e/verified.svg"); } else { return require("../../../../../res/img/e2e/warning.svg"); @@ -34,7 +34,7 @@ interface IProps { } interface IState { - icon: any; + icon: PHASE; } @replaceableComponent("views.dialogs.security.SetupEncryptionDialog") diff --git a/src/stores/SetupEncryptionStore.js b/src/stores/SetupEncryptionStore.ts similarity index 73% rename from src/stores/SetupEncryptionStore.js rename to src/stores/SetupEncryptionStore.ts index b768ae69df..86e8b7afc3 100644 --- a/src/stores/SetupEncryptionStore.js +++ b/src/stores/SetupEncryptionStore.ts @@ -15,29 +15,42 @@ limitations under the License. */ import EventEmitter from 'events'; +import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; +import { IKeyBackupVersion } from "matrix-js-sdk/src/crypto/keybackup"; +import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/matrix"; import { MatrixClientPeg } from '../MatrixClientPeg'; import { accessSecretStorage, AccessCancelledError } from '../SecurityManager'; import { PHASE_DONE as VERIF_PHASE_DONE } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; -export const PHASE_LOADING = 0; -export const PHASE_INTRO = 1; -export const PHASE_BUSY = 2; -export const PHASE_DONE = 3; //final done stage, but still showing UX -export const PHASE_CONFIRM_SKIP = 4; -export const PHASE_FINISHED = 5; //UX can be closed +export enum PHASE { + LOADING = 0, + INTRO = 1, + BUSY = 2, + DONE = 3, // final done stage, but still showing UX + CONFIRM_SKIP = 4, + FINISHED = 5, // UX can be closed +} export class SetupEncryptionStore extends EventEmitter { - static sharedInstance() { - if (!global.mx_SetupEncryptionStore) global.mx_SetupEncryptionStore = new SetupEncryptionStore(); - return global.mx_SetupEncryptionStore; + private started: boolean; + public phase: PHASE; + public verificationRequest: VerificationRequest; + public backupInfo: IKeyBackupVersion; + public keyId: string; + public keyInfo: ISecretStorageKeyInfo; + public hasDevicesToVerifyAgainst: boolean; + + public static sharedInstance() { + if (!window.mxSetupEncryptionStore) window.mxSetupEncryptionStore = new SetupEncryptionStore(); + return window.mxSetupEncryptionStore; } - start() { - if (this._started) { + public start(): void { + if (this.started) { return; } - this._started = true; - this.phase = PHASE_LOADING; + this.started = true; + this.phase = PHASE.LOADING; this.verificationRequest = null; this.backupInfo = null; @@ -48,34 +61,34 @@ export class SetupEncryptionStore extends EventEmitter { const cli = MatrixClientPeg.get(); cli.on("crypto.verification.request", this.onVerificationRequest); - cli.on('userTrustStatusChanged', this._onUserTrustStatusChanged); + cli.on('userTrustStatusChanged', this.onUserTrustStatusChanged); const requestsInProgress = cli.getVerificationRequestsToDeviceInProgress(cli.getUserId()); if (requestsInProgress.length) { // If there are multiple, we take the most recent. Equally if the user sends another request from // another device after this screen has been shown, we'll switch to the new one, so this // generally doesn't support multiple requests. - this._setActiveVerificationRequest(requestsInProgress[requestsInProgress.length - 1]); + this.setActiveVerificationRequest(requestsInProgress[requestsInProgress.length - 1]); } this.fetchKeyInfo(); } - stop() { - if (!this._started) { + public stop(): void { + if (!this.started) { return; } - this._started = false; + this.started = false; if (this.verificationRequest) { this.verificationRequest.off("change", this.onVerificationRequestChange); } if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("crypto.verification.request", this.onVerificationRequest); - MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged); + MatrixClientPeg.get().removeListener('userTrustStatusChanged', this.onUserTrustStatusChanged); } } - async fetchKeyInfo() { + public async fetchKeyInfo(): Promise { const cli = MatrixClientPeg.get(); const keys = await cli.isSecretStored('m.cross_signing.master', false); if (keys === null || Object.keys(keys).length === 0) { @@ -97,15 +110,15 @@ export class SetupEncryptionStore extends EventEmitter { if (!this.hasDevicesToVerifyAgainst && !this.keyInfo) { // skip before we can even render anything. - this.phase = PHASE_FINISHED; + this.phase = PHASE.FINISHED; } else { - this.phase = PHASE_INTRO; + this.phase = PHASE.INTRO; } this.emit("update"); } - async usePassPhrase() { - this.phase = PHASE_BUSY; + public async usePassPhrase(): Promise { + this.phase = PHASE.BUSY; this.emit("update"); const cli = MatrixClientPeg.get(); try { @@ -120,7 +133,7 @@ export class SetupEncryptionStore extends EventEmitter { // passphase cached for that work. This dialog itself will only wait // on the first trust check, and the key backup restore will happen // in the background. - await new Promise((resolve, reject) => { + await new Promise((resolve: (value?: unknown) => void, reject: (reason?: any) => void) => { accessSecretStorage(async () => { await cli.checkOwnCrossSigningTrust(); resolve(); @@ -134,7 +147,7 @@ export class SetupEncryptionStore extends EventEmitter { }); if (cli.getCrossSigningId()) { - this.phase = PHASE_DONE; + this.phase = PHASE.DONE; this.emit("update"); } } catch (e) { @@ -142,25 +155,25 @@ export class SetupEncryptionStore extends EventEmitter { console.log(e); } // this will throw if the user hits cancel, so ignore - this.phase = PHASE_INTRO; + this.phase = PHASE.INTRO; this.emit("update"); } } - _onUserTrustStatusChanged = (userId) => { + private onUserTrustStatusChanged = (userId: string) => { if (userId !== MatrixClientPeg.get().getUserId()) return; const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); if (publicKeysTrusted) { - this.phase = PHASE_DONE; + this.phase = PHASE.DONE; this.emit("update"); } } - onVerificationRequest = (request) => { - this._setActiveVerificationRequest(request); + public onVerificationRequest = (request: VerificationRequest): void => { + this.setActiveVerificationRequest(request); } - onVerificationRequestChange = () => { + public onVerificationRequestChange = (): void => { if (this.verificationRequest.cancelled) { this.verificationRequest.off("change", this.onVerificationRequestChange); this.verificationRequest = null; @@ -172,34 +185,34 @@ export class SetupEncryptionStore extends EventEmitter { // cross signing to be ready to use, so wait for the user trust status to // change (or change to DONE if it's already ready). const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); - this.phase = publicKeysTrusted ? PHASE_DONE : PHASE_BUSY; + this.phase = publicKeysTrusted ? PHASE.DONE : PHASE.BUSY; this.emit("update"); } } - skip() { - this.phase = PHASE_CONFIRM_SKIP; + public skip(): void { + this.phase = PHASE.CONFIRM_SKIP; this.emit("update"); } - skipConfirm() { - this.phase = PHASE_FINISHED; + public skipConfirm(): void { + this.phase = PHASE.FINISHED; this.emit("update"); } - returnAfterSkip() { - this.phase = PHASE_INTRO; + public returnAfterSkip(): void { + this.phase = PHASE.INTRO; this.emit("update"); } - done() { - this.phase = PHASE_FINISHED; + public done(): void { + this.phase = PHASE.FINISHED; this.emit("update"); // async - ask other clients for keys, if necessary MatrixClientPeg.get().crypto.cancelAndResendAllOutgoingKeyRequests(); } - async _setActiveVerificationRequest(request) { + private async setActiveVerificationRequest(request: VerificationRequest): Promise { if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return; if (this.verificationRequest) { From f2250af5657ce3a92b6a743a6c11b6da9e7e7bff Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:03:12 +0100 Subject: [PATCH 05/22] Migrate AskInviteAnywayDialog to TypeScript --- ...wayDialog.js => AskInviteAnywayDialog.tsx} | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) rename src/components/views/dialogs/{AskInviteAnywayDialog.js => AskInviteAnywayDialog.tsx} (73%) diff --git a/src/components/views/dialogs/AskInviteAnywayDialog.js b/src/components/views/dialogs/AskInviteAnywayDialog.tsx similarity index 73% rename from src/components/views/dialogs/AskInviteAnywayDialog.js rename to src/components/views/dialogs/AskInviteAnywayDialog.tsx index e6cd45ba6b..970883aca2 100644 --- a/src/components/views/dialogs/AskInviteAnywayDialog.js +++ b/src/components/views/dialogs/AskInviteAnywayDialog.tsx @@ -15,39 +15,41 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; -import {SettingLevel} from "../../../settings/SettingLevel"; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { SettingLevel } from "../../../settings/SettingLevel"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; + +interface IProps { + unknownProfileUsers: Array<{ + userId: string; + errorText: string; + }>; + onInviteAnyways: () => void; + onGiveUp: () => void; + onFinished: (success: boolean) => void; +} @replaceableComponent("views.dialogs.AskInviteAnywayDialog") -export default class AskInviteAnywayDialog extends React.Component { - static propTypes = { - unknownProfileUsers: PropTypes.array.isRequired, // [ {userId, errorText}... ] - onInviteAnyways: PropTypes.func.isRequired, - onGiveUp: PropTypes.func.isRequired, - onFinished: PropTypes.func.isRequired, - }; - - _onInviteClicked = () => { +export default class AskInviteAnywayDialog extends React.Component { + private onInviteClicked = (): void => { this.props.onInviteAnyways(); this.props.onFinished(true); }; - _onInviteNeverWarnClicked = () => { + private onInviteNeverWarnClicked = (): void => { SettingsStore.setValue("promptBeforeInviteUnknownUsers", null, SettingLevel.ACCOUNT, false); this.props.onInviteAnyways(); this.props.onFinished(true); }; - _onGiveUpClicked = () => { + private onGiveUpClicked = (): void => { this.props.onGiveUp(); this.props.onFinished(false); }; - render() { + public render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const errorList = this.props.unknownProfileUsers @@ -55,11 +57,12 @@ export default class AskInviteAnywayDialog extends React.Component { return (
+ {/* eslint-disable-next-line */}

{_t("Unable to find profiles for the Matrix IDs listed below - would you like to invite them anyway?")}

    { errorList } @@ -67,13 +70,13 @@ export default class AskInviteAnywayDialog extends React.Component {
- - -
From be922264485846e4f0a37fa23815326cea813c2a Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:23:28 +0100 Subject: [PATCH 06/22] Migrate BugReportDialog to TypeScript --- ...BugReportDialog.js => BugReportDialog.tsx} | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) rename src/components/views/dialogs/{BugReportDialog.js => BugReportDialog.tsx} (79%) diff --git a/src/components/views/dialogs/BugReportDialog.js b/src/components/views/dialogs/BugReportDialog.tsx similarity index 79% rename from src/components/views/dialogs/BugReportDialog.js rename to src/components/views/dialogs/BugReportDialog.tsx index cbe0130649..f938340a50 100644 --- a/src/components/views/dialogs/BugReportDialog.js +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -18,7 +18,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; @@ -27,8 +26,27 @@ import sendBugReport, {downloadBugReport} from '../../../rageshake/submit-ragesh import AccessibleButton from "../elements/AccessibleButton"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +interface IProps { + onFinished: (success: boolean) => void; + initialText?: string; + label?: string; +} + +interface IState { + sendLogs: boolean; + busy: boolean; + err: string; + issueUrl: string; + text: string; + progress: string; + downloadBusy: boolean; + downloadProgress: string; +} + @replaceableComponent("views.dialogs.BugReportDialog") -export default class BugReportDialog extends React.Component { +export default class BugReportDialog extends React.Component { + private unmounted: boolean; + constructor(props) { super(props); this.state = { @@ -41,25 +59,18 @@ export default class BugReportDialog extends React.Component { downloadBusy: false, downloadProgress: null, }; - this._unmounted = false; - this._onSubmit = this._onSubmit.bind(this); - this._onCancel = this._onCancel.bind(this); - this._onTextChange = this._onTextChange.bind(this); - this._onIssueUrlChange = this._onIssueUrlChange.bind(this); - this._onSendLogsChange = this._onSendLogsChange.bind(this); - this._sendProgressCallback = this._sendProgressCallback.bind(this); - this._downloadProgressCallback = this._downloadProgressCallback.bind(this); + this.unmounted = false; } - componentWillUnmount() { - this._unmounted = true; + public componentWillUnmount() { + this.unmounted = true; } - _onCancel(ev) { + private onCancel = (): void => { this.props.onFinished(false); } - _onSubmit(ev) { + private onSubmit = (): void => { if ((!this.state.text || !this.state.text.trim()) && (!this.state.issueUrl || !this.state.issueUrl.trim())) { this.setState({ err: _t("Please tell us what went wrong or, better, create a GitHub issue that describes the problem."), @@ -72,15 +83,15 @@ export default class BugReportDialog extends React.Component { (this.state.issueUrl.length > 0 ? this.state.issueUrl : 'No issue link given'); this.setState({ busy: true, progress: null, err: null }); - this._sendProgressCallback(_t("Preparing to send logs")); + this.sendProgressCallback(_t("Preparing to send logs")); sendBugReport(SdkConfig.get().bug_report_endpoint_url, { userText, sendLogs: true, - progressCallback: this._sendProgressCallback, + progressCallback: this.sendProgressCallback, label: this.props.label, }).then(() => { - if (!this._unmounted) { + if (!this.unmounted) { this.props.onFinished(false); const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); // N.B. first param is passed to piwik and so doesn't want i18n @@ -91,7 +102,7 @@ export default class BugReportDialog extends React.Component { }); } }, (err) => { - if (!this._unmounted) { + if (!this.unmounted) { this.setState({ busy: false, progress: null, @@ -101,14 +112,14 @@ export default class BugReportDialog extends React.Component { }); } - _onDownload = async (ev) => { + private onDownload = async (): Promise => { this.setState({ downloadBusy: true }); - this._downloadProgressCallback(_t("Preparing to download logs")); + this.downloadProgressCallback(_t("Preparing to download logs")); try { await downloadBugReport({ sendLogs: true, - progressCallback: this._downloadProgressCallback, + progressCallback: this.downloadProgressCallback, label: this.props.label, }); @@ -117,7 +128,7 @@ export default class BugReportDialog extends React.Component { downloadProgress: null, }); } catch (err) { - if (!this._unmounted) { + if (!this.unmounted) { this.setState({ downloadBusy: false, downloadProgress: _t("Failed to send logs: ") + `${err.message}`, @@ -126,33 +137,29 @@ export default class BugReportDialog extends React.Component { } }; - _onTextChange(ev) { - this.setState({ text: ev.target.value }); + private onTextChange = (ev: React.FormEvent): void => { + this.setState({ text: ev.currentTarget.value }); } - _onIssueUrlChange(ev) { - this.setState({ issueUrl: ev.target.value }); + private onIssueUrlChange = (ev: React.FormEvent): void => { + this.setState({ issueUrl: ev.currentTarget.value }); } - _onSendLogsChange(ev) { - this.setState({ sendLogs: ev.target.checked }); - } - - _sendProgressCallback(progress) { - if (this._unmounted) { + private sendProgressCallback = (progress: string): void => { + if (this.unmounted) { return; } - this.setState({progress: progress}); + this.setState({ progress }); } - _downloadProgressCallback(downloadProgress) { - if (this._unmounted) { + private downloadProgressCallback = (downloadProgress: string): void => { + if (this.unmounted) { return; } this.setState({ downloadProgress }); } - render() { + public render() { const Loader = sdk.getComponent("elements.Spinner"); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -183,7 +190,7 @@ export default class BugReportDialog extends React.Component { } return ( - @@ -213,7 +220,7 @@ export default class BugReportDialog extends React.Component {

- + { _t("Download logs") } {this.state.downloadProgress && {this.state.downloadProgress} ...} @@ -223,7 +230,7 @@ export default class BugReportDialog extends React.Component { type="text" className="mx_BugReportDialog_field_input" label={_t("GitHub issue")} - onChange={this._onIssueUrlChange} + onChange={this.onIssueUrlChange} value={this.state.issueUrl} placeholder="https://github.com/vector-im/element-web/issues/..." /> @@ -232,7 +239,7 @@ export default class BugReportDialog extends React.Component { element="textarea" label={_t("Notes")} rows={5} - onChange={this._onTextChange} + onChange={this.onTextChange} value={this.state.text} placeholder={_t( "If there is additional context that would help in " + @@ -245,17 +252,12 @@ export default class BugReportDialog extends React.Component { {error}
); } } - -BugReportDialog.propTypes = { - onFinished: PropTypes.func.isRequired, - initialText: PropTypes.string, -}; From 1ff3aa0d746d9db291090e418c8d57db6c4cb203 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:26:15 +0100 Subject: [PATCH 07/22] Migrate ChangelogDialog to TypeScript --- ...ChangelogDialog.js => ChangelogDialog.tsx} | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) rename src/components/views/dialogs/{ChangelogDialog.js => ChangelogDialog.tsx} (88%) diff --git a/src/components/views/dialogs/ChangelogDialog.js b/src/components/views/dialogs/ChangelogDialog.tsx similarity index 88% rename from src/components/views/dialogs/ChangelogDialog.js rename to src/components/views/dialogs/ChangelogDialog.tsx index efbeba3977..0ded33cdcb 100644 --- a/src/components/views/dialogs/ChangelogDialog.js +++ b/src/components/views/dialogs/ChangelogDialog.tsx @@ -16,21 +16,26 @@ Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import request from 'browser-request'; import { _t } from '../../../languageHandler'; +interface IProps { + newVersion: string; + version: string; + onFinished: (success: boolean) => void; +} + const REPOS = ['vector-im/element-web', 'matrix-org/matrix-react-sdk', 'matrix-org/matrix-js-sdk']; -export default class ChangelogDialog extends React.Component { +export default class ChangelogDialog extends React.Component { constructor(props) { super(props); this.state = {}; } - componentDidMount() { + public componentDidMount() { const version = this.props.newVersion.split('-'); const version2 = this.props.version.split('-'); if (version == null || version2 == null) return; @@ -49,7 +54,7 @@ export default class ChangelogDialog extends React.Component { } } - _elementsForCommit(commit) { + private elementsForCommit(commit): JSX.Element { return (
  • @@ -59,7 +64,7 @@ export default class ChangelogDialog extends React.Component { ); } - render() { + public render() { const Spinner = sdk.getComponent('views.elements.Spinner'); const QuestionDialog = sdk.getComponent('dialogs.QuestionDialog'); @@ -72,7 +77,7 @@ export default class ChangelogDialog extends React.Component { msg: this.state[repo], }); } else { - content = this.state[repo].map(this._elementsForCommit); + content = this.state[repo].map(this.elementsForCommit); } return (
    @@ -99,9 +104,3 @@ export default class ChangelogDialog extends React.Component { ); } } - -ChangelogDialog.propTypes = { - version: PropTypes.string.isRequired, - newVersion: PropTypes.string.isRequired, - onFinished: PropTypes.func.isRequired, -}; From 6877504f2df0044d926de3ce3986d5430df96190 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:30:28 +0100 Subject: [PATCH 08/22] Migrate ConfirmAndWaitRedactDialog to TypeScript --- ...ialog.js => ConfirmAndWaitRedactDialog.tsx} | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) rename src/components/views/dialogs/{ConfirmAndWaitRedactDialog.js => ConfirmAndWaitRedactDialog.tsx} (89%) diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx similarity index 89% rename from src/components/views/dialogs/ConfirmAndWaitRedactDialog.js rename to src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx index 37d5510756..ae7b23c2c9 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx @@ -17,7 +17,17 @@ 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 { + redact: () => Promise; + onFinished: (success: boolean) => void; +} + +interface IState { + isRedacting: boolean; + redactionErrorCode: string | number; +} /* * A dialog for confirming a redaction. @@ -32,7 +42,7 @@ import {replaceableComponent} from "../../../utils/replaceableComponent"; * To avoid this, we keep the dialog open as long as /redact is in progress. */ @replaceableComponent("views.dialogs.ConfirmAndWaitRedactDialog") -export default class ConfirmAndWaitRedactDialog extends React.PureComponent { +export default class ConfirmAndWaitRedactDialog extends React.PureComponent { constructor(props) { super(props); this.state = { @@ -41,7 +51,7 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent { }; } - onParentFinished = async (proceed) => { + public onParentFinished = async (proceed: boolean): Promise => { if (proceed) { this.setState({isRedacting: true}); try { @@ -60,7 +70,7 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent { } }; - render() { + public render() { if (this.state.isRedacting) { if (this.state.redactionErrorCode) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); From 9443ef4ff9176ae4ce54925ea8cb4aa091cc4449 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:31:17 +0100 Subject: [PATCH 09/22] Migrate ConfirmRedactDialog to TypeScript --- .../{ConfirmRedactDialog.js => ConfirmRedactDialog.tsx} | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) rename src/components/views/dialogs/{ConfirmRedactDialog.js => ConfirmRedactDialog.tsx} (95%) diff --git a/src/components/views/dialogs/ConfirmRedactDialog.js b/src/components/views/dialogs/ConfirmRedactDialog.tsx similarity index 95% rename from src/components/views/dialogs/ConfirmRedactDialog.js rename to src/components/views/dialogs/ConfirmRedactDialog.tsx index bd63d3acc1..eee05599e8 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.js +++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx @@ -19,11 +19,15 @@ import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import {replaceableComponent} from "../../../utils/replaceableComponent"; +interface IProps { + onFinished: (success: boolean) => void; +} + /* * A dialog for confirming a redaction. */ @replaceableComponent("views.dialogs.ConfirmRedactDialog") -export default class ConfirmRedactDialog extends React.Component { +export default class ConfirmRedactDialog extends React.Component { render() { const TextInputDialog = sdk.getComponent('views.dialogs.TextInputDialog'); return ( From c2aaba1f796c58f6be7f8d1c08237dd3918f1ef5 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:36:56 +0100 Subject: [PATCH 10/22] Migrate ConfirmUserActionDialog to TypeScript --- ...nDialog.js => ConfirmUserActionDialog.tsx} | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) rename src/components/views/dialogs/{ConfirmUserActionDialog.js => ConfirmUserActionDialog.tsx} (76%) diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.js b/src/components/views/dialogs/ConfirmUserActionDialog.tsx similarity index 76% rename from src/components/views/dialogs/ConfirmUserActionDialog.js rename to src/components/views/dialogs/ConfirmUserActionDialog.tsx index 8059b9172a..13be70dbab 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.js +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -15,13 +15,31 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { MatrixClient } from 'matrix-js-sdk/src/client'; +import RoomMember from "matrix-js-sdk/src/models/room-member.js"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {mediaFromMxc} from "../../../customisations/Media"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { mediaFromMxc } from "../../../customisations/Media"; + +interface IProps { + // matrix-js-sdk (room) member object. Supply either this or 'groupMember' + member: RoomMember; + // group member object. Supply either this or 'member' + groupMember: GroupMemberType; + // needed if a group member is specified + matrixClient?: MatrixClient, + action: string; // eg. 'Ban' + title: string; // eg. 'Ban this user?' + + // Whether to display a text field for a reason + // If true, the second argument to onFinished will + // be the string entered. + askReason?: boolean; + danger?: boolean; + onFinished: (success: boolean, reason?: HTMLInputElement) => void; +} /* * A dialog for confirming an operation on another user. @@ -32,24 +50,8 @@ import {mediaFromMxc} from "../../../customisations/Media"; * Also tweaks the style for 'dangerous' actions (albeit only with colour) */ @replaceableComponent("views.dialogs.ConfirmUserActionDialog") -export default class ConfirmUserActionDialog extends React.Component { - static propTypes = { - // matrix-js-sdk (room) member object. Supply either this or 'groupMember' - member: PropTypes.object, - // group member object. Supply either this or 'member' - groupMember: GroupMemberType, - // needed if a group member is specified - matrixClient: PropTypes.instanceOf(MatrixClient), - action: PropTypes.string.isRequired, // eg. 'Ban' - title: PropTypes.string.isRequired, // eg. 'Ban this user?' - - // Whether to display a text field for a reason - // If true, the second argument to onFinished will - // be the string entered. - askReason: PropTypes.bool, - danger: PropTypes.bool, - onFinished: PropTypes.func.isRequired, - }; +export default class ConfirmUserActionDialog extends React.Component { + private reasonField: React.RefObject = React.createRef(); static defaultProps = { danger: false, @@ -59,26 +61,22 @@ export default class ConfirmUserActionDialog extends React.Component { constructor(props) { super(props); - this._reasonField = null; + this.reasonField = null; } - onOk = () => { + public onOk = (): void => { let reason; - if (this._reasonField) { - reason = this._reasonField.value; + if (this.reasonField) { + reason = this.reasonField.current; } this.props.onFinished(true, reason); }; - onCancel = () => { + public onCancel = (): void => { this.props.onFinished(false); }; - _collectReasonField = e => { - this._reasonField = e; - }; - - render() { + public render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const MemberAvatar = sdk.getComponent("views.avatars.MemberAvatar"); @@ -92,7 +90,7 @@ export default class ConfirmUserActionDialog extends React.Component {
    From 5cbbb5110b01f38a95d76edd5add59d5890e3da9 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:38:10 +0100 Subject: [PATCH 11/22] Migrate ConfirmWipeDeviceDialog to TypeScript --- ...ceDialog.js => ConfirmWipeDeviceDialog.tsx} | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename src/components/views/dialogs/{ConfirmWipeDeviceDialog.js => ConfirmWipeDeviceDialog.tsx} (88%) diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.js b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx similarity index 88% rename from src/components/views/dialogs/ConfirmWipeDeviceDialog.js rename to src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx index 333e1522f1..6911c845fb 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.js +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx @@ -20,17 +20,17 @@ import {_t} from "../../../languageHandler"; import * as sdk from "../../../index"; import {replaceableComponent} from "../../../utils/replaceableComponent"; -@replaceableComponent("views.dialogs.ConfirmWipeDeviceDialog") -export default class ConfirmWipeDeviceDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; +interface IProps { + onFinished: (success: boolean) => void; +} - _onConfirm = () => { +@replaceableComponent("views.dialogs.ConfirmWipeDeviceDialog") +export default class ConfirmWipeDeviceDialog extends React.Component { + private onConfirm = (): void => { this.props.onFinished(true); }; - _onDecline = () => { + private onDecline = (): void => { this.props.onFinished(false); }; @@ -55,10 +55,10 @@ export default class ConfirmWipeDeviceDialog extends React.Component {
    ); From de95f3bc01a6e506f9751387e0b2d83cb83c4d0d Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:43:54 +0100 Subject: [PATCH 12/22] Migrate CreateGroupDialog to TypeScript --- ...teGroupDialog.js => CreateGroupDialog.tsx} | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) rename src/components/views/dialogs/{CreateGroupDialog.js => CreateGroupDialog.tsx} (82%) diff --git a/src/components/views/dialogs/CreateGroupDialog.js b/src/components/views/dialogs/CreateGroupDialog.tsx similarity index 82% rename from src/components/views/dialogs/CreateGroupDialog.js rename to src/components/views/dialogs/CreateGroupDialog.tsx index e6c7a67aca..60e4f5efb8 100644 --- a/src/components/views/dialogs/CreateGroupDialog.js +++ b/src/components/views/dialogs/CreateGroupDialog.tsx @@ -15,44 +15,51 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {replaceableComponent} from "../../../utils/replaceableComponent"; -@replaceableComponent("views.dialogs.CreateGroupDialog") -export default class CreateGroupDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; +interface IProps { + onFinished: (success: boolean) => void; +} - state = { +interface IState { + groupName: string; + groupId: string; + groupIdError: string; + creating: boolean; + createError: Error; +} + +@replaceableComponent("views.dialogs.CreateGroupDialog") +export default class CreateGroupDialog extends React.Component { + public state = { groupName: '', groupId: '', - groupError: null, + groupIdError: '', creating: false, createError: null, }; - _onGroupNameChange = e => { + private onGroupNameChange = (e: React.FormEvent): void => { this.setState({ - groupName: e.target.value, + groupName: e.currentTarget.value, }); }; - _onGroupIdChange = e => { + private onGroupIdChange = (e: React.FormEvent): void => { this.setState({ - groupId: e.target.value, + groupId: e.currentTarget.value, }); }; - _onGroupIdBlur = e => { - this._checkGroupId(); + private onGroupIdBlur = (): void => { + this.checkGroupId(); }; - _checkGroupId(e) { + private checkGroupId() { let error = null; if (!this.state.groupId) { error = _t("Community IDs cannot be empty."); @@ -67,12 +74,12 @@ export default class CreateGroupDialog extends React.Component { return error; } - _onFormSubmit = e => { + private onFormSubmit = (e: React.FormEvent) => { e.preventDefault(); - if (this._checkGroupId()) return; + if (this.checkGroupId()) return; - const profile = {}; + const profile: any = {}; if (this.state.groupName !== '') { profile.name = this.state.groupName; } @@ -121,7 +128,7 @@ export default class CreateGroupDialog extends React.Component { - +
    @@ -129,9 +136,9 @@ export default class CreateGroupDialog extends React.Component {
    @@ -144,10 +151,10 @@ export default class CreateGroupDialog extends React.Component { + From e39baf3e2301b8280d7072d2660a2ac69df843de Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:45:12 +0100 Subject: [PATCH 13/22] Migrate CryptoStoreTooNewDialog to TypeScript --- ...toStoreTooNewDialog.js => CryptoStoreTooNewDialog.tsx} | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) rename src/components/views/dialogs/{CryptoStoreTooNewDialog.js => CryptoStoreTooNewDialog.tsx} (94%) diff --git a/src/components/views/dialogs/CryptoStoreTooNewDialog.js b/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx similarity index 94% rename from src/components/views/dialogs/CryptoStoreTooNewDialog.js rename to src/components/views/dialogs/CryptoStoreTooNewDialog.tsx index 6336c635e4..2bdf732bc5 100644 --- a/src/components/views/dialogs/CryptoStoreTooNewDialog.js +++ b/src/components/views/dialogs/CryptoStoreTooNewDialog.tsx @@ -22,7 +22,11 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; -export default (props) => { +interface IProps { + onFinished: (success: boolean) => void; +} + +export default (props: IProps) => { const brand = SdkConfig.get().brand; const _onLogoutClicked = () => { @@ -40,7 +44,7 @@ export default (props) => { onFinished: (doLogout) => { if (doLogout) { dis.dispatch({action: 'logout'}); - props.onFinished(); + props.onFinished(true); } }, }); From cf822d4d4c2964a05447347d18f972f594c01fc7 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:53:44 +0100 Subject: [PATCH 14/22] Migrate DeactivateAccountDialog to TypeScript --- .../structures/auth/Registration.tsx | 2 +- ...tDialog.js => DeactivateAccountDialog.tsx} | 56 +++++++++++-------- 2 files changed, 35 insertions(+), 23 deletions(-) rename src/components/views/dialogs/{DeactivateAccountDialog.js => DeactivateAccountDialog.tsx} (87%) diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 6feb1e34f7..de02b3eb8d 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -269,7 +269,7 @@ export default class Registration extends React.Component { ); } - private onUIAuthFinished = async (success, response, extra) => { + private onUIAuthFinished = async (success, response) => { if (!success) { let msg = response.message || response.toString(); // can we give a better error message? diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.tsx similarity index 87% rename from src/components/views/dialogs/DeactivateAccountDialog.js rename to src/components/views/dialogs/DeactivateAccountDialog.tsx index 4e52549d51..4e64a354bb 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -16,7 +16,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import Analytics from '../../../Analytics'; @@ -28,8 +27,25 @@ import {DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry} from "../auth/Interactiv import StyledCheckbox from "../elements/StyledCheckbox"; import {replaceableComponent} from "../../../utils/replaceableComponent"; +interface IProps { + onFinished: (success: boolean) => void; +} + +interface IState { + shouldErase: boolean; + errStr: string; + authData: any; // for UIA + authEnabled: boolean; // see usages for information + + // A few strings that are passed to InteractiveAuth for design or are displayed + // next to the InteractiveAuth component. + bodyText: string; + continueText: string; + continueKind: string; +} + @replaceableComponent("views.dialogs.DeactivateAccountDialog") -export default class DeactivateAccountDialog extends React.Component { +export default class DeactivateAccountDialog extends React.Component { constructor(props) { super(props); @@ -46,10 +62,10 @@ export default class DeactivateAccountDialog extends React.Component { continueKind: null, }; - this._initAuth(/* shouldErase= */false); + this.initAuth(/* shouldErase= */false); } - _onStagePhaseChange = (stage, phase) => { + private onStagePhaseChange = (stage: string, phase: string): void => { const dialogAesthetics = { [SSOAuthEntry.PHASE_PREAUTH]: { body: _t("Confirm your account deactivation by using Single Sign On to prove your identity."), @@ -87,19 +103,19 @@ export default class DeactivateAccountDialog extends React.Component { this.setState({bodyText, continueText, continueKind}); }; - _onUIAuthFinished = (success, result, extra) => { + private onUIAuthFinished = (success: boolean, result: Error) => { if (success) return; // great! makeRequest() will be called too. if (result === ERROR_USER_CANCELLED) { - this._onCancel(); + this.onCancel(); return; } - console.error("Error during UI Auth:", {result, extra}); + console.error("Error during UI Auth:", { result }); this.setState({errStr: _t("There was a problem communicating with the server. Please try again.")}); }; - _onUIAuthComplete = (auth) => { + private onUIAuthComplete = (auth): void => { MatrixClientPeg.get().deactivateAccount(auth, this.state.shouldErase).then(r => { // Deactivation worked - logout & close this dialog Analytics.trackEvent('Account', 'Deactivate Account'); @@ -111,9 +127,9 @@ export default class DeactivateAccountDialog extends React.Component { }); }; - _onEraseFieldChange = (ev) => { + private onEraseFieldChange = (ev: React.FormEvent): void => { this.setState({ - shouldErase: ev.target.checked, + shouldErase: ev.currentTarget.checked, // Disable the auth form because we're going to have to reinitialize the auth // information. We do this because we can't modify the parameters in the UIA @@ -123,14 +139,14 @@ export default class DeactivateAccountDialog extends React.Component { }); // As mentioned above, set up for auth again to get updated UIA session info - this._initAuth(/* shouldErase= */ev.target.checked); + this.initAuth(/* shouldErase= */ev.currentTarget.checked); }; - _onCancel() { + private onCancel(): void { this.props.onFinished(false); } - _initAuth(shouldErase) { + private initAuth(shouldErase: boolean): void { MatrixClientPeg.get().deactivateAccount(null, shouldErase).then(r => { // If we got here, oops. The server didn't require any auth. // Our application lifecycle will catch the error and do the logout bits. @@ -148,7 +164,7 @@ export default class DeactivateAccountDialog extends React.Component { }); } - render() { + public render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); let error = null; @@ -166,9 +182,9 @@ export default class DeactivateAccountDialog extends React.Component { @@ -214,7 +230,7 @@ export default class DeactivateAccountDialog extends React.Component {

    {_t( "Please forget all messages I have sent when my account is deactivated " + @@ -235,7 +251,3 @@ export default class DeactivateAccountDialog extends React.Component { ); } } - -DeactivateAccountDialog.propTypes = { - onFinished: PropTypes.func.isRequired, -}; From a030c1270a844c40a8120cd41bd209ac4707c6ce Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 21:55:47 +0100 Subject: [PATCH 15/22] Migrate ErrorDialog to TypeScript --- .../{ErrorDialog.js => ErrorDialog.tsx} | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) rename src/components/views/dialogs/{ErrorDialog.js => ErrorDialog.tsx} (81%) diff --git a/src/components/views/dialogs/ErrorDialog.js b/src/components/views/dialogs/ErrorDialog.tsx similarity index 81% rename from src/components/views/dialogs/ErrorDialog.js rename to src/components/views/dialogs/ErrorDialog.tsx index 5197c68b5a..d50ec7bf36 100644 --- a/src/components/views/dialogs/ErrorDialog.js +++ b/src/components/views/dialogs/ErrorDialog.tsx @@ -26,37 +26,37 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import {replaceableComponent} from "../../../utils/replaceableComponent"; -@replaceableComponent("views.dialogs.ErrorDialog") -export default class ErrorDialog extends React.Component { - static propTypes = { - title: PropTypes.string, - description: PropTypes.oneOfType([ - PropTypes.element, - PropTypes.string, - ]), - button: PropTypes.string, - focus: PropTypes.bool, - onFinished: PropTypes.func.isRequired, - headerImage: PropTypes.string, - }; +interface IProps { + onFinished: (success: boolean) => void; + title?: string; + description?: React.ReactNode; + button?: string; + focus?: boolean; + headerImage?: string; +} - static defaultProps = { +interface IState { + onFinished: (success: boolean) => void; +} + +@replaceableComponent("views.dialogs.ErrorDialog") +export default class ErrorDialog extends React.Component { + public static defaultProps = { focus: true, title: null, description: null, button: null, }; - onClick = () => { + private onClick = () => { this.props.onFinished(true); }; - render() { + public render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( Date: Mon, 14 Jun 2021 23:42:36 +0100 Subject: [PATCH 16/22] Migrate UserSettingsDialog to TypeScript --- src/components/structures/SpaceRoomView.tsx | 4 +- src/components/structures/UserMenu.tsx | 6 +- .../views/dialogs/BetaFeedbackDialog.tsx | 4 +- ...ttingsDialog.js => UserSettingsDialog.tsx} | 75 ++++++++++--------- src/components/views/right_panel/UserInfo.tsx | 4 +- .../tabs/user/HelpUserSettingsTab.tsx | 2 +- .../views/spaces/SpaceCreateMenu.tsx | 4 +- src/toasts/UnverifiedSessionToast.ts | 4 +- 8 files changed, 55 insertions(+), 48 deletions(-) rename src/components/views/dialogs/{UserSettingsDialog.js => UserSettingsDialog.tsx} (76%) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 276f4ae6ca..907a0e8873 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -59,7 +59,7 @@ import IconizedContextMenu, { } from "../views/context_menus/IconizedContextMenu"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; import {BetaPill} from "../views/beta/BetaCard"; -import {USER_LABS_TAB} from "../views/dialogs/UserSettingsDialog"; +import { USER_TAB } from "../views/dialogs/UserSettingsDialog"; import SettingsStore from "../../settings/SettingsStore"; import dis from "../../dispatcher/dispatcher"; import Modal from "../../Modal"; @@ -165,7 +165,7 @@ const SpaceInfo = ({ space }) => { const onBetaClick = () => { defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_LABS_TAB, + initialTabId: USER_TAB.LABS, }); }; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index 6a449cf1a2..d942c71c4a 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -26,7 +26,7 @@ import { ActionPayload } from "../../dispatcher/payloads"; import { Action } from "../../dispatcher/actions"; import { _t } from "../../languageHandler"; import { ContextMenuButton } from "./ContextMenu"; -import { USER_NOTIFICATIONS_TAB, USER_SECURITY_TAB } from "../views/dialogs/UserSettingsDialog"; +import { USER_TAB } from "../views/dialogs/UserSettingsDialog"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import FeedbackDialog from "../views/dialogs/FeedbackDialog"; import Modal from "../../Modal"; @@ -408,12 +408,12 @@ export default class UserMenu extends React.Component { this.onSettingsOpen(e, USER_NOTIFICATIONS_TAB)} + onClick={(e) => this.onSettingsOpen(e, USER_TAB.NOTIFICATIONS)} /> this.onSettingsOpen(e, USER_SECURITY_TAB)} + onClick={(e) => this.onSettingsOpen(e, USER_TAB.SECURITY)} /> = ({featureId, onFinished}) => { onFinished(false); defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_LABS_TAB, + initialTabId: USER_TAB.LABS, }); }}> { _t("To leave the beta, visit your settings.") } diff --git a/src/components/views/dialogs/UserSettingsDialog.js b/src/components/views/dialogs/UserSettingsDialog.tsx similarity index 76% rename from src/components/views/dialogs/UserSettingsDialog.js rename to src/components/views/dialogs/UserSettingsDialog.tsx index fe29b85aea..921aece7f4 100644 --- a/src/components/views/dialogs/UserSettingsDialog.js +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -16,7 +16,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import TabbedView, {Tab} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab"; @@ -35,41 +34,49 @@ import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab import {UIFeature} from "../../../settings/UIFeature"; import {replaceableComponent} from "../../../utils/replaceableComponent"; -export const USER_GENERAL_TAB = "USER_GENERAL_TAB"; -export const USER_APPEARANCE_TAB = "USER_APPEARANCE_TAB"; -export const USER_FLAIR_TAB = "USER_FLAIR_TAB"; -export const USER_NOTIFICATIONS_TAB = "USER_NOTIFICATIONS_TAB"; -export const USER_PREFERENCES_TAB = "USER_PREFERENCES_TAB"; -export const USER_VOICE_TAB = "USER_VOICE_TAB"; -export const USER_SECURITY_TAB = "USER_SECURITY_TAB"; -export const USER_LABS_TAB = "USER_LABS_TAB"; -export const USER_MJOLNIR_TAB = "USER_MJOLNIR_TAB"; -export const USER_HELP_TAB = "USER_HELP_TAB"; +export enum USER_TAB { + GENERAL = "USER_GENERAL_TAB", + APPEARANCE = "USER_APPEARANCE_TAB", + FLAIR = "USER_FLAIR_TAB", + NOTIFICATIONS = "USER_NOTIFICATIONS_TAB", + PREFERENCES = "USER_PREFERENCES_TAB", + VOICE = "USER_VOICE_TAB", + SECURITY = "USER_SECURITY_TAB", + LABS = "USER_LABS_TAB", + MJOLNIR = "USER_MJOLNIR_TAB", + HELP = "USER_HELP_TAB", +} + +interface IProps { + onFinished: (success: boolean) => void; + initialTabId?: string; +} + +interface IState { + mjolnirEnabled: boolean; +} @replaceableComponent("views.dialogs.UserSettingsDialog") -export default class UserSettingsDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - initialTabId: PropTypes.string, - }; +export default class UserSettingsDialog extends React.Component { + private mjolnirWatcher: string; - constructor() { - super(); + constructor(props) { + super(props); this.state = { mjolnirEnabled: SettingsStore.getValue("feature_mjolnir"), }; } - componentDidMount(): void { - this._mjolnirWatcher = SettingsStore.watchSetting("feature_mjolnir", null, this._mjolnirChanged.bind(this)); + public componentDidMount(): void { + this.mjolnirWatcher = SettingsStore.watchSetting("feature_mjolnir", null, this.mjolnirChanged); } - componentWillUnmount(): void { - SettingsStore.unwatchSetting(this._mjolnirWatcher); + public componentWillUnmount(): void { + SettingsStore.unwatchSetting(this.mjolnirWatcher); } - _mjolnirChanged(settingName, roomId, atLevel, newValue) { + private mjolnirChanged = (settingName, roomId, atLevel, newValue: boolean) => { // We can cheat because we know what levels a feature is tracked at, and how it is tracked this.setState({mjolnirEnabled: newValue}); } @@ -78,33 +85,33 @@ export default class UserSettingsDialog extends React.Component { const tabs = []; tabs.push(new Tab( - USER_GENERAL_TAB, + USER_TAB.GENERAL, _td("General"), "mx_UserSettingsDialog_settingsIcon", , )); tabs.push(new Tab( - USER_APPEARANCE_TAB, + USER_TAB.APPEARANCE, _td("Appearance"), "mx_UserSettingsDialog_appearanceIcon", , )); if (SettingsStore.getValue(UIFeature.Flair)) { tabs.push(new Tab( - USER_FLAIR_TAB, + USER_TAB.FLAIR, _td("Flair"), "mx_UserSettingsDialog_flairIcon", , )); } tabs.push(new Tab( - USER_NOTIFICATIONS_TAB, + USER_TAB.NOTIFICATIONS, _td("Notifications"), "mx_UserSettingsDialog_bellIcon", , )); tabs.push(new Tab( - USER_PREFERENCES_TAB, + USER_TAB.PREFERENCES, _td("Preferences"), "mx_UserSettingsDialog_preferencesIcon", , @@ -112,7 +119,7 @@ export default class UserSettingsDialog extends React.Component { if (SettingsStore.getValue(UIFeature.Voip)) { tabs.push(new Tab( - USER_VOICE_TAB, + USER_TAB.VOICE, _td("Voice & Video"), "mx_UserSettingsDialog_voiceIcon", , @@ -120,7 +127,7 @@ export default class UserSettingsDialog extends React.Component { } tabs.push(new Tab( - USER_SECURITY_TAB, + USER_TAB.SECURITY, _td("Security & Privacy"), "mx_UserSettingsDialog_securityIcon", , @@ -130,7 +137,7 @@ export default class UserSettingsDialog extends React.Component { || SettingsStore.getFeatureSettingNames().some(k => SettingsStore.getBetaInfo(k)) ) { tabs.push(new Tab( - USER_LABS_TAB, + USER_TAB.LABS, _td("Labs"), "mx_UserSettingsDialog_labsIcon", , @@ -138,17 +145,17 @@ export default class UserSettingsDialog extends React.Component { } if (this.state.mjolnirEnabled) { tabs.push(new Tab( - USER_MJOLNIR_TAB, + USER_TAB.MJOLNIR, _td("Ignored users"), "mx_UserSettingsDialog_mjolnirIcon", , )); } tabs.push(new Tab( - USER_HELP_TAB, + USER_TAB.HELP, _td("Help & About"), "mx_UserSettingsDialog_helpIcon", - , + this.props.onFinished(true)} />, )); return tabs; diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index d6c97f9cf2..ce5a96c8a3 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -48,7 +48,7 @@ import EncryptionPanel from "./EncryptionPanel"; import { useAsyncMemo } from '../../../hooks/useAsyncMemo'; import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification'; import { Action } from "../../../dispatcher/actions"; -import { USER_SECURITY_TAB } from "../dialogs/UserSettingsDialog"; +import { USER_TAB } from "../dialogs/UserSettingsDialog"; import { useIsEncrypted } from "../../../hooks/useIsEncrypted"; import BaseCard from "./BaseCard"; import { E2EStatus } from "../../../utils/ShieldUtils"; @@ -1381,7 +1381,7 @@ const BasicUserInfo: React.FC<{ { dis.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_SECURITY_TAB, + initialTabId: USER_TAB.SECURITY, }); }}> { _t("Edit devices") } diff --git a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx index 3fa0be478c..beff033001 100644 --- a/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx @@ -32,7 +32,7 @@ import * as ContextMenu from "../../../../structures/ContextMenu"; import { toRightOf } from "../../../../structures/ContextMenu"; interface IProps { - closeSettingsFn: () => {}; + closeSettingsFn: () => void; } interface IState { diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 0ebf511018..29be03eaa4 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -29,7 +29,7 @@ import AccessibleButton from "../elements/AccessibleButton"; import {BetaPill} from "../beta/BetaCard"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import {Action} from "../../../dispatcher/actions"; -import {USER_LABS_TAB} from "../dialogs/UserSettingsDialog"; +import { USER_TAB } from "../dialogs/UserSettingsDialog"; import Field from "../elements/Field"; import withValidation from "../elements/Validation"; import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView"; @@ -222,7 +222,7 @@ const SpaceCreateMenu = ({ onFinished }) => { onFinished(); defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_LABS_TAB, + initialTabId: USER_TAB.LABS, }); }} /> { body } diff --git a/src/toasts/UnverifiedSessionToast.ts b/src/toasts/UnverifiedSessionToast.ts index c856d39d1f..8e3fa7c8a7 100644 --- a/src/toasts/UnverifiedSessionToast.ts +++ b/src/toasts/UnverifiedSessionToast.ts @@ -21,7 +21,7 @@ import DeviceListener from '../DeviceListener'; import ToastStore from "../stores/ToastStore"; import GenericToast from "../components/views/toasts/GenericToast"; import { Action } from "../dispatcher/actions"; -import { USER_SECURITY_TAB } from "../components/views/dialogs/UserSettingsDialog"; +import { USER_TAB } from "../components/views/dialogs/UserSettingsDialog"; function toastKey(deviceId: string) { return "unverified_session_" + deviceId; @@ -34,7 +34,7 @@ export const showToast = async (deviceId: string) => { DeviceListener.sharedInstance().dismissUnverifiedSessions([deviceId]); dis.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_SECURITY_TAB, + initialTabId: USER_TAB.SECURITY, }); }; From 75151b7a6c8bc690fe38c145ab77d27000438ad5 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 23:50:41 +0100 Subject: [PATCH 17/22] Migrate TermsDialog to TypeScript --- .../{TermsDialog.js => TermsDialog.tsx} | 100 ++++++++++-------- 1 file changed, 53 insertions(+), 47 deletions(-) rename src/components/views/dialogs/{TermsDialog.js => TermsDialog.tsx} (72%) diff --git a/src/components/views/dialogs/TermsDialog.js b/src/components/views/dialogs/TermsDialog.tsx similarity index 72% rename from src/components/views/dialogs/TermsDialog.js rename to src/components/views/dialogs/TermsDialog.tsx index e8625ec6cb..ace5316323 100644 --- a/src/components/views/dialogs/TermsDialog.js +++ b/src/components/views/dialogs/TermsDialog.tsx @@ -16,22 +16,21 @@ limitations under the License. import url from 'url'; import React from 'react'; -import PropTypes from 'prop-types'; import * as sdk from '../../../index'; import { _t, pickBestLanguage } from '../../../languageHandler'; import {replaceableComponent} from "../../../utils/replaceableComponent"; -import {SERVICE_TYPES} from "matrix-js-sdk/src/service-types"; +import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; -class TermsCheckbox extends React.PureComponent { - static propTypes = { - onChange: PropTypes.func.isRequired, - url: PropTypes.string.isRequired, - checked: PropTypes.bool.isRequired, - } +interface ITermsCheckboxProps { + onChange: (url: string, checked: boolean) => void; + url: string; + checked: boolean; +} - onChange = (ev) => { - this.props.onChange(this.props.url, ev.target.checked); +class TermsCheckbox extends React.PureComponent { + private onChange = (ev: React.FormEvent): void => { + this.props.onChange(this.props.url, ev.currentTarget.checked); } render() { @@ -42,30 +41,34 @@ class TermsCheckbox extends React.PureComponent { } } +interface ITermsDialogProps { + /** + * Array of [Service, policies] pairs, where policies is the response from the + * /terms endpoint for that service + */ + policiesAndServicePairs: any[], + + /** + * urls that the user has already agreed to + */ + agreedUrls?: string[], + + /** + * Called with: + * * success {bool} True if the user accepted any douments, false if cancelled + * * agreedUrls {string[]} List of agreed URLs + */ + onFinished: (success: boolean, agreedUrls?: string[]) => void, +} + +interface IState { + agreedUrls: any; +} + @replaceableComponent("views.dialogs.TermsDialog") -export default class TermsDialog extends React.PureComponent { - static propTypes = { - /** - * Array of [Service, policies] pairs, where policies is the response from the - * /terms endpoint for that service - */ - policiesAndServicePairs: PropTypes.array.isRequired, - - /** - * urls that the user has already agreed to - */ - agreedUrls: PropTypes.arrayOf(PropTypes.string), - - /** - * Called with: - * * success {bool} True if the user accepted any douments, false if cancelled - * * agreedUrls {string[]} List of agreed URLs - */ - onFinished: PropTypes.func.isRequired, - } - +export default class TermsDialog extends React.PureComponent { constructor(props) { - super(); + super(props); this.state = { // url -> boolean agreedUrls: {}, @@ -75,15 +78,15 @@ export default class TermsDialog extends React.PureComponent { } } - _onCancelClick = () => { + private onCancelClick = (): void => { this.props.onFinished(false); } - _onNextClick = () => { + private onNextClick = (): void => { this.props.onFinished(true, Object.keys(this.state.agreedUrls).filter((url) => this.state.agreedUrls[url])); } - _nameForServiceType(serviceType, host) { + private nameForServiceType(serviceType: SERVICE_TYPES, host: string): JSX.Element { switch (serviceType) { case SERVICE_TYPES.IS: return

    {_t("Identity Server")}
    ({host})
    ; @@ -92,7 +95,7 @@ export default class TermsDialog extends React.PureComponent { } } - _summaryForServiceType(serviceType) { + private summaryForServiceType(serviceType: SERVICE_TYPES): JSX.Element { switch (serviceType) { case SERVICE_TYPES.IS: return
    @@ -107,13 +110,13 @@ export default class TermsDialog extends React.PureComponent { } } - _onTermsCheckboxChange = (url, checked) => { + private onTermsCheckboxChange = (url: string, checked: boolean) => { this.setState({ agreedUrls: Object.assign({}, this.state.agreedUrls, { [url]: checked }), }); } - render() { + public render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -128,8 +131,8 @@ export default class TermsDialog extends React.PureComponent { let serviceName; let summary; if (i === 0) { - serviceName = this._nameForServiceType(policiesAndService.service.serviceType, parsedBaseUrl.host); - summary = this._summaryForServiceType( + serviceName = this.nameForServiceType(policiesAndService.service.serviceType, parsedBaseUrl.host); + summary = this.summaryForServiceType( policiesAndService.service.serviceType, ); } @@ -137,12 +140,15 @@ export default class TermsDialog extends React.PureComponent { rows.push( {serviceName} {summary} - {termDoc[termsLang].name} - - + + {termDoc[termsLang].name} + + + + ); @@ -176,7 +182,7 @@ export default class TermsDialog extends React.PureComponent { return ( From b2f20e052df53cd1a992ab0621a9d723f3891336 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 23:51:38 +0100 Subject: [PATCH 18/22] remove unused import --- src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx index 6911c845fb..d95b1fe358 100644 --- a/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx +++ b/src/components/views/dialogs/ConfirmWipeDeviceDialog.tsx @@ -15,7 +15,6 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import {_t} from "../../../languageHandler"; import * as sdk from "../../../index"; import {replaceableComponent} from "../../../utils/replaceableComponent"; From 07bdaeaf704b02569edfc3c6a33de75923bdbee2 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Mon, 14 Jun 2021 23:55:14 +0100 Subject: [PATCH 19/22] Fix mjolnir private chat enum --- src/mjolnir/Mjolnir.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mjolnir/Mjolnir.ts b/src/mjolnir/Mjolnir.ts index 891438bbb9..71d63f650c 100644 --- a/src/mjolnir/Mjolnir.ts +++ b/src/mjolnir/Mjolnir.ts @@ -20,6 +20,7 @@ import SettingsStore from "../settings/SettingsStore"; import {_t} from "../languageHandler"; import dis from "../dispatcher/dispatcher"; import {SettingLevel} from "../settings/SettingLevel"; +import { Preset } from "../createRoom"; // TODO: Move this and related files to the js-sdk or something once finalized. @@ -86,7 +87,7 @@ export class Mjolnir { const resp = await MatrixClientPeg.get().createRoom({ name: _t("My Ban List"), topic: _t("This is your list of users/servers you have blocked - don't leave the room!"), - preset: "private_chat", + preset: Preset.PrivateChat, }); personalRoomId = resp['room_id']; await SettingsStore.setValue( From 2e6dab0bcd93cfc6e8362423218372767572ae63 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Tue, 15 Jun 2021 00:01:05 +0100 Subject: [PATCH 20/22] change parameter to use preset enum --- src/components/views/dialogs/CreateRoomDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index cce6b6c34c..614ed4f645 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -72,7 +72,7 @@ export default class CreateRoomDialog extends React.Component { canChangeEncryption: true, }; - MatrixClientPeg.get().doesServerForceEncryptionForPreset("private") + MatrixClientPeg.get().doesServerForceEncryptionForPreset(Preset.PrivateChat) .then(isForced => this.setState({ canChangeEncryption: !isForced })); } From d22617c422ebabc88435bb8a8421b0b347d5e7c0 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 18 Jun 2021 12:44:15 +0100 Subject: [PATCH 21/22] More specific type definition and adhering to code style better --- src/components/structures/SpaceRoomView.tsx | 4 +- src/components/structures/UserMenu.tsx | 6 +-- .../structures/auth/Registration.tsx | 2 +- .../views/dialogs/BetaFeedbackDialog.tsx | 4 +- .../views/dialogs/ConfirmUserActionDialog.tsx | 6 --- .../views/dialogs/DeactivateAccountDialog.tsx | 2 +- .../views/dialogs/UserSettingsDialog.tsx | 46 +++++++++---------- .../security/CreateCrossSigningDialog.tsx | 6 +-- .../security/SetupEncryptionDialog.tsx | 10 ++-- src/components/views/right_panel/UserInfo.tsx | 4 +- .../views/spaces/SpaceCreateMenu.tsx | 4 +- src/stores/SetupEncryptionStore.ts | 40 ++++++++-------- src/toasts/UnverifiedSessionToast.ts | 4 +- 13 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 36da384e69..aad770888b 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -59,7 +59,7 @@ import IconizedContextMenu, { } from "../views/context_menus/IconizedContextMenu"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; import {BetaPill} from "../views/beta/BetaCard"; -import { USER_TAB } from "../views/dialogs/UserSettingsDialog"; +import { UserTab } from "../views/dialogs/UserSettingsDialog"; import SettingsStore from "../../settings/SettingsStore"; import dis from "../../dispatcher/dispatcher"; import Modal from "../../Modal"; @@ -166,7 +166,7 @@ const SpaceInfo = ({ space }) => { const onBetaClick = () => { defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_TAB.LABS, + initialTabId: UserTab.Labs, }); }; diff --git a/src/components/structures/UserMenu.tsx b/src/components/structures/UserMenu.tsx index d942c71c4a..3cf0dc5f84 100644 --- a/src/components/structures/UserMenu.tsx +++ b/src/components/structures/UserMenu.tsx @@ -26,7 +26,7 @@ import { ActionPayload } from "../../dispatcher/payloads"; import { Action } from "../../dispatcher/actions"; import { _t } from "../../languageHandler"; import { ContextMenuButton } from "./ContextMenu"; -import { USER_TAB } from "../views/dialogs/UserSettingsDialog"; +import { UserTab } from "../views/dialogs/UserSettingsDialog"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import FeedbackDialog from "../views/dialogs/FeedbackDialog"; import Modal from "../../Modal"; @@ -408,12 +408,12 @@ export default class UserMenu extends React.Component { this.onSettingsOpen(e, USER_TAB.NOTIFICATIONS)} + onClick={(e) => this.onSettingsOpen(e, UserTab.Notifications)} /> this.onSettingsOpen(e, USER_TAB.SECURITY)} + onClick={(e) => this.onSettingsOpen(e, UserTab.Security)} /> { ); } - private onUIAuthFinished = async (success, response) => { + private onUIAuthFinished = async (success: boolean, response: any) => { if (!success) { let msg = response.message || response.toString(); // can we give a better error message? diff --git a/src/components/views/dialogs/BetaFeedbackDialog.tsx b/src/components/views/dialogs/BetaFeedbackDialog.tsx index 85fe81ef4e..1c2dab4bfc 100644 --- a/src/components/views/dialogs/BetaFeedbackDialog.tsx +++ b/src/components/views/dialogs/BetaFeedbackDialog.tsx @@ -29,7 +29,7 @@ import InfoDialog from "./InfoDialog"; import AccessibleButton from "../elements/AccessibleButton"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import {Action} from "../../../dispatcher/actions"; -import { USER_TAB } from "./UserSettingsDialog"; +import { UserTab } from "./UserSettingsDialog"; interface IProps extends IDialogProps { featureId: string; @@ -70,7 +70,7 @@ const BetaFeedbackDialog: React.FC = ({featureId, onFinished}) => { onFinished(false); defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_TAB.LABS, + initialTabId: UserTab.Labs, }); }}> { _t("To leave the beta, visit your settings.") } diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx index 13be70dbab..c91dcba95c 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -58,12 +58,6 @@ export default class ConfirmUserActionDialog extends React.Component { askReason: false, }; - constructor(props) { - super(props); - - this.reasonField = null; - } - public onOk = (): void => { let reason; if (this.reasonField) { diff --git a/src/components/views/dialogs/DeactivateAccountDialog.tsx b/src/components/views/dialogs/DeactivateAccountDialog.tsx index 4e64a354bb..cf88802340 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.tsx +++ b/src/components/views/dialogs/DeactivateAccountDialog.tsx @@ -115,7 +115,7 @@ export default class DeactivateAccountDialog extends React.Component { + private onUIAuthComplete = (auth: any): void => { MatrixClientPeg.get().deactivateAccount(auth, this.state.shouldErase).then(r => { // Deactivation worked - logout & close this dialog Analytics.trackEvent('Account', 'Deactivate Account'); diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx index 921aece7f4..1a62a4ff22 100644 --- a/src/components/views/dialogs/UserSettingsDialog.tsx +++ b/src/components/views/dialogs/UserSettingsDialog.tsx @@ -19,7 +19,7 @@ import React from 'react'; import TabbedView, {Tab} from "../../structures/TabbedView"; import {_t, _td} from "../../../languageHandler"; import GeneralUserSettingsTab from "../settings/tabs/user/GeneralUserSettingsTab"; -import SettingsStore from "../../../settings/SettingsStore"; +import SettingsStore, { CallbackFn } from "../../../settings/SettingsStore"; import LabsUserSettingsTab from "../settings/tabs/user/LabsUserSettingsTab"; import AppearanceUserSettingsTab from "../settings/tabs/user/AppearanceUserSettingsTab"; import SecurityUserSettingsTab from "../settings/tabs/user/SecurityUserSettingsTab"; @@ -34,17 +34,17 @@ import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab import {UIFeature} from "../../../settings/UIFeature"; import {replaceableComponent} from "../../../utils/replaceableComponent"; -export enum USER_TAB { - GENERAL = "USER_GENERAL_TAB", - APPEARANCE = "USER_APPEARANCE_TAB", - FLAIR = "USER_FLAIR_TAB", - NOTIFICATIONS = "USER_NOTIFICATIONS_TAB", - PREFERENCES = "USER_PREFERENCES_TAB", - VOICE = "USER_VOICE_TAB", - SECURITY = "USER_SECURITY_TAB", - LABS = "USER_LABS_TAB", - MJOLNIR = "USER_MJOLNIR_TAB", - HELP = "USER_HELP_TAB", +export enum UserTab { + General = "USER_GENERAL_TAB", + Appearance = "USER_APPEARANCE_TAB", + Flair = "USER_FLAIR_TAB", + Notifications = "USER_NOTIFICATIONS_TAB", + Preferences = "USER_PREFERENCES_TAB", + Voice = "USER_VOICE_TAB", + Security = "USER_SECURITY_TAB", + Labs = "USER_LABS_TAB", + Mjolnir = "USER_MJOLNIR_TAB", + Help = "USER_HELP_TAB", } interface IProps { @@ -76,7 +76,7 @@ export default class UserSettingsDialog extends React.Component SettingsStore.unwatchSetting(this.mjolnirWatcher); } - private mjolnirChanged = (settingName, roomId, atLevel, newValue: boolean) => { + 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}); } @@ -85,33 +85,33 @@ export default class UserSettingsDialog extends React.Component const tabs = []; tabs.push(new Tab( - USER_TAB.GENERAL, + UserTab.General, _td("General"), "mx_UserSettingsDialog_settingsIcon", , )); tabs.push(new Tab( - USER_TAB.APPEARANCE, + UserTab.Appearance, _td("Appearance"), "mx_UserSettingsDialog_appearanceIcon", , )); if (SettingsStore.getValue(UIFeature.Flair)) { tabs.push(new Tab( - USER_TAB.FLAIR, + UserTab.Flair, _td("Flair"), "mx_UserSettingsDialog_flairIcon", , )); } tabs.push(new Tab( - USER_TAB.NOTIFICATIONS, + UserTab.Notifications, _td("Notifications"), "mx_UserSettingsDialog_bellIcon", , )); tabs.push(new Tab( - USER_TAB.PREFERENCES, + UserTab.Preferences, _td("Preferences"), "mx_UserSettingsDialog_preferencesIcon", , @@ -119,7 +119,7 @@ export default class UserSettingsDialog extends React.Component if (SettingsStore.getValue(UIFeature.Voip)) { tabs.push(new Tab( - USER_TAB.VOICE, + UserTab.Voice, _td("Voice & Video"), "mx_UserSettingsDialog_voiceIcon", , @@ -127,7 +127,7 @@ export default class UserSettingsDialog extends React.Component } tabs.push(new Tab( - USER_TAB.SECURITY, + UserTab.Security, _td("Security & Privacy"), "mx_UserSettingsDialog_securityIcon", , @@ -137,7 +137,7 @@ export default class UserSettingsDialog extends React.Component || SettingsStore.getFeatureSettingNames().some(k => SettingsStore.getBetaInfo(k)) ) { tabs.push(new Tab( - USER_TAB.LABS, + UserTab.Labs, _td("Labs"), "mx_UserSettingsDialog_labsIcon", , @@ -145,14 +145,14 @@ export default class UserSettingsDialog extends React.Component } if (this.state.mjolnirEnabled) { tabs.push(new Tab( - USER_TAB.MJOLNIR, + UserTab.Mjolnir, _td("Ignored users"), "mx_UserSettingsDialog_mjolnirIcon", , )); } tabs.push(new Tab( - USER_TAB.HELP, + UserTab.Help, _td("Help & About"), "mx_UserSettingsDialog_helpIcon", this.props.onFinished(true)} />, diff --git a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx index 7770da3049..840390f6fb 100644 --- a/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx +++ b/src/components/views/dialogs/security/CreateCrossSigningDialog.tsx @@ -34,7 +34,7 @@ interface IProps { interface IState { error: Error | null; - canUploadKeysWithPasswordOnly: boolean | null; + canUploadKeysWithPasswordOnly?: boolean; accountPassword: string; } @@ -45,7 +45,7 @@ interface IState { */ @replaceableComponent("views.dialogs.security.CreateCrossSigningDialog") export default class CreateCrossSigningDialog extends React.PureComponent { - constructor(props) { + constructor(props: IProps) { super(props); this.state = { @@ -90,7 +90,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent => { + private doBootstrapUIAuth = async (makeRequest: (authData: any) => void): Promise => { if (this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) { await makeRequest({ type: 'm.login.password', diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx index b86b89cede..19c7af01ff 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx @@ -18,11 +18,11 @@ import React from 'react'; import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; -import { SetupEncryptionStore, PHASE } from '../../../../stores/SetupEncryptionStore'; +import { SetupEncryptionStore, Phase } from '../../../../stores/SetupEncryptionStore'; import {replaceableComponent} from "../../../../utils/replaceableComponent"; -function iconFromPhase(phase: PHASE) { - if (phase === PHASE.DONE) { +function iconFromPhase(phase: Phase) { + if (phase === Phase.Done) { return require("../../../../../res/img/e2e/verified.svg"); } else { return require("../../../../../res/img/e2e/warning.svg"); @@ -34,14 +34,14 @@ interface IProps { } interface IState { - icon: PHASE; + icon: Phase; } @replaceableComponent("views.dialogs.security.SetupEncryptionDialog") export default class SetupEncryptionDialog extends React.Component { private store: SetupEncryptionStore; - constructor(props) { + constructor(props: IProps) { super(props); this.store = SetupEncryptionStore.sharedInstance(); diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index fe77ac0377..03954bad56 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -48,7 +48,7 @@ import EncryptionPanel from "./EncryptionPanel"; import { useAsyncMemo } from '../../../hooks/useAsyncMemo'; import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification'; import { Action } from "../../../dispatcher/actions"; -import { USER_TAB } from "../dialogs/UserSettingsDialog"; +import { UserTab } from "../dialogs/UserSettingsDialog"; import { useIsEncrypted } from "../../../hooks/useIsEncrypted"; import BaseCard from "./BaseCard"; import { E2EStatus } from "../../../utils/ShieldUtils"; @@ -1381,7 +1381,7 @@ const BasicUserInfo: React.FC<{ { dis.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_TAB.SECURITY, + initialTabId: UserTab.Security, }); }}> { _t("Edit devices") } diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index 95bbabbe53..977cd4a9aa 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -29,7 +29,7 @@ import AccessibleButton from "../elements/AccessibleButton"; import {BetaPill} from "../beta/BetaCard"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import {Action} from "../../../dispatcher/actions"; -import { USER_TAB } from "../dialogs/UserSettingsDialog"; +import { UserTab } from "../dialogs/UserSettingsDialog"; import Field from "../elements/Field"; import withValidation from "../elements/Validation"; import {SpaceFeedbackPrompt} from "../../structures/SpaceRoomView"; @@ -224,7 +224,7 @@ const SpaceCreateMenu = ({ onFinished }) => { onFinished(); defaultDispatcher.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_TAB.LABS, + initialTabId: UserTab.Labs, }); }} /> { body } diff --git a/src/stores/SetupEncryptionStore.ts b/src/stores/SetupEncryptionStore.ts index 86e8b7afc3..88385d0399 100644 --- a/src/stores/SetupEncryptionStore.ts +++ b/src/stores/SetupEncryptionStore.ts @@ -22,18 +22,18 @@ import { MatrixClientPeg } from '../MatrixClientPeg'; import { accessSecretStorage, AccessCancelledError } from '../SecurityManager'; import { PHASE_DONE as VERIF_PHASE_DONE } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; -export enum PHASE { - LOADING = 0, - INTRO = 1, - BUSY = 2, - DONE = 3, // final done stage, but still showing UX - CONFIRM_SKIP = 4, - FINISHED = 5, // UX can be closed +export enum Phase { + Loading = 0, + Intro = 1, + Busy = 2, + Done = 3, // final done stage, but still showing UX + ConfirmSkip = 4, + Finished = 5, // UX can be closed } export class SetupEncryptionStore extends EventEmitter { private started: boolean; - public phase: PHASE; + public phase: Phase; public verificationRequest: VerificationRequest; public backupInfo: IKeyBackupVersion; public keyId: string; @@ -50,7 +50,7 @@ export class SetupEncryptionStore extends EventEmitter { return; } this.started = true; - this.phase = PHASE.LOADING; + this.phase = Phase.Loading; this.verificationRequest = null; this.backupInfo = null; @@ -110,15 +110,15 @@ export class SetupEncryptionStore extends EventEmitter { if (!this.hasDevicesToVerifyAgainst && !this.keyInfo) { // skip before we can even render anything. - this.phase = PHASE.FINISHED; + this.phase = Phase.Finished; } else { - this.phase = PHASE.INTRO; + this.phase = Phase.Intro; } this.emit("update"); } public async usePassPhrase(): Promise { - this.phase = PHASE.BUSY; + this.phase = Phase.Busy; this.emit("update"); const cli = MatrixClientPeg.get(); try { @@ -147,7 +147,7 @@ export class SetupEncryptionStore extends EventEmitter { }); if (cli.getCrossSigningId()) { - this.phase = PHASE.DONE; + this.phase = Phase.Done; this.emit("update"); } } catch (e) { @@ -155,7 +155,7 @@ export class SetupEncryptionStore extends EventEmitter { console.log(e); } // this will throw if the user hits cancel, so ignore - this.phase = PHASE.INTRO; + this.phase = Phase.Intro; this.emit("update"); } } @@ -164,7 +164,7 @@ export class SetupEncryptionStore extends EventEmitter { if (userId !== MatrixClientPeg.get().getUserId()) return; const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); if (publicKeysTrusted) { - this.phase = PHASE.DONE; + this.phase = Phase.Done; this.emit("update"); } } @@ -185,28 +185,28 @@ export class SetupEncryptionStore extends EventEmitter { // cross signing to be ready to use, so wait for the user trust status to // change (or change to DONE if it's already ready). const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); - this.phase = publicKeysTrusted ? PHASE.DONE : PHASE.BUSY; + this.phase = publicKeysTrusted ? Phase.Done : Phase.Busy; this.emit("update"); } } public skip(): void { - this.phase = PHASE.CONFIRM_SKIP; + this.phase = Phase.ConfirmSkip; this.emit("update"); } public skipConfirm(): void { - this.phase = PHASE.FINISHED; + this.phase = Phase.Finished; this.emit("update"); } public returnAfterSkip(): void { - this.phase = PHASE.INTRO; + this.phase = Phase.Intro; this.emit("update"); } public done(): void { - this.phase = PHASE.FINISHED; + this.phase = Phase.Finished; this.emit("update"); // async - ask other clients for keys, if necessary MatrixClientPeg.get().crypto.cancelAndResendAllOutgoingKeyRequests(); diff --git a/src/toasts/UnverifiedSessionToast.ts b/src/toasts/UnverifiedSessionToast.ts index 8e3fa7c8a7..05425b93c0 100644 --- a/src/toasts/UnverifiedSessionToast.ts +++ b/src/toasts/UnverifiedSessionToast.ts @@ -21,7 +21,7 @@ import DeviceListener from '../DeviceListener'; import ToastStore from "../stores/ToastStore"; import GenericToast from "../components/views/toasts/GenericToast"; import { Action } from "../dispatcher/actions"; -import { USER_TAB } from "../components/views/dialogs/UserSettingsDialog"; +import { UserTab } from "../components/views/dialogs/UserSettingsDialog"; function toastKey(deviceId: string) { return "unverified_session_" + deviceId; @@ -34,7 +34,7 @@ export const showToast = async (deviceId: string) => { DeviceListener.sharedInstance().dismissUnverifiedSessions([deviceId]); dis.dispatch({ action: Action.ViewUserSettings, - initialTabId: USER_TAB.SECURITY, + initialTabId: UserTab.Security, }); }; From fcda0604e0ff1bf6531f1fd45f8c50b4145f6fa1 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 18 Jun 2021 12:48:31 +0100 Subject: [PATCH 22/22] Fix RoomMember import --- src/components/views/dialogs/ConfirmUserActionDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx index c91dcba95c..05f8c63ace 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -16,7 +16,7 @@ limitations under the License. import React from 'react'; import { MatrixClient } from 'matrix-js-sdk/src/client'; -import RoomMember from "matrix-js-sdk/src/models/room-member.js"; +import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups';