From 6aefd9318ffa9801f188e6d7b1ccd70d5dbb6617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 4 Sep 2021 16:16:21 +0200 Subject: [PATCH 01/34] Convert BaseDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../dialogs/{BaseDialog.js => BaseDialog.tsx} | 112 +++++++++--------- .../security/SetupEncryptionDialog.tsx | 2 +- 2 files changed, 57 insertions(+), 57 deletions(-) rename src/components/views/dialogs/{BaseDialog.js => BaseDialog.tsx} (61%) diff --git a/src/components/views/dialogs/BaseDialog.js b/src/components/views/dialogs/BaseDialog.tsx similarity index 61% rename from src/components/views/dialogs/BaseDialog.js rename to src/components/views/dialogs/BaseDialog.tsx index 42b21ec743..91cceb3123 100644 --- a/src/components/views/dialogs/BaseDialog.js +++ b/src/components/views/dialogs/BaseDialog.tsx @@ -18,15 +18,59 @@ limitations under the License. import React from 'react'; import FocusLock from 'react-focus-lock'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Key } from '../../../Keyboard'; -import AccessibleButton from '../elements/AccessibleButton'; +import AccessibleButton, { ButtonEvent } from '../elements/AccessibleButton'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { MatrixClient } from "matrix-js-sdk/src/client"; + +interface IProps { + // onFinished callback to call when Escape is pressed + // Take a boolean which is true if the dialog was dismissed + // with a positive / confirm action or false if it was + // cancelled (BaseDialog itself only calls this with false). + onFinished: (confirm: any) => void; + + // Whether the dialog should have a 'close' button that will + // cause the dialog to be cancelled. This should only be set + // to false if there is nothing the app can sensibly do if the + // dialog is cancelled, eg. "We can't restore your session and + // the app cannot work". Default: true. + hasCancel?: boolean; + + // called when a key is pressed + onKeyDown?: (e: KeyboardEvent | React.KeyboardEvent) => void; + + // CSS class to apply to dialog div + className?: string; + + // if true, dialog container is 60% of the viewport width. Otherwise, + // the container will have no fixed size, allowing its contents to + // determine its size. Default: true. + fixedWidth?: boolean; + + // Title for the dialog. + title?: JSX.Element | string; + + // Path to an icon to put in the header + headerImage?: string; + + // children should be the content of the dialog + children?: React.ReactNode; + + // Id of content element + // If provided, this is used to add a aria-describedby attribute + contentId?: string; + + // optional additional class for the title element (basically anything that can be passed to classnames) + titleClass?: string | string[]; + + headerButton?: JSX.Element; +} /* * Basic container for modal dialogs. @@ -35,54 +79,10 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; * dialog on escape. */ @replaceableComponent("views.dialogs.BaseDialog") -export default class BaseDialog extends React.Component { - static propTypes = { - // onFinished callback to call when Escape is pressed - // Take a boolean which is true if the dialog was dismissed - // with a positive / confirm action or false if it was - // cancelled (BaseDialog itself only calls this with false). - onFinished: PropTypes.func.isRequired, +export default class BaseDialog extends React.Component { + private matrixClient: MatrixClient; - // Whether the dialog should have a 'close' button that will - // cause the dialog to be cancelled. This should only be set - // to false if there is nothing the app can sensibly do if the - // dialog is cancelled, eg. "We can't restore your session and - // the app cannot work". Default: true. - hasCancel: PropTypes.bool, - - // called when a key is pressed - onKeyDown: PropTypes.func, - - // CSS class to apply to dialog div - className: PropTypes.string, - - // if true, dialog container is 60% of the viewport width. Otherwise, - // the container will have no fixed size, allowing its contents to - // determine its size. Default: true. - fixedWidth: PropTypes.bool, - - // Title for the dialog. - title: PropTypes.node.isRequired, - - // Path to an icon to put in the header - headerImage: PropTypes.string, - - // children should be the content of the dialog - children: PropTypes.node, - - // Id of content element - // If provided, this is used to add a aria-describedby attribute - contentId: PropTypes.string, - - // optional additional class for the title element (basically anything that can be passed to classnames) - titleClass: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.object, - PropTypes.arrayOf(PropTypes.string), - ]), - }; - - static defaultProps = { + public static defaultProps = { hasCancel: true, fixedWidth: true, }; @@ -90,10 +90,10 @@ export default class BaseDialog extends React.Component { constructor(props) { super(props); - this._matrixClient = MatrixClientPeg.get(); + this.matrixClient = MatrixClientPeg.get(); } - _onKeyDown = (e) => { + private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => { if (this.props.onKeyDown) { this.props.onKeyDown(e); } @@ -104,15 +104,15 @@ export default class BaseDialog extends React.Component { } }; - _onCancelClick = (e) => { + private onCancelClick = (e: ButtonEvent): void => { this.props.onFinished(false); }; - render() { + public render(): JSX.Element { let cancelButton; if (this.props.hasCancel) { cancelButton = ( - + ); } @@ -122,11 +122,11 @@ export default class BaseDialog extends React.Component { } return ( - + Date: Sat, 4 Sep 2021 16:36:01 +0200 Subject: [PATCH 02/34] Convert FeedbackDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/CountlyAnalytics.ts | 4 +++- .../{FeedbackDialog.js => FeedbackDialog.tsx} | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) rename src/components/views/dialogs/{FeedbackDialog.js => FeedbackDialog.tsx} (90%) diff --git a/src/CountlyAnalytics.ts b/src/CountlyAnalytics.ts index 72b0462bcd..be35597734 100644 --- a/src/CountlyAnalytics.ts +++ b/src/CountlyAnalytics.ts @@ -30,6 +30,8 @@ const HEARTBEAT_INTERVAL = 5_000; // ms const SESSION_UPDATE_INTERVAL = 60; // seconds const MAX_PENDING_EVENTS = 1000; +export type Rating = 1 | 2 | 3 | 4 | 5; + enum Orientation { Landscape = "landscape", Portrait = "portrait", @@ -451,7 +453,7 @@ export default class CountlyAnalytics { window.removeEventListener("scroll", this.onUserActivity); } - public reportFeedback(rating: 1 | 2 | 3 | 4 | 5, comment: string) { + public reportFeedback(rating: Rating, comment: string) { this.track("[CLY]_star_rating", { rating, comment }, null, {}, true); } diff --git a/src/components/views/dialogs/FeedbackDialog.js b/src/components/views/dialogs/FeedbackDialog.tsx similarity index 90% rename from src/components/views/dialogs/FeedbackDialog.js rename to src/components/views/dialogs/FeedbackDialog.tsx index ceb8cb2175..00112ab0c7 100644 --- a/src/components/views/dialogs/FeedbackDialog.js +++ b/src/components/views/dialogs/FeedbackDialog.tsx @@ -19,7 +19,7 @@ import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import Field from "../elements/Field"; import AccessibleButton from "../elements/AccessibleButton"; -import CountlyAnalytics from "../../../CountlyAnalytics"; +import CountlyAnalytics, { Rating } from "../../../CountlyAnalytics"; import SdkConfig from "../../../SdkConfig"; import Modal from "../../../Modal"; import BugReportDialog from "./BugReportDialog"; @@ -30,19 +30,23 @@ const existingIssuesUrl = "https://github.com/vector-im/element-web/issues" + "?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc"; const newIssueUrl = "https://github.com/vector-im/element-web/issues/new/choose"; -export default (props) => { - const [rating, setRating] = useState(""); - const [comment, setComment] = useState(""); +interface IProps { + onFinished: () => void; +} - const onDebugLogsLinkClick = () => { +const FeedbackDialog: React.FC = (props: IProps) => { + const [rating, setRating] = useState(); + const [comment, setComment] = useState(""); + + const onDebugLogsLinkClick = (): void => { props.onFinished(); Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, {}); }; const hasFeedback = CountlyAnalytics.instance.canEnable(); - const onFinished = (sendFeedback) => { + const onFinished = (sendFeedback: boolean): void => { if (hasFeedback && sendFeedback) { - CountlyAnalytics.instance.reportFeedback(parseInt(rating, 10), comment); + CountlyAnalytics.instance.reportFeedback((parseInt(rating) as Rating), comment); Modal.createTrackedDialog('Feedback sent', '', InfoDialog, { title: _t('Feedback sent'), description: _t('Thank you!'), @@ -142,3 +146,5 @@ export default (props) => { onFinished={onFinished} />); }; + +export default FeedbackDialog; From 3c9ded5a9acb165cfb061513ad1f62e9532273a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sat, 4 Sep 2021 18:40:54 +0200 Subject: [PATCH 03/34] Convert RestoreKeyBackupDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...upDialog.js => RestoreKeyBackupDialog.tsx} | 175 +++++++++++------- 1 file changed, 103 insertions(+), 72 deletions(-) rename src/components/views/dialogs/security/{RestoreKeyBackupDialog.js => RestoreKeyBackupDialog.tsx} (77%) diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.js b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx similarity index 77% rename from src/components/views/dialogs/security/RestoreKeyBackupDialog.js rename to src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index 2b272a3b88..d2b850eb85 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -16,30 +16,64 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../../index'; import { MatrixClientPeg } from '../../../../MatrixClientPeg'; import { MatrixClient } from 'matrix-js-sdk/src/client'; import { _t } from '../../../../languageHandler'; import { accessSecretStorage } from '../../../../SecurityManager'; +import { IKeyBackupInfo, IKeyBackupRestoreResult } from "matrix-js-sdk/src/crypto/keybackup"; +import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/crypto/api"; +import * as sdk from '../../../../index'; -const RESTORE_TYPE_PASSPHRASE = 0; -const RESTORE_TYPE_RECOVERYKEY = 1; -const RESTORE_TYPE_SECRET_STORAGE = 2; +enum RestoreType { + Passphrase = "passphrase", + RecoveryKey = "recovery_key", + SecretStorage = "secret_storage" +} + +enum ProgressState { + PreFetch = "prefetch", + Fetch = "fetch", + LoadKeys = "load_keys", + +} + +interface IProps { + // if false, will close the dialog as soon as the restore completes succesfully + // default: true + showSummary?: boolean; + // If specified, gather the key from the user but then call the function with the backup + // key rather than actually (necessarily) restoring the backup. + keyCallback?: (key: Uint8Array) => void; + + onFinished: (success: boolean) => void; +} + +interface IState { + backupInfo: IKeyBackupInfo; + backupKeyStored: Record; + loading: boolean; + loadError: string; + restoreError: { + errcode: string; + }; + recoveryKey: string; + recoverInfo: IKeyBackupRestoreResult; + recoveryKeyValid: boolean; + forceRecoveryKey: boolean; + passPhrase: ""; + restoreType: RestoreType; + progress: { + stage: ProgressState; + total?: number; + successes?: number; + failures?: number; + }; +} /* * Dialog for restoring e2e keys from a backup and the user's recovery key */ -export default class RestoreKeyBackupDialog extends React.PureComponent { - static propTypes = { - // if false, will close the dialog as soon as the restore completes succesfully - // default: true - showSummary: PropTypes.bool, - // If specified, gather the key from the user but then call the function with the backup - // key rather than actually (necessarily) restoring the backup. - keyCallback: PropTypes.func, - }; - +export default class RestoreKeyBackupDialog extends React.PureComponent { static defaultProps = { showSummary: true, }; @@ -58,58 +92,58 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { forceRecoveryKey: false, passPhrase: '', restoreType: null, - progress: { stage: "prefetch" }, + progress: { stage: ProgressState.PreFetch }, }; } - componentDidMount() { - this._loadBackupStatus(); + public componentDidMount(): void { + this.loadBackupStatus(); } - _onCancel = () => { + private onCancel = (): void => { this.props.onFinished(false); - } + }; - _onDone = () => { + private onDone = (): void => { this.props.onFinished(true); - } + }; - _onUseRecoveryKeyClick = () => { + private onUseRecoveryKeyClick = (): void => { this.setState({ forceRecoveryKey: true, }); - } + }; - _progressCallback = (data) => { + private progressCallback = (data): void => { this.setState({ progress: data, }); - } + }; - _onResetRecoveryClick = () => { + private onResetRecoveryClick = (): void => { this.props.onFinished(false); - accessSecretStorage(() => {}, /* forceReset = */ true); - } + accessSecretStorage(async () => {}, /* forceReset = */ true); + }; - _onRecoveryKeyChange = (e) => { + private onRecoveryKeyChange = (e): void => { this.setState({ recoveryKey: e.target.value, recoveryKeyValid: MatrixClientPeg.get().isValidRecoveryKey(e.target.value), }); - } + }; - _onPassPhraseNext = async () => { + private onPassPhraseNext = async (): Promise => { this.setState({ loading: true, restoreError: null, - restoreType: RESTORE_TYPE_PASSPHRASE, + restoreType: RestoreType.Passphrase, }); try { // We do still restore the key backup: we must ensure that the key backup key // is the right one and restoring it is currently the only way we can do this. const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword( this.state.passPhrase, undefined, undefined, this.state.backupInfo, - { progressCallback: this._progressCallback }, + { progressCallback: this.progressCallback }, ); if (this.props.keyCallback) { const key = await MatrixClientPeg.get().keyBackupKeyFromPassword( @@ -133,20 +167,20 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { restoreError: e, }); } - } + }; - _onRecoveryKeyNext = async () => { + private onRecoveryKeyNext = async (): Promise => { if (!this.state.recoveryKeyValid) return; this.setState({ loading: true, restoreError: null, - restoreType: RESTORE_TYPE_RECOVERYKEY, + restoreType: RestoreType.RecoveryKey, }); try { const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey( this.state.recoveryKey, undefined, undefined, this.state.backupInfo, - { progressCallback: this._progressCallback }, + { progressCallback: this.progressCallback }, ); if (this.props.keyCallback) { const key = MatrixClientPeg.get().keyBackupKeyFromRecoveryKey(this.state.recoveryKey); @@ -167,31 +201,30 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { restoreError: e, }); } - } + }; - _onPassPhraseChange = (e) => { + private onPassPhraseChange = (e): void => { this.setState({ passPhrase: e.target.value, }); - } + }; - async _restoreWithSecretStorage() { + private async restoreWithSecretStorage(): Promise { this.setState({ loading: true, restoreError: null, - restoreType: RESTORE_TYPE_SECRET_STORAGE, + restoreType: RestoreType.SecretStorage, }); try { // `accessSecretStorage` may prompt for storage access as needed. - const recoverInfo = await accessSecretStorage(async () => { - return MatrixClientPeg.get().restoreKeyBackupWithSecretStorage( + await accessSecretStorage(async () => { + await MatrixClientPeg.get().restoreKeyBackupWithSecretStorage( this.state.backupInfo, undefined, undefined, - { progressCallback: this._progressCallback }, + { progressCallback: this.progressCallback }, ); }); this.setState({ loading: false, - recoverInfo, }); } catch (e) { console.log("Error restoring backup", e); @@ -202,14 +235,14 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { } } - async _restoreWithCachedKey(backupInfo) { + private async restoreWithCachedKey(backupInfo): Promise { if (!backupInfo) return false; try { const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithCache( undefined, /* targetRoomId */ undefined, /* targetSessionId */ backupInfo, - { progressCallback: this._progressCallback }, + { progressCallback: this.progressCallback }, ); this.setState({ recoverInfo, @@ -221,7 +254,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { } } - async _loadBackupStatus() { + private async loadBackupStatus(): Promise { this.setState({ loading: true, loadError: null, @@ -236,7 +269,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { backupKeyStored, }); - const gotCache = await this._restoreWithCachedKey(backupInfo); + const gotCache = await this.restoreWithCachedKey(backupInfo); if (gotCache) { console.log("RestoreKeyBackupDialog: found cached backup key"); this.setState({ @@ -247,7 +280,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { // If the backup key is stored, we can proceed directly to restore. if (backupKeyStored) { - return this._restoreWithSecretStorage(); + return this.restoreWithSecretStorage(); } this.setState({ @@ -263,7 +296,10 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { } } - render() { + public render(): JSX.Element { + // FIXME: Making these into imports will break tests + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const Spinner = sdk.getComponent("elements.Spinner"); @@ -279,12 +315,12 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { if (this.state.loading) { title = _t("Restoring keys from backup"); let details; - if (this.state.progress.stage === "fetch") { + if (this.state.progress.stage === ProgressState.Fetch) { details = _t("Fetching keys from server..."); - } else if (this.state.progress.stage === "load_keys") { + } else if (this.state.progress.stage === ProgressState.LoadKeys) { const { total, successes, failures } = this.state.progress; details = _t("%(completed)s of %(total)s keys restored", { total, completed: successes + failures }); - } else if (this.state.progress.stage === "prefetch") { + } else if (this.state.progress.stage === ProgressState.PreFetch) { details = _t("Fetching keys from server..."); } content =
@@ -296,7 +332,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { content = _t("Unable to load backup status"); } else if (this.state.restoreError) { if (this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) { - if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) { + if (this.state.restoreType === RestoreType.RecoveryKey) { title = _t("Security Key mismatch"); content =

{ _t( @@ -321,7 +357,6 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { title = _t("Error"); content = _t("No backup found!"); } else if (this.state.recoverInfo) { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); title = _t("Keys restored"); let failedToDecrypt; if (this.state.recoverInfo.total > this.state.recoverInfo.imported) { @@ -334,14 +369,12 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {

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

{ failedToDecrypt }
; } else if (backupHasPassphrase && !this.state.forceRecoveryKey) { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); title = _t("Enter Security Phrase"); content =

{ _t( @@ -357,16 +390,16 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {

@@ -379,14 +412,14 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { button1: s => { s } , button2: s => { s } , @@ -394,8 +427,6 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
; } else { title = _t("Enter Security Key"); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let keyStatus; if (this.state.recoveryKey.length === 0) { @@ -423,15 +454,15 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
{ keyStatus } @@ -443,7 +474,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent { { button: s => { s } , From 0b9255f5eecb2a8c0ea8f9804c03704e81de620a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 08:31:06 +0200 Subject: [PATCH 04/34] Convert UploadFailureDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...ilureDialog.js => UploadFailureDialog.tsx} | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) rename src/components/views/dialogs/{UploadFailureDialog.js => UploadFailureDialog.tsx} (80%) diff --git a/src/components/views/dialogs/UploadFailureDialog.js b/src/components/views/dialogs/UploadFailureDialog.tsx similarity index 80% rename from src/components/views/dialogs/UploadFailureDialog.js rename to src/components/views/dialogs/UploadFailureDialog.tsx index 224098f935..807cb08195 100644 --- a/src/components/views/dialogs/UploadFailureDialog.js +++ b/src/components/views/dialogs/UploadFailureDialog.tsx @@ -17,11 +17,18 @@ limitations under the License. import filesize from 'filesize'; import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; + +interface IProps { + badFiles: File[]; + totalFiles: number; + contentMessages: ContentMessages; + onFinished: (success: boolean) => void; +} /* * Tells the user about files we know cannot be uploaded before we even try uploading @@ -29,26 +36,16 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; * the size of the file. */ @replaceableComponent("views.dialogs.UploadFailureDialog") -export default class UploadFailureDialog extends React.Component { - static propTypes = { - badFiles: PropTypes.arrayOf(PropTypes.object).isRequired, - totalFiles: PropTypes.number.isRequired, - contentMessages: PropTypes.instanceOf(ContentMessages).isRequired, - onFinished: PropTypes.func.isRequired, - } - - _onCancelClick = () => { +export default class UploadFailureDialog extends React.Component { + private onCancelClick = (): void => { this.props.onFinished(false); - } + }; - _onUploadClick = () => { + private onUploadClick = (): void => { this.props.onFinished(true); - } - - render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + }; + public render(): JSX.Element { let message; let preview; let buttons; @@ -65,7 +62,7 @@ export default class UploadFailureDialog extends React.Component { ); buttons = ; } else if (this.props.totalFiles === this.props.badFiles.length) { @@ -80,7 +77,7 @@ export default class UploadFailureDialog extends React.Component { ); buttons = ; } else { @@ -96,17 +93,17 @@ export default class UploadFailureDialog extends React.Component { const howManyOthers = this.props.totalFiles - this.props.badFiles.length; buttons = ; } return ( From 37099fd188c585fce7867a75df74d0dd3b84d64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 08:35:24 +0200 Subject: [PATCH 05/34] Convert TextInputDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...TextInputDialog.js => TextInputDialog.tsx} | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) rename src/components/views/dialogs/{TextInputDialog.js => TextInputDialog.tsx} (67%) diff --git a/src/components/views/dialogs/TextInputDialog.js b/src/components/views/dialogs/TextInputDialog.tsx similarity index 67% rename from src/components/views/dialogs/TextInputDialog.js rename to src/components/views/dialogs/TextInputDialog.tsx index 3d37c89424..624e2a58cb 100644 --- a/src/components/views/dialogs/TextInputDialog.js +++ b/src/components/views/dialogs/TextInputDialog.tsx @@ -14,33 +14,39 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { createRef } from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; +import React, { ChangeEvent, createRef } from 'react'; import Field from "../elements/Field"; import { _t, _td } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { IFieldState, IValidationResult } from "../elements/Validation"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; + + interface IProps { + title?: string; + description?: string | JSX.Element; + value?: string; + placeholder?: string; + button?: string; + busyMessage?: string; // pass _td string + focus?: boolean; + onFinished: (success: boolean, value?: string) => void; + hasCancel?: boolean; + validator?: (fieldState: IFieldState) => IValidationResult; // result of withValidation + fixedWidth?: boolean; +} + +interface IState { + value: string; + busy: boolean; + valid: boolean; +} @replaceableComponent("views.dialogs.TextInputDialog") -export default class TextInputDialog extends React.Component { - static propTypes = { - title: PropTypes.string, - description: PropTypes.oneOfType([ - PropTypes.element, - PropTypes.string, - ]), - value: PropTypes.string, - placeholder: PropTypes.string, - button: PropTypes.string, - busyMessage: PropTypes.string, // pass _td string - focus: PropTypes.bool, - onFinished: PropTypes.func.isRequired, - hasCancel: PropTypes.bool, - validator: PropTypes.func, // result of withValidation - fixedWidth: PropTypes.bool, - }; +export default class TextInputDialog extends React.Component { + private field = createRef(); - static defaultProps = { + public static defaultProps = { title: "", value: "", description: "", @@ -49,11 +55,9 @@ export default class TextInputDialog extends React.Component { hasCancel: true, }; - constructor(props) { + constructor(props: IProps) { super(props); - this._field = createRef(); - this.state = { value: this.props.value, busy: false, @@ -61,23 +65,23 @@ export default class TextInputDialog extends React.Component { }; } - componentDidMount() { + public componentDidMount(): void { if (this.props.focus) { // Set the cursor at the end of the text input // this._field.current.value = this.props.value; - this._field.current.focus(); + this.field.current.focus(); } } - onOk = async ev => { + private onOk = async (ev: React.FormEvent): Promise => { ev.preventDefault(); if (this.props.validator) { this.setState({ busy: true }); - await this._field.current.validate({ allowEmpty: false }); + await this.field.current.validate({ allowEmpty: false }); - if (!this._field.current.state.valid) { - this._field.current.focus(); - this._field.current.validate({ allowEmpty: false, focused: true }); + if (!this.field.current.state.valid) { + this.field.current.focus(); + this.field.current.validate({ allowEmpty: false, focused: true }); this.setState({ busy: false }); return; } @@ -85,17 +89,17 @@ export default class TextInputDialog extends React.Component { this.props.onFinished(true, this.state.value); }; - onCancel = () => { + private onCancel = (): void => { this.props.onFinished(false); }; - onChange = ev => { + private onChange = (ev: ChangeEvent): void => { this.setState({ value: ev.target.value, }); }; - onValidate = async fieldState => { + private onValidate = async (fieldState: IFieldState): Promise => { const result = await this.props.validator(fieldState); this.setState({ valid: result.valid, @@ -103,9 +107,7 @@ export default class TextInputDialog extends React.Component { return result; }; - render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + public render(): JSX.Element { return (
From 161937ac924311f87cc1aa95d932f7e53cc25e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 09:11:08 +0200 Subject: [PATCH 06/34] Convert TabbedIntegrationManagerDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ....js => TabbedIntegrationManagerDialog.tsx} | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) rename src/components/views/dialogs/{TabbedIntegrationManagerDialog.js => TabbedIntegrationManagerDialog.tsx} (76%) diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx similarity index 76% rename from src/components/views/dialogs/TabbedIntegrationManagerDialog.js rename to src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx index 8723d4a453..c8ab25b1bb 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.js +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx @@ -15,42 +15,53 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { IntegrationManagers } from "../../../integrations/IntegrationManagers"; import { Room } from "matrix-js-sdk/src/models/room"; -import * as sdk from '../../../index'; import { dialogTermsInteractionCallback, TermsNotSignedError } from "../../../Terms"; import classNames from 'classnames'; import * as ScalarMessaging from "../../../ScalarMessaging"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { IntegrationManagerInstance } from "../../../integrations/IntegrationManagerInstance"; +import ScalarAuthClient from "../../../ScalarAuthClient"; +import AccessibleButton from "../elements/AccessibleButton"; +import IntegrationManager from "../settings/IntegrationManager"; + +interface IProps { + /** + * Called with: + * * success {bool} True if the user accepted any douments, false if cancelled + * * agreedUrls {string[]} List of agreed URLs + */ + onFinished: () => void; + + /** + * Optional room where the integration manager should be open to + */ + room: Room; + + /** + * Optional screen to open on the integration manager + */ + screen?: string; + + /** + * Optional integration ID to open in the integration manager + */ + integrationId?: string; +} + +interface IState { + managers: IntegrationManagerInstance[]; + busy: boolean; + currentIndex: number; + currentConnected: boolean; + currentLoading: boolean; + currentScalarClient: ScalarAuthClient; +} @replaceableComponent("views.dialogs.TabbedIntegrationManagerDialog") -export default class TabbedIntegrationManagerDialog extends React.Component { - static propTypes = { - /** - * Called with: - * * success {bool} True if the user accepted any douments, false if cancelled - * * agreedUrls {string[]} List of agreed URLs - */ - onFinished: PropTypes.func.isRequired, - - /** - * Optional room where the integration manager should be open to - */ - room: PropTypes.instanceOf(Room), - - /** - * Optional screen to open on the integration manager - */ - screen: PropTypes.string, - - /** - * Optional integration ID to open in the integration manager - */ - integrationId: PropTypes.string, - }; - - constructor(props) { +export default class TabbedIntegrationManagerDialog extends React.Component { + constructor(props: IProps) { super(props); this.state = { @@ -63,11 +74,11 @@ export default class TabbedIntegrationManagerDialog extends React.Component { }; } - componentDidMount() { + public componentDidMount(): void { this.openManager(0, true); } - openManager = async (i, force = false) => { + private openManager = async (i: number, force = false): Promise => { if (i === this.state.currentIndex && !force) return; const manager = this.state.managers[i]; @@ -120,8 +131,7 @@ export default class TabbedIntegrationManagerDialog extends React.Component { } }; - _renderTabs() { - const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton"); + private renderTabs(): JSX.Element[] { return this.state.managers.map((m, i) => { const classes = classNames({ 'mx_TabbedIntegrationManagerDialog_tab': true, @@ -140,8 +150,7 @@ export default class TabbedIntegrationManagerDialog extends React.Component { }); } - _renderTab() { - const IntegrationManager = sdk.getComponent("views.settings.IntegrationManager"); + public renderTab(): JSX.Element { let uiUrl = null; if (this.state.currentScalarClient) { uiUrl = this.state.currentScalarClient.getScalarInterfaceUrlForRoom( @@ -151,7 +160,6 @@ export default class TabbedIntegrationManagerDialog extends React.Component { ); } return ; } - render() { + public render(): JSX.Element { return (
- { this._renderTabs() } + { this.renderTabs() }
- { this._renderTab() } + { this.renderTab() }
); From 1f670e225c0c71d3afc15be8d289860556f8df00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 10:53:57 +0200 Subject: [PATCH 07/34] Convert StorageEvictedDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...ctedDialog.js => StorageEvictedDialog.tsx} | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) rename src/components/views/dialogs/{StorageEvictedDialog.js => StorageEvictedDialog.tsx} (79%) diff --git a/src/components/views/dialogs/StorageEvictedDialog.js b/src/components/views/dialogs/StorageEvictedDialog.tsx similarity index 79% rename from src/components/views/dialogs/StorageEvictedDialog.js rename to src/components/views/dialogs/StorageEvictedDialog.tsx index 507ee09e75..60ae049bf6 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.js +++ b/src/components/views/dialogs/StorageEvictedDialog.tsx @@ -15,40 +15,37 @@ 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'; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; +import BugReportDialog from "./BugReportDialog"; + +interface IProps { + onFinished: (confirmed: boolean) => void; +} @replaceableComponent("views.dialogs.StorageEvictedDialog") -export default class StorageEvictedDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; - - _sendBugReport = ev => { +export default class StorageEvictedDialog extends React.Component { + private sendBugReport = (ev: React.MouseEvent): void => { ev.preventDefault(); - const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog"); Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {}); }; - _onSignOutClick = () => { + private onSignOutClick = (): void => { this.props.onFinished(true); }; - render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - + public render(): JSX.Element { let logRequest; if (SdkConfig.get().bug_report_endpoint_url) { logRequest = _t( "To help us prevent this in future, please send us logs.", {}, { - a: text => { text }, + a: text => { text }, }, ); } @@ -73,7 +70,7 @@ export default class StorageEvictedDialog extends React.Component { ) } { logRequest }

From 444a0da2973a44e33d186e4fcfed432d6de90a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 11:58:38 +0200 Subject: [PATCH 08/34] Convert SlashCommandHelpDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...CommandHelpDialog.js => SlashCommandHelpDialog.tsx} | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) rename src/components/views/dialogs/{SlashCommandHelpDialog.js => SlashCommandHelpDialog.tsx} (90%) diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.js b/src/components/views/dialogs/SlashCommandHelpDialog.tsx similarity index 90% rename from src/components/views/dialogs/SlashCommandHelpDialog.js rename to src/components/views/dialogs/SlashCommandHelpDialog.tsx index d21ccbe47f..c47555567e 100644 --- a/src/components/views/dialogs/SlashCommandHelpDialog.js +++ b/src/components/views/dialogs/SlashCommandHelpDialog.tsx @@ -17,11 +17,13 @@ limitations under the License. import React from 'react'; import { _t } from "../../../languageHandler"; import { CommandCategories, Commands } from "../../../SlashCommands"; -import * as sdk from "../../../index"; +import InfoDialog from "./InfoDialog"; -export default ({ onFinished }) => { - const InfoDialog = sdk.getComponent('dialogs.InfoDialog'); +interface IProps { + onFinished: () => void; +} +const SlashCommandHelpDialog: React.FC = ({ onFinished }) => { const categories = {}; Commands.forEach(cmd => { if (!cmd.isEnabled()) return; @@ -62,3 +64,5 @@ export default ({ onFinished }) => { hasCloseButton={true} onFinished={onFinished} />; }; + +export default SlashCommandHelpDialog; From 02f672570a5c5bc9421c76dc5167464be22d269a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 12:02:43 +0200 Subject: [PATCH 09/34] Convert WidgetOpenIDPermissionsDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...g.js => WidgetOpenIDPermissionsDialog.tsx} | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) rename src/components/views/dialogs/{WidgetOpenIDPermissionsDialog.js => WidgetOpenIDPermissionsDialog.tsx} (71%) diff --git a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx similarity index 71% rename from src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js rename to src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx index 1bc6444ac1..81bd53a32e 100644 --- a/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.js +++ b/src/components/views/dialogs/WidgetOpenIDPermissionsDialog.tsx @@ -15,42 +15,46 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { _t } from "../../../languageHandler"; -import * as sdk from "../../../index"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; -import { Widget } from "matrix-widget-api"; +import { Widget, WidgetKind } from "matrix-widget-api"; import { OIDCState, WidgetPermissionStore } from "../../../stores/widgets/WidgetPermissionStore"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import DialogButtons from "../elements/DialogButtons"; +import BaseDialog from "./BaseDialog"; + +interface IProps { + onFinished: (confirmed: boolean) => void; + widget: Widget; + widgetKind: WidgetKind; // WidgetKind from widget-api + inRoomId?: string; +} + +interface IState { + rememberSelection: boolean; +} @replaceableComponent("views.dialogs.WidgetOpenIDPermissionsDialog") -export default class WidgetOpenIDPermissionsDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - widget: PropTypes.objectOf(Widget).isRequired, - widgetKind: PropTypes.string.isRequired, // WidgetKind from widget-api - inRoomId: PropTypes.string, - }; - - constructor() { - super(); +export default class WidgetOpenIDPermissionsDialog extends React.Component { + constructor(props: IProps) { + super(props); this.state = { rememberSelection: false, }; } - _onAllow = () => { - this._onPermissionSelection(true); + private onAllow = (): void => { + this.onPermissionSelection(true); }; - _onDeny = () => { - this._onPermissionSelection(false); + private onDeny = (): void => { + this.onPermissionSelection(false); }; - _onPermissionSelection(allowed) { + private onPermissionSelection(allowed: boolean): void { if (this.state.rememberSelection) { - console.log(`Remembering ${this.props.widgetId} as allowed=${allowed} for OpenID`); + console.log(`Remembering ${this.props.widget.id} as allowed=${allowed} for OpenID`); WidgetPermissionStore.instance.setOIDCState( this.props.widget, this.props.widgetKind, this.props.inRoomId, @@ -61,14 +65,11 @@ export default class WidgetOpenIDPermissionsDialog extends React.Component { this.props.onFinished(allowed); } - _onRememberSelectionChange = (newVal) => { + private onRememberSelectionChange = (newVal: boolean): void => { this.setState({ rememberSelection: newVal }); }; render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - return ( } /> From 5bf64c2075e5e09183e89a392cb9478d703fb197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 12:42:18 +0200 Subject: [PATCH 10/34] Convert SetEmailDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../{SetEmailDialog.js => SetEmailDialog.tsx} | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) rename src/components/views/dialogs/{SetEmailDialog.js => SetEmailDialog.tsx} (81%) diff --git a/src/components/views/dialogs/SetEmailDialog.js b/src/components/views/dialogs/SetEmailDialog.tsx similarity index 81% rename from src/components/views/dialogs/SetEmailDialog.js rename to src/components/views/dialogs/SetEmailDialog.tsx index 3dad3821fb..506399d15d 100644 --- a/src/components/views/dialogs/SetEmailDialog.js +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -16,13 +16,26 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; import * as Email from '../../../email'; import AddThreepid from '../../../AddThreepid'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import Spinner from "../elements/Spinner"; +import ErrorDialog from "./ErrorDialog"; +import QuestionDialog from "./QuestionDialog"; +import BaseDialog from "./BaseDialog"; +import EditableText from "../elements/EditableText"; + +interface IProps { + title: string; + onFinished: (confirmed: boolean) => void; +} + +interface IState { + emailAddress: string; + emailBusy: boolean; +} /* * Prompt the user to set an email address. @@ -30,26 +43,25 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; * On success, `onFinished(true)` is called. */ @replaceableComponent("views.dialogs.SetEmailDialog") -export default class SetEmailDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; +export default class SetEmailDialog extends React.Component { + private addThreepid: AddThreepid; - state = { - emailAddress: '', - emailBusy: false, - }; + constructor(props: IProps) { + super(props); - onEmailAddressChanged = value => { + this.state = { + emailAddress: '', + emailBusy: false, + }; + } + + private onEmailAddressChanged = (value: string): void => { this.setState({ emailAddress: value, }); }; - onSubmit = () => { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - + private onSubmit = (): void => { const emailAddress = this.state.emailAddress; if (!Email.looksValid(emailAddress)) { Modal.createTrackedDialog('Invalid Email Address', '', ErrorDialog, { @@ -58,8 +70,8 @@ export default class SetEmailDialog extends React.Component { }); return; } - this._addThreepid = new AddThreepid(); - this._addThreepid.addEmailAddress(emailAddress).then(() => { + this.addThreepid = new AddThreepid(); + this.addThreepid.addEmailAddress(emailAddress).then(() => { Modal.createTrackedDialog('Verification Pending', '', QuestionDialog, { title: _t("Verification Pending"), description: _t( @@ -80,11 +92,11 @@ export default class SetEmailDialog extends React.Component { this.setState({ emailBusy: true }); }; - onCancelled = () => { + private onCancelled = (): void => { this.props.onFinished(false); }; - onEmailDialogFinished = ok => { + private onEmailDialogFinished = (ok: boolean): void => { if (ok) { this.verifyEmailAddress(); } else { @@ -92,13 +104,12 @@ export default class SetEmailDialog extends React.Component { } }; - verifyEmailAddress() { - this._addThreepid.checkEmailLinkClicked().then(() => { + private verifyEmailAddress(): void { + this.addThreepid.checkEmailLinkClicked().then(() => { this.props.onFinished(true); }, (err) => { this.setState({ emailBusy: false }); if (err.errcode == 'M_THREEPID_AUTH_FAILED') { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); const message = _t("Unable to verify email address.") + " " + _t("Please check your email and click on the link it contains. Once this is done, click continue."); Modal.createTrackedDialog('Verification Pending', '3pid Auth Failed', QuestionDialog, { @@ -108,7 +119,6 @@ export default class SetEmailDialog extends React.Component { onFinished: this.onEmailDialogFinished, }); } else { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Unable to verify email address: " + err); Modal.createTrackedDialog('Unable to verify email address', '', ErrorDialog, { title: _t("Unable to verify email address."), @@ -118,11 +128,7 @@ export default class SetEmailDialog extends React.Component { }); } - render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const Spinner = sdk.getComponent('elements.Spinner'); - const EditableText = sdk.getComponent('elements.EditableText'); - + public render(): JSX.Element { const emailInput = this.state.emailBusy ? : Date: Sun, 5 Sep 2021 12:57:41 +0200 Subject: [PATCH 11/34] Convert QuestionDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../{QuestionDialog.js => QuestionDialog.tsx} | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) rename src/components/views/dialogs/{QuestionDialog.js => QuestionDialog.tsx} (76%) diff --git a/src/components/views/dialogs/QuestionDialog.js b/src/components/views/dialogs/QuestionDialog.tsx similarity index 76% rename from src/components/views/dialogs/QuestionDialog.js rename to src/components/views/dialogs/QuestionDialog.tsx index 3d90236b08..df036293f0 100644 --- a/src/components/views/dialogs/QuestionDialog.js +++ b/src/components/views/dialogs/QuestionDialog.tsx @@ -16,29 +16,30 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from "classnames"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; -export default class QuestionDialog extends React.Component { - static propTypes = { - title: PropTypes.string, - description: PropTypes.node, - extraButtons: PropTypes.node, - button: PropTypes.string, - buttonDisabled: PropTypes.bool, - danger: PropTypes.bool, - focus: PropTypes.bool, - onFinished: PropTypes.func.isRequired, - headerImage: PropTypes.string, - quitOnly: PropTypes.bool, // quitOnly doesn't show the cancel button just the quit [x]. - fixedWidth: PropTypes.bool, - className: PropTypes.string, - }; +interface IProps { + title?: string; + description?: React.ReactNode; + extraButtons?: React.ReactNode; + button?: string; + buttonDisabled?: boolean; + danger?: boolean; + focus?: boolean; + onFinished: (confirmed: boolean) => void; + headerImage?: string; + quitOnly?: boolean; // quitOnly doesn't show the cancel button just the quit [x]. + fixedWidth?: boolean; + className?: string; + hasCancelButton?: boolean; + cancelButton?: JSX.Element; +} - static defaultProps = { +export default class QuestionDialog extends React.Component { + public static defaultProps: Partial = { title: "", description: "", extraButtons: null, @@ -48,17 +49,19 @@ export default class QuestionDialog extends React.Component { quitOnly: false, }; - onOk = () => { + private onOk = (): void => { this.props.onFinished(true); }; - onCancel = () => { + private onCancel = (): void => { this.props.onFinished(false); }; - render() { + public render(): JSX.Element { + // Converting these to imports breaks wrench tests const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + let primaryButtonClass = ""; if (this.props.danger) { primaryButtonClass = "danger"; From b396383e06c00877f1fc531d957afdd817158f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 13:09:29 +0200 Subject: [PATCH 12/34] Convert LazyLoadingResyncDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...LoadingResyncDialog.js => LazyLoadingResyncDialog.tsx} | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) rename src/components/views/dialogs/{LazyLoadingResyncDialog.js => LazyLoadingResyncDialog.tsx} (89%) diff --git a/src/components/views/dialogs/LazyLoadingResyncDialog.js b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx similarity index 89% rename from src/components/views/dialogs/LazyLoadingResyncDialog.js rename to src/components/views/dialogs/LazyLoadingResyncDialog.tsx index a5db15ebbe..c942126d12 100644 --- a/src/components/views/dialogs/LazyLoadingResyncDialog.js +++ b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx @@ -20,7 +20,11 @@ import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; -export default (props) => { +interface IProps { + onFinished: () => void; +} + +const LazyLoadingResyncDialog: React.FC = (props: IProps) => { const brand = SdkConfig.get().brand; const description = _t( @@ -38,3 +42,5 @@ export default (props) => { onFinished={props.onFinished} />); }; + +export default LazyLoadingResyncDialog; From b2331d1e21a7d989896560595432974a463a9518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:03:08 +0200 Subject: [PATCH 13/34] Convert MessageEditHistoryDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...Dialog.js => MessageEditHistoryDialog.tsx} | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) rename src/components/views/dialogs/{MessageEditHistoryDialog.js => MessageEditHistoryDialog.tsx} (84%) diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.js b/src/components/views/dialogs/MessageEditHistoryDialog.tsx similarity index 84% rename from src/components/views/dialogs/MessageEditHistoryDialog.js rename to src/components/views/dialogs/MessageEditHistoryDialog.tsx index 6fce8aecd4..30c16b03bd 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.js +++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx @@ -15,21 +15,37 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { _t } from '../../../languageHandler'; -import * as sdk from "../../../index"; import { wantsDateSeparator } from '../../../DateUtils'; import SettingsStore from '../../../settings/SettingsStore'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import BaseDialog from "./BaseDialog"; +import ScrollPanel from "../../structures/ScrollPanel"; +import Spinner from "../elements/Spinner"; +import EditHistoryMessage from "../messages/EditHistoryMessage"; +import DateSeparator from "../messages/DateSeparator"; + +interface IProps { + mxEvent: MatrixEvent; + onFinished: () => void; +} + +interface IState { + originalEvent: MatrixEvent; + error: { + errcode: string; + }; + events: MatrixEvent[]; + nextBatch: string; + isLoading: boolean; + isTwelveHour: boolean; +} @replaceableComponent("views.dialogs.MessageEditHistoryDialog") -export default class MessageEditHistoryDialog extends React.PureComponent { - static propTypes = { - mxEvent: PropTypes.object.isRequired, - }; - - constructor(props) { +export default class MessageEditHistoryDialog extends React.PureComponent { + constructor(props: IProps) { super(props); this.state = { originalEvent: null, @@ -41,7 +57,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { }; } - loadMoreEdits = async (backwards) => { + private loadMoreEdits = async (backwards?: boolean): Promise => { if (backwards || (!this.state.nextBatch && !this.state.isLoading)) { // bail out on backwards as we only paginate in one direction return false; @@ -53,7 +69,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { let result; let resolve; let reject; - const promise = new Promise((_resolve, _reject) => {resolve = _resolve; reject = _reject;}); + const promise = new Promise((_resolve, _reject) => {resolve = _resolve; reject = _reject;}); try { result = await client.relations( roomId, eventId, "m.replace", "m.room.message", opts); @@ -67,7 +83,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { } const newEvents = result.events; - this._locallyRedactEventsIfNeeded(newEvents); + this.locallyRedactEventsIfNeeded(newEvents); this.setState({ originalEvent: this.state.originalEvent || result.originalEvent, events: this.state.events.concat(newEvents), @@ -78,9 +94,9 @@ export default class MessageEditHistoryDialog extends React.PureComponent { resolve(hasMoreResults); }); return promise; - } + }; - _locallyRedactEventsIfNeeded(newEvents) { + private locallyRedactEventsIfNeeded(newEvents: MatrixEvent[]): void { const roomId = this.props.mxEvent.getRoomId(); const client = MatrixClientPeg.get(); const room = client.getRoom(roomId); @@ -95,13 +111,11 @@ export default class MessageEditHistoryDialog extends React.PureComponent { } } - componentDidMount() { + public componentDidMount(): void { this.loadMoreEdits(); } - _renderEdits() { - const EditHistoryMessage = sdk.getComponent('messages.EditHistoryMessage'); - const DateSeparator = sdk.getComponent('messages.DateSeparator'); + private renderEdits(): JSX.Element[] { const nodes = []; let lastEvent; let allEvents = this.state.events; @@ -128,7 +142,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent { return nodes; } - render() { + public render(): JSX.Element { let content; if (this.state.error) { const { error } = this.state; @@ -149,20 +163,17 @@ export default class MessageEditHistoryDialog extends React.PureComponent {

); } } else if (this.state.isLoading) { - const Spinner = sdk.getComponent("elements.Spinner"); content = ; } else { - const ScrollPanel = sdk.getComponent("structures.ScrollPanel"); content = ( -
    { this._renderEdits() }
+
    { this.renderEdits() }
); } - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( Date: Sun, 5 Sep 2021 16:09:33 +0200 Subject: [PATCH 14/34] Convert IntegrationsDisabledDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...alog.js => IntegrationsDisabledDialog.tsx} | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) rename src/components/views/dialogs/{IntegrationsDisabledDialog.js => IntegrationsDisabledDialog.tsx} (76%) diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.js b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx similarity index 76% rename from src/components/views/dialogs/IntegrationsDisabledDialog.js rename to src/components/views/dialogs/IntegrationsDisabledDialog.tsx index 6a5b2f08f9..f76ed46577 100644 --- a/src/components/views/dialogs/IntegrationsDisabledDialog.js +++ b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx @@ -15,32 +15,29 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { _t } from "../../../languageHandler"; -import * as sdk from "../../../index"; import dis from '../../../dispatcher/dispatcher'; import { Action } from "../../../dispatcher/actions"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; + +interface IProps { + onFinished: () => void; +} @replaceableComponent("views.dialogs.IntegrationsDisabledDialog") -export default class IntegrationsDisabledDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; - - _onAcknowledgeClick = () => { +export default class IntegrationsDisabledDialog extends React.Component { + private onAcknowledgeClick = (): void => { this.props.onFinished(); }; - _onOpenSettingsClick = () => { + private onOpenSettingsClick = (): void => { this.props.onFinished(); dis.fire(Action.ViewUserSettings); }; - render() { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - + public render(): JSX.Element { return ( ); From 9e74477771a5b50de721f9c5a57021c6d6097370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:11:10 +0200 Subject: [PATCH 15/34] Convert IntegrationsImpossibleDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...log.js => IntegrationsImpossibleDialog.tsx} | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename src/components/views/dialogs/{IntegrationsImpossibleDialog.js => IntegrationsImpossibleDialog.tsx} (89%) diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.js b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx similarity index 89% rename from src/components/views/dialogs/IntegrationsImpossibleDialog.js rename to src/components/views/dialogs/IntegrationsImpossibleDialog.tsx index 6cfb96a1b4..36dc42b783 100644 --- a/src/components/views/dialogs/IntegrationsImpossibleDialog.js +++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx @@ -15,23 +15,23 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import * as sdk from "../../../index"; import { replaceableComponent } from "../../../utils/replaceableComponent"; -@replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") -export default class IntegrationsImpossibleDialog extends React.Component { - static propTypes = { - onFinished: PropTypes.func.isRequired, - }; +interface IProps { + onFinished: () => void; - _onAcknowledgeClick = () => { +} + +@replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") +export default class IntegrationsImpossibleDialog extends React.Component { + private onAcknowledgeClick = (): void => { this.props.onFinished(); }; - render() { + public render(): JSX.Element { const brand = SdkConfig.get().brand; const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); @@ -54,7 +54,7 @@ export default class IntegrationsImpossibleDialog extends React.Component { From aba966034e5dc173637385e9354ff0aec298989f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:17:44 +0200 Subject: [PATCH 16/34] Convert LazyLoadingDisabledDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...ngDisabledDialog.js => LazyLoadingDisabledDialog.tsx} | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) rename src/components/views/dialogs/{LazyLoadingDisabledDialog.js => LazyLoadingDisabledDialog.tsx} (90%) diff --git a/src/components/views/dialogs/LazyLoadingDisabledDialog.js b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx similarity index 90% rename from src/components/views/dialogs/LazyLoadingDisabledDialog.js rename to src/components/views/dialogs/LazyLoadingDisabledDialog.tsx index e43cb28a22..32aaf9c531 100644 --- a/src/components/views/dialogs/LazyLoadingDisabledDialog.js +++ b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx @@ -20,7 +20,12 @@ import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; -export default (props) => { +interface IProps { + onFinished: () => void; + host: string; +} + +const LazyLoadingDisabledDialog: React.FC = (props: IProps) => { const brand = SdkConfig.get().brand; const description1 = _t( "You've previously used %(brand)s on %(host)s with lazy loading of members enabled. " + @@ -49,3 +54,5 @@ export default (props) => { onFinished={props.onFinished} />); }; + +export default LazyLoadingDisabledDialog; From e80939d3e25a4cde9d8938ecefafd951562dab01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:27:46 +0200 Subject: [PATCH 17/34] Convert KeySignatureUploadFailedDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ....js => KeySignatureUploadFailedDialog.tsx} | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) rename src/components/views/dialogs/{KeySignatureUploadFailedDialog.js => KeySignatureUploadFailedDialog.tsx} (88%) diff --git a/src/components/views/dialogs/KeySignatureUploadFailedDialog.js b/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx similarity index 88% rename from src/components/views/dialogs/KeySignatureUploadFailedDialog.js rename to src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx index 6b36c19977..20841c46f4 100644 --- a/src/components/views/dialogs/KeySignatureUploadFailedDialog.js +++ b/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx @@ -15,20 +15,29 @@ limitations under the License. */ import React, { useState, useCallback, useRef } from 'react'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; +import Spinner from "../elements/Spinner"; -export default function KeySignatureUploadFailedDialog({ +interface IProps { + failures: Record>; + source: string; + continuation: () => void; + onFinished: () => void; +} + +const KeySignatureUploadFailedDialog: React.FC = ({ failures, source, continuation, onFinished, -}) { +}) => { const RETRIES = 2; - const BaseDialog = sdk.getComponent('dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const Spinner = sdk.getComponent('elements.Spinner'); const [retry, setRetry] = useState(RETRIES); const [cancelled, setCancelled] = useState(false); const [retrying, setRetrying] = useState(false); @@ -107,4 +116,6 @@ export default function KeySignatureUploadFailedDialog({ { body } ); -} +}; + +export default KeySignatureUploadFailedDialog; From 4ca2ab11fbac3fdceac6ac8a36c07be73c7b3a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:36:36 +0200 Subject: [PATCH 18/34] Convert ManualDeviceKeyVerificationDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ... => ManualDeviceKeyVerificationDialog.tsx} | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) rename src/components/views/dialogs/{ManualDeviceKeyVerificationDialog.js => ManualDeviceKeyVerificationDialog.tsx} (84%) diff --git a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx similarity index 84% rename from src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js rename to src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx index 4387108fac..a4c989d7b5 100644 --- a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.js +++ b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx @@ -19,37 +19,31 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import * as sdk from '../../../index'; import * as FormattingUtils from '../../../utils/FormattingUtils'; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import QuestionDialog from "./QuestionDialog"; +import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo"; + +interface IProps { + userId: string; + device: DeviceInfo; + onFinished: (confirmed: boolean) => void; +} @replaceableComponent("views.dialogs.ManualDeviceKeyVerificationDialog") -export default class ManualDeviceKeyVerificationDialog extends React.Component { - static propTypes = { - userId: PropTypes.string.isRequired, - device: PropTypes.object.isRequired, - onFinished: PropTypes.func.isRequired, - }; - - _onCancelClick = () => { - this.props.onFinished(false); - } - - _onLegacyFinished = (confirm) => { +export default class ManualDeviceKeyVerificationDialog extends React.Component { + private onLegacyFinished = (confirm: boolean): void => { if (confirm) { MatrixClientPeg.get().setDeviceVerified( this.props.userId, this.props.device.deviceId, true, ); } this.props.onFinished(confirm); - } - - render() { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + }; + public render(): JSX.Element { let text; if (MatrixClientPeg.get().getUserId() === this.props.userId) { text = _t("Confirm by comparing the following with the User Settings in your other session:"); @@ -81,7 +75,7 @@ export default class ManualDeviceKeyVerificationDialog extends React.Component { title={_t("Verify session")} description={body} button={_t("Verify session")} - onFinished={this._onLegacyFinished} + onFinished={this.onLegacyFinished} /> ); } From 0285bb555fa2a9530b42ec4221d1ebff851957f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:40:46 +0200 Subject: [PATCH 19/34] Convert SessionRestoreErrorDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...ialog.js => SessionRestoreErrorDialog.tsx} | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) rename src/components/views/dialogs/{SessionRestoreErrorDialog.js => SessionRestoreErrorDialog.tsx} (80%) diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx similarity index 80% rename from src/components/views/dialogs/SessionRestoreErrorDialog.js rename to src/components/views/dialogs/SessionRestoreErrorDialog.tsx index eeeadbbfe5..752b023f0b 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx @@ -17,27 +17,27 @@ 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'; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import QuestionDialog from "./QuestionDialog"; +import BugReportDialog from "./BugReportDialog"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; + +interface IProps { + error: string; + onFinished: () => void; +} @replaceableComponent("views.dialogs.SessionRestoreErrorDialog") -export default class SessionRestoreErrorDialog extends React.Component { - static propTypes = { - error: PropTypes.string.isRequired, - onFinished: PropTypes.func.isRequired, - }; - - _sendBugReport = () => { - const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog"); +export default class SessionRestoreErrorDialog extends React.Component { + private sendBugReport = (): void => { Modal.createTrackedDialog('Session Restore Error', 'Send Bug Report Dialog', BugReportDialog, {}); }; - _onClearStorageClick = () => { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + private onClearStorageClick = (): void => { Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, { title: _t("Sign out"), description: @@ -48,19 +48,17 @@ export default class SessionRestoreErrorDialog extends React.Component { }); }; - _onRefreshClick = () => { + private onRefreshClick = (): void => { // Is this likely to help? Probably not, but giving only one button // that clears your storage seems awful. - window.location.reload(true); + window.location.reload(); }; - render() { + public render(): JSX.Element { const brand = SdkConfig.get().brand; - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const clearStorageButton = ( - ); @@ -68,7 +66,7 @@ export default class SessionRestoreErrorDialog extends React.Component { let dialogButtons; if (SdkConfig.get().bug_report_endpoint_url) { dialogButtons = @@ -76,7 +74,7 @@ export default class SessionRestoreErrorDialog extends React.Component { ; } else { dialogButtons = From 5967811cda85c00f00d788a28147b78768a77abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 16:57:36 +0200 Subject: [PATCH 20/34] Convert InteractiveAuthDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...uthDialog.js => InteractiveAuthDialog.tsx} | 139 ++++++++++-------- 1 file changed, 74 insertions(+), 65 deletions(-) rename src/components/views/dialogs/{InteractiveAuthDialog.js => InteractiveAuthDialog.tsx} (65%) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.js b/src/components/views/dialogs/InteractiveAuthDialog.tsx similarity index 65% rename from src/components/views/dialogs/InteractiveAuthDialog.js rename to src/components/views/dialogs/InteractiveAuthDialog.tsx index e5f4887f06..e9667c84b5 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.js +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -17,69 +17,82 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; -import { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth"; +import InteractiveAuth, { ERROR_USER_CANCELLED } from "../../structures/InteractiveAuth"; import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import BaseDialog from "./BaseDialog"; +import { IAuthData } from "matrix-js-sdk/src/interactive-auth"; + +interface IProps { + // matrix client to use for UI auth requests + matrixClient: MatrixClient; + + // response from initial request. If not supplied, will do a request on + // mount. + authData?: { + flows: []; + params: {}; + session: string; + }; + + // callback + makeRequest: (auth: IAuthData) => Promise; + + onFinished: (confirmed: boolean, result?) => void; + + // Optional title and body to show when not showing a particular stage + title?: string; + body?: string; + + // Optional title and body pairs for particular stages and phases within + // those stages. Object structure/example is: + // { + // "org.example.stage_type": { + // 1: { + // "body": "This is a body for phase 1" of org.example.stage_type, + // "title": "Title for phase 1 of org.example.stage_type" + // }, + // 2: { + // "body": "This is a body for phase 2 of org.example.stage_type", + // "title": "Title for phase 2 of org.example.stage_type" + // "continueText": "Confirm identity with Example Auth", + // "continueKind": "danger" + // } + // } + // } + // + // Default is defined in _getDefaultDialogAesthetics() + aestheticsForStagePhases?: {}; +} + +interface IState { + authError: Error; + + // See _onUpdateStagePhase() + uiaStage: number; + uiaStagePhase: number; +} @replaceableComponent("views.dialogs.InteractiveAuthDialog") -export default class InteractiveAuthDialog extends React.Component { - static propTypes = { - // matrix client to use for UI auth requests - matrixClient: PropTypes.object.isRequired, +export default class InteractiveAuthDialog extends React.Component { + constructor(props: IProps) { + super(props); - // response from initial request. If not supplied, will do a request on - // mount. - authData: PropTypes.shape({ - flows: PropTypes.array, - params: PropTypes.object, - session: PropTypes.string, - }), + this.state = { + authError: null, - // callback - makeRequest: PropTypes.func.isRequired, + // See _onUpdateStagePhase() + uiaStage: null, + uiaStagePhase: null, + }; + } - onFinished: PropTypes.func.isRequired, - - // Optional title and body to show when not showing a particular stage - title: PropTypes.string, - body: PropTypes.string, - - // Optional title and body pairs for particular stages and phases within - // those stages. Object structure/example is: - // { - // "org.example.stage_type": { - // 1: { - // "body": "This is a body for phase 1" of org.example.stage_type, - // "title": "Title for phase 1 of org.example.stage_type" - // }, - // 2: { - // "body": "This is a body for phase 2 of org.example.stage_type", - // "title": "Title for phase 2 of org.example.stage_type" - // "continueText": "Confirm identity with Example Auth", - // "continueKind": "danger" - // } - // } - // } - // - // Default is defined in _getDefaultDialogAesthetics() - aestheticsForStagePhases: PropTypes.object, - }; - - state = { - authError: null, - - // See _onUpdateStagePhase() - uiaStage: null, - uiaStagePhase: null, - }; - - _getDefaultDialogAesthetics() { + private getDefaultDialogAesthetics() { const ssoAesthetics = { [SSOAuthEntry.PHASE_PREAUTH]: { title: _t("Use Single Sign On to continue"), @@ -101,7 +114,7 @@ export default class InteractiveAuthDialog extends React.Component { }; } - _onAuthFinished = (success, result) => { + private onAuthFinished = (success: boolean, result: Error): void => { if (success) { this.props.onFinished(true, result); } else { @@ -115,19 +128,16 @@ export default class InteractiveAuthDialog extends React.Component { } }; - _onUpdateStagePhase = (newStage, newPhase) => { + private onUpdateStagePhase = (newStage, newPhase): void => { // We copy the stage and stage phase params into state for title selection in render() this.setState({ uiaStage: newStage, uiaStagePhase: newPhase }); }; - _onDismissClick = () => { + private onDismissClick = (): void => { this.props.onFinished(false); }; - render() { - const InteractiveAuth = sdk.getComponent("structures.InteractiveAuth"); - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - + public render(): JSX.Element { // Let's pick a title, body, and other params text that we'll show to the user. The order // is most specific first, so stagePhase > our props > defaults. @@ -135,7 +145,7 @@ export default class InteractiveAuthDialog extends React.Component { let body = this.state.authError ? null : this.props.body; let continueText = null; let continueKind = null; - const dialogAesthetics = this.props.aestheticsForStagePhases || this._getDefaultDialogAesthetics(); + const dialogAesthetics = this.props.aestheticsForStagePhases || this.getDefaultDialogAesthetics(); if (!this.state.authError && dialogAesthetics) { if (dialogAesthetics[this.state.uiaStage]) { const aesthetics = dialogAesthetics[this.state.uiaStage][this.state.uiaStagePhase]; @@ -152,9 +162,9 @@ export default class InteractiveAuthDialog extends React.Component {
{ this.state.authError.message || this.state.authError.toString() }

- { _t("Dismiss") } @@ -165,12 +175,11 @@ export default class InteractiveAuthDialog extends React.Component {
{ body } From ae631f9fce392987d6e5dfaa37ee9e39b24a4968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 5 Sep 2021 17:15:33 +0200 Subject: [PATCH 21/34] Convert IncomingSasDialog to TS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- ...mingSasDialog.js => IncomingSasDialog.tsx} | 133 ++++++++++-------- 1 file changed, 73 insertions(+), 60 deletions(-) rename src/components/views/dialogs/{IncomingSasDialog.js => IncomingSasDialog.tsx} (69%) diff --git a/src/components/views/dialogs/IncomingSasDialog.js b/src/components/views/dialogs/IncomingSasDialog.tsx similarity index 69% rename from src/components/views/dialogs/IncomingSasDialog.js rename to src/components/views/dialogs/IncomingSasDialog.tsx index a5c9f2107f..8903b00221 100644 --- a/src/components/views/dialogs/IncomingSasDialog.js +++ b/src/components/views/dialogs/IncomingSasDialog.tsx @@ -15,12 +15,17 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { mediaFromMxc } from "../../../customisations/Media"; +import VerificationComplete from "../verification/VerificationComplete"; +import VerificationCancelled from "../verification/VerificationCancelled"; +import BaseAvatar from "../avatars/BaseAvatar"; +import Spinner from "../elements/Spinner"; +import VerificationShowSas from "../verification/VerificationShowSas"; +import BaseDialog from "./BaseDialog"; +import DialogButtons from "../elements/DialogButtons"; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -28,13 +33,28 @@ const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2; const PHASE_VERIFIED = 3; const PHASE_CANCELLED = 4; -@replaceableComponent("views.dialogs.IncomingSasDialog") -export default class IncomingSasDialog extends React.Component { - static propTypes = { - verifier: PropTypes.object.isRequired, - }; +interface IProps { + verifier: any; // TODO types + onFinished: (confirmed: boolean) => void; +} - constructor(props) { +interface IState { + phase: number; + sasVerified: boolean; + opponentProfile: { + // eslint-disable-next-line camelcase + avatar_url?: string; + displayname?: string; + }; + opponentProfileError: Error; + sas: any; // TODO types +} + +@replaceableComponent("views.dialogs.IncomingSasDialog") +export default class IncomingSasDialog extends React.Component { + private showSasEvent: any; // TODO: Types + + constructor(props: IProps) { super(props); let phase = PHASE_START; @@ -43,26 +63,27 @@ export default class IncomingSasDialog extends React.Component { phase = PHASE_CANCELLED; } - this._showSasEvent = null; + this.showSasEvent = null; this.state = { phase: phase, sasVerified: false, opponentProfile: null, opponentProfileError: null, + sas: null, }; - this.props.verifier.on('show_sas', this._onVerifierShowSas); - this.props.verifier.on('cancel', this._onVerifierCancel); - this._fetchOpponentProfile(); + this.props.verifier.on('show_sas', this.onVerifierShowSas); + this.props.verifier.on('cancel', this.onVerifierCancel); + this.fetchOpponentProfile(); } - componentWillUnmount() { + public componentWillUnmount(): void { if (this.state.phase !== PHASE_CANCELLED && this.state.phase !== PHASE_VERIFIED) { this.props.verifier.cancel('User cancel'); } - this.props.verifier.removeListener('show_sas', this._onVerifierShowSas); + this.props.verifier.removeListener('show_sas', this.onVerifierShowSas); } - async _fetchOpponentProfile() { + private async fetchOpponentProfile(): Promise { try { const prof = await MatrixClientPeg.get().getProfileInfo( this.props.verifier.userId, @@ -77,53 +98,51 @@ export default class IncomingSasDialog extends React.Component { } } - _onFinished = () => { + private onFinished = (): void => { this.props.onFinished(this.state.phase === PHASE_VERIFIED); - } + }; - _onCancelClick = () => { + private onCancelClick = (): void => { this.props.onFinished(this.state.phase === PHASE_VERIFIED); - } + }; - _onContinueClick = () => { + private onContinueClick = (): void => { this.setState({ phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM }); this.props.verifier.verify().then(() => { this.setState({ phase: PHASE_VERIFIED }); }).catch((e) => { console.log("Verification failed", e); }); - } + }; - _onVerifierShowSas = (e) => { - this._showSasEvent = e; + // TODO: Types + private onVerifierShowSas = (e): void => { + this.showSasEvent = e; this.setState({ phase: PHASE_SHOW_SAS, sas: e.sas, }); - } + }; - _onVerifierCancel = (e) => { + // TODO: Types + private onVerifierCancel = (e): void => { this.setState({ phase: PHASE_CANCELLED, }); - } + }; - _onSasMatchesClick = () => { - this._showSasEvent.confirm(); + private onSasMatchesClick = (): void => { + this.showSasEvent.confirm(); this.setState({ phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, }); - } + }; - _onVerifiedDoneClick = () => { + private onVerifiedDoneClick = (): void => { this.props.onFinished(true); - } - - _renderPhaseStart() { - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const Spinner = sdk.getComponent("views.elements.Spinner"); - const BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); + }; + private renderPhaseStart(): JSX.Element { const isSelf = this.props.verifier.userId === MatrixClientPeg.get().getUserId(); let profile; @@ -190,27 +209,24 @@ export default class IncomingSasDialog extends React.Component {
); } - _renderPhaseShowSas() { - const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); + private renderPhaseShowSas(): JSX.Element { return ; } - _renderPhaseWaitForPartnerToConfirm() { - const Spinner = sdk.getComponent("views.elements.Spinner"); - + private renderPhaseWaitForPartnerToConfirm(): JSX.Element { return (
@@ -219,41 +235,38 @@ export default class IncomingSasDialog extends React.Component { ); } - _renderPhaseVerified() { - const VerificationComplete = sdk.getComponent('views.verification.VerificationComplete'); - return ; + private renderPhaseVerified(): JSX.Element { + return ; } - _renderPhaseCancelled() { - const VerificationCancelled = sdk.getComponent('views.verification.VerificationCancelled'); - return ; + private renderPhaseCancelled(): JSX.Element { + return ; } - render() { + public render(): JSX.Element { let body; switch (this.state.phase) { case PHASE_START: - body = this._renderPhaseStart(); + body = this.renderPhaseStart(); break; case PHASE_SHOW_SAS: - body = this._renderPhaseShowSas(); + body = this.renderPhaseShowSas(); break; case PHASE_WAIT_FOR_PARTNER_TO_CONFIRM: - body = this._renderPhaseWaitForPartnerToConfirm(); + body = this.renderPhaseWaitForPartnerToConfirm(); break; case PHASE_VERIFIED: - body = this._renderPhaseVerified(); + body = this.renderPhaseVerified(); break; case PHASE_CANCELLED: - body = this._renderPhaseCancelled(); + body = this.renderPhaseCancelled(); break; } - const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); return ( { body } From 6e11f2478cb092ad55abd3b657e11d61f1996ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:01:05 +0200 Subject: [PATCH 22/34] Use IDialogProps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/BaseDialog.tsx | 9 ++------- src/components/views/dialogs/FeedbackDialog.tsx | 5 ++--- src/components/views/dialogs/IncomingSasDialog.tsx | 4 ++-- .../views/dialogs/IntegrationsDisabledDialog.tsx | 5 ++--- .../views/dialogs/IntegrationsImpossibleDialog.tsx | 6 ++---- src/components/views/dialogs/InteractiveAuthDialog.tsx | 5 ++--- .../views/dialogs/KeySignatureUploadFailedDialog.tsx | 4 ++-- .../views/dialogs/LazyLoadingDisabledDialog.tsx | 3 +-- .../views/dialogs/LazyLoadingResyncDialog.tsx | 5 ++--- .../dialogs/ManualDeviceKeyVerificationDialog.tsx | 4 ++-- .../views/dialogs/MessageEditHistoryDialog.tsx | 4 ++-- src/components/views/dialogs/QuestionDialog.tsx | 4 ++-- .../views/dialogs/SessionRestoreErrorDialog.tsx | 4 ++-- src/components/views/dialogs/SetEmailDialog.tsx | 4 ++-- .../views/dialogs/SlashCommandHelpDialog.tsx | 5 ++--- src/components/views/dialogs/StorageEvictedDialog.tsx | 5 ++--- .../views/dialogs/TabbedIntegrationManagerDialog.tsx | 10 ++-------- src/components/views/dialogs/TextInputDialog.tsx | 4 ++-- src/components/views/dialogs/UploadFailureDialog.tsx | 4 ++-- .../views/dialogs/security/RestoreKeyBackupDialog.tsx | 5 ++--- .../views/dialogs/security/SetupEncryptionDialog.tsx | 6 ++---- 21 files changed, 41 insertions(+), 64 deletions(-) diff --git a/src/components/views/dialogs/BaseDialog.tsx b/src/components/views/dialogs/BaseDialog.tsx index 91cceb3123..0af494f53e 100644 --- a/src/components/views/dialogs/BaseDialog.tsx +++ b/src/components/views/dialogs/BaseDialog.tsx @@ -27,14 +27,9 @@ import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClient } from "matrix-js-sdk/src/client"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - // onFinished callback to call when Escape is pressed - // Take a boolean which is true if the dialog was dismissed - // with a positive / confirm action or false if it was - // cancelled (BaseDialog itself only calls this with false). - onFinished: (confirm: any) => void; - +interface IProps extends IDialogProps { // Whether the dialog should have a 'close' button that will // cause the dialog to be cancelled. This should only be set // to false if there is nothing the app can sensibly do if the diff --git a/src/components/views/dialogs/FeedbackDialog.tsx b/src/components/views/dialogs/FeedbackDialog.tsx index 00112ab0c7..6f957452bc 100644 --- a/src/components/views/dialogs/FeedbackDialog.tsx +++ b/src/components/views/dialogs/FeedbackDialog.tsx @@ -25,14 +25,13 @@ import Modal from "../../../Modal"; import BugReportDialog from "./BugReportDialog"; import InfoDialog from "./InfoDialog"; import StyledRadioGroup from "../elements/StyledRadioGroup"; +import { IDialogProps } from "./IDialogProps"; const existingIssuesUrl = "https://github.com/vector-im/element-web/issues" + "?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc"; const newIssueUrl = "https://github.com/vector-im/element-web/issues/new/choose"; -interface IProps { - onFinished: () => void; -} +interface IProps extends IDialogProps {} const FeedbackDialog: React.FC = (props: IProps) => { const [rating, setRating] = useState(); diff --git a/src/components/views/dialogs/IncomingSasDialog.tsx b/src/components/views/dialogs/IncomingSasDialog.tsx index 8903b00221..0c689e198d 100644 --- a/src/components/views/dialogs/IncomingSasDialog.tsx +++ b/src/components/views/dialogs/IncomingSasDialog.tsx @@ -26,6 +26,7 @@ import Spinner from "../elements/Spinner"; import VerificationShowSas from "../verification/VerificationShowSas"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import { IDialogProps } from "./IDialogProps"; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -33,9 +34,8 @@ const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2; const PHASE_VERIFIED = 3; const PHASE_CANCELLED = 4; -interface IProps { +interface IProps extends IDialogProps { verifier: any; // TODO types - onFinished: (confirmed: boolean) => void; } interface IState { diff --git a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx index f76ed46577..7da4bb84b9 100644 --- a/src/components/views/dialogs/IntegrationsDisabledDialog.tsx +++ b/src/components/views/dialogs/IntegrationsDisabledDialog.tsx @@ -21,10 +21,9 @@ import { Action } from "../../../dispatcher/actions"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - onFinished: () => void; -} +interface IProps extends IDialogProps {} @replaceableComponent("views.dialogs.IntegrationsDisabledDialog") export default class IntegrationsDisabledDialog extends React.Component { diff --git a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx index 36dc42b783..52e3a2fbb8 100644 --- a/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx +++ b/src/components/views/dialogs/IntegrationsImpossibleDialog.tsx @@ -19,11 +19,9 @@ import { _t } from "../../../languageHandler"; import SdkConfig from "../../../SdkConfig"; import * as sdk from "../../../index"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - onFinished: () => void; - -} +interface IProps extends IDialogProps {} @replaceableComponent("views.dialogs.IntegrationsImpossibleDialog") export default class IntegrationsImpossibleDialog extends React.Component { diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index e9667c84b5..ededfa3bc0 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -27,8 +27,9 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; import { MatrixClient } from "matrix-js-sdk/src/client"; import BaseDialog from "./BaseDialog"; import { IAuthData } from "matrix-js-sdk/src/interactive-auth"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { // matrix client to use for UI auth requests matrixClient: MatrixClient; @@ -43,8 +44,6 @@ interface IProps { // callback makeRequest: (auth: IAuthData) => Promise; - onFinished: (confirmed: boolean, result?) => void; - // Optional title and body to show when not showing a particular stage title?: string; body?: string; diff --git a/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx b/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx index 20841c46f4..28e4d1ca80 100644 --- a/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx +++ b/src/components/views/dialogs/KeySignatureUploadFailedDialog.tsx @@ -20,15 +20,15 @@ import SdkConfig from '../../../SdkConfig'; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import Spinner from "../elements/Spinner"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { failures: Record>; source: string; continuation: () => void; - onFinished: () => void; } const KeySignatureUploadFailedDialog: React.FC = ({ diff --git a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx index 32aaf9c531..79b8306989 100644 --- a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx +++ b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx @@ -20,8 +20,7 @@ import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; -interface IProps { - onFinished: () => void; +interface IProps extends IDialogProps { host: string; } diff --git a/src/components/views/dialogs/LazyLoadingResyncDialog.tsx b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx index c942126d12..3acedc77e4 100644 --- a/src/components/views/dialogs/LazyLoadingResyncDialog.tsx +++ b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx @@ -19,10 +19,9 @@ import React from 'react'; import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - onFinished: () => void; -} +interface IProps extends IDialogProps {} const LazyLoadingResyncDialog: React.FC = (props: IProps) => { const brand = SdkConfig.get().brand; diff --git a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx index a4c989d7b5..88419d26b8 100644 --- a/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx +++ b/src/components/views/dialogs/ManualDeviceKeyVerificationDialog.tsx @@ -25,11 +25,11 @@ import { _t } from '../../../languageHandler'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import QuestionDialog from "./QuestionDialog"; import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { userId: string; device: DeviceInfo; - onFinished: (confirmed: boolean) => void; } @replaceableComponent("views.dialogs.ManualDeviceKeyVerificationDialog") diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.tsx b/src/components/views/dialogs/MessageEditHistoryDialog.tsx index 30c16b03bd..04313ed9a0 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.tsx +++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx @@ -26,10 +26,10 @@ import ScrollPanel from "../../structures/ScrollPanel"; import Spinner from "../elements/Spinner"; import EditHistoryMessage from "../messages/EditHistoryMessage"; import DateSeparator from "../messages/DateSeparator"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { mxEvent: MatrixEvent; - onFinished: () => void; } interface IState { diff --git a/src/components/views/dialogs/QuestionDialog.tsx b/src/components/views/dialogs/QuestionDialog.tsx index df036293f0..8c6334bac1 100644 --- a/src/components/views/dialogs/QuestionDialog.tsx +++ b/src/components/views/dialogs/QuestionDialog.tsx @@ -20,8 +20,9 @@ import classNames from "classnames"; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { title?: string; description?: React.ReactNode; extraButtons?: React.ReactNode; @@ -29,7 +30,6 @@ interface IProps { buttonDisabled?: boolean; danger?: boolean; focus?: boolean; - onFinished: (confirmed: boolean) => void; headerImage?: string; quitOnly?: boolean; // quitOnly doesn't show the cancel button just the quit [x]. fixedWidth?: boolean; diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx index 752b023f0b..b36dbf548e 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.tsx +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.tsx @@ -25,10 +25,10 @@ import QuestionDialog from "./QuestionDialog"; import BugReportDialog from "./BugReportDialog"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { error: string; - onFinished: () => void; } @replaceableComponent("views.dialogs.SessionRestoreErrorDialog") diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx index 506399d15d..0fa898f1b9 100644 --- a/src/components/views/dialogs/SetEmailDialog.tsx +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -26,10 +26,10 @@ import ErrorDialog from "./ErrorDialog"; import QuestionDialog from "./QuestionDialog"; import BaseDialog from "./BaseDialog"; import EditableText from "../elements/EditableText"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { title: string; - onFinished: (confirmed: boolean) => void; } interface IState { diff --git a/src/components/views/dialogs/SlashCommandHelpDialog.tsx b/src/components/views/dialogs/SlashCommandHelpDialog.tsx index c47555567e..ccb157f025 100644 --- a/src/components/views/dialogs/SlashCommandHelpDialog.tsx +++ b/src/components/views/dialogs/SlashCommandHelpDialog.tsx @@ -17,11 +17,10 @@ limitations under the License. import React from 'react'; import { _t } from "../../../languageHandler"; import { CommandCategories, Commands } from "../../../SlashCommands"; +import { IDialogProps } from "./IDialogProps"; import InfoDialog from "./InfoDialog"; -interface IProps { - onFinished: () => void; -} +interface IProps extends IDialogProps {} const SlashCommandHelpDialog: React.FC = ({ onFinished }) => { const categories = {}; diff --git a/src/components/views/dialogs/StorageEvictedDialog.tsx b/src/components/views/dialogs/StorageEvictedDialog.tsx index 60ae049bf6..bdbbf815e6 100644 --- a/src/components/views/dialogs/StorageEvictedDialog.tsx +++ b/src/components/views/dialogs/StorageEvictedDialog.tsx @@ -22,10 +22,9 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import BugReportDialog from "./BugReportDialog"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - onFinished: (confirmed: boolean) => void; -} +interface IProps extends IDialogProps { } @replaceableComponent("views.dialogs.StorageEvictedDialog") export default class StorageEvictedDialog extends React.Component { diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx index c8ab25b1bb..7ee54403bd 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx @@ -25,15 +25,9 @@ import { IntegrationManagerInstance } from "../../../integrations/IntegrationMan import ScalarAuthClient from "../../../ScalarAuthClient"; import AccessibleButton from "../elements/AccessibleButton"; import IntegrationManager from "../settings/IntegrationManager"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { - /** - * Called with: - * * success {bool} True if the user accepted any douments, false if cancelled - * * agreedUrls {string[]} List of agreed URLs - */ - onFinished: () => void; - +interface IProps extends IDialogProps { /** * Optional room where the integration manager should be open to */ diff --git a/src/components/views/dialogs/TextInputDialog.tsx b/src/components/views/dialogs/TextInputDialog.tsx index 624e2a58cb..cc321a0af6 100644 --- a/src/components/views/dialogs/TextInputDialog.tsx +++ b/src/components/views/dialogs/TextInputDialog.tsx @@ -21,8 +21,9 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IFieldState, IValidationResult } from "../elements/Validation"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import { IDialogProps } from "./IDialogProps"; - interface IProps { +interface IProps extends IDialogProps { title?: string; description?: string | JSX.Element; value?: string; @@ -30,7 +31,6 @@ import DialogButtons from "../elements/DialogButtons"; button?: string; busyMessage?: string; // pass _td string focus?: boolean; - onFinished: (success: boolean, value?: string) => void; hasCancel?: boolean; validator?: (fieldState: IFieldState) => IValidationResult; // result of withValidation fixedWidth?: boolean; diff --git a/src/components/views/dialogs/UploadFailureDialog.tsx b/src/components/views/dialogs/UploadFailureDialog.tsx index 807cb08195..bb8d14e161 100644 --- a/src/components/views/dialogs/UploadFailureDialog.tsx +++ b/src/components/views/dialogs/UploadFailureDialog.tsx @@ -22,12 +22,12 @@ import ContentMessages from '../../../ContentMessages'; import { replaceableComponent } from "../../../utils/replaceableComponent"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import { IDialogProps } from "./IDialogProps"; -interface IProps { +interface IProps extends IDialogProps { badFiles: File[]; totalFiles: number; contentMessages: ContentMessages; - onFinished: (success: boolean) => void; } /* diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index d2b850eb85..7d5c3cf857 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -23,6 +23,7 @@ import { accessSecretStorage } from '../../../../SecurityManager'; import { IKeyBackupInfo, IKeyBackupRestoreResult } from "matrix-js-sdk/src/crypto/keybackup"; import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/crypto/api"; import * as sdk from '../../../../index'; +import { IDialogProps } from "../IDialogProps"; enum RestoreType { Passphrase = "passphrase", @@ -37,15 +38,13 @@ enum ProgressState { } -interface IProps { +interface IProps extends IDialogProps { // if false, will close the dialog as soon as the restore completes succesfully // default: true showSummary?: boolean; // If specified, gather the key from the user but then call the function with the backup // key rather than actually (necessarily) restoring the backup. keyCallback?: (key: Uint8Array) => void; - - onFinished: (success: boolean) => void; } interface IState { diff --git a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx index b601353d1d..0323769536 100644 --- a/src/components/views/dialogs/security/SetupEncryptionDialog.tsx +++ b/src/components/views/dialogs/security/SetupEncryptionDialog.tsx @@ -20,6 +20,7 @@ import BaseDialog from '../BaseDialog'; import { _t } from '../../../../languageHandler'; import { SetupEncryptionStore, Phase } from '../../../../stores/SetupEncryptionStore'; import { replaceableComponent } from "../../../../utils/replaceableComponent"; +import { IDialogProps } from "../IDialogProps"; function iconFromPhase(phase: Phase) { if (phase === Phase.Done) { @@ -29,10 +30,7 @@ function iconFromPhase(phase: Phase) { } } -interface IProps { - onFinished: (success: boolean) => void; -} - +interface IProps extends IDialogProps {} interface IState { icon: string; } From f2b2a04a217104429db4024937df01016d9a16b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:03:29 +0200 Subject: [PATCH 23/34] Make room optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx index 7ee54403bd..0f87b5c18d 100644 --- a/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx +++ b/src/components/views/dialogs/TabbedIntegrationManagerDialog.tsx @@ -31,7 +31,7 @@ interface IProps extends IDialogProps { /** * Optional room where the integration manager should be open to */ - room: Room; + room?: Room; /** * Optional screen to open on the integration manager From 6568e22d70fc127010a21e7ee338fd948fc3487d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:06:09 +0200 Subject: [PATCH 24/34] Add missing import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/LazyLoadingDisabledDialog.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx index 79b8306989..76e7407173 100644 --- a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx +++ b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx @@ -19,6 +19,7 @@ import React from 'react'; import QuestionDialog from './QuestionDialog'; import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; +import { IDialogProps } from "./IDialogProps"; interface IProps extends IDialogProps { host: string; From 52d203dd8e1033325be8681bf629fdf734127dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:07:55 +0200 Subject: [PATCH 25/34] Add missing types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/InteractiveAuthDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index ededfa3bc0..9a1bec70c9 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -127,7 +127,7 @@ export default class InteractiveAuthDialog extends React.Component { + private onUpdateStagePhase = (newStage: number, newPhase: number): void => { // We copy the stage and stage phase params into state for title selection in render() this.setState({ uiaStage: newStage, uiaStagePhase: newPhase }); }; From 0efd59901420572e1cb5e0086fa99e903936837b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:12:33 +0200 Subject: [PATCH 26/34] Fix types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/InteractiveAuthDialog.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index 9a1bec70c9..e6cf72cf9a 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -73,8 +73,8 @@ interface IState { authError: Error; // See _onUpdateStagePhase() - uiaStage: number; - uiaStagePhase: number; + uiaStage: number | string; + uiaStagePhase: number | string; } @replaceableComponent("views.dialogs.InteractiveAuthDialog") @@ -127,7 +127,7 @@ export default class InteractiveAuthDialog extends React.Component { + private onUpdateStagePhase = (newStage: string | number, newPhase: string | number): void => { // We copy the stage and stage phase params into state for title selection in render() this.setState({ uiaStage: newStage, uiaStagePhase: newPhase }); }; From 3fffbb084537635b5897b9b1ba0bbc272724259d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Fri, 10 Sep 2021 19:19:29 +0200 Subject: [PATCH 27/34] Use ISasEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/IncomingSasDialog.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/views/dialogs/IncomingSasDialog.tsx b/src/components/views/dialogs/IncomingSasDialog.tsx index 0c689e198d..e81a233055 100644 --- a/src/components/views/dialogs/IncomingSasDialog.tsx +++ b/src/components/views/dialogs/IncomingSasDialog.tsx @@ -27,6 +27,7 @@ import VerificationShowSas from "../verification/VerificationShowSas"; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import { IDialogProps } from "./IDialogProps"; +import { IGeneratedSas, ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS"; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -47,12 +48,12 @@ interface IState { displayname?: string; }; opponentProfileError: Error; - sas: any; // TODO types + sas: IGeneratedSas; } @replaceableComponent("views.dialogs.IncomingSasDialog") export default class IncomingSasDialog extends React.Component { - private showSasEvent: any; // TODO: Types + private showSasEvent: ISasEvent; constructor(props: IProps) { super(props); @@ -115,8 +116,7 @@ export default class IncomingSasDialog extends React.Component { }); }; - // TODO: Types - private onVerifierShowSas = (e): void => { + private onVerifierShowSas = (e: ISasEvent): void => { this.showSasEvent = e; this.setState({ phase: PHASE_SHOW_SAS, @@ -124,8 +124,7 @@ export default class IncomingSasDialog extends React.Component { }); }; - // TODO: Types - private onVerifierCancel = (e): void => { + private onVerifierCancel = (): void => { this.setState({ phase: PHASE_CANCELLED, }); From 71e84ccb75aeb002b236d9c73c867496b5c89e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 13 Sep 2021 18:03:05 +0200 Subject: [PATCH 28/34] Iterate PR first round MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/IncomingSasDialog.tsx | 7 ++++--- src/components/views/dialogs/LazyLoadingDisabledDialog.tsx | 2 +- src/components/views/dialogs/LazyLoadingResyncDialog.tsx | 2 +- src/components/views/dialogs/QuestionDialog.tsx | 2 +- src/components/views/dialogs/TextInputDialog.tsx | 2 +- .../views/dialogs/security/RestoreKeyBackupDialog.tsx | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/views/dialogs/IncomingSasDialog.tsx b/src/components/views/dialogs/IncomingSasDialog.tsx index e81a233055..0e9d8cbf4e 100644 --- a/src/components/views/dialogs/IncomingSasDialog.tsx +++ b/src/components/views/dialogs/IncomingSasDialog.tsx @@ -28,6 +28,7 @@ import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; import { IDialogProps } from "./IDialogProps"; import { IGeneratedSas, ISasEvent } from "matrix-js-sdk/src/crypto/verification/SAS"; +import { VerificationBase } from "matrix-js-sdk/src/crypto/verification/Base"; const PHASE_START = 0; const PHASE_SHOW_SAS = 1; @@ -36,7 +37,7 @@ const PHASE_VERIFIED = 3; const PHASE_CANCELLED = 4; interface IProps extends IDialogProps { - verifier: any; // TODO types + verifier: VerificationBase; // TODO types } interface IState { @@ -59,7 +60,7 @@ export default class IncomingSasDialog extends React.Component { super(props); let phase = PHASE_START; - if (this.props.verifier.cancelled) { + if (this.props.verifier.hasBeenCancelled) { console.log("Verifier was cancelled in the background."); phase = PHASE_CANCELLED; } @@ -79,7 +80,7 @@ export default class IncomingSasDialog extends React.Component { public componentWillUnmount(): void { if (this.state.phase !== PHASE_CANCELLED && this.state.phase !== PHASE_VERIFIED) { - this.props.verifier.cancel('User cancel'); + this.props.verifier.cancel(new Error('User cancel')); } this.props.verifier.removeListener('show_sas', this.onVerifierShowSas); } diff --git a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx index 76e7407173..ec30123436 100644 --- a/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx +++ b/src/components/views/dialogs/LazyLoadingDisabledDialog.tsx @@ -25,7 +25,7 @@ interface IProps extends IDialogProps { host: string; } -const LazyLoadingDisabledDialog: React.FC = (props: IProps) => { +const LazyLoadingDisabledDialog: React.FC = (props) => { const brand = SdkConfig.get().brand; const description1 = _t( "You've previously used %(brand)s on %(host)s with lazy loading of members enabled. " + diff --git a/src/components/views/dialogs/LazyLoadingResyncDialog.tsx b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx index 3acedc77e4..e6a505511c 100644 --- a/src/components/views/dialogs/LazyLoadingResyncDialog.tsx +++ b/src/components/views/dialogs/LazyLoadingResyncDialog.tsx @@ -23,7 +23,7 @@ import { IDialogProps } from "./IDialogProps"; interface IProps extends IDialogProps {} -const LazyLoadingResyncDialog: React.FC = (props: IProps) => { +const LazyLoadingResyncDialog: React.FC = (props) => { const brand = SdkConfig.get().brand; const description = _t( diff --git a/src/components/views/dialogs/QuestionDialog.tsx b/src/components/views/dialogs/QuestionDialog.tsx index 8c6334bac1..aaddff34ed 100644 --- a/src/components/views/dialogs/QuestionDialog.tsx +++ b/src/components/views/dialogs/QuestionDialog.tsx @@ -35,7 +35,7 @@ interface IProps extends IDialogProps { fixedWidth?: boolean; className?: string; hasCancelButton?: boolean; - cancelButton?: JSX.Element; + cancelButton?: React.ReactNode; } export default class QuestionDialog extends React.Component { diff --git a/src/components/views/dialogs/TextInputDialog.tsx b/src/components/views/dialogs/TextInputDialog.tsx index cc321a0af6..7a5887f053 100644 --- a/src/components/views/dialogs/TextInputDialog.tsx +++ b/src/components/views/dialogs/TextInputDialog.tsx @@ -25,7 +25,7 @@ import { IDialogProps } from "./IDialogProps"; interface IProps extends IDialogProps { title?: string; - description?: string | JSX.Element; + description?: React.ReactNode; value?: string; placeholder?: string; button?: string; diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index 7d5c3cf857..afeec726b6 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -59,7 +59,7 @@ interface IState { recoverInfo: IKeyBackupRestoreResult; recoveryKeyValid: boolean; forceRecoveryKey: boolean; - passPhrase: ""; + passPhrase: string; restoreType: RestoreType; progress: { stage: ProgressState; From adb325b3bd9bcd889e25c2ed4de828aabd562bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 13 Sep 2021 18:05:59 +0200 Subject: [PATCH 29/34] Use enums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/MessageEditHistoryDialog.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.tsx b/src/components/views/dialogs/MessageEditHistoryDialog.tsx index 04313ed9a0..427924e445 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.tsx +++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx @@ -27,6 +27,7 @@ import Spinner from "../elements/Spinner"; import EditHistoryMessage from "../messages/EditHistoryMessage"; import DateSeparator from "../messages/DateSeparator"; import { IDialogProps } from "./IDialogProps"; +import { EventType, RelationType } from "matrix-js-sdk/src/@types/event"; interface IProps extends IDialogProps { mxEvent: MatrixEvent; @@ -72,7 +73,7 @@ export default class MessageEditHistoryDialog extends React.PureComponent((_resolve, _reject) => {resolve = _resolve; reject = _reject;}); try { result = await client.relations( - roomId, eventId, "m.replace", "m.room.message", opts); + roomId, eventId, RelationType.Replace, EventType.RoomMessage, opts); } catch (error) { // log if the server returned an error if (error.errcode) { From c9dea9948fb9a3affc79f38255e1e42b8f8ef45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 13 Sep 2021 18:06:35 +0200 Subject: [PATCH 30/34] Use IAuthData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/InteractiveAuthDialog.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index e6cf72cf9a..c0d108bf06 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -35,11 +35,7 @@ interface IProps extends IDialogProps { // response from initial request. If not supplied, will do a request on // mount. - authData?: { - flows: []; - params: {}; - session: string; - }; + authData?: IAuthData; // callback makeRequest: (auth: IAuthData) => Promise; From 27b9175ca347510422c5102c1578cee8f5e1bb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 13 Sep 2021 18:09:45 +0200 Subject: [PATCH 31/34] Use defer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/MessageEditHistoryDialog.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.tsx b/src/components/views/dialogs/MessageEditHistoryDialog.tsx index 427924e445..7753eba199 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.tsx +++ b/src/components/views/dialogs/MessageEditHistoryDialog.tsx @@ -28,6 +28,7 @@ import EditHistoryMessage from "../messages/EditHistoryMessage"; import DateSeparator from "../messages/DateSeparator"; import { IDialogProps } from "./IDialogProps"; import { EventType, RelationType } from "matrix-js-sdk/src/@types/event"; +import { defer } from "matrix-js-sdk/src/utils"; interface IProps extends IDialogProps { mxEvent: MatrixEvent; @@ -67,10 +68,10 @@ export default class MessageEditHistoryDialog extends React.PureComponent(); let result; - let resolve; - let reject; - const promise = new Promise((_resolve, _reject) => {resolve = _resolve; reject = _reject;}); + try { result = await client.relations( roomId, eventId, RelationType.Replace, EventType.RoomMessage, opts); From 29ff5f3f9ce4b932cbb1adb5db769d61bdd395a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Mon, 13 Sep 2021 18:12:47 +0200 Subject: [PATCH 32/34] Add IDialogAesthetics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/dialogs/InteractiveAuthDialog.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/InteractiveAuthDialog.tsx b/src/components/views/dialogs/InteractiveAuthDialog.tsx index c0d108bf06..2ea97f91c3 100644 --- a/src/components/views/dialogs/InteractiveAuthDialog.tsx +++ b/src/components/views/dialogs/InteractiveAuthDialog.tsx @@ -29,6 +29,17 @@ import BaseDialog from "./BaseDialog"; import { IAuthData } from "matrix-js-sdk/src/interactive-auth"; import { IDialogProps } from "./IDialogProps"; +interface IDialogAesthetics { + [x: string]: { + [x: number]: { + title: string; + body: string; + continueText: string; + continueKind: string; + }; + }; +} + interface IProps extends IDialogProps { // matrix client to use for UI auth requests matrixClient: MatrixClient; @@ -62,7 +73,7 @@ interface IProps extends IDialogProps { // } // // Default is defined in _getDefaultDialogAesthetics() - aestheticsForStagePhases?: {}; + aestheticsForStagePhases?: IDialogAesthetics; } interface IState { @@ -87,7 +98,7 @@ export default class InteractiveAuthDialog extends React.Component Date: Tue, 14 Sep 2021 17:38:34 +0200 Subject: [PATCH 33/34] Improve typing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/FeedbackDialog.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/FeedbackDialog.tsx b/src/components/views/dialogs/FeedbackDialog.tsx index 6f957452bc..e7089283e4 100644 --- a/src/components/views/dialogs/FeedbackDialog.tsx +++ b/src/components/views/dialogs/FeedbackDialog.tsx @@ -34,7 +34,7 @@ const newIssueUrl = "https://github.com/vector-im/element-web/issues/new/choose" interface IProps extends IDialogProps {} const FeedbackDialog: React.FC = (props: IProps) => { - const [rating, setRating] = useState(); + const [rating, setRating] = useState(); const [comment, setComment] = useState(""); const onDebugLogsLinkClick = (): void => { @@ -45,7 +45,7 @@ const FeedbackDialog: React.FC = (props: IProps) => { const hasFeedback = CountlyAnalytics.instance.canEnable(); const onFinished = (sendFeedback: boolean): void => { if (hasFeedback && sendFeedback) { - CountlyAnalytics.instance.reportFeedback((parseInt(rating) as Rating), comment); + CountlyAnalytics.instance.reportFeedback(rating, comment); Modal.createTrackedDialog('Feedback sent', '', InfoDialog, { title: _t('Feedback sent'), description: _t('Thank you!'), @@ -68,8 +68,8 @@ const FeedbackDialog: React.FC = (props: IProps) => { setRating(parseInt(r, 10) as Rating)} definitions={[ { value: "1", label: "😠" }, { value: "2", label: "😞" }, @@ -141,7 +141,7 @@ const FeedbackDialog: React.FC = (props: IProps) => { { countlyFeedbackSection } } button={hasFeedback ? _t("Send feedback") : _t("Go back")} - buttonDisabled={hasFeedback && rating === ""} + buttonDisabled={hasFeedback && !rating} onFinished={onFinished} />); }; From 4adc900d00e827a6725f0385ca19e0db5d740a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 22 Sep 2021 10:46:59 +0200 Subject: [PATCH 34/34] Remove autoFocus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/dialogs/SetEmailDialog.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx index 0fa898f1b9..a8b8207f7d 100644 --- a/src/components/views/dialogs/SetEmailDialog.tsx +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -132,7 +132,6 @@ export default class SetEmailDialog extends React.Component { const emailInput = this.state.emailBusy ? :