Skip to content

Commit 13394f7

Browse files
author
Maja Grubic
committed
Add onAppLeave handler and ditch confirmModal
1 parent 6214a92 commit 13394f7

File tree

11 files changed

+81
-240
lines changed

11 files changed

+81
-240
lines changed

src/plugins/dashboard/public/application/top_nav/get_top_nav_config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
import { i18n } from '@kbn/i18n';
21+
import { AppMountParameters } from 'kibana/public';
2122
import { ViewMode } from '../../embeddable_plugin';
2223
import { TopNavIds } from './top_nav_ids';
2324
import { NavAction } from '../../types';
@@ -31,7 +32,8 @@ import { NavAction } from '../../types';
3132
export function getTopNavConfig(
3233
dashboardMode: ViewMode,
3334
actions: { [key: string]: NavAction },
34-
hideWriteControls: boolean
35+
hideWriteControls: boolean,
36+
onAppLeave?: AppMountParameters['onAppLeave']
3537
) {
3638
switch (dashboardMode) {
3739
case ViewMode.VIEW:

src/plugins/visualize/public/application/app.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import './app.scss';
2121
import React, { useEffect } from 'react';
2222
import { Route, Switch, useLocation } from 'react-router-dom';
2323

24+
import { AppMountParameters } from 'kibana/public';
2425
import { syncQueryStateWithUrl } from '../../../data/public';
2526
import { useKibana } from '../../../kibana_react/public';
2627
import { VisualizeServices } from './types';
@@ -32,7 +33,11 @@ import {
3233
} from './components';
3334
import { VisualizeConstants } from './visualize_constants';
3435

35-
export const VisualizeApp = () => {
36+
export interface VisualizeAppProps {
37+
onAppLeave: AppMountParameters['onAppLeave'];
38+
}
39+
40+
export const VisualizeApp = ({ onAppLeave }: VisualizeAppProps) => {
3641
const {
3742
services: {
3843
data: { query },
@@ -54,10 +59,10 @@ export const VisualizeApp = () => {
5459
return (
5560
<Switch>
5661
<Route exact path={`${VisualizeConstants.EDIT_BY_VALUE_PATH}`}>
57-
<VisualizeByValueEditor />
62+
<VisualizeByValueEditor onAppLeave={onAppLeave} />
5863
</Route>
5964
<Route path={[VisualizeConstants.CREATE_PATH, `${VisualizeConstants.EDIT_PATH}/:id`]}>
60-
<VisualizeEditor />
65+
<VisualizeEditor onAppLeave={onAppLeave} />
6166
</Route>
6267
<Route
6368
exact

src/plugins/visualize/public/application/components/visualize_byvalue_editor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ import {
3232
} from '../utils';
3333
import { VisualizeServices } from '../types';
3434
import { VisualizeEditorCommon } from './visualize_editor_common';
35+
import { VisualizeAppProps } from '../app';
3536

36-
export const VisualizeByValueEditor = () => {
37+
export const VisualizeByValueEditor = ({ onAppLeave }: VisualizeAppProps) => {
3738
const [originatingApp, setOriginatingApp] = useState<string>();
3839
const { services } = useKibana<VisualizeServices>();
3940
const [eventEmitter] = useState(new EventEmitter());
@@ -100,6 +101,7 @@ export const VisualizeByValueEditor = () => {
100101
setHasUnsavedChanges={setHasUnsavedChanges}
101102
visEditorRef={visEditorRef}
102103
embeddableId={embeddableId}
104+
onAppLeave={onAppLeave}
103105
/>
104106
);
105107
};

src/plugins/visualize/public/application/components/visualize_editor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ import {
3232
} from '../utils';
3333
import { VisualizeServices } from '../types';
3434
import { VisualizeEditorCommon } from './visualize_editor_common';
35+
import { VisualizeAppProps } from '../app';
3536

36-
export const VisualizeEditor = () => {
37+
export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => {
3738
const { id: visualizationIdFromUrl } = useParams<{ id: string }>();
3839
const [originatingApp, setOriginatingApp] = useState<string>();
3940
const { services } = useKibana<VisualizeServices>();
@@ -91,6 +92,7 @@ export const VisualizeEditor = () => {
9192
visualizationIdFromUrl={visualizationIdFromUrl}
9293
setHasUnsavedChanges={setHasUnsavedChanges}
9394
visEditorRef={visEditorRef}
95+
onAppLeave={onAppLeave}
9496
/>
9597
);
9698
};

src/plugins/visualize/public/application/components/visualize_editor_common.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import './visualize_editor.scss';
2020
import React, { RefObject } from 'react';
2121
import { FormattedMessage } from '@kbn/i18n/react';
2222
import { EuiScreenReaderOnly } from '@elastic/eui';
23+
import { AppMountParameters } from 'kibana/public';
2324
import { VisualizeTopNav } from './visualize_top_nav';
2425
import { ExperimentalVisInfo } from './experimental_vis_info';
2526
import {
@@ -38,6 +39,7 @@ interface VisualizeEditorCommonProps {
3839
setHasUnsavedChanges: (value: boolean) => void;
3940
hasUnappliedChanges: boolean;
4041
isEmbeddableRendered: boolean;
42+
onAppLeave: AppMountParameters['onAppLeave'];
4143
visEditorRef: RefObject<HTMLDivElement>;
4244
originatingApp?: string;
4345
setOriginatingApp?: (originatingApp: string | undefined) => void;
@@ -54,6 +56,7 @@ export const VisualizeEditorCommon = ({
5456
setHasUnsavedChanges,
5557
hasUnappliedChanges,
5658
isEmbeddableRendered,
59+
onAppLeave,
5760
originatingApp,
5861
setOriginatingApp,
5962
visualizationIdFromUrl,
@@ -76,6 +79,7 @@ export const VisualizeEditorCommon = ({
7679
stateContainer={appState}
7780
visualizationIdFromUrl={visualizationIdFromUrl}
7881
embeddableId={embeddableId}
82+
onAppLeave={onAppLeave}
7983
/>
8084
)}
8185
{visInstance?.vis?.type?.isExperimental && <ExperimentalVisInfo />}

src/plugins/visualize/public/application/components/visualize_top_nav.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
import React, { memo, useCallback, useMemo, useState, useEffect } from 'react';
2121

22-
import { OverlayRef } from 'kibana/public';
22+
import { AppMountParameters, OverlayRef } from 'kibana/public';
23+
import _ from 'lodash';
24+
import { i18n } from '@kbn/i18n';
2325
import { useKibana } from '../../../../kibana_react/public';
2426
import {
2527
VisualizeServices,
@@ -43,6 +45,7 @@ interface VisualizeTopNavProps {
4345
stateContainer: VisualizeAppStateContainer;
4446
visualizationIdFromUrl?: string;
4547
embeddableId?: string;
48+
onAppLeave: AppMountParameters['onAppLeave'];
4649
}
4750

4851
const TopNav = ({
@@ -58,10 +61,11 @@ const TopNav = ({
5861
stateContainer,
5962
visualizationIdFromUrl,
6063
embeddableId,
64+
onAppLeave,
6165
}: VisualizeTopNavProps) => {
6266
const { services } = useKibana<VisualizeServices>();
6367
const { TopNavMenu } = services.navigation.ui;
64-
const { setHeaderActionMenu } = services;
68+
const { setHeaderActionMenu, visualizeCapabilities } = services;
6569
const { embeddableHandler, vis } = visInstance;
6670
const [inspectorSession, setInspectorSession] = useState<OverlayRef>();
6771
const openInspector = useCallback(() => {
@@ -93,6 +97,7 @@ const TopNav = ({
9397
visualizationIdFromUrl,
9498
stateTransfer,
9599
embeddableId,
100+
onAppLeave,
96101
},
97102
services
98103
);
@@ -111,6 +116,7 @@ const TopNav = ({
111116
services,
112117
embeddableId,
113118
stateTransfer,
119+
onAppLeave,
114120
]);
115121
const [indexPattern, setIndexPattern] = useState(vis.data.indexPattern);
116122
const showDatePicker = () => {
@@ -131,6 +137,25 @@ const TopNav = ({
131137
};
132138
}, [inspectorSession]);
133139

140+
useEffect(() => {
141+
onAppLeave((actions) => {
142+
// Confirm when the user has made any changes to an existing doc
143+
// or when the user has configured something without saving
144+
if (hasUnappliedChanges || hasUnsavedChanges) {
145+
return actions.confirm(
146+
i18n.translate('visualize.confirmModal.confirmTextDescription', {
147+
defaultMessage: 'Leave Visualize editor with unsaved changes?',
148+
}),
149+
i18n.translate('visualize.confirmModal.title', {
150+
defaultMessage: 'Unsaved changes',
151+
})
152+
);
153+
} else {
154+
return actions.default();
155+
}
156+
});
157+
}, [onAppLeave, hasUnappliedChanges, hasUnsavedChanges, visualizeCapabilities.save]);
158+
134159
useEffect(() => {
135160
if (!vis.data.indexPattern) {
136161
services.data.indexPatterns.getDefault().then((index) => {

src/plugins/visualize/public/application/index.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ import { VisualizeApp } from './app';
2727
import { VisualizeServices } from './types';
2828
import { addHelpMenuToAppChrome, addBadgeToAppChrome } from './utils';
2929

30-
export const renderApp = ({ element }: AppMountParameters, services: VisualizeServices) => {
30+
export const renderApp = (
31+
{ element, onAppLeave }: AppMountParameters,
32+
services: VisualizeServices
33+
) => {
3134
// add help link to visualize docs into app chrome menu
3235
addHelpMenuToAppChrome(services.chrome, services.docLinks);
3336
// add readonly badge if saving restricted
@@ -39,7 +42,7 @@ export const renderApp = ({ element }: AppMountParameters, services: VisualizeSe
3942
<Router history={services.history}>
4043
<KibanaContextProvider services={services}>
4144
<services.i18n.Context>
42-
<VisualizeApp />
45+
<VisualizeApp onAppLeave={onAppLeave} />
4346
</services.i18n.Context>
4447
</KibanaContextProvider>
4548
</Router>

src/plugins/visualize/public/application/utils/confirm_modal.test.tsx

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/plugins/visualize/public/application/utils/confirm_modal.tsx

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)