diff --git a/web/packages/base/components/MiniDialog.tsx b/web/packages/base/components/MiniDialog.tsx index c9ffd04692..4da3333613 100644 --- a/web/packages/base/components/MiniDialog.tsx +++ b/web/packages/base/components/MiniDialog.tsx @@ -43,6 +43,22 @@ export interface MiniDialogAttributes { * actions. */ nonClosable?: boolean; + /** + * If `true`, then the dialog cannot be replaced by another dialog while it + * is being displayed. + * + * The app uses a single component to render mini dialogs, and it is + * possible that new dialog contents might preempt and replace contents in a + * dialog that is already being shown. Usually if such preemption is + * expected then both dialogs use differing mechanisms, but it can happen in + * rare unforeseen cases. + * + * This flag allow a dialog to indicate that it should not be preempted, as + * it contains some critical information. + * + * Use this flag sparingly. + */ + disablePreemption?: boolean; /** * Customize the primary action button shown in the dialog. * diff --git a/web/packages/base/components/utils/dialog.tsx b/web/packages/base/components/utils/dialog.tsx index 0232b6fba3..0a4237a8a0 100644 --- a/web/packages/base/components/utils/dialog.tsx +++ b/web/packages/base/components/utils/dialog.tsx @@ -15,10 +15,19 @@ export const useAttributedMiniDialog = () => { const [open, setOpen] = useState(false); - const showMiniDialog = useCallback((attributes: MiniDialogAttributes) => { - setAttributes(attributes); - setOpen(true); - }, []); + const showMiniDialog = useCallback( + (newAttributes: MiniDialogAttributes) => { + setAttributes((attributes) => { + if (attributes?.disablePreemption) { + // Don't replace a dialog that set the disablePreemption flag. + return attributes; + } + return newAttributes; + }); + setOpen(true); + }, + [], + ); const handleClose = useCallback(() => setOpen(false), []);