Files
element-web/src/stores/ModalWidgetStore.ts
Richard van der Hoff f25fbdebc7 Modal: remove support for onFinished callback (#29852)
* Fix up type for `finished` result of Modal

The `finished` promise can be called with an empty array, for example if the
dialog is closed by a background click. This was not correctly represented in
the typing. Fix that, and add some documentation while we're at it.

* Type fixes to onFinished callbacks from Modal

These can all be called with zero arguments, despite what the type annotations
may say, so mark them accordingly.

* Remove uses of Modal `onFinished` property

... because it is confusing.

Instead, use the `finished` promise returned by `createDialog`.

* Modal: remove support for now-unused `onFinished` prop

* StopGapWidgetDriver: use `await` instead of promise chaining

* Fix up unit tests
2025-04-30 16:56:21 +01:00

101 lines
3.4 KiB
TypeScript

/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type IModalWidgetOpenRequestData, type IModalWidgetReturnData, type Widget } from "matrix-widget-api";
import { logger } from "matrix-js-sdk/src/logger";
import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
import defaultDispatcher from "../dispatcher/dispatcher";
import { type ActionPayload } from "../dispatcher/payloads";
import Modal, { type IHandle, type IModal } from "../Modal";
import ModalWidgetDialog from "../components/views/dialogs/ModalWidgetDialog";
import { WidgetMessagingStore } from "./widgets/WidgetMessagingStore";
interface IState {
modal?: IModal<any>;
openedFromId?: string;
}
export class ModalWidgetStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new ModalWidgetStore();
instance.start();
return instance;
})();
private modalInstance: IHandle<typeof ModalWidgetDialog> | null = null;
private openSourceWidgetId: string | null = null;
private openSourceWidgetRoomId: string | null = null;
private constructor() {
super(defaultDispatcher, {});
}
public static get instance(): ModalWidgetStore {
return ModalWidgetStore.internalInstance;
}
protected async onAction(payload: ActionPayload): Promise<any> {
// nothing
}
public canOpenModalWidget = (): boolean => {
return !this.modalInstance;
};
public openModalWidget = (
requestData: IModalWidgetOpenRequestData,
sourceWidget: Widget,
widgetRoomId?: string,
): void => {
if (this.modalInstance) return;
this.openSourceWidgetId = sourceWidget.id;
this.openSourceWidgetRoomId = widgetRoomId ?? null;
this.modalInstance = Modal.createDialog(
ModalWidgetDialog,
{
widgetDefinition: { ...requestData },
widgetRoomId,
sourceWidgetId: sourceWidget.id,
},
undefined,
/* priority = */ false,
/* static = */ true,
);
this.modalInstance!.finished.then(([success, data]) => {
this.closeModalWidget(sourceWidget, widgetRoomId, success && data ? data : { "m.exited": true });
this.openSourceWidgetId = null;
this.openSourceWidgetRoomId = null;
this.modalInstance = null;
});
};
public closeModalWidget = (
sourceWidget: Widget,
widgetRoomId: string | undefined,
data: IModalWidgetReturnData,
): void => {
if (!this.modalInstance) return;
if (this.openSourceWidgetId === sourceWidget.id && this.openSourceWidgetRoomId === widgetRoomId) {
this.openSourceWidgetId = null;
this.openSourceWidgetRoomId = null;
this.modalInstance.close();
this.modalInstance = null;
const sourceMessaging = WidgetMessagingStore.instance.getMessaging(sourceWidget, widgetRoomId);
if (!sourceMessaging) {
logger.error("No source widget messaging for modal widget");
return;
}
sourceMessaging.notifyModalWidgetClose(data);
}
};
}
window.mxModalWidgetStore = ModalWidgetStore.instance;