mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Time to Visualize] Combine Discard & Cancel (#91267)
* recombined discard and cancel button functionality
This commit is contained in:
parent
d5aea9378a
commit
6f857dd7f3
9 changed files with 139 additions and 70 deletions
|
@ -40,6 +40,60 @@ export const confirmDiscardUnsavedChanges = (
|
|||
}
|
||||
});
|
||||
|
||||
export type DiscardOrKeepSelection = 'cancel' | 'discard' | 'keep';
|
||||
|
||||
export const confirmDiscardOrKeepUnsavedChanges = (
|
||||
overlays: OverlayStart
|
||||
): Promise<DiscardOrKeepSelection> => {
|
||||
return new Promise((resolve) => {
|
||||
const session = overlays.openModal(
|
||||
toMountPoint(
|
||||
<>
|
||||
<EuiModalHeader data-test-subj="dashboardDiscardConfirm">
|
||||
<EuiModalHeaderTitle>{leaveConfirmStrings.getLeaveEditModeTitle()}</EuiModalHeaderTitle>
|
||||
</EuiModalHeader>
|
||||
|
||||
<EuiModalBody>
|
||||
<EuiText>{leaveConfirmStrings.getLeaveEditModeSubtitle()}</EuiText>
|
||||
</EuiModalBody>
|
||||
|
||||
<EuiModalFooter>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="dashboardDiscardConfirmCancel"
|
||||
onClick={() => session.close()}
|
||||
>
|
||||
{leaveConfirmStrings.getCancelButtonText()}
|
||||
</EuiButtonEmpty>
|
||||
<EuiButtonEmpty
|
||||
data-test-subj="dashboardDiscardConfirmKeep"
|
||||
onClick={() => {
|
||||
session.close();
|
||||
resolve('keep');
|
||||
}}
|
||||
>
|
||||
{leaveConfirmStrings.getKeepChangesText()}
|
||||
</EuiButtonEmpty>
|
||||
<EuiButton
|
||||
fill
|
||||
color="danger"
|
||||
data-test-subj="dashboardDiscardConfirmDiscard"
|
||||
onClick={() => {
|
||||
session.close();
|
||||
resolve('discard');
|
||||
}}
|
||||
>
|
||||
{leaveConfirmStrings.getConfirmButtonText()}
|
||||
</EuiButton>
|
||||
</EuiModalFooter>
|
||||
</>
|
||||
),
|
||||
{
|
||||
'data-test-subj': 'dashboardDiscardConfirmModal',
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const confirmCreateWithUnsaved = (
|
||||
overlays: OverlayStart,
|
||||
startBlankCallback: () => void,
|
||||
|
|
|
@ -43,7 +43,7 @@ import { showOptionsPopover } from './show_options_popover';
|
|||
import { TopNavIds } from './top_nav_ids';
|
||||
import { ShowShareModal } from './show_share_modal';
|
||||
import { PanelToolbar } from './panel_toolbar';
|
||||
import { confirmDiscardUnsavedChanges } from '../listing/confirm_overlays';
|
||||
import { confirmDiscardOrKeepUnsavedChanges } from '../listing/confirm_overlays';
|
||||
import { OverlayRef } from '../../../../../core/public';
|
||||
import { getNewDashboardTitle } from '../../dashboard_strings';
|
||||
import { DASHBOARD_PANELS_UNSAVED_ID } from '../lib/dashboard_panel_storage';
|
||||
|
@ -152,34 +152,53 @@ export function DashboardTopNav({
|
|||
}
|
||||
}, [state.addPanelOverlay]);
|
||||
|
||||
const onDiscardChanges = useCallback(() => {
|
||||
function revertChangesAndExitEditMode() {
|
||||
dashboardStateManager.resetState();
|
||||
dashboardStateManager.clearUnsavedPanels();
|
||||
|
||||
// We need to do a hard reset of the timepicker. appState will not reload like
|
||||
// it does on 'open' because it's been saved to the url and the getAppState.previouslyStored() check on
|
||||
// reload will cause it not to sync.
|
||||
if (dashboardStateManager.getIsTimeSavedWithDashboard()) {
|
||||
dashboardStateManager.syncTimefilterWithDashboardTime(timefilter);
|
||||
dashboardStateManager.syncTimefilterWithDashboardRefreshInterval(timefilter);
|
||||
}
|
||||
dashboardStateManager.switchViewMode(ViewMode.VIEW);
|
||||
}
|
||||
confirmDiscardUnsavedChanges(core.overlays, revertChangesAndExitEditMode);
|
||||
}, [core.overlays, dashboardStateManager, timefilter]);
|
||||
|
||||
const onChangeViewMode = useCallback(
|
||||
(newMode: ViewMode) => {
|
||||
clearAddPanel();
|
||||
if (savedDashboard?.id && allowByValueEmbeddables) {
|
||||
const { getFullEditPath, title, id } = savedDashboard;
|
||||
chrome.recentlyAccessed.add(getFullEditPath(newMode === ViewMode.EDIT), title, id);
|
||||
const isPageRefresh = newMode === dashboardStateManager.getViewMode();
|
||||
const isLeavingEditMode = !isPageRefresh && newMode === ViewMode.VIEW;
|
||||
const willLoseChanges = isLeavingEditMode && dashboardStateManager.getIsDirty(timefilter);
|
||||
|
||||
function switchViewMode() {
|
||||
dashboardStateManager.switchViewMode(newMode);
|
||||
dashboardStateManager.restorePanels();
|
||||
|
||||
if (savedDashboard?.id && allowByValueEmbeddables) {
|
||||
const { getFullEditPath, title, id } = savedDashboard;
|
||||
chrome.recentlyAccessed.add(getFullEditPath(newMode === ViewMode.EDIT), title, id);
|
||||
}
|
||||
}
|
||||
dashboardStateManager.switchViewMode(newMode);
|
||||
dashboardStateManager.restorePanels();
|
||||
|
||||
if (!willLoseChanges) {
|
||||
switchViewMode();
|
||||
return;
|
||||
}
|
||||
|
||||
function discardChanges() {
|
||||
dashboardStateManager.resetState();
|
||||
dashboardStateManager.clearUnsavedPanels();
|
||||
|
||||
// We need to do a hard reset of the timepicker. appState will not reload like
|
||||
// it does on 'open' because it's been saved to the url and the getAppState.previouslyStored() check on
|
||||
// reload will cause it not to sync.
|
||||
if (dashboardStateManager.getIsTimeSavedWithDashboard()) {
|
||||
dashboardStateManager.syncTimefilterWithDashboardTime(timefilter);
|
||||
dashboardStateManager.syncTimefilterWithDashboardRefreshInterval(timefilter);
|
||||
}
|
||||
dashboardStateManager.switchViewMode(ViewMode.VIEW);
|
||||
}
|
||||
confirmDiscardOrKeepUnsavedChanges(core.overlays).then((selection) => {
|
||||
if (selection === 'discard') {
|
||||
discardChanges();
|
||||
}
|
||||
if (selection !== 'cancel') {
|
||||
switchViewMode();
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
timefilter,
|
||||
core.overlays,
|
||||
clearAddPanel,
|
||||
savedDashboard,
|
||||
dashboardStateManager,
|
||||
|
@ -381,7 +400,6 @@ export function DashboardTopNav({
|
|||
},
|
||||
[TopNavIds.EXIT_EDIT_MODE]: () => onChangeViewMode(ViewMode.VIEW),
|
||||
[TopNavIds.ENTER_EDIT_MODE]: () => onChangeViewMode(ViewMode.EDIT),
|
||||
[TopNavIds.DISCARD_CHANGES]: onDiscardChanges,
|
||||
[TopNavIds.SAVE]: runSave,
|
||||
[TopNavIds.QUICK_SAVE]: runQuickSave,
|
||||
[TopNavIds.CLONE]: runClone,
|
||||
|
@ -417,7 +435,6 @@ export function DashboardTopNav({
|
|||
}, [
|
||||
dashboardCapabilities,
|
||||
dashboardStateManager,
|
||||
onDiscardChanges,
|
||||
onChangeViewMode,
|
||||
savedDashboard,
|
||||
runClone,
|
||||
|
|
|
@ -41,14 +41,12 @@ export function getTopNavConfig(
|
|||
getOptionsConfig(actions[TopNavIds.OPTIONS]),
|
||||
getShareConfig(actions[TopNavIds.SHARE]),
|
||||
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
|
||||
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
|
||||
getSaveConfig(actions[TopNavIds.SAVE], options.isNewDashboard),
|
||||
]
|
||||
: [
|
||||
getOptionsConfig(actions[TopNavIds.OPTIONS]),
|
||||
getShareConfig(actions[TopNavIds.SHARE]),
|
||||
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
|
||||
getDiscardConfig(actions[TopNavIds.DISCARD_CHANGES]),
|
||||
getSaveConfig(actions[TopNavIds.SAVE]),
|
||||
getQuickSave(actions[TopNavIds.QUICK_SAVE]),
|
||||
];
|
||||
|
@ -154,23 +152,6 @@ function getViewConfig(action: NavAction) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {kbnTopNavConfig}
|
||||
*/
|
||||
function getDiscardConfig(action: NavAction) {
|
||||
return {
|
||||
id: 'discard',
|
||||
label: i18n.translate('dashboard.topNave.discardlButtonAriaLabel', {
|
||||
defaultMessage: 'discard',
|
||||
}),
|
||||
description: i18n.translate('dashboard.topNave.discardConfigDescription', {
|
||||
defaultMessage: 'Discard unsaved changes',
|
||||
}),
|
||||
testId: 'dashboardDiscardChanges',
|
||||
run: action,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {kbnTopNavConfig}
|
||||
*/
|
||||
|
|
|
@ -13,7 +13,6 @@ export const TopNavIds = {
|
|||
SAVE: 'save',
|
||||
EXIT_EDIT_MODE: 'exitEditMode',
|
||||
ENTER_EDIT_MODE: 'enterEditMode',
|
||||
DISCARD_CHANGES: 'discard',
|
||||
CLONE: 'clone',
|
||||
FULL_SCREEN: 'fullScreenMode',
|
||||
};
|
||||
|
|
|
@ -253,6 +253,18 @@ export const leaveConfirmStrings = {
|
|||
i18n.translate('dashboard.appLeaveConfirmModal.unsavedChangesSubtitle', {
|
||||
defaultMessage: 'Leave Dashboard with unsaved work?',
|
||||
}),
|
||||
getKeepChangesText: () =>
|
||||
i18n.translate('dashboard.appLeaveConfirmModal.keepUnsavedChangesButtonLabel', {
|
||||
defaultMessage: 'Keep unsaved changes',
|
||||
}),
|
||||
getLeaveEditModeTitle: () =>
|
||||
i18n.translate('dashboard.changeViewModeConfirmModal.leaveEditMode', {
|
||||
defaultMessage: 'Leave edit mode with unsaved work?',
|
||||
}),
|
||||
getLeaveEditModeSubtitle: () =>
|
||||
i18n.translate('dashboard.changeViewModeConfirmModal.discardChangesOptionalDescription', {
|
||||
defaultMessage: `If you discard your changes, there's no getting them back.`,
|
||||
}),
|
||||
getDiscardTitle: () =>
|
||||
i18n.translate('dashboard.changeViewModeConfirmModal.discardChangesTitle', {
|
||||
defaultMessage: 'Discard changes to dashboard?',
|
||||
|
|
|
@ -110,12 +110,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('Exit out of edit mode', async () => {
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
await PageObjects.dashboard.clickDiscardChanges(false);
|
||||
await a11y.testAppSnapshot();
|
||||
});
|
||||
|
||||
it('Discard changes', async () => {
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
await testSubjects.exists('dashboardDiscardConfirmDiscard');
|
||||
await testSubjects.click('dashboardDiscardConfirmDiscard');
|
||||
await PageObjects.dashboard.getIsInViewMode();
|
||||
await a11y.testAppSnapshot();
|
||||
});
|
||||
|
|
|
@ -80,6 +80,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
it('retains unsaved panel count after returning to edit mode', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(unsavedPanelCount);
|
||||
});
|
||||
|
|
|
@ -15,6 +15,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['dashboard', 'header', 'common', 'visualize', 'timePicker']);
|
||||
const dashboardName = 'dashboard with filter';
|
||||
const filterBar = getService('filterBar');
|
||||
|
@ -74,9 +75,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
);
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
|
||||
// confirm lose changes
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
const newTime = await PageObjects.timePicker.getTimeConfig();
|
||||
|
||||
expect(newTime.start).to.equal(originalTime.start);
|
||||
|
@ -90,9 +88,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
|
||||
// confirm lose changes
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
const query = await queryBar.getQueryString();
|
||||
expect(query).to.equal(originalQuery);
|
||||
});
|
||||
|
@ -113,9 +108,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
|
||||
// confirm lose changes
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
hasFilter = await filterBar.hasFilter('animal', 'dog');
|
||||
expect(hasFilter).to.be(true);
|
||||
});
|
||||
|
@ -133,12 +125,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
redirectToOrigin: true,
|
||||
});
|
||||
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
await PageObjects.dashboard.clickDiscardChanges(false);
|
||||
// for this sleep see https://github.com/elastic/kibana/issues/22299
|
||||
await PageObjects.common.sleep(500);
|
||||
|
||||
// confirm lose changes
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
await testSubjects.exists('dashboardDiscardConfirmDiscard');
|
||||
await testSubjects.click('dashboardDiscardConfirmDiscard');
|
||||
|
||||
const panelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(panelCount).to.eql(originalPanelCount);
|
||||
|
@ -150,9 +143,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await dashboardAddPanel.addVisualization('new viz panel');
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
|
||||
// confirm lose changes
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
|
||||
const panelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(panelCount).to.eql(originalPanelCount);
|
||||
});
|
||||
|
@ -171,9 +161,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
'Sep 19, 2015 @ 06:31:44.000',
|
||||
'Sep 19, 2015 @ 06:31:44.000'
|
||||
);
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
await PageObjects.dashboard.clickDiscardChanges(false);
|
||||
|
||||
await PageObjects.common.clickCancelOnModal();
|
||||
await testSubjects.exists('dashboardDiscardConfirmCancel');
|
||||
await testSubjects.click('dashboardDiscardConfirmCancel');
|
||||
await PageObjects.dashboard.saveDashboard(dashboardName, {
|
||||
storeTimeWithDashboard: true,
|
||||
});
|
||||
|
@ -200,9 +191,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
);
|
||||
const newTime = await PageObjects.timePicker.getTimeConfig();
|
||||
|
||||
await PageObjects.dashboard.clickDiscardChanges();
|
||||
await PageObjects.dashboard.clickDiscardChanges(false);
|
||||
|
||||
await PageObjects.common.clickCancelOnModal();
|
||||
await testSubjects.exists('dashboardDiscardConfirmCancel');
|
||||
await testSubjects.click('dashboardDiscardConfirmCancel');
|
||||
await PageObjects.dashboard.saveDashboard(dashboardName, { storeTimeWithDashboard: true });
|
||||
|
||||
await PageObjects.dashboard.loadSavedDashboard(dashboardName);
|
||||
|
@ -223,7 +215,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
'Oct 19, 2014 @ 06:31:44.000',
|
||||
'Dec 19, 2014 @ 06:31:44.000'
|
||||
);
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode();
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode(false);
|
||||
|
||||
await PageObjects.common.expectConfirmModalOpenState(false);
|
||||
});
|
||||
|
@ -235,7 +227,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const originalQuery = await queryBar.getQueryString();
|
||||
await queryBar.setQuery(`${originalQuery}extra stuff`);
|
||||
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode();
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode(false);
|
||||
|
||||
await PageObjects.common.expectConfirmModalOpenState(false);
|
||||
|
||||
|
|
|
@ -246,14 +246,26 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide
|
|||
return await testSubjects.exists('dashboardEditMode');
|
||||
}
|
||||
|
||||
public async clickCancelOutOfEditMode() {
|
||||
public async clickCancelOutOfEditMode(accept = true) {
|
||||
log.debug('clickCancelOutOfEditMode');
|
||||
await testSubjects.click('dashboardViewOnlyMode');
|
||||
if (accept) {
|
||||
const confirmation = await testSubjects.exists('dashboardDiscardConfirmKeep');
|
||||
if (confirmation) {
|
||||
await testSubjects.click('dashboardDiscardConfirmKeep');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async clickDiscardChanges() {
|
||||
public async clickDiscardChanges(accept = true) {
|
||||
log.debug('clickDiscardChanges');
|
||||
await testSubjects.click('dashboardDiscardChanges');
|
||||
await testSubjects.click('dashboardViewOnlyMode');
|
||||
if (accept) {
|
||||
const confirmation = await testSubjects.exists('dashboardDiscardConfirmDiscard');
|
||||
if (confirmation) {
|
||||
await testSubjects.click('dashboardDiscardConfirmDiscard');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async clickQuickSave() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue