[Maps] fix double fetch when filters are modified (#74893)

* [Maps] fix double fetch when filters are modified

* add unit tests

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2020-08-17 09:44:08 -06:00 committed by GitHub
parent b07db9dec8
commit 4ac0e81554
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 17 deletions

View file

@ -11,7 +11,7 @@ jest.mock('./data_request_actions', () => {
};
});
import { mapExtentChanged, setMouseCoordinates } from './map_actions';
import { mapExtentChanged, setMouseCoordinates, setQuery } from './map_actions';
const getStoreMock = jest.fn();
const dispatchMock = jest.fn();
@ -226,4 +226,95 @@ describe('map_actions', () => {
});
});
});
describe('setQuery', () => {
const query = {
language: 'kuery',
query: '',
queryLastTriggeredAt: '2020-08-14T15:07:12.276Z',
};
const timeFilters = { from: 'now-1y', to: 'now' };
const filters = [
{
meta: {
index: '90943e30-9a47-11e8-b64d-95841ca0b247',
alias: null,
negate: false,
disabled: false,
type: 'phrase',
key: 'extension',
params: { query: 'png' },
},
query: { match_phrase: { extension: 'png' } },
$state: { store: 'appState' },
},
];
beforeEach(() => {
//Mocks the "previous" state
require('../selectors/map_selectors').getQuery = () => {
return query;
};
require('../selectors/map_selectors').getTimeFilters = () => {
return timeFilters;
};
require('../selectors/map_selectors').getFilters = () => {
return filters;
};
require('../selectors/map_selectors').getMapSettings = () => {
return {
autoFitToDataBounds: false,
};
};
});
it('should dispatch query action and resync when query changes', async () => {
const newQuery = {
language: 'kuery',
query: 'foobar',
queryLastTriggeredAt: '2020-08-14T15:07:12.276Z',
};
const setQueryAction = await setQuery({
query: newQuery,
filters,
});
await setQueryAction(dispatchMock, getStoreMock);
expect(dispatchMock.mock.calls).toEqual([
[
{
timeFilters,
query: newQuery,
filters,
type: 'SET_QUERY',
},
],
[undefined], // dispatch<any>(syncDataForAllLayers());
]);
});
it('should not dispatch query action when nothing changes', async () => {
const setQueryAction = await setQuery({
timeFilters,
query,
filters,
});
await setQueryAction(dispatchMock, getStoreMock);
expect(dispatchMock.mock.calls.length).toEqual(0);
});
it('should dispatch query action when nothing changes and force refresh', async () => {
const setQueryAction = await setQuery({
timeFilters,
query,
filters,
forceRefresh: true,
});
await setQueryAction(dispatchMock, getStoreMock);
// Only checking calls length instead of calls because queryLastTriggeredAt changes on this run
expect(dispatchMock.mock.calls.length).toEqual(2);
});
});
});

View file

@ -3,6 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import _ from 'lodash';
import { Dispatch } from 'redux';
import turfBboxPolygon from '@turf/bbox-polygon';
import turfBooleanContains from '@turf/boolean-contains';
@ -204,12 +205,12 @@ export function setQuery({
query,
timeFilters,
filters = [],
refresh = false,
forceRefresh = false,
}: {
filters: Filter[];
filters?: Filter[];
query?: Query;
timeFilters?: TimeRange;
refresh?: boolean;
forceRefresh?: boolean;
}) {
return async (dispatch: Dispatch, getState: () => MapStoreState) => {
const prevQuery = getQuery(getState());
@ -218,15 +219,30 @@ export function setQuery({
? prevQuery.queryLastTriggeredAt
: generateQueryTimestamp();
dispatch({
type: SET_QUERY,
const nextQueryContext = {
timeFilters: timeFilters ? timeFilters : getTimeFilters(getState()),
query: {
...(query ? query : getQuery(getState())),
// ensure query changes to trigger re-fetch when "Refresh" clicked
queryLastTriggeredAt: refresh ? generateQueryTimestamp() : prevTriggeredAt,
queryLastTriggeredAt: forceRefresh ? generateQueryTimestamp() : prevTriggeredAt,
},
filters: filters ? filters : getFilters(getState()),
};
const prevQueryContext = {
timeFilters: getTimeFilters(getState()),
query: getQuery(getState()),
filters: getFilters(getState()),
};
if (_.isEqual(nextQueryContext, prevQueryContext)) {
// do nothing if query context has not changed
return;
}
dispatch({
type: SET_QUERY,
...nextQueryContext,
});
if (getMapSettings(getState()).autoFitToDataBounds) {

View file

@ -129,12 +129,12 @@ export class MapEmbeddable extends Embeddable<MapEmbeddableInput, MapEmbeddableO
query,
timeRange,
filters,
refresh,
forceRefresh,
}: {
query?: Query;
timeRange?: TimeRange;
filters: Filter[];
refresh?: boolean;
forceRefresh?: boolean;
}) {
this._prevTimeRange = timeRange;
this._prevQuery = query;
@ -144,7 +144,7 @@ export class MapEmbeddable extends Embeddable<MapEmbeddableInput, MapEmbeddableO
filters: filters.filter((filter) => !filter.meta.disabled),
query,
timeFilters: timeRange,
refresh,
forceRefresh,
})
);
}
@ -270,7 +270,7 @@ export class MapEmbeddable extends Embeddable<MapEmbeddableInput, MapEmbeddableO
query: this._prevQuery,
timeRange: this._prevTimeRange,
filters: this._prevFilters ?? [],
refresh: true,
forceRefresh: true,
});
}

View file

@ -52,13 +52,13 @@ function mapStateToProps(state = {}) {
function mapDispatchToProps(dispatch) {
return {
dispatchSetQuery: ({ refresh, filters, query, timeFilters }) => {
dispatchSetQuery: ({ forceRefresh, filters, query, timeFilters }) => {
dispatch(
setQuery({
filters,
query,
timeFilters,
refresh,
forceRefresh,
})
);
},

View file

@ -142,7 +142,7 @@ export class MapsAppView extends React.Component {
return;
}
this._onQueryChange({ time: globalState.time, refresh: true });
this._onQueryChange({ time: globalState.time });
};
async _updateIndexPatterns() {
@ -160,7 +160,7 @@ export class MapsAppView extends React.Component {
}
}
_onQueryChange = ({ filters, query, time, refresh = false }) => {
_onQueryChange = ({ filters, query, time, forceRefresh = false }) => {
const { filterManager } = getData().query;
if (filters) {
@ -168,7 +168,7 @@ export class MapsAppView extends React.Component {
}
this.props.dispatchSetQuery({
refresh,
forceRefresh,
filters: filterManager.getFilters(),
query,
timeFilters: time,
@ -336,7 +336,7 @@ export class MapsAppView extends React.Component {
this._onQueryChange({
query,
time: dateRange,
refresh: true,
forceRefresh: true,
});
}}
onFiltersUpdated={this._onFiltersChange}