Skip to content

Commit

Permalink
[Time to Visualize] Stay in Edit Mode After Dashboard Quicksave (#91729)
Browse files Browse the repository at this point in the history
* Make quicksave function stay in edit mode
  • Loading branch information
ThomThomson committed Feb 19, 2021
1 parent 269a633 commit 0095681
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 110 deletions.
1 change: 1 addition & 0 deletions src/plugins/dashboard/public/application/dashboard_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ export function DashboardApp({
}}
viewMode={viewMode}
lastDashboardId={savedDashboardId}
clearUnsavedChanges={() => setUnsavedChanges(false)}
timefilter={data.query.timefilter.timefilter}
onQuerySubmit={(_payload, isUpdate) => {
if (isUpdate === false) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export class DashboardStateManager {
/**
* Resets the state back to the last saved version of the dashboard.
*/
public resetState() {
public resetState(resetViewMode: boolean) {
// In order to show the correct warning, we have to store the unsaved
// title on the dashboard object. We should fix this at some point, but this is how all the other object
// save panels work at the moment.
Expand All @@ -366,9 +366,14 @@ export class DashboardStateManager {
this.stateDefaults.query = this.lastSavedDashboardFilters.query;
// Need to make a copy to ensure they are not overwritten.
this.stateDefaults.filters = [...this.getLastSavedFilterBars()];

this.isDirty = false;
this.stateContainer.set(this.stateDefaults);

if (resetViewMode) {
this.stateContainer.set(this.stateDefaults);
} else {
const currentViewMode = this.stateContainer.get().viewMode;
this.stateContainer.set({ ...this.stateDefaults, viewMode: currentViewMode });
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { SavedObjectSaveOpts } from '../../services/saved_objects';
import { updateSavedDashboard } from './update_saved_dashboard';
import { DashboardStateManager } from '../dashboard_state_manager';

export type SavedDashboardSaveOpts = SavedObjectSaveOpts & { stayInEditMode?: boolean };

/**
* Saves the dashboard.
* @param toJson A custom toJson function. Used because the previous code used
Expand All @@ -23,7 +25,7 @@ export function saveDashboard(
toJson: (obj: any) => string,
timeFilter: TimefilterContract,
dashboardStateManager: DashboardStateManager,
saveOptions: SavedObjectSaveOpts
saveOptions: SavedDashboardSaveOpts
): Promise<string> {
const savedDashboard = dashboardStateManager.savedDashboard;
const appState = dashboardStateManager.appState;
Expand All @@ -36,7 +38,7 @@ export function saveDashboard(
// reset state only when save() was successful
// e.g. save() could be interrupted if title is duplicated and not confirmed
dashboardStateManager.lastSavedDashboardFilters = dashboardStateManager.getFilterState();
dashboardStateManager.resetState();
dashboardStateManager.resetState(!saveOptions.stayInEditMode);
}

return id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@ import {
} from '@elastic/eui';
import React from 'react';
import { OverlayStart } from '../../../../../core/public';
import { createConfirmStrings, leaveConfirmStrings } from '../../dashboard_strings';
import {
createConfirmStrings,
discardConfirmStrings,
leaveEditModeConfirmStrings,
} from '../../dashboard_strings';
import { toMountPoint } from '../../services/kibana_react';

export const confirmDiscardUnsavedChanges = (
overlays: OverlayStart,
discardCallback: () => void,
cancelButtonText = leaveConfirmStrings.getCancelButtonText()
) =>
export type DiscardOrKeepSelection = 'cancel' | 'discard' | 'keep';

export const confirmDiscardUnsavedChanges = (overlays: OverlayStart, discardCallback: () => void) =>
overlays
.openConfirm(leaveConfirmStrings.getDiscardSubtitle(), {
confirmButtonText: leaveConfirmStrings.getConfirmButtonText(),
cancelButtonText,
.openConfirm(discardConfirmStrings.getDiscardSubtitle(), {
confirmButtonText: discardConfirmStrings.getDiscardConfirmButtonText(),
cancelButtonText: discardConfirmStrings.getDiscardCancelButtonText(),
buttonColor: 'danger',
defaultFocusedButton: EUI_MODAL_CANCEL_BUTTON,
title: leaveConfirmStrings.getDiscardTitle(),
title: discardConfirmStrings.getDiscardTitle(),
})
.then((isConfirmed) => {
if (isConfirmed) {
discardCallback();
}
});

export type DiscardOrKeepSelection = 'cancel' | 'discard' | 'keep';

export const confirmDiscardOrKeepUnsavedChanges = (
overlays: OverlayStart
): Promise<DiscardOrKeepSelection> => {
Expand All @@ -50,45 +50,48 @@ export const confirmDiscardOrKeepUnsavedChanges = (
toMountPoint(
<>
<EuiModalHeader data-test-subj="dashboardDiscardConfirm">
<EuiModalHeaderTitle>{leaveConfirmStrings.getLeaveEditModeTitle()}</EuiModalHeaderTitle>
<EuiModalHeaderTitle>
{leaveEditModeConfirmStrings.getLeaveEditModeTitle()}
</EuiModalHeaderTitle>
</EuiModalHeader>

<EuiModalBody>
<EuiText>{leaveConfirmStrings.getLeaveEditModeSubtitle()}</EuiText>
<EuiText>{leaveEditModeConfirmStrings.getLeaveEditModeSubtitle()}</EuiText>
</EuiModalBody>

<EuiModalFooter>
<EuiButtonEmpty
data-test-subj="dashboardDiscardConfirmCancel"
onClick={() => session.close()}
>
{leaveConfirmStrings.getCancelButtonText()}
{leaveEditModeConfirmStrings.getLeaveEditModeCancelButtonText()}
</EuiButtonEmpty>
<EuiButtonEmpty
data-test-subj="dashboardDiscardConfirmKeep"
color="danger"
data-test-subj="dashboardDiscardConfirmDiscard"
onClick={() => {
session.close();
resolve('keep');
resolve('discard');
}}
>
{leaveConfirmStrings.getKeepChangesText()}
{leaveEditModeConfirmStrings.getLeaveEditModeDiscardButtonText()}
</EuiButtonEmpty>
<EuiButton
fill
color="danger"
data-test-subj="dashboardDiscardConfirmDiscard"
data-test-subj="dashboardDiscardConfirmKeep"
onClick={() => {
session.close();
resolve('discard');
resolve('keep');
}}
>
{leaveConfirmStrings.getConfirmButtonText()}
{leaveEditModeConfirmStrings.getLeaveEditModeKeepChangesText()}
</EuiButton>
</EuiModalFooter>
</>
),
{
'data-test-subj': 'dashboardDiscardConfirmModal',
maxWidth: 550,
}
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ import {
} from '@elastic/eui';
import React, { useCallback, useEffect, useState } from 'react';
import { DashboardSavedObject } from '../..';
import {
createConfirmStrings,
dashboardUnsavedListingStrings,
getNewDashboardTitle,
} from '../../dashboard_strings';
import { dashboardUnsavedListingStrings, getNewDashboardTitle } from '../../dashboard_strings';
import { useKibana } from '../../services/kibana_react';
import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage';
import { DashboardAppServices, DashboardRedirect } from '../types';
Expand Down Expand Up @@ -136,14 +132,10 @@ export const DashboardUnsavedListing = ({

const onDiscard = useCallback(
(id?: string) => {
confirmDiscardUnsavedChanges(
overlays,
() => {
dashboardPanelStorage.clearPanels(id);
refreshUnsavedDashboards();
},
createConfirmStrings.getCancelButtonText()
);
confirmDiscardUnsavedChanges(overlays, () => {
dashboardPanelStorage.clearPanels(id);
refreshUnsavedDashboards();
});
},
[overlays, refreshUnsavedDashboards, dashboardPanelStorage]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ import {
openAddPanelFlyout,
ViewMode,
} from '../../services/embeddable';
import {
getSavedObjectFinder,
SavedObjectSaveOpts,
SaveResult,
showSaveModal,
} from '../../services/saved_objects';
import { getSavedObjectFinder, SaveResult, showSaveModal } from '../../services/saved_objects';

import { NavAction } from '../../types';
import { DashboardSavedObject } from '../..';
Expand All @@ -48,6 +43,7 @@ import { OverlayRef } from '../../../../../core/public';
import { getNewDashboardTitle, unsavedChangesBadge } from '../../dashboard_strings';
import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage';
import { DashboardContainer } from '..';
import { SavedDashboardSaveOpts } from '../lib/save_dashboard';

export interface DashboardTopNavState {
chromeIsVisible: boolean;
Expand All @@ -64,13 +60,15 @@ export interface DashboardTopNavProps {
timefilter: TimefilterContract;
indexPatterns: IndexPattern[];
redirectTo: DashboardRedirect;
unsavedChanges?: boolean;
unsavedChanges: boolean;
clearUnsavedChanges: () => void;
lastDashboardId?: string;
viewMode: ViewMode;
}

export function DashboardTopNav({
dashboardStateManager,
clearUnsavedChanges,
dashboardContainer,
lastDashboardId,
unsavedChanges,
Expand Down Expand Up @@ -98,6 +96,7 @@ export function DashboardTopNav({
} = useKibana<DashboardAppServices>().services;

const [state, setState] = useState<DashboardTopNavState>({ chromeIsVisible: false });
const [isSaveInProgress, setIsSaveInProgress] = useState(false);

useEffect(() => {
const visibleSubscription = chrome.getIsVisible$().subscribe((chromeIsVisible) => {
Expand Down Expand Up @@ -177,7 +176,7 @@ export function DashboardTopNav({
}

function discardChanges() {
dashboardStateManager.resetState();
dashboardStateManager.resetState(true);
dashboardStateManager.clearUnsavedPanels();

// We need to do a hard reset of the timepicker. appState will not reload like
Expand Down Expand Up @@ -222,7 +221,7 @@ export function DashboardTopNav({
* @resolved {String} - The id of the doc
*/
const save = useCallback(
async (saveOptions: SavedObjectSaveOpts) => {
async (saveOptions: SavedDashboardSaveOpts) => {
return saveDashboard(angular.toJson, timefilter, dashboardStateManager, saveOptions)
.then(function (id) {
if (id) {
Expand All @@ -239,7 +238,6 @@ export function DashboardTopNav({
redirectTo({ destination: 'dashboard', id, useReplace: !lastDashboardId });
} else {
chrome.docTitle.change(dashboardStateManager.savedDashboard.lastSavedTitle);
dashboardStateManager.switchViewMode(ViewMode.VIEW);
}
}
return { id };
Expand Down Expand Up @@ -355,7 +353,8 @@ export function DashboardTopNav({
}
}

save({}).then((response: SaveResult) => {
setIsSaveInProgress(true);
save({ stayInEditMode: true }).then((response: SaveResult) => {
// If the save wasn't successful, put the original values back.
if (!(response as { id: string }).id) {
dashboardStateManager.setTitle(currentTitle);
Expand All @@ -364,10 +363,13 @@ export function DashboardTopNav({
if (savedObjectsTagging) {
dashboardStateManager.setTags(currentTags);
}
} else {
clearUnsavedChanges();
}
setIsSaveInProgress(false);
return response;
});
}, [save, savedObjectsTagging, dashboardStateManager]);
}, [save, savedObjectsTagging, dashboardStateManager, clearUnsavedChanges]);

const runClone = useCallback(() => {
const currentTitle = dashboardStateManager.getTitle();
Expand Down Expand Up @@ -467,6 +469,7 @@ export function DashboardTopNav({
hideWriteControls: dashboardCapabilities.hideWriteControls,
isNewDashboard: !savedDashboard.id,
isDirty: dashboardStateManager.isDirty,
isSaveInProgress,
});

const badges = unsavedChanges
Expand Down
Loading

0 comments on commit 0095681

Please sign in to comment.