[Discover] Fix duplicate request in Discover when adding a filter (#161992)

This PR fixes a bug in Discover that can cause a duplicate request to be
sent when adding a filter under certain circumstances. It also reenables
the flaky tests that were skipped in #161157 which were failing due to
this bug.

Flaky test runs:
- x50:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2645
🔴
- x100:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2646
🔴
- x100:
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2647
🟢

Resolves #161157.
This commit is contained in:
Davis McPhee 2023-07-17 10:52:51 -03:00 committed by GitHub
parent 8960f61242
commit 9191bd9939
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 116 additions and 61 deletions

View file

@ -47,6 +47,7 @@ import { getRawRecordType } from '../../utils/get_raw_record_type';
import { SavedSearchURLConflictCallout } from '../../../../components/saved_search_url_conflict_callout/saved_search_url_conflict_callout';
import { DiscoverHistogramLayout } from './discover_histogram_layout';
import { ErrorCallout } from '../../../../components/common/error_callout';
import { addLog } from '../../../../utils/add_log';
/**
* Local storage key for sidebar persistence state
@ -209,6 +210,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) {
}
if (resultState === 'uninitialized') {
addLog('[DiscoverLayout] uninitialized triggers data fetching');
return <DiscoverUninitialized onRefresh={() => stateContainer.dataState.fetch()} />;
}

View file

@ -18,6 +18,7 @@ import { getHeaderActionMenuMounter } from '../../../../kibana_services';
import { DiscoverStateContainer } from '../../services/discover_state';
import { onSaveSearch } from './on_save_search';
import { useDiscoverCustomization } from '../../../../customizations';
import { addLog } from '../../../../utils/add_log';
export interface DiscoverTopNavProps {
onOpenInspector: () => void;
@ -143,6 +144,7 @@ export const DiscoverTopNav = ({
await stateContainer.actions.updateAdHocDataViewId();
}
stateContainer.actions.loadDataViewList();
addLog('[DiscoverTopNav] onEditDataView triggers data fetching');
stateContainer.dataState.fetch();
};

View file

@ -18,6 +18,7 @@ import { useSavedSearchAliasMatchRedirect } from '../../hooks/saved_search_alias
import { useSavedSearchInitial } from './services/discover_state_provider';
import { useAdHocDataViews } from './hooks/use_adhoc_data_views';
import { useTextBasedQueryLanguage } from './hooks/use_text_based_query_language';
import { addLog } from '../../utils/add_log';
const DiscoverLayoutMemoized = React.memo(DiscoverLayout);
@ -53,6 +54,7 @@ export function DiscoverMainApp(props: DiscoverMainProps) {
*/
useEffect(() => {
const unsubscribe = stateContainer.actions.initializeAndSync();
addLog('[DiscoverMainApp] state container initialization triggers data fetching');
stateContainer.actions.fetchData(true);
return () => unsubscribe();
}, [stateContainer]);

View file

@ -139,16 +139,13 @@ export function DiscoverMainRoute({ customizationCallbacks, isDev }: MainRoutePr
}
try {
await stateContainer.actions.loadDataViewList();
// reset appState in case a saved search with id is loaded and the url is empty
// so the saved search is loaded in a clean state
// else it might be updated by the previous app state
const useAppState = !stateContainer.appState.isEmptyURL();
const currentSavedSearch = await stateContainer.actions.loadSavedSearch({
savedSearchId,
dataView: nextDataView,
dataViewSpec: historyLocationState?.dataViewSpec,
useAppState,
});
if (currentSavedSearch?.id) {
chrome.recentlyAccessed.add(
getSavedSearchFullPathUrl(currentSavedSearch.id),

View file

@ -45,7 +45,7 @@ describe('buildStateSubscribe', () => {
it('should not call refetch$ if nothing changes', async () => {
await getSubscribeFn()(stateContainer.appState.getState());
expect(stateContainer.dataState.refetch$.next).toHaveBeenCalled();
expect(stateContainer.dataState.refetch$.next).not.toHaveBeenCalled();
});
it('should call refetch$ if the chart is hidden', async () => {

View file

@ -105,7 +105,30 @@ export const buildStateSubscribe =
dataViewChanged ||
queryChanged
) {
addLog('[appstate] subscribe triggers data fetching');
const logData = {
chartDisplayChanged: logEntry(chartDisplayChanged, hideChart, nextState.hideChart),
chartIntervalChanged: logEntry(chartIntervalChanged, interval, nextState.interval),
breakdownFieldChanged: logEntry(
breakdownFieldChanged,
breakdownField,
nextState.breakdownField
),
docTableSortChanged: logEntry(docTableSortChanged, sort, nextState.sort),
dataViewChanged: logEntry(dataViewChanged, index, nextState.index),
queryChanged: logEntry(queryChanged, prevQuery, nextQuery),
};
addLog(
'[buildStateSubscribe] state changes triggers data fetching',
JSON.stringify(logData, null, 2)
);
dataState.fetch();
}
};
const logEntry = <T>(changed: boolean, prevState: T, nextState: T) => ({
changed,
prevState,
nextState,
});

View file

@ -23,12 +23,12 @@ import { SavedSearch, VIEW_MODE } from '@kbn/saved-search-plugin/public';
import { IKbnUrlStateStorage, ISyncStateRef, syncState } from '@kbn/kibana-utils-plugin/public';
import { isEqual } from 'lodash';
import { connectToQueryState, syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public';
import { DiscoverServices } from '../../../build_services';
import type { DiscoverServices } from '../../../build_services';
import { addLog } from '../../../utils/add_log';
import { cleanupUrlState } from '../utils/cleanup_url_state';
import { getStateDefaults } from '../utils/get_state_defaults';
import { handleSourceColumnState } from '../../../utils/state_helpers';
import { DiscoverGridSettings } from '../../../components/discover_grid/types';
import type { DiscoverGridSettings } from '../../../components/discover_grid/types';
export const APP_STATE_URL_KEY = '_a';
export interface DiscoverAppStateContainer extends ReduxLikeStateContainer<DiscoverAppState> {
@ -55,6 +55,10 @@ export interface DiscoverAppStateContainer extends ReduxLikeStateContainer<Disco
* @param merge if true, the given state is merged with the current state
*/
replaceUrlState: (newPartial: DiscoverAppState, merge?: boolean) => Promise<void>;
/**
* Resets the state container to a given state, clearing the previous state
*/
resetToState: (state: DiscoverAppState) => void;
/**
* Resets the current state to the initial state
*/
@ -148,8 +152,8 @@ export const getDiscoverAppStateContainer = ({
savedSearch: SavedSearch;
services: DiscoverServices;
}): DiscoverAppStateContainer => {
let previousState: DiscoverAppState = {};
let initialState = getInitialState(stateStorage, savedSearch, services);
let previousState = initialState;
const appStateContainer = createStateContainer<DiscoverAppState>(initialState);
const enhancedAppContainer = {
@ -166,6 +170,12 @@ export const getDiscoverAppStateContainer = ({
return !isEqualState(initialState, appStateContainer.getState());
};
const resetToState = (state: DiscoverAppState) => {
addLog('[appState] reset state to', state);
previousState = state;
appStateContainer.set(state);
};
const resetInitialState = () => {
addLog('[appState] reset initial state to the current state');
initialState = appStateContainer.getState();
@ -245,6 +255,7 @@ export const getDiscoverAppStateContainer = ({
getPrevious,
hasChanged,
initAndSync: initializeAndSync,
resetToState,
resetInitialState,
replaceUrlState,
syncState: startAppStateUrlSync,

View file

@ -34,7 +34,10 @@ const startSync = (appState: DiscoverAppStateContainer) => {
return stop;
};
async function getState(url: string = '/', savedSearch?: SavedSearch) {
async function getState(
url: string = '/',
{ savedSearch, isEmptyUrl }: { savedSearch?: SavedSearch; isEmptyUrl?: boolean } = {}
) {
const nextHistory = createBrowserHistory();
nextHistory.push(url);
@ -49,6 +52,7 @@ async function getState(url: string = '/', savedSearch?: SavedSearch) {
services: discoverServiceMock,
history: nextHistory,
});
nextState.appState.isEmptyURL = jest.fn(() => isEmptyUrl ?? true);
jest.spyOn(nextState.dataState, 'fetch');
await nextState.actions.loadDataViewList();
if (savedSearch) {
@ -144,14 +148,14 @@ describe('Test discover initial state sort handling', () => {
...{ sort: [['bytes', 'desc']] },
} as SavedSearch;
const { state } = await getState('/#?_a=(sort:!(!(timestamp,desc)))', savedSearch);
const { state } = await getState('/#?_a=(sort:!(!(timestamp,desc)))', { savedSearch });
const unsubscribe = state.actions.initializeAndSync();
expect(state.appState.getState().sort).toEqual([['timestamp', 'desc']]);
unsubscribe();
});
test('Empty URL should use saved search sort for state', async () => {
const nextSavedSearch = { ...savedSearchMock, ...{ sort: [['bytes', 'desc']] as SortOrder[] } };
const { state } = await getState('/', nextSavedSearch);
const { state } = await getState('/', { savedSearch: nextSavedSearch });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
expect(state.appState.getState().sort).toEqual([['bytes', 'desc']]);
@ -163,7 +167,7 @@ describe('Test discover state with legacy migration', () => {
test('migration of legacy query ', async () => {
const { state } = await getState(
"/#?_a=(query:(query_string:(analyze_wildcard:!t,query:'type:nice%20name:%22yeah%22')))",
savedSearchMockWithTimeFieldNew
{ savedSearch: savedSearchMockWithTimeFieldNew }
);
expect(state.appState.getState().query).toMatchInlineSnapshot(`
Object {
@ -384,9 +388,10 @@ describe('Test discover state actions', () => {
});
test('loadNewSavedSearch with URL changing interval state', async () => {
const { state, getCurrentUrl } = await getState(
'/#?_a=(interval:month,columns:!(bytes))&_g=()'
'/#?_a=(interval:month,columns:!(bytes))&_g=()',
{ isEmptyUrl: false }
);
const newSavedSearch = await state.actions.loadSavedSearch({ useAppState: true });
const newSavedSearch = await state.actions.loadSavedSearch();
expect(newSavedSearch?.id).toBeUndefined();
const unsubscribe = state.actions.initializeAndSync();
await new Promise(process.nextTick);
@ -398,9 +403,10 @@ describe('Test discover state actions', () => {
});
test('loadSavedSearch with no id, given URL changes state', async () => {
const { state, getCurrentUrl } = await getState(
'/#?_a=(interval:month,columns:!(bytes))&_g=()'
'/#?_a=(interval:month,columns:!(bytes))&_g=()',
{ isEmptyUrl: false }
);
const newSavedSearch = await state.actions.loadSavedSearch({ useAppState: true });
const newSavedSearch = await state.actions.loadSavedSearch();
expect(newSavedSearch?.id).toBeUndefined();
const unsubscribe = state.actions.initializeAndSync();
await new Promise(process.nextTick);
@ -411,7 +417,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('loadSavedSearch given an empty URL, no state changes', async () => {
const { state, getCurrentUrl } = await getState('/', savedSearchMock);
const { state, getCurrentUrl } = await getState('/', { savedSearch: savedSearchMock });
const newSavedSearch = await state.actions.loadSavedSearch({
savedSearchId: 'the-saved-search-id',
});
@ -426,8 +432,11 @@ describe('Test discover state actions', () => {
});
test('loadSavedSearch given a URL with different interval and columns modifying the state', async () => {
const url = '/#?_a=(interval:month,columns:!(message))&_g=()';
const { state, getCurrentUrl } = await getState(url, savedSearchMock);
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id, useAppState: true });
const { state, getCurrentUrl } = await getState(url, {
savedSearch: savedSearchMock,
isEmptyUrl: false,
});
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
await new Promise(process.nextTick);
expect(getCurrentUrl()).toMatchInlineSnapshot(
@ -439,7 +448,7 @@ describe('Test discover state actions', () => {
test('loadSavedSearch ignoring hideChart in URL', async () => {
const url = '/#?_a=(hideChart:true,columns:!(message))&_g=()';
const { state } = await getState(url, savedSearchMock);
const { state } = await getState(url, { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch();
expect(state.savedSearchState.getState().hideChart).toBe(undefined);
expect(state.appState.getState().hideChart).toBe(undefined);
@ -447,8 +456,8 @@ describe('Test discover state actions', () => {
test('loadSavedSearch without id ignoring invalid index in URL, adding a warning toast', async () => {
const url = '/#?_a=(index:abc)&_g=()';
const { state } = await getState(url, savedSearchMock);
await state.actions.loadSavedSearch({ useAppState: true });
const { state } = await getState(url, { savedSearch: savedSearchMock, isEmptyUrl: false });
await state.actions.loadSavedSearch();
expect(state.savedSearchState.getState().searchSource.getField('index')?.id).toBe(
'the-data-view-id'
);
@ -461,15 +470,15 @@ describe('Test discover state actions', () => {
test('loadSavedSearch without id containing sql, adding no warning toast with an invalid index', async () => {
const url = "/#?_a=(index:abcde,query:(sql:'Select * from test'))&_g=()";
const { state } = await getState(url, savedSearchMock);
await state.actions.loadSavedSearch({ useAppState: true });
const { state } = await getState(url, { savedSearch: savedSearchMock, isEmptyUrl: false });
await state.actions.loadSavedSearch();
expect(discoverServiceMock.toastNotifications.addWarning).not.toHaveBeenCalled();
});
test('loadSavedSearch with id ignoring invalid index in URL, adding a warning toast', async () => {
const url = '/#?_a=(index:abc)&_g=()';
const { state } = await getState(url, savedSearchMock);
await state.actions.loadSavedSearch({ useAppState: true, savedSearchId: savedSearchMock.id });
const { state } = await getState(url, { savedSearch: savedSearchMock, isEmptyUrl: false });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(state.savedSearchState.getState().searchSource.getField('index')?.id).toBe(
'the-data-view-id'
);
@ -481,7 +490,7 @@ describe('Test discover state actions', () => {
});
test('loadSavedSearch data view handling', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(state.savedSearchState.getState().searchSource.getField('index')?.id).toBe(
'the-data-view-id'
@ -498,7 +507,8 @@ describe('Test discover state actions', () => {
expect(state.savedSearchState.getHasChanged$().getValue()).toBe(false);
// switch back to the previous savedSearch, but not cleaning up appState index, so it's considered as update to the persisted saved search
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id, useAppState: true });
state.appState.isEmptyURL = jest.fn().mockReturnValue(false);
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(state.savedSearchState.getState().searchSource.getField('index')?.id).toBe(
'index-pattern-with-timefield-id'
);
@ -531,7 +541,7 @@ describe('Test discover state actions', () => {
});
test('loadSavedSearch resetting query & filters of data service', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(discoverServiceMock.data.query.queryString.clearQuery).toHaveBeenCalled();
expect(discoverServiceMock.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([]);
@ -543,7 +553,7 @@ describe('Test discover state actions', () => {
const filters = [{ meta: { index: 'the-data-view-id' }, query: { match_all: {} } }];
savedSearchWithQueryAndFilters.searchSource.setField('query', query);
savedSearchWithQueryAndFilters.searchSource.setField('filter', filters);
const { state } = await getState('/', savedSearchWithQueryAndFilters);
const { state } = await getState('/', { savedSearch: savedSearchWithQueryAndFilters });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(discoverServiceMock.data.query.queryString.setQuery).toHaveBeenCalledWith(query);
expect(discoverServiceMock.data.query.filterManager.setAppFilters).toHaveBeenCalledWith(
@ -554,14 +564,14 @@ describe('Test discover state actions', () => {
test('loadSavedSearch with ad-hoc data view being added to internal state adHocDataViews', async () => {
const savedSearchAdHocCopy = copySavedSearch(savedSearchAdHoc);
const adHocDataViewId = savedSearchAdHoc.searchSource.getField('index')!.id;
const { state } = await getState('/', savedSearchAdHocCopy);
const { state } = await getState('/', { savedSearch: savedSearchAdHocCopy });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchAdHoc.id });
expect(state.appState.getState().index).toBe(adHocDataViewId);
expect(state.internalState.getState().adHocDataViews[0].id).toBe(adHocDataViewId);
});
test('onChangeDataView', async () => {
const { state, getCurrentUrl } = await getState('/', savedSearchMock);
const { state, getCurrentUrl } = await getState('/', { savedSearch: savedSearchMock });
const { actions, savedSearchState, dataState, appState } = state;
await actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
@ -587,7 +597,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('onDataViewCreated - persisted data view', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
await state.actions.onDataViewCreated(dataViewComplexMock);
@ -601,7 +611,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('onDataViewCreated - ad-hoc data view', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
await state.actions.onDataViewCreated(dataViewAdHoc);
@ -615,7 +625,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('onDataViewEdited - persisted data view', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const selectedDataView = state.internalState.getState().dataView;
await waitFor(() => {
@ -630,7 +640,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('onDataViewEdited - ad-hoc data view', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
const unsubscribe = state.actions.initializeAndSync();
await state.actions.onDataViewCreated(dataViewAdHoc);
const previousId = dataViewAdHoc.id;
@ -642,7 +652,7 @@ describe('Test discover state actions', () => {
});
test('onOpenSavedSearch - same target id', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
const unsubscribe = state.actions.initializeAndSync();
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
await state.savedSearchState.update({ nextState: { hideChart: true } });
@ -655,16 +665,17 @@ describe('Test discover state actions', () => {
test('onOpenSavedSearch - cleanup of previous filter', async () => {
const { state } = await getState(
"/#?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:now-15m,to:now))&_a=(columns:!(customer_first_name),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:ff959d40-b880-11e8-a6d9-e546fe2bba5f,key:customer_first_name,negate:!f,params:(query:Mary),type:phrase),query:(match_phrase:(customer_first_name:Mary)))),hideChart:!f,index:ff959d40-b880-11e8-a6d9-e546fe2bba5f,interval:auto,query:(language:kuery,query:''),sort:!())",
savedSearchMock
{ savedSearch: savedSearchMock, isEmptyUrl: false }
);
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id, useAppState: true });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
expect(state.appState.get().filters).toHaveLength(1);
await state.actions.loadSavedSearch({ useAppState: false });
state.appState.isEmptyURL = jest.fn().mockReturnValue(true);
await state.actions.loadSavedSearch();
expect(state.appState.get().filters).toHaveLength(0);
});
test('onCreateDefaultAdHocDataView', async () => {
const { state } = await getState('/', savedSearchMock);
const { state } = await getState('/', { savedSearch: savedSearchMock });
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
await state.actions.onCreateDefaultAdHocDataView({ title: 'ad-hoc-test' });
@ -673,7 +684,7 @@ describe('Test discover state actions', () => {
unsubscribe();
});
test('undoSavedSearchChanges - when changing data views', async () => {
const { state, getCurrentUrl } = await getState('/', savedSearchMock);
const { state, getCurrentUrl } = await getState('/', { savedSearch: savedSearchMock });
// Load a given persisted saved search
await state.actions.loadSavedSearch({ savedSearchId: savedSearchMock.id });
const unsubscribe = state.actions.initializeAndSync();
@ -708,10 +719,12 @@ describe('Test discover state actions', () => {
test('undoSavedSearchChanges with timeRestore', async () => {
const { state } = await getState('/', {
...savedSearchMockWithTimeField,
timeRestore: true,
refreshInterval: { pause: false, value: 1000 },
timeRange: { from: 'now-15d', to: 'now-10d' },
savedSearch: {
...savedSearchMockWithTimeField,
timeRestore: true,
refreshInterval: { pause: false, value: 1000 },
timeRange: { from: 'now-15d', to: 'now-10d' },
},
});
const setTime = jest.fn();
const setRefreshInterval = jest.fn();

View file

@ -78,11 +78,6 @@ export interface LoadParams {
* the data view spec to use, if undefined, the saved search's data view will be used
*/
dataViewSpec?: DataViewSpec;
/**
* determines if AppState should be used to update the saved search
* URL is overwriting savedSearch params in this case
*/
useAppState?: boolean;
}
export interface DiscoverStateContainer {
@ -321,6 +316,7 @@ export function getDiscoverStateContainer({
await updateAdHocDataViewId();
}
loadDataViewList();
addLog('[getDiscoverStateContainer] onDataViewEdited triggers data fetching');
fetchData();
};
@ -364,6 +360,7 @@ export function getDiscoverStateContainer({
nextState: appStateContainer.getState(),
useFilterAndQueryServices: true,
});
addLog('[getDiscoverStateContainer] filter changes triggers data fetching');
fetchData();
});
@ -411,6 +408,7 @@ export function getDiscoverStateContainer({
if (isUpdate === false) {
// remove the search session if the given query is not just updated
searchSessionManager.removeSearchSessionIdFromURL({ replace: false });
addLog('[getDiscoverStateContainer] onUpdateQuery triggers data fetching');
dataStateContainer.fetch();
}
};

View file

@ -43,9 +43,10 @@ export const loadSavedSearch = async (
deps: LoadSavedSearchDeps
): Promise<SavedSearch> => {
addLog('[discoverState] loadSavedSearch');
const { savedSearchId, useAppState } = params ?? {};
const { savedSearchId } = params ?? {};
const { appStateContainer, internalStateContainer, savedSearchContainer, services } = deps;
const appState = useAppState ? appStateContainer.getState() : undefined;
const appStateExists = !appStateContainer.isEmptyURL();
const appState = appStateExists ? appStateContainer.getState() : undefined;
// Loading the saved search or creating a new one
let nextSavedSearch = savedSearchId
@ -57,7 +58,11 @@ export const loadSavedSearch = async (
// Cleaning up the previous state
services.filterManager.setAppFilters([]);
services.data.query.queryString.clearQuery();
if (!useAppState) {
// reset appState in case a saved search with id is loaded and
// the url is empty so the saved search is loaded in a clean
// state else it might be updated by the previous app state
if (!appStateExists) {
appStateContainer.set({});
}
@ -85,12 +90,15 @@ export const loadSavedSearch = async (
// Update app state container with the next state derived from the next saved search
const nextAppState = getInitialState(undefined, nextSavedSearch, services);
appStateContainer.set(
appState ? { ...nextAppState, ...cleanupUrlState({ ...appState }) } : nextAppState
);
const mergedAppState = appState
? { ...nextAppState, ...cleanupUrlState({ ...appState }) }
: nextAppState;
appStateContainer.resetToState(mergedAppState);
// Update all other services and state containers by the next saved search
updateBySavedSearch(nextSavedSearch, deps);
return nextSavedSearch;
};

View file

@ -27,8 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const queryBar = getService('queryBar');
const elasticChart = getService('elasticChart');
// Failing: See https://github.com/elastic/kibana/issues/161157
describe.skip('discover request counts', function describeIndexTests() {
describe('discover request counts', function describeIndexTests() {
before(async function () {
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional');
await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/long_window_logstash');