Skip to content

Commit

Permalink
Display confirm modal when clicking outside the flyout
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga committed Jun 21, 2021
1 parent ca73545 commit 8f33eb0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 12 deletions.
13 changes: 12 additions & 1 deletion src/core/public/overlays/flyout/flyout_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface OverlayFlyoutOpenOptions {
size?: EuiFlyoutSize;
maxWidth?: boolean | number | string;
hideCloseButton?: boolean;
onClose?: () => void | boolean;
}

interface StartDeps {
Expand Down Expand Up @@ -119,9 +120,19 @@ export class FlyoutService {

this.activeFlyout = flyout;

const onCloseFlyout = () => {
if (options.onClose) {
const canClose = options.onClose();
if (!canClose) {
return;
}
}
flyout.close();
};

render(
<i18n.Context>
<EuiFlyout {...options} onClose={() => flyout.close()}>
<EuiFlyout {...options} onClose={onCloseFlyout}>
<MountWrapper mount={mount} className="kbnOverlayMountWrapper" />
</EuiFlyout>
</i18n.Context>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React, { useState, useCallback, useMemo } from 'react';
import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
Expand Down Expand Up @@ -60,6 +60,10 @@ export interface Props {
/** Optional field to process */
field?: Field;
isSavingField: boolean;
/** Handler to call when the component mounts.
* We will pass "up" data that the parent component might need
*/
onMounted?: (args: { canCloseValidator: () => boolean }) => void;
}

const FieldEditorFlyoutContentComponent = ({
Expand All @@ -68,6 +72,7 @@ const FieldEditorFlyoutContentComponent = ({
onCancel,
runtimeFieldValidator,
isSavingField,
onMounted,
}: Props) => {
const isEditingExistingField = !!field;
const { indexPattern } = useFieldEditorContext();
Expand Down Expand Up @@ -104,6 +109,16 @@ const FieldEditorFlyoutContentComponent = ({
[painlessSyntaxError, clearSyntaxError]
);

const canCloseValidator = useCallback(() => {
if (isFormModified) {
setModalVisibility({
...defaultModalVisibility,
confirmUnsavedChanges: true,
});
}
return !isFormModified;
}, [isFormModified]);

const onClickSave = useCallback(async () => {
const { isValid, data } = await submit();
const nameChange = field?.name !== data.name;
Expand Down Expand Up @@ -138,16 +153,12 @@ const FieldEditorFlyoutContentComponent = ({
}, [onSave, submit, runtimeFieldValidator, field, isEditingExistingField]);

const onClickCancel = useCallback(() => {
if (isFormModified) {
setModalVisibility({
...defaultModalVisibility,
confirmUnsavedChanges: true,
});
return;
}
const canClose = canCloseValidator();

onCancel();
}, [onCancel, isFormModified]);
if (canClose) {
onCancel();
}
}, [onCancel, canCloseValidator]);

const renderModal = () => {
if (modalVisibility.confirmChangeNameOrType) {
Expand Down Expand Up @@ -182,6 +193,19 @@ const FieldEditorFlyoutContentComponent = ({
return null;
};

useEffect(() => {
if (onMounted) {
// When the flyout mounts we send to the parent the validator to check
// if we can close the flyout or not (and display a confirm modal if needed).
// This is required to display the confirm modal when clicking outside the flyout.
onMounted({ canCloseValidator });

return () => {
onMounted({ canCloseValidator: () => true });
};
}
}, [onMounted, canCloseValidator]);

return (
<>
<FlyoutPanels.Group
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import {
import type { Field, PluginStart, InternalFieldType } from '../types';
import { pluginName } from '../constants';
import { deserializeField, getRuntimeFieldValidator, getLinks, ApiService } from '../lib';
import { FieldEditorFlyoutContent } from './field_editor_flyout_content';
import {
FieldEditorFlyoutContent,
Props as FieldEditorFlyoutContentProps,
} from './field_editor_flyout_content';
import { FieldEditorProvider } from './field_editor_context';
import { FieldPreviewProvider } from './preview';

Expand All @@ -30,6 +33,7 @@ export interface Props {
onSave: (field: IndexPatternField) => void;
/** Handler for the "cancel" footer button */
onCancel: () => void;
onMounted?: FieldEditorFlyoutContentProps['onMounted'];
/** The docLinks start service from core */
docLinks: DocLinksStart;
/** The index pattern where the field will be added */
Expand Down Expand Up @@ -61,6 +65,7 @@ export const FieldEditorFlyoutContentContainer = ({
field,
onSave,
onCancel,
onMounted,
docLinks,
fieldTypeToProcess,
indexPattern,
Expand Down Expand Up @@ -200,6 +205,7 @@ export const FieldEditorFlyoutContentContainer = ({
<FieldEditorFlyoutContent
onSave={saveField}
onCancel={onCancel}
onMounted={onMounted}
field={fieldToEdit}
runtimeFieldValidator={validateRuntimeField}
isSavingField={isSaving}
Expand Down
11 changes: 11 additions & 0 deletions src/plugins/index_pattern_field_editor/public/open_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ export const getFieldEditorOpener = ({
});

let overlayRef: OverlayRef | null = null;
const canCloseValidator = {
current: () => true,
};

const onMounted = (args: { canCloseValidator: () => boolean }) => {
canCloseValidator.current = args.canCloseValidator;
};

const openEditor = ({
onSave,
Expand Down Expand Up @@ -103,6 +110,7 @@ export const getFieldEditorOpener = ({
<FieldEditorLoader
onSave={onSaveField}
onCancel={closeEditor}
onMounted={onMounted}
docLinks={docLinks}
field={field}
fieldTypeToProcess={fieldTypeToProcess}
Expand All @@ -124,6 +132,9 @@ export const getFieldEditorOpener = ({
size: 'l',
ownFocus: true,
hideCloseButton: true,
onClose: () => {
return canCloseValidator.current();
},
}
);

Expand Down

0 comments on commit 8f33eb0

Please sign in to comment.