mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Dashboard] Retain Viewmode State in Session (#112302)
* Made dashboard retain viewmode state in session. This means filters and query will be kept over reloads and navigations
This commit is contained in:
parent
126b87bd55
commit
5408a3e301
3 changed files with 125 additions and 78 deletions
|
@ -237,27 +237,25 @@ export const useDashboardAppState = ({
|
|||
.pipe(debounceTime(DashboardConstants.CHANGE_CHECK_DEBOUNCE))
|
||||
.subscribe((states) => {
|
||||
const [lastSaved, current] = states;
|
||||
const unsavedChanges =
|
||||
current.viewMode === ViewMode.EDIT ? diffDashboardState(lastSaved, current) : {};
|
||||
const unsavedChanges = diffDashboardState(lastSaved, current);
|
||||
|
||||
let savedTimeChanged = false;
|
||||
const savedTimeChanged =
|
||||
lastSaved.timeRestore &&
|
||||
!areTimeRangesEqual(
|
||||
{
|
||||
from: savedDashboard?.timeFrom,
|
||||
to: savedDashboard?.timeTo,
|
||||
},
|
||||
timefilter.getTime()
|
||||
);
|
||||
|
||||
/**
|
||||
* changes to the time filter should only be considered 'unsaved changes' when
|
||||
* changes to the dashboard should only be considered 'unsaved changes' when
|
||||
* editing the dashboard
|
||||
*/
|
||||
if (current.viewMode === ViewMode.EDIT) {
|
||||
savedTimeChanged =
|
||||
lastSaved.timeRestore &&
|
||||
!areTimeRangesEqual(
|
||||
{
|
||||
from: savedDashboard?.timeFrom,
|
||||
to: savedDashboard?.timeTo,
|
||||
},
|
||||
timefilter.getTime()
|
||||
);
|
||||
}
|
||||
const hasUnsavedChanges = Object.keys(unsavedChanges).length > 0 || savedTimeChanged;
|
||||
const hasUnsavedChanges =
|
||||
current.viewMode === ViewMode.EDIT &&
|
||||
(Object.keys(unsavedChanges).length > 0 || savedTimeChanged);
|
||||
setDashboardAppState((s) => ({ ...s, hasUnsavedChanges }));
|
||||
|
||||
unsavedChanges.viewMode = current.viewMode; // always push view mode into session store.
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Storage } from '../../services/kibana_utils';
|
|||
import { NotificationsStart } from '../../services/core';
|
||||
import { panelStorageErrorStrings } from '../../dashboard_strings';
|
||||
import { DashboardState } from '../../types';
|
||||
import { ViewMode } from '../../services/embeddable';
|
||||
|
||||
export const DASHBOARD_PANELS_UNSAVED_ID = 'unsavedDashboard';
|
||||
const DASHBOARD_PANELS_SESSION_KEY = 'dashboardStateManagerPanels';
|
||||
|
@ -69,6 +70,7 @@ export class DashboardSessionStorage {
|
|||
const dashboardsWithUnsavedChanges: string[] = [];
|
||||
Object.keys(dashboardStatesInSpace).map((dashboardId) => {
|
||||
if (
|
||||
dashboardStatesInSpace[dashboardId].viewMode === ViewMode.EDIT &&
|
||||
Object.keys(dashboardStatesInSpace[dashboardId]).some(
|
||||
(stateKey) => stateKey !== 'viewMode'
|
||||
)
|
||||
|
|
|
@ -12,6 +12,9 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const PageObjects = getPageObjects(['dashboard', 'header', 'visualize', 'settings', 'common']);
|
||||
const browser = getService('browser');
|
||||
const queryBar = getService('queryBar');
|
||||
const filterBar = getService('filterBar');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
@ -19,9 +22,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
let originalPanelCount = 0;
|
||||
let unsavedPanelCount = 0;
|
||||
const testQuery = 'Test Query';
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/91191
|
||||
describe.skip('dashboard unsaved panels', () => {
|
||||
describe('dashboard unsaved state', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('test/functional/fixtures/es_archiver/dashboard/current/kibana');
|
||||
await kibanaServer.uiSettings.replace({
|
||||
|
@ -31,79 +34,123 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.preserveCrossAppState();
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
originalPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
});
|
||||
|
||||
it('does not show unsaved changes badge when there are no unsaved changes', async () => {
|
||||
await testSubjects.missingOrFail('dashboardUnsavedChangesBadge');
|
||||
describe('view mode state', () => {
|
||||
before(async () => {
|
||||
await queryBar.setQuery(testQuery);
|
||||
await filterBar.addFilter('bytes', 'exists');
|
||||
await queryBar.submitQuery();
|
||||
});
|
||||
|
||||
const validateQueryAndFilter = async () => {
|
||||
const query = await queryBar.getQueryString();
|
||||
expect(query).to.eql(testQuery);
|
||||
const filterCount = await filterBar.getFilterCount();
|
||||
expect(filterCount).to.eql(1);
|
||||
};
|
||||
|
||||
it('persists after navigating to the listing page and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.gotoDashboardLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await validateQueryAndFilter();
|
||||
});
|
||||
|
||||
it('persists after navigating to Visualize and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.visualize.gotoVisualizationLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.common.navigateToApp('dashboards');
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await validateQueryAndFilter();
|
||||
});
|
||||
|
||||
it('persists after a hard refresh', async () => {
|
||||
await browser.refresh();
|
||||
const alert = await browser.getAlert();
|
||||
await alert?.accept();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await validateQueryAndFilter();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
// discard changes made in view mode
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows the unsaved changes badge after adding panels', async () => {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
// add an area chart by value
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationAndReturn();
|
||||
describe('edit mode state', () => {
|
||||
const addPanels = async () => {
|
||||
// add an area chart by value
|
||||
await dashboardAddPanel.clickEditorMenuButton();
|
||||
await dashboardAddPanel.clickAggBasedVisualizations();
|
||||
await PageObjects.visualize.clickAreaChart();
|
||||
await PageObjects.visualize.clickNewSearch();
|
||||
await PageObjects.visualize.saveVisualizationAndReturn();
|
||||
|
||||
// add a metric by reference
|
||||
await dashboardAddPanel.addVisualization('Rendering-Test: metric');
|
||||
// add a metric by reference
|
||||
await dashboardAddPanel.addVisualization('Rendering-Test: metric');
|
||||
};
|
||||
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.existOrFail('dashboardUnsavedChangesBadge');
|
||||
});
|
||||
it('does not show unsaved changes badge when there are no unsaved changes', async () => {
|
||||
await testSubjects.missingOrFail('dashboardUnsavedChangesBadge');
|
||||
});
|
||||
|
||||
it('has correct number of panels', async () => {
|
||||
unsavedPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(unsavedPanelCount).to.eql(originalPanelCount + 2);
|
||||
});
|
||||
it('shows the unsaved changes badge after adding panels', async () => {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await addPanels();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.existOrFail('dashboardUnsavedChangesBadge');
|
||||
});
|
||||
|
||||
it('retains unsaved panel count after navigating to listing page and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.gotoDashboardLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(unsavedPanelCount);
|
||||
});
|
||||
it('has correct number of panels', async () => {
|
||||
unsavedPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(unsavedPanelCount).to.eql(originalPanelCount + 2);
|
||||
});
|
||||
|
||||
it('retains unsaved panel count after navigating to another app and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.visualize.gotoVisualizationLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.common.navigateToApp('dashboards');
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(unsavedPanelCount);
|
||||
});
|
||||
it('retains unsaved panel count after navigating to listing page and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.gotoDashboardLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(unsavedPanelCount);
|
||||
});
|
||||
|
||||
it('resets to original panel count upon entering view mode', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(originalPanelCount);
|
||||
});
|
||||
it('retains unsaved panel count after navigating to another app and back', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.visualize.gotoVisualizationLandingPage();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.common.navigateToApp('dashboards');
|
||||
await PageObjects.dashboard.loadSavedDashboard('few panels');
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(unsavedPanelCount);
|
||||
});
|
||||
|
||||
it('shows unsaved changes badge in view mode if changes have not been discarded', async () => {
|
||||
await testSubjects.existOrFail('dashboardUnsavedChangesBadge');
|
||||
});
|
||||
it('resets to original panel count after discarding changes', async () => {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.clickCancelOutOfEditMode();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const currentPanelCount = await PageObjects.dashboard.getPanelCount();
|
||||
expect(currentPanelCount).to.eql(originalPanelCount);
|
||||
expect(PageObjects.dashboard.getIsInViewMode()).to.eql(true);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
it('does not show unsaved changes badge after saving', async () => {
|
||||
await PageObjects.dashboard.saveDashboard('Unsaved State Test');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.missingOrFail('dashboardUnsavedChangesBadge');
|
||||
it('does not show unsaved changes badge after saving', async () => {
|
||||
await PageObjects.dashboard.switchToEditMode();
|
||||
await addPanels();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.saveDashboard('Unsaved State Test');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.missingOrFail('dashboardUnsavedChangesBadge');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue