Properly type Modal props to ensure useful typescript checking (#10238

* Properly type Modal props to ensure useful typescript checking

* delint

* Iterate

* Iterate

* Fix modal.close loop

* Iterate

* Fix tests

* Add comment

* Fix test
This commit is contained in:
Michael Telatyński 2023-02-28 10:31:48 +00:00 committed by GitHub
parent ae5725b24c
commit 629e5cb01f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
124 changed files with 600 additions and 560 deletions

View file

@ -184,7 +184,7 @@ export default class AddThreepid {
* with a "message" property which contains a human-readable message detailing why * with a "message" property which contains a human-readable message detailing why
* the request failed. * the request failed.
*/ */
public async checkEmailLinkClicked(): Promise<[boolean, IAuthData | Error | null] | undefined> { public async checkEmailLinkClicked(): Promise<[success?: boolean, result?: IAuthData | Error | null]> {
try { try {
if (await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) { if (await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) {
if (this.bind) { if (this.bind) {
@ -202,7 +202,7 @@ export default class AddThreepid {
// The spec has always required this to use UI auth but synapse briefly // The spec has always required this to use UI auth but synapse briefly
// implemented it without, so this may just succeed and that's OK. // implemented it without, so this may just succeed and that's OK.
return; return [true];
} catch (e) { } catch (e) {
if (e.httpStatus !== 401 || !e.data || !e.data.flows) { if (e.httpStatus !== 401 || !e.data || !e.data.flows) {
// doesn't look like an interactive-auth failure // doesn't look like an interactive-auth failure
@ -225,9 +225,7 @@ export default class AddThreepid {
continueKind: "primary", continueKind: "primary",
}, },
}; };
const { finished } = Modal.createDialog<[boolean, IAuthData | Error | null]>( const { finished } = Modal.createDialog(InteractiveAuthDialog, {
InteractiveAuthDialog,
{
title: _t("Add Email Address"), title: _t("Add Email Address"),
matrixClient: MatrixClientPeg.get(), matrixClient: MatrixClientPeg.get(),
authData: e.data, authData: e.data,
@ -236,8 +234,7 @@ export default class AddThreepid {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics, [SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
[SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics, [SSOAuthEntry.UNSTABLE_LOGIN_TYPE]: dialogAesthetics,
}, },
}, });
);
return finished; return finished;
} }
} }
@ -259,6 +256,7 @@ export default class AddThreepid {
} }
throw err; throw err;
} }
return [];
} }
/** /**

View file

@ -18,16 +18,16 @@ import React, { ComponentType } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "./languageHandler"; import { _t } from "./languageHandler";
import { IDialogProps } from "./components/views/dialogs/IDialogProps";
import BaseDialog from "./components/views/dialogs/BaseDialog"; import BaseDialog from "./components/views/dialogs/BaseDialog";
import DialogButtons from "./components/views/elements/DialogButtons"; import DialogButtons from "./components/views/elements/DialogButtons";
import Spinner from "./components/views/elements/Spinner"; import Spinner from "./components/views/elements/Spinner";
type AsyncImport<T> = { default: T }; type AsyncImport<T> = { default: T };
interface IProps extends IDialogProps { interface IProps {
// A promise which resolves with the real component // A promise which resolves with the real component
prom: Promise<ComponentType | AsyncImport<ComponentType>>; prom: Promise<ComponentType<any> | AsyncImport<ComponentType<any>>>;
onFinished(): void;
} }
interface IState { interface IState {
@ -71,7 +71,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
} }
private onWrapperCancelClick = (): void => { private onWrapperCancelClick = (): void => {
this.props.onFinished(false); this.props.onFinished();
}; };
public render(): React.ReactNode { public render(): React.ReactNode {

View file

@ -389,7 +389,7 @@ export default class ContentMessages {
} }
if (tooBigFiles.length > 0) { if (tooBigFiles.length > 0) {
const { finished } = Modal.createDialog<[boolean]>(UploadFailureDialog, { const { finished } = Modal.createDialog(UploadFailureDialog, {
badFiles: tooBigFiles, badFiles: tooBigFiles,
totalFiles: files.length, totalFiles: files.length,
contentMessages: this, contentMessages: this,
@ -407,7 +407,7 @@ export default class ContentMessages {
const loopPromiseBefore = promBefore; const loopPromiseBefore = promBefore;
if (!uploadAll) { if (!uploadAll) {
const { finished } = Modal.createDialog<[boolean, boolean]>(UploadConfirmDialog, { const { finished } = Modal.createDialog(UploadConfirmDialog, {
file, file,
currentIndex: i, currentIndex: i,
totalFiles: okFiles.length, totalFiles: okFiles.length,

View file

@ -58,7 +58,7 @@ import IncomingLegacyCallToast, { getIncomingLegacyCallToastKey } from "./toasts
import ToastStore from "./stores/ToastStore"; import ToastStore from "./stores/ToastStore";
import Resend from "./Resend"; import Resend from "./Resend";
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
import { KIND_CALL_TRANSFER } from "./components/views/dialogs/InviteDialogTypes"; import { InviteKind } from "./components/views/dialogs/InviteDialogTypes";
import { OpenInviteDialogPayload } from "./dispatcher/payloads/OpenInviteDialogPayload"; import { OpenInviteDialogPayload } from "./dispatcher/payloads/OpenInviteDialogPayload";
import { findDMForUser } from "./utils/dm/findDMForUser"; import { findDMForUser } from "./utils/dm/findDMForUser";
import { getJoinedNonFunctionalMembers } from "./utils/room/getJoinedNonFunctionalMembers"; import { getJoinedNonFunctionalMembers } from "./utils/room/getJoinedNonFunctionalMembers";
@ -1214,7 +1214,7 @@ export default class LegacyCallHandler extends EventEmitter {
call.setRemoteOnHold(true); call.setRemoteOnHold(true);
dis.dispatch<OpenInviteDialogPayload>({ dis.dispatch<OpenInviteDialogPayload>({
action: Action.OpenInviteDialog, action: Action.OpenInviteDialog,
kind: KIND_CALL_TRANSFER, kind: InviteKind.CallTransfer,
call, call,
analyticsName: "Transfer Call", analyticsName: "Transfer Call",
className: "mx_InviteDialog_transferWrapper", className: "mx_InviteDialog_transferWrapper",

View file

@ -265,7 +265,7 @@ export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> {
.then(() => { .then(() => {
const lazyLoadEnabled = e.value; const lazyLoadEnabled = e.value;
if (lazyLoadEnabled) { if (lazyLoadEnabled) {
return new Promise((resolve) => { return new Promise<void>((resolve) => {
Modal.createDialog(LazyLoadingResyncDialog, { Modal.createDialog(LazyLoadingResyncDialog, {
onFinished: resolve, onFinished: resolve,
}); });
@ -275,7 +275,7 @@ export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> {
// between LL/non-LL version on same host. // between LL/non-LL version on same host.
// as disabling LL when previously enabled // as disabling LL when previously enabled
// is a strong indicator of this (/develop & /app) // is a strong indicator of this (/develop & /app)
return new Promise((resolve) => { return new Promise<void>((resolve) => {
Modal.createDialog(LazyLoadingDisabledDialog, { Modal.createDialog(LazyLoadingDisabledDialog, {
onFinished: resolve, onFinished: resolve,
host: window.location.host, host: window.location.host,

View file

@ -27,34 +27,35 @@ import AsyncWrapper from "./AsyncWrapper";
const DIALOG_CONTAINER_ID = "mx_Dialog_Container"; const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer"; const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer";
export interface IModal<T extends any[]> { // Type which accepts a React Component which looks like a Modal (accepts an onFinished prop)
export type ComponentType = React.ComponentType<{
onFinished?(...args: any): void;
}>;
// Generic type which returns the props of the Modal component with the onFinished being optional.
export type ComponentProps<C extends ComponentType> = Omit<React.ComponentProps<C>, "onFinished"> &
Partial<Pick<React.ComponentProps<C>, "onFinished">>;
export interface IModal<C extends ComponentType> {
elem: React.ReactNode; elem: React.ReactNode;
className?: string; className?: string;
beforeClosePromise?: Promise<boolean>; beforeClosePromise?: Promise<boolean>;
closeReason?: string; closeReason?: string;
onBeforeClose?(reason?: string): Promise<boolean>; onBeforeClose?(reason?: string): Promise<boolean>;
onFinished?(...args: T): void; onFinished: ComponentProps<C>["onFinished"];
close(...args: T): void; close(...args: Parameters<ComponentProps<C>["onFinished"]>): void;
hidden?: boolean; hidden?: boolean;
} }
export interface IHandle<T extends any[]> { export interface IHandle<C extends ComponentType> {
finished: Promise<T>; finished: Promise<Parameters<ComponentProps<C>["onFinished"]>>;
close(...args: T): void; close(...args: Parameters<ComponentProps<C>["onFinished"]>): void;
} }
interface IProps<T extends any[]> { interface IOptions<C extends ComponentType> {
onFinished?(...args: T): void; onBeforeClose?: IModal<C>["onBeforeClose"];
// TODO improve typing here once all Modals are TS and we can exhaustively check the props
[key: string]: any;
} }
interface IOptions<T extends any[]> {
onBeforeClose?: IModal<T>["onBeforeClose"];
}
type ParametersWithoutFirst<T extends (...args: any) => any> = T extends (a: any, ...args: infer P) => any ? P : never;
export enum ModalManagerEvent { export enum ModalManagerEvent {
Opened = "opened", Opened = "opened",
} }
@ -111,18 +112,30 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
return !!this.priorityModal || !!this.staticModal || this.modals.length > 0; return !!this.priorityModal || !!this.staticModal || this.modals.length > 0;
} }
public createDialog<T extends any[]>( public createDialog<C extends ComponentType>(
Element: React.ComponentType<any>, Element: C,
...rest: ParametersWithoutFirst<ModalManager["createDialogAsync"]> props?: ComponentProps<C>,
): IHandle<T> { className?: string,
return this.createDialogAsync<T>(Promise.resolve(Element), ...rest); isPriorityModal = false,
isStaticModal = false,
options: IOptions<C> = {},
): IHandle<C> {
return this.createDialogAsync<C>(
Promise.resolve(Element),
props,
className,
isPriorityModal,
isStaticModal,
options,
);
} }
public appendDialog<T extends any[]>( public appendDialog<C extends ComponentType>(
Element: React.ComponentType, Element: React.ComponentType,
...rest: ParametersWithoutFirst<ModalManager["appendDialogAsync"]> props?: ComponentProps<C>,
): IHandle<T> { className?: string,
return this.appendDialogAsync<T>(Promise.resolve(Element), ...rest); ): IHandle<C> {
return this.appendDialogAsync<C>(Promise.resolve(Element), props, className);
} }
public closeCurrentModal(reason: string): void { public closeCurrentModal(reason: string): void {
@ -134,15 +147,15 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
modal.close(); modal.close();
} }
private buildModal<T extends any[]>( private buildModal<C extends ComponentType>(
prom: Promise<React.ComponentType>, prom: Promise<React.ComponentType>,
props?: IProps<T>, props?: ComponentProps<C>,
className?: string, className?: string,
options?: IOptions<T>, options?: IOptions<C>,
): { ): {
modal: IModal<T>; modal: IModal<C>;
closeDialog: IHandle<T>["close"]; closeDialog: IHandle<C>["close"];
onFinishedProm: IHandle<T>["finished"]; onFinishedProm: IHandle<C>["finished"];
} { } {
const modal = { const modal = {
onFinished: props?.onFinished, onFinished: props?.onFinished,
@ -151,10 +164,10 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
// these will be set below but we need an object reference to pass to getCloseFn before we can do that // these will be set below but we need an object reference to pass to getCloseFn before we can do that
elem: null, elem: null,
} as IModal<T>; } as IModal<C>;
// never call this from onFinished() otherwise it will loop // never call this from onFinished() otherwise it will loop
const [closeDialog, onFinishedProm] = this.getCloseFn<T>(modal, props); const [closeDialog, onFinishedProm] = this.getCloseFn<C>(modal, props);
// don't attempt to reuse the same AsyncWrapper for different dialogs, // don't attempt to reuse the same AsyncWrapper for different dialogs,
// otherwise we'll get confused. // otherwise we'll get confused.
@ -168,13 +181,13 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
return { modal, closeDialog, onFinishedProm }; return { modal, closeDialog, onFinishedProm };
} }
private getCloseFn<T extends any[]>( private getCloseFn<C extends ComponentType>(
modal: IModal<T>, modal: IModal<C>,
props?: IProps<T>, props?: ComponentProps<C>,
): [IHandle<T>["close"], IHandle<T>["finished"]] { ): [IHandle<C>["close"], IHandle<C>["finished"]] {
const deferred = defer<T>(); const deferred = defer<Parameters<ComponentProps<C>["onFinished"]>>();
return [ return [
async (...args: T): Promise<void> => { async (...args: Parameters<ComponentProps<C>["onFinished"]>): Promise<void> => {
if (modal.beforeClosePromise) { if (modal.beforeClosePromise) {
await modal.beforeClosePromise; await modal.beforeClosePromise;
} else if (modal.onBeforeClose) { } else if (modal.onBeforeClose) {
@ -249,16 +262,16 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
* @param {onBeforeClose} options.onBeforeClose a callback to decide whether to close the dialog * @param {onBeforeClose} options.onBeforeClose a callback to decide whether to close the dialog
* @returns {object} Object with 'close' parameter being a function that will close the dialog * @returns {object} Object with 'close' parameter being a function that will close the dialog
*/ */
public createDialogAsync<T extends any[]>( public createDialogAsync<C extends ComponentType>(
prom: Promise<React.ComponentType>, prom: Promise<C>,
props?: IProps<T>, props?: ComponentProps<C>,
className?: string, className?: string,
isPriorityModal = false, isPriorityModal = false,
isStaticModal = false, isStaticModal = false,
options: IOptions<T> = {}, options: IOptions<C> = {},
): IHandle<T> { ): IHandle<C> {
const beforeModal = this.getCurrentModal(); const beforeModal = this.getCurrentModal();
const { modal, closeDialog, onFinishedProm } = this.buildModal<T>(prom, props, className, options); const { modal, closeDialog, onFinishedProm } = this.buildModal<C>(prom, props, className, options);
if (isPriorityModal) { if (isPriorityModal) {
// XXX: This is destructive // XXX: This is destructive
this.priorityModal = modal; this.priorityModal = modal;
@ -278,13 +291,13 @@ export class ModalManager extends TypedEventEmitter<ModalManagerEvent, HandlerMa
}; };
} }
private appendDialogAsync<T extends any[]>( private appendDialogAsync<C extends ComponentType>(
prom: Promise<React.ComponentType>, prom: Promise<React.ComponentType>,
props?: IProps<T>, props?: ComponentProps<C>,
className?: string, className?: string,
): IHandle<T> { ): IHandle<C> {
const beforeModal = this.getCurrentModal(); const beforeModal = this.getCurrentModal();
const { modal, closeDialog, onFinishedProm } = this.buildModal<T>(prom, props, className, {}); const { modal, closeDialog, onFinishedProm } = this.buildModal<C>(prom, props, className, {});
this.modals.push(modal); this.modals.push(modal);

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from "react"; import React, { ComponentProps } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { User } from "matrix-js-sdk/src/models/user"; import { User } from "matrix-js-sdk/src/models/user";
@ -29,7 +29,7 @@ import InviteDialog from "./components/views/dialogs/InviteDialog";
import BaseAvatar from "./components/views/avatars/BaseAvatar"; import BaseAvatar from "./components/views/avatars/BaseAvatar";
import { mediaFromMxc } from "./customisations/Media"; import { mediaFromMxc } from "./customisations/Media";
import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import { KIND_DM, KIND_INVITE } from "./components/views/dialogs/InviteDialogTypes"; import { InviteKind } from "./components/views/dialogs/InviteDialogTypes";
import { Member } from "./utils/direct-messages"; import { Member } from "./utils/direct-messages";
export interface IInviteResult { export interface IInviteResult {
@ -64,7 +64,7 @@ export function showStartChatInviteDialog(initialText = ""): void {
// This dialog handles the room creation internally - we don't need to worry about it. // This dialog handles the room creation internally - we don't need to worry about it.
Modal.createDialog( Modal.createDialog(
InviteDialog, InviteDialog,
{ kind: KIND_DM, initialText }, { kind: InviteKind.Dm, initialText },
/*className=*/ "mx_InviteDialog_flexWrapper", /*className=*/ "mx_InviteDialog_flexWrapper",
/*isPriority=*/ false, /*isPriority=*/ false,
/*isStatic=*/ true, /*isStatic=*/ true,
@ -76,10 +76,10 @@ export function showRoomInviteDialog(roomId: string, initialText = ""): void {
Modal.createDialog( Modal.createDialog(
InviteDialog, InviteDialog,
{ {
kind: KIND_INVITE, kind: InviteKind.Invite,
initialText, initialText,
roomId, roomId,
}, } as Omit<ComponentProps<typeof InviteDialog>, "onFinished">,
/*className=*/ "mx_InviteDialog_flexWrapper", /*className=*/ "mx_InviteDialog_flexWrapper",
/*isPriority=*/ false, /*isPriority=*/ false,
/*isStatic=*/ true, /*isStatic=*/ true,

View file

@ -22,13 +22,13 @@ import { decodeRecoveryKey } from "matrix-js-sdk/src/crypto/recoverykey";
import { encodeBase64 } from "matrix-js-sdk/src/crypto/olmlib"; import { encodeBase64 } from "matrix-js-sdk/src/crypto/olmlib";
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning"; import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { ComponentType } from "react";
import type CreateSecretStorageDialog from "./async-components/views/dialogs/security/CreateSecretStorageDialog";
import Modal from "./Modal"; import Modal from "./Modal";
import { MatrixClientPeg } from "./MatrixClientPeg"; import { MatrixClientPeg } from "./MatrixClientPeg";
import { _t } from "./languageHandler"; import { _t } from "./languageHandler";
import { isSecureBackupRequired } from "./utils/WellKnownUtils"; import { isSecureBackupRequired } from "./utils/WellKnownUtils";
import AccessSecretStorageDialog from "./components/views/dialogs/security/AccessSecretStorageDialog"; import AccessSecretStorageDialog, { KeyParams } from "./components/views/dialogs/security/AccessSecretStorageDialog";
import RestoreKeyBackupDialog from "./components/views/dialogs/security/RestoreKeyBackupDialog"; import RestoreKeyBackupDialog from "./components/views/dialogs/security/RestoreKeyBackupDialog";
import SettingsStore from "./settings/SettingsStore"; import SettingsStore from "./settings/SettingsStore";
import SecurityCustomisations from "./customisations/Security"; import SecurityCustomisations from "./customisations/Security";
@ -83,8 +83,6 @@ async function confirmToDismiss(): Promise<boolean> {
return !sure; return !sure;
} }
type KeyParams = { passphrase: string; recoveryKey: string };
function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise<Uint8Array> { function makeInputToKey(keyInfo: ISecretStorageKeyInfo): (keyParams: KeyParams) => Promise<Uint8Array> {
return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => { return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => {
if (passphrase) { if (passphrase) {
@ -333,7 +331,7 @@ export async function accessSecretStorage(func = async (): Promise<void> => {},
// passphrase creation. // passphrase creation.
const { finished } = Modal.createDialogAsync( const { finished } = Modal.createDialogAsync(
import("./async-components/views/dialogs/security/CreateSecretStorageDialog") as unknown as Promise< import("./async-components/views/dialogs/security/CreateSecretStorageDialog") as unknown as Promise<
ComponentType<{}> typeof CreateSecretStorageDialog
>, >,
{ {
forceReset, forceReset,

View file

@ -551,7 +551,7 @@ export const Commands = [
) { ) {
const defaultIdentityServerUrl = getDefaultIdentityServerUrl(); const defaultIdentityServerUrl = getDefaultIdentityServerUrl();
if (defaultIdentityServerUrl) { if (defaultIdentityServerUrl) {
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Use an identity server"), title: _t("Use an identity server"),
description: ( description: (
<p> <p>

View file

@ -191,7 +191,7 @@ export async function dialogTermsInteractionCallback(
): Promise<string[]> { ): Promise<string[]> {
logger.log("Terms that need agreement", policiesAndServicePairs); logger.log("Terms that need agreement", policiesAndServicePairs);
const { finished } = Modal.createDialog<[boolean, string[]]>( const { finished } = Modal.createDialog(
TermsDialog, TermsDialog,
{ {
policiesAndServicePairs, policiesAndServicePairs,

View file

@ -27,7 +27,7 @@ import { Action } from "../../../../dispatcher/actions";
import { SettingLevel } from "../../../../settings/SettingLevel"; import { SettingLevel } from "../../../../settings/SettingLevel";
interface IProps { interface IProps {
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
} }
interface IState { interface IState {

View file

@ -27,10 +27,11 @@ import { SettingLevel } from "../../../../settings/SettingLevel";
import Field from "../../../../components/views/elements/Field"; import Field from "../../../../components/views/elements/Field";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import DialogButtons from "../../../../components/views/elements/DialogButtons"; import DialogButtons from "../../../../components/views/elements/DialogButtons";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import { IIndexStats } from "../../../../indexing/BaseEventIndexManager"; import { IIndexStats } from "../../../../indexing/BaseEventIndexManager";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
interface IState { interface IState {
eventIndexSize: number; eventIndexSize: number;

View file

@ -26,7 +26,6 @@ import { accessSecretStorage } from "../../../../SecurityManager";
import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
import { copyNode } from "../../../../utils/strings"; import { copyNode } from "../../../../utils/strings";
import PassphraseField from "../../../../components/views/auth/PassphraseField"; import PassphraseField from "../../../../components/views/auth/PassphraseField";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import Field from "../../../../components/views/elements/Field"; import Field from "../../../../components/views/elements/Field";
import Spinner from "../../../../components/views/elements/Spinner"; import Spinner from "../../../../components/views/elements/Spinner";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
@ -45,7 +44,9 @@ enum Phase {
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc. const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
interface IProps extends IDialogProps {} interface IProps {
onFinished(done?: boolean): void;
}
interface IState { interface IState {
secureSecretStorage: boolean; secureSecretStorage: boolean;

View file

@ -43,7 +43,6 @@ import {
SecureBackupSetupMethod, SecureBackupSetupMethod,
} from "../../../../utils/WellKnownUtils"; } from "../../../../utils/WellKnownUtils";
import SecurityCustomisations from "../../../../customisations/Security"; import SecurityCustomisations from "../../../../customisations/Security";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import Field from "../../../../components/views/elements/Field"; import Field from "../../../../components/views/elements/Field";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import Spinner from "../../../../components/views/elements/Spinner"; import Spinner from "../../../../components/views/elements/Spinner";
@ -67,10 +66,11 @@ enum Phase {
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc. const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
interface IProps extends IDialogProps { interface IProps {
hasCancel: boolean; hasCancel?: boolean;
accountPassword: string; accountPassword?: string;
forceReset: boolean; forceReset?: boolean;
onFinished(ok?: boolean): void;
} }
interface IState { interface IState {

View file

@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import * as MegolmExportEncryption from "../../../../utils/MegolmExportEncryption"; import * as MegolmExportEncryption from "../../../../utils/MegolmExportEncryption";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import Field from "../../../../components/views/elements/Field"; import Field from "../../../../components/views/elements/Field";
import { KeysStartingWith } from "../../../../@types/common"; import { KeysStartingWith } from "../../../../@types/common";
@ -32,8 +31,9 @@ enum Phase {
Exporting = "exporting", Exporting = "exporting",
} }
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
onFinished(doExport?: boolean): void;
} }
interface IState { interface IState {

View file

@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import * as MegolmExportEncryption from "../../../../utils/MegolmExportEncryption"; import * as MegolmExportEncryption from "../../../../utils/MegolmExportEncryption";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import Field from "../../../../components/views/elements/Field"; import Field from "../../../../components/views/elements/Field";
@ -42,8 +41,9 @@ enum Phase {
Importing = "importing", Importing = "importing",
} }
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
onFinished(imported?: boolean): void;
} }
interface IState { interface IState {

View file

@ -24,12 +24,12 @@ import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal"; import Modal from "../../../../Modal";
import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog"; import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog";
import { Action } from "../../../../dispatcher/actions"; import { Action } from "../../../../dispatcher/actions";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import DialogButtons from "../../../../components/views/elements/DialogButtons"; import DialogButtons from "../../../../components/views/elements/DialogButtons";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
interface IProps extends IDialogProps { interface IProps {
newVersionInfo: IKeyBackupInfo; newVersionInfo: IKeyBackupInfo;
onFinished(): void;
} }
export default class NewRecoveryMethodDialog extends React.PureComponent<IProps> { export default class NewRecoveryMethodDialog extends React.PureComponent<IProps> {

View file

@ -21,11 +21,12 @@ import dis from "../../../../dispatcher/dispatcher";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import Modal from "../../../../Modal"; import Modal from "../../../../Modal";
import { Action } from "../../../../dispatcher/actions"; import { Action } from "../../../../dispatcher/actions";
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
import BaseDialog from "../../../../components/views/dialogs/BaseDialog"; import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
import DialogButtons from "../../../../components/views/elements/DialogButtons"; import DialogButtons from "../../../../components/views/elements/DialogButtons";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
export default class RecoveryMethodRemovedDialog extends React.PureComponent<IProps> { export default class RecoveryMethodRemovedDialog extends React.PureComponent<IProps> {
private onGoToSettingsClick = (): void => { private onGoToSettingsClick = (): void => {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ComponentType, createRef } from "react"; import React, { createRef } from "react";
import { import {
ClientEvent, ClientEvent,
createClient, createClient,
@ -38,6 +38,8 @@ import "focus-visible";
// what-input helps improve keyboard accessibility // what-input helps improve keyboard accessibility
import "what-input"; import "what-input";
import type NewRecoveryMethodDialog from "../../async-components/views/dialogs/security/NewRecoveryMethodDialog";
import type RecoveryMethodRemovedDialog from "../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { DecryptionFailureTracker } from "../../DecryptionFailureTracker"; import { DecryptionFailureTracker } from "../../DecryptionFailureTracker";
import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg"; import { IMatrixClientCreds, MatrixClientPeg } from "../../MatrixClientPeg";
@ -140,6 +142,7 @@ import RovingSpotlightDialog, { Filter } from "../views/dialogs/spotlight/Spotli
import { findDMForUser } from "../../utils/dm/findDMForUser"; import { findDMForUser } from "../../utils/dm/findDMForUser";
import { Linkify } from "../../HtmlUtils"; import { Linkify } from "../../HtmlUtils";
import { NotificationColor } from "../../stores/notifications/NotificationColor"; import { NotificationColor } from "../../stores/notifications/NotificationColor";
import { UserTab } from "../views/dialogs/UserTab";
// legacy export // legacy export
export { default as Views } from "../../Views"; export { default as Views } from "../../Views";
@ -705,7 +708,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
const tabPayload = payload as OpenToTabPayload; const tabPayload = payload as OpenToTabPayload;
Modal.createDialog( Modal.createDialog(
UserSettingsDialog, UserSettingsDialog,
{ initialTabId: tabPayload.initialTabId }, { initialTabId: tabPayload.initialTabId as UserTab },
/*className=*/ null, /*className=*/ null,
/*isPriority=*/ false, /*isPriority=*/ false,
/*isStatic=*/ true, /*isStatic=*/ true,
@ -1629,14 +1632,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
Modal.createDialogAsync( Modal.createDialogAsync(
import( import(
"../../async-components/views/dialogs/security/NewRecoveryMethodDialog" "../../async-components/views/dialogs/security/NewRecoveryMethodDialog"
) as unknown as Promise<ComponentType<{}>>, ) as unknown as Promise<typeof NewRecoveryMethodDialog>,
{ newVersionInfo }, { newVersionInfo },
); );
} else { } else {
Modal.createDialogAsync( Modal.createDialogAsync(
import( import(
"../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog" "../../async-components/views/dialogs/security/RecoveryMethodRemovedDialog"
) as unknown as Promise<ComponentType<{}>>, ) as unknown as Promise<typeof RecoveryMethodRemovedDialog>,
); );
} }
}); });

View file

@ -23,15 +23,15 @@ import { _t } from "../../languageHandler";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import { canEditContent } from "../../utils/EventUtils"; import { canEditContent } from "../../utils/EventUtils";
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { MatrixClientPeg } from "../../MatrixClientPeg";
import { IDialogProps } from "../views/dialogs/IDialogProps";
import BaseDialog from "../views/dialogs/BaseDialog"; import BaseDialog from "../views/dialogs/BaseDialog";
import { DevtoolsContext } from "../views/dialogs/devtools/BaseTool"; import { DevtoolsContext } from "../views/dialogs/devtools/BaseTool";
import { StateEventEditor } from "../views/dialogs/devtools/RoomState"; import { StateEventEditor } from "../views/dialogs/devtools/RoomState";
import { stringify, TimelineEventEditor } from "../views/dialogs/devtools/Event"; import { stringify, TimelineEventEditor } from "../views/dialogs/devtools/Event";
import CopyableText from "../views/elements/CopyableText"; import CopyableText from "../views/elements/CopyableText";
interface IProps extends IDialogProps { interface IProps {
mxEvent: MatrixEvent; // the MatrixEvent associated with the context menu mxEvent: MatrixEvent; // the MatrixEvent associated with the context menu
onFinished(): void;
} }
interface IState { interface IState {

View file

@ -368,7 +368,7 @@ export default class ForgotPassword extends React.Component<Props, State> {
} }
public async renderConfirmLogoutDevicesDialog(): Promise<boolean> { public async renderConfirmLogoutDevicesDialog(): Promise<boolean> {
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Warning!"), title: _t("Warning!"),
description: ( description: (
<div> <div>

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from "react"; import React, { ReactNode } from "react";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import AccessibleButton from "../../../views/elements/AccessibleButton"; import AccessibleButton from "../../../views/elements/AccessibleButton";
@ -26,7 +26,8 @@ import { ErrorMessage } from "../../ErrorMessage";
interface Props { interface Props {
email: string; email: string;
errorText: string | null; errorText: ReactNode | null;
onFinished(): void; // This modal is weird in that the way you close it signals intent
onCloseClick: () => void; onCloseClick: () => void;
onReEnterEmailClick: () => void; onReEnterEmailClick: () => void;
onResendClick: () => Promise<boolean>; onResendClick: () => Promise<boolean>;

View file

@ -23,7 +23,6 @@ import { Icon as LiveLocationIcon } from "../../../../res/img/location/live-loca
import { useLiveBeacons } from "../../../utils/beacon/useLiveBeacons"; import { useLiveBeacons } from "../../../utils/beacon/useLiveBeacons";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import { IDialogProps } from "../dialogs/IDialogProps";
import Map from "../location/Map"; import Map from "../location/Map";
import ZoomButtons from "../location/ZoomButtons"; import ZoomButtons from "../location/ZoomButtons";
import BeaconMarker from "./BeaconMarker"; import BeaconMarker from "./BeaconMarker";
@ -38,11 +37,12 @@ import MapFallback from "../location/MapFallback";
import { MapError } from "../location/MapError"; import { MapError } from "../location/MapError";
import { LocationShareError } from "../../../utils/location"; import { LocationShareError } from "../../../utils/location";
interface IProps extends IDialogProps { interface IProps {
roomId: Room["roomId"]; roomId: Room["roomId"];
matrixClient: MatrixClient; matrixClient: MatrixClient;
// open the map centered on this beacon's location // open the map centered on this beacon's location
initialFocusedBeacon?: Beacon; initialFocusedBeacon?: Beacon;
onFinished(): void;
} }
// track the 'focused time' as ts // track the 'focused time' as ts

View file

@ -25,13 +25,16 @@ import AccessibleButton from "../elements/AccessibleButton";
import QRCode from "../elements/QRCode"; import QRCode from "../elements/QRCode";
import Heading from "../typography/Heading"; import Heading from "../typography/Heading";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { IDialogProps } from "./IDialogProps";
const fallbackAppStore = "https://apps.apple.com/app/vector/id1083446067"; const fallbackAppStore = "https://apps.apple.com/app/vector/id1083446067";
const fallbackGooglePlay = "https://play.google.com/store/apps/details?id=im.vector.app"; const fallbackGooglePlay = "https://play.google.com/store/apps/details?id=im.vector.app";
const fallbackFDroid = "https://f-droid.org/repository/browse/?fdid=im.vector.app"; const fallbackFDroid = "https://f-droid.org/repository/browse/?fdid=im.vector.app";
export const AppDownloadDialog: FC<IDialogProps> = ({ onFinished }: IDialogProps) => { interface Props {
onFinished(): void;
}
export const AppDownloadDialog: FC<Props> = ({ onFinished }) => {
const brand = SdkConfig.get("brand"); const brand = SdkConfig.get("brand");
const desktopBuilds = SdkConfig.getObject("desktop_builds"); const desktopBuilds = SdkConfig.getObject("desktop_builds");
const mobileBuilds = SdkConfig.getObject("mobile_builds"); const mobileBuilds = SdkConfig.getObject("mobile_builds");

View file

@ -21,17 +21,16 @@ import FocusLock from "react-focus-lock";
import classNames from "classnames"; import classNames from "classnames";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import Heading from "../typography/Heading"; import Heading from "../typography/Heading";
import { IDialogProps } from "./IDialogProps";
import { PosthogScreenTracker, ScreenName } from "../../../PosthogTrackers"; import { PosthogScreenTracker, ScreenName } from "../../../PosthogTrackers";
import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IProps extends IDialogProps { interface IProps {
// Whether the dialog should have a 'close' button that will // Whether the dialog should have a 'close' button that will
// cause the dialog to be cancelled. This should only be set // cause the dialog to be cancelled. This should only be set
// to false if there is nothing the app can sensibly do if the // to false if there is nothing the app can sensibly do if the
@ -75,6 +74,7 @@ interface IProps extends IDialogProps {
// optional Posthog ScreenName to supply during the lifetime of this dialog // optional Posthog ScreenName to supply during the lifetime of this dialog
"screenName"?: ScreenName; "screenName"?: ScreenName;
onFinished(): void;
} }
/* /*
@ -86,7 +86,7 @@ interface IProps extends IDialogProps {
export default class BaseDialog extends React.Component<IProps> { export default class BaseDialog extends React.Component<IProps> {
private matrixClient: MatrixClient; private matrixClient: MatrixClient;
public static defaultProps = { public static defaultProps: Partial<IProps> = {
hasCancel: true, hasCancel: true,
fixedWidth: true, fixedWidth: true,
}; };
@ -98,9 +98,7 @@ export default class BaseDialog extends React.Component<IProps> {
} }
private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => { private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => {
if (this.props.onKeyDown) { this.props.onKeyDown?.(e);
this.props.onKeyDown(e);
}
const action = getKeyBindingsManager().getAccessibilityAction(e); const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) { switch (action) {
@ -109,13 +107,13 @@ export default class BaseDialog extends React.Component<IProps> {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
this.props.onFinished(false); this.props.onFinished();
break; break;
} }
}; };
private onCancelClick = (e: ButtonEvent): void => { private onCancelClick = (): void => {
this.props.onFinished(false); this.props.onFinished();
}; };
public render(): React.ReactNode { public render(): React.ReactNode {

View file

@ -17,7 +17,6 @@ limitations under the License.
import React from "react"; import React from "react";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher";
@ -27,8 +26,9 @@ import GenericFeatureFeedbackDialog from "./GenericFeatureFeedbackDialog";
// XXX: Keep this around for re-use in future Betas // XXX: Keep this around for re-use in future Betas
interface IProps extends IDialogProps { interface IProps {
featureId: string; featureId: string;
onFinished(sendFeedback?: boolean): void;
} }
const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => { const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
@ -49,7 +49,7 @@ const BetaFeedbackDialog: React.FC<IProps> = ({ featureId, onFinished }) => {
<AccessibleButton <AccessibleButton
kind="link_inline" kind="link_inline"
onClick={() => { onClick={() => {
onFinished(false); onFinished();
defaultDispatcher.dispatch({ defaultDispatcher.dispatch({
action: Action.ViewUserSettings, action: Action.ViewUserSettings,
initialTabId: UserTab.Labs, initialTabId: UserTab.Labs,

View file

@ -26,19 +26,19 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import InfoDialog from "../dialogs/InfoDialog"; import InfoDialog from "../dialogs/InfoDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
interface IBulkRedactDialogProps extends IDialogProps { interface Props {
matrixClient: MatrixClient; matrixClient: MatrixClient;
room: Room; room: Room;
member: RoomMember; member: RoomMember;
onFinished(redact?: boolean): void;
} }
const BulkRedactDialog: React.FC<IBulkRedactDialogProps> = (props) => { const BulkRedactDialog: React.FC<Props> = (props) => {
const { matrixClient: cli, room, member, onFinished } = props; const { matrixClient: cli, room, member, onFinished } = props;
const [keepStateEvents, setKeepStateEvents] = useState(true); const [keepStateEvents, setKeepStateEvents] = useState(true);

View file

@ -24,7 +24,7 @@ import Spinner from "../elements/Spinner";
interface IProps { interface IProps {
redact: () => Promise<void>; redact: () => Promise<void>;
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
} }
interface IState { interface IState {

View file

@ -39,7 +39,7 @@ interface IProps {
children?: ReactNode; children?: ReactNode;
className?: string; className?: string;
roomId?: string; roomId?: string;
onFinished: (success: boolean, reason?: string) => void; onFinished: (success?: boolean, reason?: string) => void;
} }
interface IState { interface IState {
@ -55,7 +55,7 @@ interface IState {
* Also tweaks the style for 'dangerous' actions (albeit only with colour) * Also tweaks the style for 'dangerous' actions (albeit only with colour)
*/ */
export default class ConfirmUserActionDialog extends React.Component<IProps, IState> { export default class ConfirmUserActionDialog extends React.Component<IProps, IState> {
public static defaultProps = { public static defaultProps: Partial<IProps> = {
danger: false, danger: false,
askReason: false, askReason: false,
}; };

View file

@ -21,7 +21,7 @@ import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
interface IProps { interface IProps {
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
} }
export default class ConfirmWipeDeviceDialog extends React.Component<IProps> { export default class ConfirmWipeDeviceDialog extends React.Component<IProps> {

View file

@ -41,7 +41,7 @@ interface IProps {
defaultName?: string; defaultName?: string;
parentSpace?: Room; parentSpace?: Room;
defaultEncrypted?: boolean; defaultEncrypted?: boolean;
onFinished(proceed: boolean, opts?: IOpts): void; onFinished(proceed?: boolean, opts?: IOpts): void;
} }
interface IState { interface IState {

View file

@ -24,9 +24,10 @@ import Modal from "../../../Modal";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps {} interface IProps {
onFinished(logout?: boolean): void;
}
const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => { const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;
@ -72,7 +73,7 @@ const CryptoStoreTooNewDialog: React.FC<IProps> = (props: IProps) => {
<DialogButtons <DialogButtons
primaryButton={_t("Continue With Encryption Disabled")} primaryButton={_t("Continue With Encryption Disabled")}
hasCancel={false} hasCancel={false}
onPrimaryButtonClick={props.onFinished} onPrimaryButtonClick={() => props.onFinished(false)}
> >
<button onClick={_onLogoutClicked}>{_t("Sign out")}</button> <button onClick={_onLogoutClicked}>{_t("Sign out")}</button>
</DialogButtons> </DialogButtons>

View file

@ -39,7 +39,7 @@ type DialogAesthetics = Partial<{
}>; }>;
interface IProps { interface IProps {
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
} }
interface IState { interface IState {

View file

@ -65,7 +65,7 @@ const Tools: Record<Category, [label: string, tool: Tool][]> = {
interface IProps { interface IProps {
roomId: string; roomId: string;
onFinished(finished: boolean): void; onFinished(finished?: boolean): void;
} }
type ToolInfo = [label: string, tool: Tool]; type ToolInfo = [label: string, tool: Tool];

View file

@ -20,17 +20,16 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import { PollEndEvent } from "matrix-js-sdk/src/extensible_events_v1/PollEndEvent"; import { PollEndEvent } from "matrix-js-sdk/src/extensible_events_v1/PollEndEvent";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import { findTopAnswer } from "../messages/MPollBody"; import { findTopAnswer } from "../messages/MPollBody";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import ErrorDialog from "./ErrorDialog"; import ErrorDialog from "./ErrorDialog";
import { GetRelationsForEvent } from "../rooms/EventTile"; import { GetRelationsForEvent } from "../rooms/EventTile";
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
event: MatrixEvent; event: MatrixEvent;
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
getRelationsForEvent?: GetRelationsForEvent; getRelationsForEvent?: GetRelationsForEvent;
} }

View file

@ -31,7 +31,7 @@ import { _t } from "../../../languageHandler";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
interface IProps { interface IProps {
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
title?: string; title?: string;
description?: React.ReactNode; description?: React.ReactNode;
button?: string; button?: string;
@ -44,7 +44,7 @@ interface IState {
} }
export default class ErrorDialog extends React.Component<IProps, IState> { export default class ErrorDialog extends React.Component<IProps, IState> {
public static defaultProps = { public static defaultProps: Partial<IProps> = {
focus: true, focus: true,
}; };

View file

@ -19,7 +19,6 @@ import { Room } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import Field from "../elements/Field"; import Field from "../elements/Field";
@ -44,8 +43,9 @@ import InfoDialog from "./InfoDialog";
import ChatExport from "../../../customisations/ChatExport"; import ChatExport from "../../../customisations/ChatExport";
import { validateNumberInRange } from "../../../utils/validate"; import { validateNumberInRange } from "../../../utils/validate";
interface IProps extends IDialogProps { interface IProps {
room: Room; room: Room;
onFinished(doExport?: boolean): void;
} }
interface ExportConfig { interface ExportConfig {

View file

@ -24,7 +24,6 @@ import SdkConfig from "../../../SdkConfig";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import BugReportDialog from "./BugReportDialog"; import BugReportDialog from "./BugReportDialog";
import InfoDialog from "./InfoDialog"; import InfoDialog from "./InfoDialog";
import { IDialogProps } from "./IDialogProps";
import { submitFeedback } from "../../../rageshake/submit-rageshake"; import { submitFeedback } from "../../../rageshake/submit-rageshake";
import { useStateToggle } from "../../../hooks/useStateToggle"; import { useStateToggle } from "../../../hooks/useStateToggle";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
@ -33,8 +32,9 @@ const existingIssuesUrl =
"https://github.com/vector-im/element-web/issues" + "?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc"; "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"; const newIssueUrl = "https://github.com/vector-im/element-web/issues/new/choose";
interface IProps extends IDialogProps { interface IProps {
feature?: string; feature?: string;
onFinished(): void;
} }
const FeedbackDialog: React.FC<IProps> = (props: IProps) => { const FeedbackDialog: React.FC<IProps> = (props: IProps) => {

View file

@ -29,7 +29,6 @@ import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import { useSettingValue } from "../../../hooks/useSettings"; import { useSettingValue } from "../../../hooks/useSettings";
import { Layout } from "../../../settings/enums/Layout"; import { Layout } from "../../../settings/enums/Layout";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { avatarUrlForUser } from "../../../Avatar"; import { avatarUrlForUser } from "../../../Avatar";
import EventTile from "../rooms/EventTile"; import EventTile from "../rooms/EventTile";
@ -55,13 +54,14 @@ import { RoomContextDetails } from "../rooms/RoomContextDetails";
const AVATAR_SIZE = 30; const AVATAR_SIZE = 30;
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
// The event to forward // The event to forward
event: MatrixEvent; event: MatrixEvent;
// We need a permalink creator for the source room to pass through to EventTile // We need a permalink creator for the source room to pass through to EventTile
// in case the event is a reply (even though the user can't get at the link) // in case the event is a reply (even though the user can't get at the link)
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
onFinished(): void;
} }
interface IEntryProps { interface IEntryProps {

View file

@ -20,17 +20,17 @@ import QuestionDialog from "./QuestionDialog";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import Field from "../elements/Field"; import Field from "../elements/Field";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { IDialogProps } from "./IDialogProps";
import { submitFeedback } from "../../../rageshake/submit-rageshake"; import { submitFeedback } from "../../../rageshake/submit-rageshake";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import InfoDialog from "./InfoDialog"; import InfoDialog from "./InfoDialog";
interface IProps extends IDialogProps { interface IProps {
title: string; title: string;
subheading: string; subheading: string;
rageshakeLabel: string; rageshakeLabel: string;
rageshakeData?: Record<string, string>; rageshakeData?: Record<string, string>;
onFinished(sendFeedback?: boolean): void;
} }
const GenericFeatureFeedbackDialog: React.FC<IProps> = ({ const GenericFeatureFeedbackDialog: React.FC<IProps> = ({

View file

@ -1,19 +0,0 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export interface IDialogProps {
onFinished(...args: any): void;
}

View file

@ -29,7 +29,6 @@ import Spinner from "../elements/Spinner";
import VerificationShowSas from "../verification/VerificationShowSas"; import VerificationShowSas from "../verification/VerificationShowSas";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
const PHASE_START = 0; const PHASE_START = 0;
const PHASE_SHOW_SAS = 1; const PHASE_SHOW_SAS = 1;
@ -37,8 +36,9 @@ const PHASE_WAIT_FOR_PARTNER_TO_CONFIRM = 2;
const PHASE_VERIFIED = 3; const PHASE_VERIFIED = 3;
const PHASE_CANCELLED = 4; const PHASE_CANCELLED = 4;
interface IProps extends IDialogProps { interface IProps {
verifier: VerificationBase<SasEvent, any>; verifier: VerificationBase<SasEvent, any>;
onFinished(verified?: boolean): void;
} }
interface IState { interface IState {

View file

@ -19,11 +19,10 @@ import React, { ReactNode, KeyboardEvent } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
interface IProps extends IDialogProps { interface IProps {
top?: ReactNode; top?: ReactNode;
title?: string; title?: string;
description?: ReactNode; description?: ReactNode;
@ -32,10 +31,11 @@ interface IProps extends IDialogProps {
hasCloseButton?: boolean; hasCloseButton?: boolean;
fixedWidth?: boolean; fixedWidth?: boolean;
onKeyDown?(event: KeyboardEvent): void; onKeyDown?(event: KeyboardEvent): void;
onFinished(): void;
} }
export default class InfoDialog extends React.Component<IProps> { export default class InfoDialog extends React.Component<IProps> {
public static defaultProps = { public static defaultProps: Partial<IProps> = {
title: "", title: "",
description: "", description: "",
hasCloseButton: false, hasCloseButton: false,

View file

@ -21,9 +21,10 @@ import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
export default class IntegrationsDisabledDialog extends React.Component<IProps> { export default class IntegrationsDisabledDialog extends React.Component<IProps> {
private onAcknowledgeClick = (): void => { private onAcknowledgeClick = (): void => {

View file

@ -18,11 +18,12 @@ import React from "react";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
export default class IntegrationsImpossibleDialog extends React.Component<IProps> { export default class IntegrationsImpossibleDialog extends React.Component<IProps> {
private onAcknowledgeClick = (): void => { private onAcknowledgeClick = (): void => {

View file

@ -25,7 +25,6 @@ import AccessibleButton from "../elements/AccessibleButton";
import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth"; import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents"; import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { IDialogProps } from "./IDialogProps";
type DialogAesthetics = Partial<{ type DialogAesthetics = Partial<{
[x in AuthType]: { [x in AuthType]: {
@ -38,7 +37,7 @@ type DialogAesthetics = Partial<{
}; };
}>; }>;
export interface InteractiveAuthDialogProps extends IDialogProps { export interface InteractiveAuthDialogProps {
// matrix client to use for UI auth requests // matrix client to use for UI auth requests
matrixClient: MatrixClient; matrixClient: MatrixClient;
@ -72,6 +71,8 @@ export interface InteractiveAuthDialogProps extends IDialogProps {
// //
// Default is defined in _getDefaultDialogAesthetics() // Default is defined in _getDefaultDialogAesthetics()
aestheticsForStagePhases?: DialogAesthetics; aestheticsForStagePhases?: DialogAesthetics;
onFinished(success?: boolean, result?: IAuthData | Error | null): void;
} }
interface IState { interface IState {
@ -152,14 +153,14 @@ export default class InteractiveAuthDialog extends React.Component<InteractiveAu
if (!this.state.authError && dialogAesthetics) { if (!this.state.authError && dialogAesthetics) {
if (dialogAesthetics[this.state.uiaStage]) { if (dialogAesthetics[this.state.uiaStage]) {
const aesthetics = dialogAesthetics[this.state.uiaStage][this.state.uiaStagePhase]; const aesthetics = dialogAesthetics[this.state.uiaStage][this.state.uiaStagePhase];
if (aesthetics && aesthetics.title) title = aesthetics.title; if (aesthetics?.title) title = aesthetics.title;
if (aesthetics && aesthetics.body) body = aesthetics.body; if (aesthetics?.body) body = aesthetics.body;
if (aesthetics && aesthetics.continueText) continueText = aesthetics.continueText; if (aesthetics?.continueText) continueText = aesthetics.continueText;
if (aesthetics && aesthetics.continueKind) continueKind = aesthetics.continueKind; if (aesthetics?.continueKind) continueKind = aesthetics.continueKind;
} }
} }
let content; let content: JSX.Element;
if (this.state.authError) { if (this.state.authError) {
content = ( content = (
<div id="mx_Dialog_content"> <div id="mx_Dialog_content">

View file

@ -70,7 +70,7 @@ import {
startDmOnFirstMessage, startDmOnFirstMessage,
ThreepidMember, ThreepidMember,
} from "../../../utils/direct-messages"; } from "../../../utils/direct-messages";
import { KIND_CALL_TRANSFER, KIND_DM, KIND_INVITE } from "./InviteDialogTypes"; import { InviteKind } from "./InviteDialogTypes";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
@ -253,32 +253,32 @@ interface BaseProps {
// Takes a boolean which is true if a user / users were invited / // Takes a boolean which is true if a user / users were invited /
// a call transfer was initiated or false if the dialog was cancelled // a call transfer was initiated or false if the dialog was cancelled
// with no action taken. // with no action taken.
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
// Initial value to populate the filter with // Initial value to populate the filter with
initialText?: string; initialText?: string;
} }
interface InviteDMProps extends BaseProps { interface InviteDMProps extends BaseProps {
// The kind of invite being performed. Assumed to be KIND_DM if not provided. // The kind of invite being performed. Assumed to be InviteKind.Dm if not provided.
kind?: typeof KIND_DM; kind?: InviteKind.Dm;
} }
interface InviteRoomProps extends BaseProps { interface InviteRoomProps extends BaseProps {
kind: typeof KIND_INVITE; kind: InviteKind.Invite;
// The room ID this dialog is for. Only required for KIND_INVITE. // The room ID this dialog is for. Only required for InviteKind.Invite.
roomId: string; roomId: string;
} }
function isRoomInvite(props: Props): props is InviteRoomProps { function isRoomInvite(props: Props): props is InviteRoomProps {
return props.kind === KIND_INVITE; return props.kind === InviteKind.Invite;
} }
interface InviteCallProps extends BaseProps { interface InviteCallProps extends BaseProps {
kind: typeof KIND_CALL_TRANSFER; kind: InviteKind.CallTransfer;
// The call to transfer. Only required for KIND_CALL_TRANSFER. // The call to transfer. Only required for InviteKind.CallTransfer.
call: MatrixCall; call: MatrixCall;
} }
@ -305,8 +305,8 @@ interface IInviteDialogState {
} }
export default class InviteDialog extends React.PureComponent<Props, IInviteDialogState> { export default class InviteDialog extends React.PureComponent<Props, IInviteDialogState> {
public static defaultProps = { public static defaultProps: Partial<Props> = {
kind: KIND_DM, kind: InviteKind.Dm,
initialText: "", initialText: "",
}; };
@ -318,10 +318,10 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
public constructor(props: Props) { public constructor(props: Props) {
super(props); super(props);
if (props.kind === KIND_INVITE && !props.roomId) { if (props.kind === InviteKind.Invite && !props.roomId) {
throw new Error("When using KIND_INVITE a roomId is required for an InviteDialog"); throw new Error("When using InviteKind.Invite a roomId is required for an InviteDialog");
} else if (props.kind === KIND_CALL_TRANSFER && !props.call) { } else if (props.kind === InviteKind.CallTransfer && !props.call) {
throw new Error("When using KIND_CALL_TRANSFER a call is required for an InviteDialog"); throw new Error("When using InviteKind.CallTransfer a call is required for an InviteDialog");
} }
const alreadyInvited = new Set([MatrixClientPeg.get().getUserId()!, SdkConfig.get("welcome_user_id")]); const alreadyInvited = new Set([MatrixClientPeg.get().getUserId()!, SdkConfig.get("welcome_user_id")]);
@ -493,7 +493,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
}; };
private inviteUsers = async (): Promise<void> => { private inviteUsers = async (): Promise<void> => {
if (this.props.kind !== KIND_INVITE) return; if (this.props.kind !== InviteKind.Invite) return;
this.setState({ busy: true }); this.setState({ busy: true });
this.convertFilter(); this.convertFilter();
const targets = this.convertFilter(); const targets = this.convertFilter();
@ -528,7 +528,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
}; };
private transferCall = async (): Promise<void> => { private transferCall = async (): Promise<void> => {
if (this.props.kind !== KIND_CALL_TRANSFER) return; if (this.props.kind !== InviteKind.CallTransfer) return;
if (this.state.currentTabId == TabId.UserDirectory) { if (this.state.currentTabId == TabId.UserDirectory) {
this.convertFilter(); this.convertFilter();
const targets = this.convertFilter(); const targets = this.convertFilter();
@ -737,7 +737,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
if (idx >= 0) { if (idx >= 0) {
targets.splice(idx, 1); targets.splice(idx, 1);
} else { } else {
if (this.props.kind === KIND_CALL_TRANSFER && targets.length > 0) { if (this.props.kind === InviteKind.CallTransfer && targets.length > 0) {
targets = []; targets = [];
} }
targets.push(member); targets.push(member);
@ -869,7 +869,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
const lastActive = (m: Result): number | undefined => (kind === "recents" ? m.lastActive : undefined); const lastActive = (m: Result): number | undefined => (kind === "recents" ? m.lastActive : undefined);
let sectionName = kind === "recents" ? _t("Recent Conversations") : _t("Suggestions"); let sectionName = kind === "recents" ? _t("Recent Conversations") : _t("Suggestions");
if (this.props.kind === KIND_INVITE) { if (this.props.kind === InviteKind.Invite) {
sectionName = kind === "recents" ? _t("Recently Direct Messaged") : _t("Suggestions"); sectionName = kind === "recents" ? _t("Recently Direct Messaged") : _t("Suggestions");
} }
@ -959,7 +959,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
private renderEditor(): JSX.Element { private renderEditor(): JSX.Element {
const hasPlaceholder = const hasPlaceholder =
this.props.kind == KIND_CALL_TRANSFER && this.props.kind == InviteKind.CallTransfer &&
this.state.targets.length === 0 && this.state.targets.length === 0 &&
this.state.filterText.length === 0; this.state.filterText.length === 0;
const targets = this.state.targets.map((t) => ( const targets = this.state.targets.map((t) => (
@ -974,7 +974,9 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
ref={this.editorRef} ref={this.editorRef}
onPaste={this.onPaste} onPaste={this.onPaste}
autoFocus={true} autoFocus={true}
disabled={this.state.busy || (this.props.kind == KIND_CALL_TRANSFER && this.state.targets.length > 0)} disabled={
this.state.busy || (this.props.kind == InviteKind.CallTransfer && this.state.targets.length > 0)
}
autoComplete="off" autoComplete="off"
placeholder={hasPlaceholder ? _t("Search") : undefined} placeholder={hasPlaceholder ? _t("Search") : undefined}
data-testid="invite-dialog-input" data-testid="invite-dialog-input"
@ -1085,7 +1087,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
private get screenName(): ScreenName | undefined { private get screenName(): ScreenName | undefined {
switch (this.props.kind) { switch (this.props.kind) {
case KIND_DM: case InviteKind.Dm:
return "StartChat"; return "StartChat";
} }
} }
@ -1112,7 +1114,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const userId = cli.getUserId()!; const userId = cli.getUserId()!;
if (this.props.kind === KIND_DM) { if (this.props.kind === InviteKind.Dm) {
title = _t("Direct Messages"); title = _t("Direct Messages");
if (identityServersEnabled) { if (identityServersEnabled) {
@ -1164,7 +1166,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
</CopyableText> </CopyableText>
</div> </div>
); );
} else if (this.props.kind === KIND_INVITE) { } else if (this.props.kind === InviteKind.Invite) {
const roomId = this.props.roomId; const roomId = this.props.roomId;
const room = MatrixClientPeg.get()?.getRoom(roomId); const room = MatrixClientPeg.get()?.getRoom(roomId);
const isSpace = room?.isSpaceRoom(); const isSpace = room?.isSpaceRoom();
@ -1235,7 +1237,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
); );
} }
} }
} else if (this.props.kind === KIND_CALL_TRANSFER) { } else if (this.props.kind === InviteKind.CallTransfer) {
title = _t("Transfer"); title = _t("Transfer");
consultConnectSection = ( consultConnectSection = (
@ -1264,7 +1266,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
} }
const goButton = const goButton =
this.props.kind == KIND_CALL_TRANSFER ? null : ( this.props.kind == InviteKind.CallTransfer ? null : (
<AccessibleButton <AccessibleButton
kind="primary" kind="primary"
onClick={goButtonFn} onClick={goButtonFn}
@ -1298,7 +1300,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
); );
let dialogContent; let dialogContent;
if (this.props.kind === KIND_CALL_TRANSFER) { if (this.props.kind === InviteKind.CallTransfer) {
const tabs: Tab[] = []; const tabs: Tab[] = [];
tabs.push( tabs.push(
new Tab(TabId.UserDirectory, _td("User Directory"), "mx_InviteDialog_userDirectoryIcon", usersSection), new Tab(TabId.UserDirectory, _td("User Directory"), "mx_InviteDialog_userDirectoryIcon", usersSection),
@ -1363,8 +1365,8 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
return ( return (
<BaseDialog <BaseDialog
className={classNames({ className={classNames({
mx_InviteDialog_transfer: this.props.kind === KIND_CALL_TRANSFER, mx_InviteDialog_transfer: this.props.kind === InviteKind.CallTransfer,
mx_InviteDialog_other: this.props.kind !== KIND_CALL_TRANSFER, mx_InviteDialog_other: this.props.kind !== InviteKind.CallTransfer,
mx_InviteDialog_hasFooter: !!footer, mx_InviteDialog_hasFooter: !!footer,
})} })}
hasCancel={true} hasCancel={true}

View file

@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
export const KIND_DM = "dm"; export enum InviteKind {
export const KIND_INVITE = "invite"; Dm = "dm",
Invite = "invite",
// NB. This dialog needs the 'mx_InviteDialog_transferWrapper' wrapper class to have the correct // NB. This dialog needs the 'mx_InviteDialog_transferWrapper' wrapper class to have the correct
// padding on the bottom (because all modals have 24px padding on all sides), so this needs to // padding on the bottom (because all modals have 24px padding on all sides), so this needs to
// be passed when creating the modal // be passed when creating the modal
export const KIND_CALL_TRANSFER = "call_transfer"; CallTransfer = "call_transfer",
}
export type AnyInviteKind = typeof KIND_INVITE | typeof KIND_DM | typeof KIND_CALL_TRANSFER;

View file

@ -21,9 +21,8 @@ import SdkConfig from "../../../SdkConfig";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
failures: Record< failures: Record<
string, string,
Record< Record<
@ -35,7 +34,8 @@ interface IProps extends IDialogProps {
> >
>; >;
source: string; source: string;
continuation: () => Promise<void>; continuation: (opts: { shouldEmit: boolean }) => Promise<void>;
onFinished(): void;
} }
const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, continuation, onFinished }) => { const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, continuation, onFinished }) => {
@ -61,7 +61,7 @@ const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, co
}).finally(() => { }).finally(() => {
setCancelled(true); setCancelled(true);
}); });
await Promise.race([continuation(), cancel]); await Promise.race([continuation({ shouldEmit: false }), cancel]);
setSuccess(true); setSuccess(true);
} catch (e) { } catch (e) {
setRetry((r) => r - 1); setRetry((r) => r - 1);

View file

@ -20,10 +20,10 @@ import React from "react";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
host: string; host: string;
onFinished(): void;
} }
const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => { const LazyLoadingDisabledDialog: React.FC<IProps> = (props) => {

View file

@ -20,9 +20,10 @@ import React from "react";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
const LazyLoadingResyncDialog: React.FC<IProps> = (props) => { const LazyLoadingResyncDialog: React.FC<IProps> = (props) => {
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;

View file

@ -15,10 +15,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ComponentType } from "react"; import React from "react";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import type CreateKeyBackupDialog from "../../../async-components/views/dialogs/security/CreateKeyBackupDialog";
import type ExportE2eKeysDialog from "../../../async-components/views/dialogs/security/ExportE2eKeysDialog";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@ -81,7 +83,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
private onExportE2eKeysClicked = (): void => { private onExportE2eKeysClicked = (): void => {
Modal.createDialogAsync( Modal.createDialogAsync(
import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise< import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise<
ComponentType<{}> typeof ExportE2eKeysDialog
>, >,
{ {
matrixClient: MatrixClientPeg.get(), matrixClient: MatrixClientPeg.get(),
@ -89,7 +91,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
); );
}; };
private onFinished = (confirmed: boolean): void => { private onFinished = (confirmed?: boolean): void => {
if (confirmed) { if (confirmed) {
dis.dispatch({ action: "logout" }); dis.dispatch({ action: "logout" });
} }
@ -112,7 +114,7 @@ export default class LogoutDialog extends React.Component<IProps, IState> {
} else { } else {
Modal.createDialogAsync( Modal.createDialogAsync(
import("../../../async-components/views/dialogs/security/CreateKeyBackupDialog") as unknown as Promise< import("../../../async-components/views/dialogs/security/CreateKeyBackupDialog") as unknown as Promise<
ComponentType<{}> typeof CreateKeyBackupDialog
>, >,
undefined, undefined,
undefined, undefined,

View file

@ -18,7 +18,6 @@ import React, { useMemo, useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import SearchBox from "../../structures/SearchBox"; import SearchBox from "../../structures/SearchBox";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore";
@ -28,9 +27,10 @@ import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
interface IProps extends IDialogProps { interface IProps {
room: Room; room: Room;
selected?: string[]; selected?: string[];
onFinished(rooms?: string[]): void;
} }
const Entry: React.FC<{ const Entry: React.FC<{

View file

@ -25,11 +25,11 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import * as FormattingUtils from "../../../utils/FormattingUtils"; import * as FormattingUtils from "../../../utils/FormattingUtils";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
userId: string; userId: string;
device: DeviceInfo; device: DeviceInfo;
onFinished(confirm?: boolean): void;
} }
export default class ManualDeviceKeyVerificationDialog extends React.Component<IProps> { export default class ManualDeviceKeyVerificationDialog extends React.Component<IProps> {

View file

@ -30,10 +30,10 @@ import ScrollPanel from "../../structures/ScrollPanel";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
import EditHistoryMessage from "../messages/EditHistoryMessage"; import EditHistoryMessage from "../messages/EditHistoryMessage";
import DateSeparator from "../messages/DateSeparator"; import DateSeparator from "../messages/DateSeparator";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onFinished(): void;
} }
interface IState { interface IState {

View file

@ -46,7 +46,7 @@ interface IProps {
widgetDefinition: IModalWidgetOpenRequestData; widgetDefinition: IModalWidgetOpenRequestData;
widgetRoomId?: string; widgetRoomId?: string;
sourceWidgetId: string; sourceWidgetId: string;
onFinished(success: boolean, data?: IModalWidgetReturnData): void; onFinished(success?: boolean, data?: IModalWidgetReturnData): void;
} }
interface IState { interface IState {

View file

@ -19,13 +19,13 @@ import { DialogContent, DialogProps } from "@matrix-org/react-sdk-module-api/lib
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import ScrollableBaseModal, { IScrollableBaseState } from "./ScrollableBaseModal"; import ScrollableBaseModal, { IScrollableBaseState } from "./ScrollableBaseModal";
import { IDialogProps } from "./IDialogProps";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
interface IProps extends IDialogProps { interface IProps<C extends React.Component = React.Component> {
contentFactory: (props: DialogProps, ref: React.Ref<DialogContent>) => React.ReactNode; contentFactory: (props: DialogProps, ref: React.Ref<C>) => React.ReactNode;
contentProps: DialogProps; contentProps: DialogProps;
title: string; title: string;
onFinished(ok?: boolean, model?: Awaited<ReturnType<DialogContent["trySubmit"]>>): void;
} }
interface IState extends IScrollableBaseState { interface IState extends IScrollableBaseState {

View file

@ -19,11 +19,10 @@ import React from "react";
import classNames from "classnames"; import classNames from "classnames";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
export interface IQuestionDialogProps extends IDialogProps { export interface IQuestionDialogProps {
title?: string; title?: string;
description?: React.ReactNode; description?: React.ReactNode;
extraButtons?: React.ReactNode; extraButtons?: React.ReactNode;
@ -37,6 +36,7 @@ export interface IQuestionDialogProps extends IDialogProps {
className?: string; className?: string;
hasCancelButton?: boolean; hasCancelButton?: boolean;
cancelButton?: React.ReactNode; cancelButton?: React.ReactNode;
onFinished(ok?: boolean): void;
} }
export default class QuestionDialog extends React.Component<IQuestionDialogProps> { export default class QuestionDialog extends React.Component<IQuestionDialogProps> {

View file

@ -18,13 +18,12 @@ import * as React from "react";
import { SyntheticEvent, useRef, useState } from "react"; import { SyntheticEvent, useRef, useState } from "react";
import { _t, _td } from "../../../languageHandler"; import { _t, _td } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import Field from "../elements/Field"; import Field from "../elements/Field";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import EmailField from "../auth/EmailField"; import EmailField from "../auth/EmailField";
interface IProps extends IDialogProps { interface IProps {
onFinished(continued: boolean, email?: string): void; onFinished(continued: boolean, email?: string): void;
} }

View file

@ -21,7 +21,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { ensureDMExists } from "../../../createRoom"; import { ensureDMExists } from "../../../createRoom";
import { IDialogProps } from "./IDialogProps";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import SdkConfig from "../../../SdkConfig"; import SdkConfig from "../../../SdkConfig";
import Markdown from "../../../Markdown"; import Markdown from "../../../Markdown";
@ -33,8 +32,9 @@ import Field from "../elements/Field";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
import LabelledCheckbox from "../elements/LabelledCheckbox"; import LabelledCheckbox from "../elements/LabelledCheckbox";
interface IProps extends IDialogProps { interface IProps {
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onFinished(report?: boolean): void;
} }
interface IState { interface IState {

View file

@ -45,7 +45,7 @@ export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB";
interface IProps { interface IProps {
roomId: string; roomId: string;
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
initialTabId?: string; initialTabId?: string;
} }

View file

@ -20,14 +20,14 @@ import { Room } from "matrix-js-sdk/src/models/room";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { upgradeRoom } from "../../../utils/RoomUpgrade"; import { upgradeRoom } from "../../../utils/RoomUpgrade";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import ErrorDialog from "./ErrorDialog"; import ErrorDialog from "./ErrorDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import Spinner from "../elements/Spinner"; import Spinner from "../elements/Spinner";
interface IProps extends IDialogProps { interface IProps {
room: Room; room: Room;
onFinished(upgrade?: boolean): void;
} }
interface IState { interface IState {

View file

@ -23,7 +23,6 @@ import SdkConfig from "../../../SdkConfig";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import { IDialogProps } from "./IDialogProps";
import BugReportDialog from "./BugReportDialog"; import BugReportDialog from "./BugReportDialog";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
@ -35,11 +34,12 @@ export interface IFinishedOpts {
invite: boolean; invite: boolean;
} }
interface IProps extends IDialogProps { interface IProps {
roomId: string; roomId: string;
targetVersion: string; targetVersion: string;
description?: ReactNode; description?: ReactNode;
doUpgrade?(opts: IFinishedOpts, fn: (progressText: string, progress: number, total: number) => void): Promise<void>; doUpgrade?(opts: IFinishedOpts, fn: (progressText: string, progress: number, total: number) => void): Promise<void>;
onFinished(opts?: IFinishedOpts): void;
} }
interface IState { interface IState {
@ -70,19 +70,14 @@ export default class RoomUpgradeWarningDialog extends React.Component<IProps, IS
this.setState({ progressText, progress, total }); this.setState({ progressText, progress, total });
}; };
private onContinue = (): void => { private onContinue = async (): Promise<void> => {
const opts = { const opts = {
continue: true, continue: true,
invite: this.isPrivate && this.state.inviteUsersToNewRoom, invite: this.isPrivate && this.state.inviteUsersToNewRoom,
}; };
if (this.props.doUpgrade) { await this.props.doUpgrade?.(opts, this.onProgressCallback);
this.props.doUpgrade(opts, this.onProgressCallback).then(() => {
this.props.onFinished(opts); this.props.onFinished(opts);
});
} else {
this.props.onFinished(opts);
}
}; };
private onCancel = (): void => { private onCancel = (): void => {

View file

@ -19,7 +19,6 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
import FocusLock from "react-focus-lock"; import FocusLock from "react-focus-lock";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { IDialogProps } from "./IDialogProps";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
@ -36,7 +35,7 @@ export interface IScrollableBaseState {
* Scrollable dialog base from Compound (Web Components). * Scrollable dialog base from Compound (Web Components).
*/ */
export default abstract class ScrollableBaseModal< export default abstract class ScrollableBaseModal<
TProps extends IDialogProps, TProps extends { onFinished?: (...args: any[]) => void },
TState extends IScrollableBaseState, TState extends IScrollableBaseState,
> extends React.PureComponent<TProps, TState> { > extends React.PureComponent<TProps, TState> {
protected constructor(props: TProps) { protected constructor(props: TProps) {

View file

@ -28,9 +28,10 @@ import Spinner from "../elements/Spinner";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import { UPDATE_EVENT } from "../../../stores/AsyncStore"; import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
export default class ServerOfflineDialog extends React.PureComponent<IProps> { export default class ServerOfflineDialog extends React.PureComponent<IProps> {
public componentDidMount(): void { public componentDidMount(): void {

View file

@ -19,9 +19,12 @@ import React from "react";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
export default class SeshatResetDialog extends React.PureComponent<IDialogProps> { interface Props {
onFinished(reset?: boolean): void;
}
export default class SeshatResetDialog extends React.PureComponent<Props> {
public render(): React.ReactNode { public render(): React.ReactNode {
return ( return (
<BaseDialog <BaseDialog

View file

@ -25,10 +25,10 @@ import QuestionDialog from "./QuestionDialog";
import BugReportDialog from "./BugReportDialog"; import BugReportDialog from "./BugReportDialog";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
error: Error; error: Error;
onFinished(clear?: boolean): void;
} }
export default class SessionRestoreErrorDialog extends React.Component<IProps> { export default class SessionRestoreErrorDialog extends React.Component<IProps> {

View file

@ -27,10 +27,10 @@ import ErrorDialog from "./ErrorDialog";
import QuestionDialog from "./QuestionDialog"; import QuestionDialog from "./QuestionDialog";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import EditableText from "../elements/EditableText"; import EditableText from "../elements/EditableText";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
title: string; title: string;
onFinished(ok?: boolean): void;
} }
interface IState { interface IState {

View file

@ -26,7 +26,6 @@ import QRCode from "../elements/QRCode";
import { RoomPermalinkCreator, makeUserPermalink } from "../../../utils/permalinks/Permalinks"; import { RoomPermalinkCreator, makeUserPermalink } from "../../../utils/permalinks/Permalinks";
import { selectText } from "../../../utils/strings"; import { selectText } from "../../../utils/strings";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import { IDialogProps } from "./IDialogProps";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import { UIFeature } from "../../../settings/UIFeature"; import { UIFeature } from "../../../settings/UIFeature";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
@ -64,9 +63,10 @@ const socials = [
}, },
]; ];
interface IProps extends IDialogProps { interface IProps {
target: Room | User | RoomMember | MatrixEvent; target: Room | User | RoomMember | MatrixEvent;
permalinkCreator: RoomPermalinkCreator; permalinkCreator?: RoomPermalinkCreator;
onFinished(): void;
} }
interface IState { interface IState {

View file

@ -18,10 +18,11 @@ import React from "react";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { Command, CommandCategories, Commands } from "../../../SlashCommands"; import { Command, CommandCategories, Commands } from "../../../SlashCommands";
import { IDialogProps } from "./IDialogProps";
import InfoDialog from "./InfoDialog"; import InfoDialog from "./InfoDialog";
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => { const SlashCommandHelpDialog: React.FC<IProps> = ({ onFinished }) => {
const categories: Record<string, Command[]> = {}; const categories: Record<string, Command[]> = {};

View file

@ -19,7 +19,6 @@ import { MatrixClient, Method } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import TextInputDialog from "./TextInputDialog"; import TextInputDialog from "./TextInputDialog";
import withValidation from "../elements/Validation"; import withValidation from "../elements/Validation";
@ -63,7 +62,7 @@ async function proxyHealthCheck(endpoint: string, hsUrl?: string): Promise<void>
logger.info("sliding sync proxy is OK"); logger.info("sliding sync proxy is OK");
} }
export const SlidingSyncOptionsDialog: React.FC<IDialogProps> = ({ onFinished }) => { export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean): void }> = ({ onFinished }) => {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const currentProxy = SettingsStore.getValue("feature_sliding_sync_proxy_url"); const currentProxy = SettingsStore.getValue("feature_sliding_sync_proxy_url");
const hasNativeSupport = useAsyncMemo( const hasNativeSupport = useAsyncMemo(

View file

@ -19,7 +19,6 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { _t, _td } from "../../../languageHandler"; import { _t, _td } from "../../../languageHandler";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import { IDialogProps } from "./IDialogProps";
import TabbedView, { Tab } from "../../structures/TabbedView"; import TabbedView, { Tab } from "../../structures/TabbedView";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import { useSettingValue } from "../../../hooks/useSettings"; import { useSettingValue } from "../../../hooks/useSettings";
@ -28,9 +27,10 @@ import { SettingLevel } from "../../../settings/SettingLevel";
import RoomName from "../elements/RoomName"; import RoomName from "../elements/RoomName";
import { SpacePreferenceTab } from "../../../dispatcher/payloads/OpenSpacePreferencesPayload"; import { SpacePreferenceTab } from "../../../dispatcher/payloads/OpenSpacePreferencesPayload";
interface IProps extends IDialogProps { interface IProps {
space: Room; space: Room;
initialTabId?: SpacePreferenceTab; initialTabId?: SpacePreferenceTab;
onFinished(): void;
} }
const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space }) => { const SpacePreferencesAppearanceTab: React.FC<Pick<IProps, "space">> = ({ space }) => {

View file

@ -19,7 +19,6 @@ import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import { _t, _td } from "../../../languageHandler"; import { _t, _td } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import defaultDispatcher from "../../../dispatcher/dispatcher";
import { useDispatcher } from "../../../hooks/useDispatcher"; import { useDispatcher } from "../../../hooks/useDispatcher";
@ -39,15 +38,16 @@ export enum SpaceSettingsTab {
Advanced = "SPACE_ADVANCED_TAB", Advanced = "SPACE_ADVANCED_TAB",
} }
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
space: Room; space: Room;
onFinished(): void;
} }
const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => { const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFinished }) => {
useDispatcher(defaultDispatcher, (payload) => { useDispatcher(defaultDispatcher, (payload) => {
if (payload.action === Action.AfterLeaveRoom && payload.room_id === space.roomId) { if (payload.action === Action.AfterLeaveRoom && payload.room_id === space.roomId) {
onFinished(false); onFinished();
} }
}); });
@ -57,7 +57,7 @@ const SpaceSettingsDialog: React.FC<IProps> = ({ matrixClient: cli, space, onFin
SpaceSettingsTab.General, SpaceSettingsTab.General,
_td("General"), _td("General"),
"mx_SpaceSettingsDialog_generalIcon", "mx_SpaceSettingsDialog_generalIcon",
<SpaceSettingsGeneralTab matrixClient={cli} space={space} onFinished={onFinished} />, <SpaceSettingsGeneralTab matrixClient={cli} space={space} />,
), ),
new Tab( new Tab(
SpaceSettingsTab.Visibility, SpaceSettingsTab.Visibility,

View file

@ -22,10 +22,11 @@ import { _t } from "../../../languageHandler";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import BugReportDialog from "./BugReportDialog"; import BugReportDialog from "./BugReportDialog";
import { IDialogProps } from "./IDialogProps";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
interface IProps extends IDialogProps {} interface IProps {
onFinished(signOut?: boolean): void;
}
export default class StorageEvictedDialog extends React.Component<IProps> { export default class StorageEvictedDialog extends React.Component<IProps> {
private sendBugReport = (ev: React.MouseEvent): void => { private sendBugReport = (ev: React.MouseEvent): void => {

View file

@ -21,9 +21,8 @@ import { _t, _td } from "../../../languageHandler";
import { IFieldState, IValidationResult } from "../elements/Validation"; import { IFieldState, IValidationResult } from "../elements/Validation";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
title?: string; title?: string;
description?: React.ReactNode; description?: React.ReactNode;
value?: string; value?: string;
@ -34,6 +33,7 @@ interface IProps extends IDialogProps {
hasCancel?: boolean; hasCancel?: boolean;
validator?: (fieldState: IFieldState) => Promise<IValidationResult>; // result of withValidation validator?: (fieldState: IFieldState) => Promise<IValidationResult>; // result of withValidation
fixedWidth?: boolean; fixedWidth?: boolean;
onFinished(ok?: boolean, text?: string): void;
} }
interface IState { interface IState {
@ -45,7 +45,7 @@ interface IState {
export default class TextInputDialog extends React.Component<IProps, IState> { export default class TextInputDialog extends React.Component<IProps, IState> {
private field = createRef<Field>(); private field = createRef<Field>();
public static defaultProps = { public static defaultProps: Partial<IProps> = {
title: "", title: "",
value: "", value: "",
description: "", description: "",

View file

@ -22,12 +22,12 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import E2EIcon, { E2EState } from "../rooms/E2EIcon"; import E2EIcon, { E2EState } from "../rooms/E2EIcon";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { IDialogProps } from "./IDialogProps";
import { IDevice } from "../right_panel/UserInfo"; import { IDevice } from "../right_panel/UserInfo";
interface IProps extends IDialogProps { interface IProps {
user: User; user: User;
device: IDevice; device: IDevice;
onFinished(mode?: "legacy" | "sas" | false): void;
} }
const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => { const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => {

View file

@ -26,7 +26,7 @@ import DialogButtons from "../elements/DialogButtons";
interface IProps { interface IProps {
file: File; file: File;
currentIndex: number; currentIndex?: number;
totalFiles?: number; totalFiles?: number;
onFinished: (uploadConfirmed: boolean, uploadAll?: boolean) => void; onFinished: (uploadConfirmed: boolean, uploadAll?: boolean) => void;
} }
@ -35,7 +35,7 @@ export default class UploadConfirmDialog extends React.Component<IProps> {
private readonly objectUrl: string; private readonly objectUrl: string;
private readonly mimeType: string; private readonly mimeType: string;
public static defaultProps = { public static defaultProps: Partial<IProps> = {
totalFiles: 1, totalFiles: 1,
}; };

View file

@ -21,12 +21,12 @@ import { _t } from "../../../languageHandler";
import ContentMessages from "../../../ContentMessages"; import ContentMessages from "../../../ContentMessages";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { IDialogProps } from "./IDialogProps";
interface IProps extends IDialogProps { interface IProps {
badFiles: File[]; badFiles: File[];
totalFiles: number; totalFiles: number;
contentMessages: ContentMessages; contentMessages: ContentMessages;
onFinished(upload?: boolean): void;
} }
/* /*

View file

@ -32,14 +32,14 @@ import SdkConfig from "../../../SdkConfig";
import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab"; import MjolnirUserSettingsTab from "../settings/tabs/user/MjolnirUserSettingsTab";
import { UIFeature } from "../../../settings/UIFeature"; import { UIFeature } from "../../../settings/UIFeature";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { IDialogProps } from "./IDialogProps";
import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab"; import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab";
import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab"; import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab";
import SessionManagerTab from "../settings/tabs/user/SessionManagerTab"; import SessionManagerTab from "../settings/tabs/user/SessionManagerTab";
import { UserTab } from "./UserTab"; import { UserTab } from "./UserTab";
interface IProps extends IDialogProps { interface IProps {
initialTabId?: UserTab; initialTabId?: UserTab;
onFinished(): void;
} }
interface IState { interface IState {
@ -202,7 +202,7 @@ export default class UserSettingsDialog extends React.Component<IProps, IState>
UserTab.Help, UserTab.Help,
_td("Help & About"), _td("Help & About"),
"mx_UserSettingsDialog_helpIcon", "mx_UserSettingsDialog_helpIcon",
<HelpUserSettingsTab closeSettingsFn={() => this.props.onFinished(true)} />, <HelpUserSettingsTab closeSettingsFn={() => this.props.onFinished()} />,
"UserSettingsHelpAbout", "UserSettingsHelpAbout",
), ),
); );

View file

@ -24,14 +24,14 @@ import BaseDialog from "./BaseDialog";
import EncryptionPanel from "../right_panel/EncryptionPanel"; import EncryptionPanel from "../right_panel/EncryptionPanel";
interface IProps { interface IProps {
verificationRequest: VerificationRequest; verificationRequest?: VerificationRequest;
verificationRequestPromise: Promise<VerificationRequest>; verificationRequestPromise?: Promise<VerificationRequest>;
onFinished: () => void; onFinished: () => void;
member: User; member?: User;
} }
interface IState { interface IState {
verificationRequest: VerificationRequest; verificationRequest?: VerificationRequest;
} }
export default class VerificationRequestDialog extends React.Component<IProps, IState> { export default class VerificationRequestDialog extends React.Component<IProps, IState> {
@ -40,18 +40,16 @@ export default class VerificationRequestDialog extends React.Component<IProps, I
this.state = { this.state = {
verificationRequest: this.props.verificationRequest, verificationRequest: this.props.verificationRequest,
}; };
if (this.props.verificationRequestPromise) { this.props.verificationRequestPromise?.then((r) => {
this.props.verificationRequestPromise.then((r) => {
this.setState({ verificationRequest: r }); this.setState({ verificationRequest: r });
}); });
} }
}
public render(): React.ReactNode { public render(): React.ReactNode {
const request = this.state.verificationRequest; const request = this.state.verificationRequest;
const otherUserId = request && request.otherUserId; const otherUserId = request?.otherUserId;
const member = this.props.member || (otherUserId && MatrixClientPeg.get().getUser(otherUserId)); const member = this.props.member || (otherUserId ? MatrixClientPeg.get().getUser(otherUserId) : null);
const title = request && request.isSelfVerification ? _t("Verify other device") : _t("Verification Request"); const title = request?.isSelfVerification ? _t("Verify other device") : _t("Verification Request");
return ( return (
<BaseDialog <BaseDialog

View file

@ -20,17 +20,17 @@ import { lexicographicCompare } from "matrix-js-sdk/src/utils";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { IDialogProps } from "./IDialogProps";
import { objectShallowClone } from "../../../utils/objects"; import { objectShallowClone } from "../../../utils/objects";
import StyledCheckbox from "../elements/StyledCheckbox"; import StyledCheckbox from "../elements/StyledCheckbox";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { CapabilityText } from "../../../widgets/CapabilityText"; import { CapabilityText } from "../../../widgets/CapabilityText";
interface IProps extends IDialogProps { interface IProps {
requestedCapabilities: Set<Capability>; requestedCapabilities: Set<Capability>;
widget: Widget; widget: Widget;
widgetKind: WidgetKind; // TODO: Refactor into the Widget class widgetKind: WidgetKind; // TODO: Refactor into the Widget class
onFinished(result?: { approved: Capability[]; remember: boolean }): void;
} }
type BooleanStates = Partial<{ type BooleanStates = Partial<{

View file

@ -22,15 +22,15 @@ import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import { OIDCState } from "../../../stores/widgets/WidgetPermissionStore"; import { OIDCState } from "../../../stores/widgets/WidgetPermissionStore";
import { IDialogProps } from "./IDialogProps";
import BaseDialog from "./BaseDialog"; import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons"; import DialogButtons from "../elements/DialogButtons";
import { SdkContextClass } from "../../../contexts/SDKContext"; import { SdkContextClass } from "../../../contexts/SDKContext";
interface IProps extends IDialogProps { interface IProps {
widget: Widget; widget: Widget;
widgetKind: WidgetKind; widgetKind: WidgetKind;
inRoomId?: string; inRoomId?: string;
onFinished(allowed?: boolean): void;
} }
interface IState { interface IState {

View file

@ -20,7 +20,6 @@ import { MatrixEvent, Poll, Room } from "matrix-js-sdk/src/matrix";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import BaseDialog from "../BaseDialog"; import BaseDialog from "../BaseDialog";
import { IDialogProps } from "../IDialogProps";
import { PollHistoryList } from "./PollHistoryList"; import { PollHistoryList } from "./PollHistoryList";
import { PollHistoryFilter } from "./types"; import { PollHistoryFilter } from "./types";
import { PollDetailHeader } from "./PollDetailHeader"; import { PollDetailHeader } from "./PollDetailHeader";
@ -29,10 +28,11 @@ import { RoomPermalinkCreator } from "../../../../utils/permalinks/Permalinks";
import { usePollsWithRelations } from "./usePollHistory"; import { usePollsWithRelations } from "./usePollHistory";
import { useFetchPastPolls } from "./fetchPastPolls"; import { useFetchPastPolls } from "./fetchPastPolls";
type PollHistoryDialogProps = Pick<IDialogProps, "onFinished"> & { type PollHistoryDialogProps = {
room: Room; room: Room;
matrixClient: MatrixClient; matrixClient: MatrixClient;
permalinkCreator: RoomPermalinkCreator; permalinkCreator: RoomPermalinkCreator;
onFinished(): void;
}; };
const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs(); const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs();

View file

@ -24,7 +24,6 @@ import { MatrixClientPeg } from "../../../../MatrixClientPeg";
import Field from "../../elements/Field"; import Field from "../../elements/Field";
import AccessibleButton from "../../elements/AccessibleButton"; import AccessibleButton from "../../elements/AccessibleButton";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import { IDialogProps } from "../IDialogProps";
import { accessSecretStorage } from "../../../../SecurityManager"; import { accessSecretStorage } from "../../../../SecurityManager";
import Modal from "../../../../Modal"; import Modal from "../../../../Modal";
import InteractiveAuthDialog from "../InteractiveAuthDialog"; import InteractiveAuthDialog from "../InteractiveAuthDialog";
@ -40,9 +39,12 @@ const KEY_FILE_MAX_SIZE = 128;
// Don't shout at the user that their key is invalid every time they type a key: wait a short time // Don't shout at the user that their key is invalid every time they type a key: wait a short time
const VALIDATION_THROTTLE_MS = 200; const VALIDATION_THROTTLE_MS = 200;
interface IProps extends IDialogProps { export type KeyParams = { passphrase?: string; recoveryKey?: string };
interface IProps {
keyInfo?: ISecretStorageKeyInfo; keyInfo?: ISecretStorageKeyInfo;
checkPrivateKey: (k: { passphrase?: string; recoveryKey?: string }) => boolean; checkPrivateKey: (k: KeyParams) => Promise<boolean>;
onFinished(result?: false | KeyParams): void;
} }
interface IState { interface IState {
@ -246,7 +248,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp
// Now we can indicate that the user is done pressing buttons, finally. // Now we can indicate that the user is done pressing buttons, finally.
// Upstream flows will detect the new secret storage, key backup, etc and use it. // Upstream flows will detect the new secret storage, key backup, etc and use it.
this.props.onFinished(true); this.props.onFinished({});
}, true); }, true);
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);

View file

@ -21,7 +21,7 @@ import BaseDialog from "../BaseDialog";
import DialogButtons from "../../elements/DialogButtons"; import DialogButtons from "../../elements/DialogButtons";
interface IProps { interface IProps {
onFinished: (success: boolean) => void; onFinished: (success?: boolean) => void;
} }
export default class ConfirmDestroyCrossSigningDialog extends React.Component<IProps> { export default class ConfirmDestroyCrossSigningDialog extends React.Component<IProps> {

View file

@ -32,7 +32,7 @@ import InteractiveAuthDialog from "../InteractiveAuthDialog";
interface IProps { interface IProps {
accountPassword?: string; accountPassword?: string;
tokenLogin?: boolean; tokenLogin?: boolean;
onFinished?: (success: boolean) => void; onFinished?: (success?: boolean) => void;
} }
interface IState { interface IState {

View file

@ -24,7 +24,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClientPeg } from "../../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../../MatrixClientPeg";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import { accessSecretStorage } from "../../../../SecurityManager"; import { accessSecretStorage } from "../../../../SecurityManager";
import { IDialogProps } from "../IDialogProps";
import Spinner from "../../elements/Spinner"; import Spinner from "../../elements/Spinner";
import DialogButtons from "../../elements/DialogButtons"; import DialogButtons from "../../elements/DialogButtons";
import AccessibleButton from "../../elements/AccessibleButton"; import AccessibleButton from "../../elements/AccessibleButton";
@ -42,13 +41,14 @@ enum ProgressState {
LoadKeys = "load_keys", LoadKeys = "load_keys",
} }
interface IProps extends IDialogProps { interface IProps {
// if false, will close the dialog as soon as the restore completes successfully // if false, will close the dialog as soon as the restore completes successfully
// default: true // default: true
showSummary?: boolean; showSummary?: boolean;
// If specified, gather the key from the user but then call the function with the backup // If specified, gather the key from the user but then call the function with the backup
// key rather than actually (necessarily) restoring the backup. // key rather than actually (necessarily) restoring the backup.
keyCallback?: (key: Uint8Array) => void; keyCallback?: (key: Uint8Array) => void;
onFinished(done?: boolean): void;
} }
interface IState { interface IState {
@ -77,7 +77,7 @@ interface IState {
* Dialog for restoring e2e keys from a backup and the user's recovery key * Dialog for restoring e2e keys from a backup and the user's recovery key
*/ */
export default class RestoreKeyBackupDialog extends React.PureComponent<IProps, IState> { export default class RestoreKeyBackupDialog extends React.PureComponent<IProps, IState> {
public static defaultProps = { public static defaultProps: Partial<IProps> = {
showSummary: true, showSummary: true,
}; };

View file

@ -20,7 +20,6 @@ import SetupEncryptionBody from "../../../structures/auth/SetupEncryptionBody";
import BaseDialog from "../BaseDialog"; import BaseDialog from "../BaseDialog";
import { _t } from "../../../../languageHandler"; import { _t } from "../../../../languageHandler";
import { SetupEncryptionStore, Phase } from "../../../../stores/SetupEncryptionStore"; import { SetupEncryptionStore, Phase } from "../../../../stores/SetupEncryptionStore";
import { IDialogProps } from "../IDialogProps";
function iconFromPhase(phase: Phase): string { function iconFromPhase(phase: Phase): string {
if (phase === Phase.Done) { if (phase === Phase.Done) {
@ -30,7 +29,9 @@ function iconFromPhase(phase: Phase): string {
} }
} }
interface IProps extends IDialogProps {} interface IProps {
onFinished(): void;
}
interface IState { interface IState {
icon: string; icon: string;
} }

View file

@ -83,7 +83,6 @@ import Spinner from "../../elements/Spinner";
import NotificationBadge from "../../rooms/NotificationBadge"; import NotificationBadge from "../../rooms/NotificationBadge";
import BaseDialog from "../BaseDialog"; import BaseDialog from "../BaseDialog";
import FeedbackDialog from "../FeedbackDialog"; import FeedbackDialog from "../FeedbackDialog";
import { IDialogProps } from "../IDialogProps";
import { Option } from "./Option"; import { Option } from "./Option";
import { PublicRoomResultDetails } from "./PublicRoomResultDetails"; import { PublicRoomResultDetails } from "./PublicRoomResultDetails";
import { RoomResultContextMenus } from "./RoomResultContextMenus"; import { RoomResultContextMenus } from "./RoomResultContextMenus";
@ -99,9 +98,10 @@ const MAX_RECENT_SEARCHES = 10;
const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons
const AVATAR_SIZE = 24; const AVATAR_SIZE = 24;
interface IProps extends IDialogProps { interface IProps {
initialText?: string; initialText?: string;
initialFilter?: Filter; initialFilter?: Filter;
onFinished(): void;
} }
function refIsForRecentlyViewed(ref: RefObject<HTMLElement>): boolean { function refIsForRecentlyViewed(ref: RefObject<HTMLElement>): boolean {

View file

@ -33,7 +33,6 @@ import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions"; import { Action } from "../../../dispatcher/actions";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
import { normalizeWheelEvent } from "../../../utils/Mouse"; import { normalizeWheelEvent } from "../../../utils/Mouse";
import { IDialogProps } from "../dialogs/IDialogProps";
import UIStore from "../../../stores/UIStore"; import UIStore from "../../../stores/UIStore";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
@ -56,7 +55,7 @@ const getPanelHeight = (): number => {
return parseInt(value.slice(0, value.length - 2)); return parseInt(value.slice(0, value.length - 2));
}; };
interface IProps extends IDialogProps { interface IProps {
src: string; // the source of the image being displayed src: string; // the source of the image being displayed
name?: string; // the main title ('name') for the image name?: string; // the main title ('name') for the image
link?: string; // the link (if any) applied to the name of the image link?: string; // the link (if any) applied to the name of the image
@ -77,6 +76,7 @@ interface IProps extends IDialogProps {
width: number; width: number;
height: number; height: number;
}; };
onFinished(): void;
} }
interface IState { interface IState {

View file

@ -27,7 +27,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { IPartialEvent } from "matrix-js-sdk/src/@types/extensible_events"; import { IPartialEvent } from "matrix-js-sdk/src/@types/extensible_events";
import ScrollableBaseModal, { IScrollableBaseState } from "../dialogs/ScrollableBaseModal"; import ScrollableBaseModal, { IScrollableBaseState } from "../dialogs/ScrollableBaseModal";
import { IDialogProps } from "../dialogs/IDialogProps";
import QuestionDialog from "../dialogs/QuestionDialog"; import QuestionDialog from "../dialogs/QuestionDialog";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
@ -37,10 +36,11 @@ import AccessibleButton from "./AccessibleButton";
import Spinner from "./Spinner"; import Spinner from "./Spinner";
import { doMaybeLocalRoomAction } from "../../../utils/local-room"; import { doMaybeLocalRoomAction } from "../../../utils/local-room";
interface IProps extends IDialogProps { interface IProps {
room: Room; room: Room;
threadId?: string; threadId?: string;
editingMxEvent?: MatrixEvent; // Truthy if we are editing an existing poll editingMxEvent?: MatrixEvent; // Truthy if we are editing an existing poll
onFinished(pollCreated?: boolean): void;
} }
enum FocusTarget { enum FocusTarget {

View file

@ -22,6 +22,7 @@ interface IProps {
w?: number; w?: number;
h?: number; h?: number;
message?: string; message?: string;
onFinished: any; // XXX: Spinner pretends to be a dialog so it must accept an onFinished, but it never calls it
} }
export default class Spinner extends React.PureComponent<IProps> { export default class Spinner extends React.PureComponent<IProps> {

View file

@ -19,15 +19,15 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import { IDialogProps } from "../dialogs/IDialogProps";
import { locationEventGeoUri, isSelfLocation } from "../../../utils/location"; import { locationEventGeoUri, isSelfLocation } from "../../../utils/location";
import Map from "./Map"; import Map from "./Map";
import SmartMarker from "./SmartMarker"; import SmartMarker from "./SmartMarker";
import ZoomButtons from "./ZoomButtons"; import ZoomButtons from "./ZoomButtons";
interface IProps extends IDialogProps { interface IProps {
matrixClient: MatrixClient; matrixClient: MatrixClient;
mxEvent: MatrixEvent; mxEvent: MatrixEvent;
onFinished(): void;
} }
interface IState { interface IState {

View file

@ -80,7 +80,9 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
Modal.createDialog( Modal.createDialog(
ConfirmAndWaitRedactDialog, ConfirmAndWaitRedactDialog,
{ {
redact: () => cli.redactEvent(event.getRoomId(), event.getId()), redact: async () => {
await cli.redactEvent(event.getRoomId(), event.getId());
},
}, },
"mx_Dialog_confirmredact", "mx_Dialog_confirmredact",
); );

View file

@ -162,7 +162,6 @@ const MBeaconBody: React.FC<IBodyProps> = React.forwardRef(({ mxEvent, getRelati
roomId: mxEvent.getRoomId(), roomId: mxEvent.getRoomId(),
matrixClient, matrixClient,
initialFocusedBeacon: beacon, initialFocusedBeacon: beacon,
isMapDisplayError,
}, },
"mx_BeaconViewDialog_wrapper", "mx_BeaconViewDialog_wrapper",
false, // isPriority false, // isPriority

View file

@ -41,7 +41,7 @@ const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
interface IProps { interface IProps {
member: RoomMember | User; member: RoomMember | User;
onClose: () => void; onClose: () => void;
verificationRequest: VerificationRequest; verificationRequest?: VerificationRequest;
verificationRequestPromise?: Promise<VerificationRequest>; verificationRequestPromise?: Promise<VerificationRequest>;
layout: string; layout: string;
isRoomEncrypted: boolean; isRoomEncrypted: boolean;

View file

@ -30,6 +30,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning"; import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
import dis from "../../../dispatcher/dispatcher"; import dis from "../../../dispatcher/dispatcher";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
@ -79,10 +80,8 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { DirectoryMember, startDmOnFirstMessage } from "../../../utils/direct-messages"; import { DirectoryMember, startDmOnFirstMessage } from "../../../utils/direct-messages";
import { SdkContextClass } from "../../../contexts/SDKContext"; import { SdkContextClass } from "../../../contexts/SDKContext";
export interface IDevice { export interface IDevice extends DeviceInfo {
deviceId: string;
ambiguous?: boolean; ambiguous?: boolean;
getDisplayName(): string;
} }
export const disambiguateDevices = (devices: IDevice[]): void => { export const disambiguateDevices = (devices: IDevice[]): void => {
@ -239,8 +238,8 @@ function DevicesSection({
const isMe = userId === cli.getUserId(); const isMe = userId === cli.getUserId();
const deviceTrusts = devices.map((d) => cli.checkDeviceTrust(userId, d.deviceId)); const deviceTrusts = devices.map((d) => cli.checkDeviceTrust(userId, d.deviceId));
let expandSectionDevices = []; let expandSectionDevices: IDevice[] = [];
const unverifiedDevices = []; const unverifiedDevices: IDevice[] = [];
let expandCountCaption; let expandCountCaption;
let expandHideCaption; let expandHideCaption;
@ -487,7 +486,7 @@ export const UserOptionsSection: React.FC<{
}; };
const warnSelfDemote = async (isSpace: boolean): Promise<boolean> => { const warnSelfDemote = async (isSpace: boolean): Promise<boolean> => {
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Demote yourself?"), title: _t("Demote yourself?"),
description: ( description: (
<div> <div>
@ -592,9 +591,7 @@ export const RoomKickButton = ({
if (member.membership !== "invite" && member.membership !== "join") return null; if (member.membership !== "invite" && member.membership !== "join") return null;
const onKick = async (): Promise<void> => { const onKick = async (): Promise<void> => {
const { finished } = Modal.createDialog( const commonProps = {
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
{
member, member,
action: room.isSpaceRoom() action: room.isSpaceRoom()
? member.membership === "invite" ? member.membership === "invite"
@ -609,7 +606,15 @@ export const RoomKickButton = ({
: _t("Remove from %(roomName)s", { roomName: room.name }), : _t("Remove from %(roomName)s", { roomName: room.name }),
askReason: member.membership === "join", askReason: member.membership === "join",
danger: true, danger: true,
// space-specific props };
let finished: Promise<[success?: boolean, reason?: string, rooms?: Room[]]>;
if (room.isSpaceRoom()) {
({ finished } = Modal.createDialog(
ConfirmSpaceUserActionDialog,
{
...commonProps,
space: room, space: room,
spaceChildFilter: (child: Room) => { spaceChildFilter: (child: Room) => {
// Return true if the target member is not banned and we have sufficient PL to ban them // Return true if the target member is not banned and we have sufficient PL to ban them
@ -627,8 +632,11 @@ export const RoomKickButton = ({
specificLabel: _t("Remove them from specific things I'm able to"), specificLabel: _t("Remove them from specific things I'm able to"),
warningMessage: _t("They'll still be able to access whatever you're not an admin of."), warningMessage: _t("They'll still be able to access whatever you're not an admin of."),
}, },
room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, "mx_ConfirmSpaceUserActionDialog_wrapper",
); ));
} else {
({ finished } = Modal.createDialog(ConfirmUserActionDialog, commonProps));
}
const [proceed, reason, rooms = []] = await finished; const [proceed, reason, rooms = []] = await finished;
if (!proceed) return; if (!proceed) return;
@ -705,9 +713,7 @@ export const BanToggleButton = ({
const isBanned = member.membership === "ban"; const isBanned = member.membership === "ban";
const onBanOrUnban = async (): Promise<void> => { const onBanOrUnban = async (): Promise<void> => {
const { finished } = Modal.createDialog( const commonProps = {
room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog,
{
member, member,
action: room.isSpaceRoom() action: room.isSpaceRoom()
? isBanned ? isBanned
@ -721,7 +727,15 @@ export const BanToggleButton = ({
: _t("Ban from %(roomName)s", { roomName: room.name }), : _t("Ban from %(roomName)s", { roomName: room.name }),
askReason: !isBanned, askReason: !isBanned,
danger: !isBanned, danger: !isBanned,
// space-specific props };
let finished: Promise<[success?: boolean, reason?: string, rooms?: Room[]]>;
if (room.isSpaceRoom()) {
({ finished } = Modal.createDialog(
ConfirmSpaceUserActionDialog,
{
...commonProps,
space: room, space: room,
spaceChildFilter: isBanned spaceChildFilter: isBanned
? (child: Room) => { ? (child: Room) => {
@ -758,8 +772,11 @@ export const BanToggleButton = ({
? _t("They won't be able to access whatever you're not an admin of.") ? _t("They won't be able to access whatever you're not an admin of.")
: _t("They'll still be able to access whatever you're not an admin of."), : _t("They'll still be able to access whatever you're not an admin of."),
}, },
room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, "mx_ConfirmSpaceUserActionDialog_wrapper",
); ));
} else {
({ finished } = Modal.createDialog(ConfirmUserActionDialog, commonProps));
}
const [proceed, reason, rooms = []] = await finished; const [proceed, reason, rooms = []] = await finished;
if (!proceed) return; if (!proceed) return;
@ -1173,8 +1190,8 @@ export const useDevices = (userId: string): IDevice[] | undefined | null => {
return; return;
} }
disambiguateDevices(devices as IDevice[]); disambiguateDevices(devices);
setDevices(devices as IDevice[]); setDevices(devices);
} catch (err) { } catch (err) {
setDevices(null); setDevices(null);
} }
@ -1193,7 +1210,7 @@ export const useDevices = (userId: string): IDevice[] | undefined | null => {
const updateDevices = async (): Promise<void> => { const updateDevices = async (): Promise<void> => {
const newDevices = cli.getStoredDevicesForUser(userId); const newDevices = cli.getStoredDevicesForUser(userId);
if (cancel) return; if (cancel) return;
setDevices(newDevices as IDevice[]); setDevices(newDevices);
}; };
const onDevicesUpdated = (users: string[]): void => { const onDevicesUpdated = (users: string[]): void => {
if (!users.includes(userId)) return; if (!users.includes(userId)) return;
@ -1603,7 +1620,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
RightPanelStore.instance.popCard(); RightPanelStore.instance.popCard();
}; };
let content; let content: JSX.Element | undefined;
switch (phase) { switch (phase) {
case RightPanelPhases.RoomMemberInfo: case RightPanelPhases.RoomMemberInfo:
case RightPanelPhases.SpaceMemberInfo: case RightPanelPhases.SpaceMemberInfo:
@ -1611,7 +1628,7 @@ const UserInfo: React.FC<IProps> = ({ user, room, onClose, phase = RightPanelPha
<BasicUserInfo <BasicUserInfo
room={room as Room} room={room as Room}
member={member as User} member={member as User}
devices={devices as IDevice[]} devices={devices}
isRoomEncrypted={Boolean(isRoomEncrypted)} isRoomEncrypted={Boolean(isRoomEncrypted)}
/> />
); );

View file

@ -30,12 +30,11 @@ export function openLinkModal(
composerContext: ComposerContextState, composerContext: ComposerContextState,
isEditing: boolean, isEditing: boolean,
): void { ): void {
const modal = Modal.createDialog( Modal.createDialog(
LinkModal, LinkModal,
{ {
composerContext, composerContext,
composer, composer,
onClose: () => modal.close(),
isTextEnabled: isSelectionEmpty(), isTextEnabled: isSelectionEmpty(),
isEditing, isEditing,
}, },
@ -52,18 +51,18 @@ function isEmpty(text: string): boolean {
interface LinkModalProps { interface LinkModalProps {
composer: FormattingFunctions; composer: FormattingFunctions;
isTextEnabled: boolean; isTextEnabled: boolean;
onClose: () => void; onFinished: () => void;
composerContext: ComposerContextState; composerContext: ComposerContextState;
isEditing: boolean; isEditing: boolean;
} }
export function LinkModal({ export const LinkModal: React.FC<LinkModalProps> = ({
composer, composer,
isTextEnabled, isTextEnabled,
onClose, onFinished,
composerContext, composerContext,
isEditing, isEditing,
}: LinkModalProps): JSX.Element { }) => {
const [hasLinkChanged, setHasLinkChanged] = useState(false); const [hasLinkChanged, setHasLinkChanged] = useState(false);
const [fields, setFields] = useState({ text: "", link: isEditing ? composer.getLink() : "" }); const [fields, setFields] = useState({ text: "", link: isEditing ? composer.getLink() : "" });
const hasText = !isEditing && isTextEnabled; const hasText = !isEditing && isTextEnabled;
@ -74,7 +73,7 @@ export function LinkModal({
className="mx_LinkModal" className="mx_LinkModal"
title={isEditing ? _t("Edit link") : _t("Create a link")} title={isEditing ? _t("Edit link") : _t("Create a link")}
hasCancel={true} hasCancel={true}
onFinished={onClose} onFinished={onFinished}
> >
<form <form
className="mx_LinkModal_content" className="mx_LinkModal_content"
@ -82,7 +81,7 @@ export function LinkModal({
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation(); evt.stopPropagation();
onClose(); onFinished();
// When submitting is done when pressing enter when the link field has the focus, // When submitting is done when pressing enter when the link field has the focus,
// The link field is getting back the focus (due to react-focus-lock) // The link field is getting back the focus (due to react-focus-lock)
@ -126,7 +125,7 @@ export function LinkModal({
className="danger" className="danger"
onClick={() => { onClick={() => {
composer.removeLinks(); composer.removeLinks();
onClose(); onFinished();
}} }}
> >
{_t("Remove")} {_t("Remove")}
@ -136,10 +135,10 @@ export function LinkModal({
primaryButton={_t("Save")} primaryButton={_t("Save")}
primaryDisabled={isSaveDisabled} primaryDisabled={isSaveDisabled}
primaryIsSubmit={true} primaryIsSubmit={true}
onCancel={onClose} onCancel={onFinished}
/> />
</div> </div>
</form> </form>
</BaseDialog> </BaseDialog>
); );
} };

View file

@ -15,9 +15,10 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ComponentType } from "react"; import React from "react";
import { MatrixClient } from "matrix-js-sdk/src/client"; import { MatrixClient } from "matrix-js-sdk/src/client";
import type ExportE2eKeysDialog from "../../../async-components/views/dialogs/security/ExportE2eKeysDialog";
import Field from "../elements/Field"; import Field from "../elements/Field";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
@ -100,7 +101,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) { if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) {
// warn about logging out all devices // warn about logging out all devices
const { finished } = Modal.createDialog<[boolean]>(QuestionDialog, { const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("Warning!"), title: _t("Warning!"),
description: ( description: (
<div> <div>
@ -218,7 +219,7 @@ export default class ChangePassword extends React.Component<IProps, IState> {
private onExportE2eKeysClicked = (): void => { private onExportE2eKeysClicked = (): void => {
Modal.createDialogAsync( Modal.createDialogAsync(
import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise< import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise<
ComponentType<{}> typeof ExportE2eKeysDialog
>, >,
{ {
matrixClient: MatrixClientPeg.get(), matrixClient: MatrixClientPeg.get(),

View file

@ -14,8 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ComponentType } from "react"; import React from "react";
import type ExportE2eKeysDialog from "../../../async-components/views/dialogs/security/ExportE2eKeysDialog";
import type ImportE2eKeysDialog from "../../../async-components/views/dialogs/security/ImportE2eKeysDialog";
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
@ -44,7 +46,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
identityKey = FormattingUtils.formatCryptoKey(identityKey); identityKey = FormattingUtils.formatCryptoKey(identityKey);
} }
let importExportButtons = null; let importExportButtons: JSX.Element | undefined;
if (client.isCryptoEnabled()) { if (client.isCryptoEnabled()) {
importExportButtons = ( importExportButtons = (
<div className="mx_CryptographyPanel_importExportButtons"> <div className="mx_CryptographyPanel_importExportButtons">
@ -58,7 +60,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
); );
} }
let noSendUnverifiedSetting; let noSendUnverifiedSetting: JSX.Element | undefined;
if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) { if (SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
noSendUnverifiedSetting = ( noSendUnverifiedSetting = (
<SettingsFlag <SettingsFlag
@ -99,7 +101,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
private onExportE2eKeysClicked = (): void => { private onExportE2eKeysClicked = (): void => {
Modal.createDialogAsync( Modal.createDialogAsync(
import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise< import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise<
ComponentType<{}> typeof ExportE2eKeysDialog
>, >,
{ matrixClient: MatrixClientPeg.get() }, { matrixClient: MatrixClientPeg.get() },
); );
@ -108,7 +110,7 @@ export default class CryptographyPanel extends React.Component<IProps, IState> {
private onImportE2eKeysClicked = (): void => { private onImportE2eKeysClicked = (): void => {
Modal.createDialogAsync( Modal.createDialogAsync(
import("../../../async-components/views/dialogs/security/ImportE2eKeysDialog") as unknown as Promise< import("../../../async-components/views/dialogs/security/ImportE2eKeysDialog") as unknown as Promise<
ComponentType<{}> typeof ImportE2eKeysDialog
>, >,
{ matrixClient: MatrixClientPeg.get() }, { matrixClient: MatrixClientPeg.get() },
); );

Some files were not shown because too many files have changed in this diff Show more