mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Lens] unnecessary unsavedChanges badge on dashboard for text based (#162482)
## Summary When you have a text based visualization in a dashboard and you click to edit it, then the unsaved changes badge appears. What happens is we create store, and then we run loadInitial action with the data from the attributes and then the store gets the state from those attributes and pushes the change to the new updater middleware with exactly the same data. It doesn’t affect visualization in any way as the state is correct, but the dashboard thinks there were some changes. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
7f002de706
commit
580b1765f7
2 changed files with 105 additions and 5 deletions
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { mockStoreDeps } from '../../../mocks';
|
||||
import {
|
||||
initEmpty,
|
||||
initExisting,
|
||||
makeConfigureStore,
|
||||
setState,
|
||||
updateDatasourceState,
|
||||
updateVisualizationState,
|
||||
} from '../../../state_management';
|
||||
import { updatingMiddleware } from './get_edit_lens_configuration';
|
||||
|
||||
describe('Lens flyout', () => {
|
||||
let store: ReturnType<typeof makeConfigureStore>;
|
||||
const updaterFn = jest.fn();
|
||||
beforeEach(() => {
|
||||
store = makeConfigureStore(mockStoreDeps(), undefined, updatingMiddleware(updaterFn));
|
||||
store.dispatch = jest.fn(store.dispatch);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('updatingMiddleware for the Lens flyout', () => {
|
||||
test('updater is not run on store creation', () => {
|
||||
expect(updaterFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('updater is run if modifies visualization or datasource state', () => {
|
||||
store.dispatch(
|
||||
updateDatasourceState({
|
||||
datasourceId: 'testDatasource2',
|
||||
newDatasourceState: 'newDatasourceState',
|
||||
})
|
||||
);
|
||||
expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', null);
|
||||
store.dispatch(
|
||||
updateVisualizationState({ visualizationId: 'testVis', newState: 'newVisState' })
|
||||
);
|
||||
expect(updaterFn).toHaveBeenCalledWith('newDatasourceState', 'newVisState');
|
||||
});
|
||||
|
||||
test('updater is not run if it does not modify visualization or datasource state', () => {
|
||||
// assigning the states to {} to test equality by value check
|
||||
store.dispatch(
|
||||
setState({
|
||||
datasourceStates: {
|
||||
testDatasource: { state: {}, isLoading: true },
|
||||
testDatasource2: { state: {}, isLoading: true },
|
||||
},
|
||||
visualization: { state: {}, activeId: 'testVis' },
|
||||
})
|
||||
);
|
||||
updaterFn.mockClear();
|
||||
|
||||
// testing
|
||||
store.dispatch(
|
||||
updateDatasourceState({
|
||||
datasourceId: 'testDatasource2',
|
||||
newDatasourceState: {},
|
||||
})
|
||||
);
|
||||
store.dispatch(updateVisualizationState({ visualizationId: 'testVis', newState: {} }));
|
||||
expect(updaterFn).not.toHaveBeenCalled();
|
||||
});
|
||||
test('updater is not run on store initialization actions', () => {
|
||||
store.dispatch(
|
||||
initEmpty({
|
||||
newState: { visualization: { state: {}, activeId: 'testVis' } },
|
||||
})
|
||||
);
|
||||
store.dispatch(
|
||||
initExisting({
|
||||
visualization: { state: {}, activeId: 'testVis' },
|
||||
})
|
||||
);
|
||||
expect(updaterFn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -15,7 +15,13 @@ import type { CoreStart } from '@kbn/core/public';
|
|||
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import { isEqual } from 'lodash';
|
||||
import type { LensPluginStartDependencies } from '../../../plugin';
|
||||
import { makeConfigureStore, LensRootStore, loadInitial } from '../../../state_management';
|
||||
import {
|
||||
makeConfigureStore,
|
||||
LensRootStore,
|
||||
loadInitial,
|
||||
initExisting,
|
||||
initEmpty,
|
||||
} from '../../../state_management';
|
||||
import { generateId } from '../../../id_generator';
|
||||
import type { DatasourceMap, VisualizationMap } from '../../../types';
|
||||
import {
|
||||
|
@ -38,7 +44,8 @@ function LoadingSpinnerWithOverlay() {
|
|||
|
||||
type UpdaterType = (datasourceState: unknown, visualizationState: unknown) => void;
|
||||
|
||||
const updatingMiddleware =
|
||||
// exported for testing
|
||||
export const updatingMiddleware =
|
||||
(updater: UpdaterType) => (store: MiddlewareAPI) => (next: Dispatch) => (action: Action) => {
|
||||
const {
|
||||
datasourceStates: prevDatasourceStates,
|
||||
|
@ -48,10 +55,17 @@ const updatingMiddleware =
|
|||
next(action);
|
||||
const { datasourceStates, visualization, activeDatasourceId } = store.getState().lens;
|
||||
if (
|
||||
!isEqual(prevDatasourceStates, datasourceStates) ||
|
||||
!isEqual(prevVisualization, visualization) ||
|
||||
prevActiveDatasourceId !== activeDatasourceId
|
||||
prevActiveDatasourceId !== activeDatasourceId ||
|
||||
!isEqual(
|
||||
prevDatasourceStates[prevActiveDatasourceId].state,
|
||||
datasourceStates[activeDatasourceId].state
|
||||
) ||
|
||||
!isEqual(prevVisualization, visualization)
|
||||
) {
|
||||
// ignore the actions that initialize the store with the state from the attributes
|
||||
if (initExisting.match(action) || initEmpty.match(action)) {
|
||||
return;
|
||||
}
|
||||
updater(datasourceStates[activeDatasourceId].state, visualization.state);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue