[Discover] Refactor default appState generation (#140572)

This commit is contained in:
Matthias Wilhelm 2022-09-19 08:56:15 +02:00 committed by GitHub
parent 2c4e1fb547
commit d0a43c9688
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 117 additions and 154 deletions

View file

@ -46,6 +46,7 @@ const fields = [
scripted: false, scripted: false,
filterable: true, filterable: true,
aggregatable: true, aggregatable: true,
sortable: true,
}, },
{ {
name: 'scripted', name: 'scripted',

View file

@ -20,3 +20,11 @@ export const savedSearchMockWithTimeField = {
id: 'the-saved-search-id-with-timefield', id: 'the-saved-search-id-with-timefield',
searchSource: createSearchSourceMock({ index: dataViewWithTimefieldMock }), searchSource: createSearchSourceMock({ index: dataViewWithTimefieldMock }),
} as unknown as SavedSearch; } as unknown as SavedSearch;
export const savedSearchMockWithSQL = {
id: 'the-saved-search-id-sql',
searchSource: createSearchSourceMock({
index: dataViewWithTimefieldMock,
query: { sql: 'SELECT * FROM "the-saved-search-id-sql"' },
}),
} as unknown as SavedSearch;

View file

@ -63,7 +63,7 @@ export const discoverServiceMock = {
if (key === 'fields:popularLimit') { if (key === 'fields:popularLimit') {
return 5; return 5;
} else if (key === DEFAULT_COLUMNS_SETTING) { } else if (key === DEFAULT_COLUMNS_SETTING) {
return []; return ['default_column'];
} else if (key === UI_SETTINGS.META_FIELDS) { } else if (key === UI_SETTINGS.META_FIELDS) {
return []; return [];
} else if (key === DOC_HIDE_TIME_COLUMN_SETTING) { } else if (key === DOC_HIDE_TIME_COLUMN_SETTING) {

View file

@ -53,7 +53,7 @@ async function saveDataSource({
navigateTo(`/view/${encodeURIComponent(id)}`); navigateTo(`/view/${encodeURIComponent(id)}`);
} else { } else {
// Update defaults so that "reload saved query" functions correctly // Update defaults so that "reload saved query" functions correctly
state.resetAppState(); state.resetAppState(savedSearch);
services.chrome.docTitle.change(savedSearch.title!); services.chrome.docTitle.change(savedSearch.title!);
setBreadcrumbsTitle( setBreadcrumbsTitle(

View file

@ -8,7 +8,6 @@
import React, { useEffect, useState, memo, useCallback } from 'react'; import React, { useEffect, useState, memo, useCallback } from 'react';
import { useParams, useHistory } from 'react-router-dom'; import { useParams, useHistory } from 'react-router-dom';
import { DataViewListItem } from '@kbn/data-plugin/public'; import { DataViewListItem } from '@kbn/data-plugin/public';
import { ISearchSource } from '@kbn/data-plugin/public';
import { DataViewSavedObjectConflictError } from '@kbn/data-views-plugin/public'; import { DataViewSavedObjectConflictError } from '@kbn/data-views-plugin/public';
import { redirectWhenMissing } from '@kbn/kibana-utils-plugin/public'; import { redirectWhenMissing } from '@kbn/kibana-utils-plugin/public';
import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; import { useExecutionContext } from '@kbn/kibana-react-plugin/public';
@ -70,7 +69,7 @@ export function DiscoverMainRoute(props: Props) {
}); });
const loadDefaultOrCurrentDataView = useCallback( const loadDefaultOrCurrentDataView = useCallback(
async (searchSource: ISearchSource) => { async (nextSavedSearch: SavedSearch) => {
try { try {
const hasUserDataViewValue = await data.dataViews.hasData const hasUserDataViewValue = await data.dataViews.hasData
.hasUserDataView() .hasUserDataView()
@ -92,12 +91,12 @@ export function DiscoverMainRoute(props: Props) {
return; return;
} }
const { appStateContainer } = getState({ history, uiSettings: config }); const { appStateContainer } = getState({ history, savedSearch: nextSavedSearch, services });
const { index } = appStateContainer.getState(); const { index } = appStateContainer.getState();
const ip = await loadDataView(data.dataViews, config, index); const ip = await loadDataView(data.dataViews, config, index);
const ipList = ip.list; const ipList = ip.list;
const dataViewData = resolveDataView(ip, searchSource, toastNotifications); const dataViewData = resolveDataView(ip, nextSavedSearch.searchSource, toastNotifications);
await data.dataViews.refreshFields(dataViewData); await data.dataViews.refreshFields(dataViewData);
setDataViewList(ipList); setDataViewList(ipList);
@ -106,7 +105,7 @@ export function DiscoverMainRoute(props: Props) {
setError(e); setError(e);
} }
}, },
[config, data.dataViews, history, isDev, toastNotifications] [config, data.dataViews, history, isDev, toastNotifications, services]
); );
const loadSavedSearch = useCallback(async () => { const loadSavedSearch = useCallback(async () => {
@ -118,7 +117,7 @@ export function DiscoverMainRoute(props: Props) {
savedObjectsTagging: services.savedObjectsTagging, savedObjectsTagging: services.savedObjectsTagging,
}); });
const currentDataView = await loadDefaultOrCurrentDataView(currentSavedSearch.searchSource); const currentDataView = await loadDefaultOrCurrentDataView(currentSavedSearch);
if (!currentDataView) { if (!currentDataView) {
return; return;

View file

@ -44,7 +44,7 @@ export function useDiscoverState({
setExpandedDoc: (doc?: DataTableRecord) => void; setExpandedDoc: (doc?: DataTableRecord) => void;
dataViewList: DataViewListItem[]; dataViewList: DataViewListItem[];
}) { }) {
const { uiSettings, data, filterManager, dataViews, storage } = services; const { uiSettings, data, filterManager, dataViews } = services;
const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]); const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]);
const { timefilter } = data.query.timefilter; const { timefilter } = data.query.timefilter;
@ -60,19 +60,11 @@ export function useDiscoverState({
const stateContainer = useMemo( const stateContainer = useMemo(
() => () =>
getState({ getState({
getStateDefaults: () =>
getStateDefaults({
config: uiSettings,
data,
savedSearch,
storage,
}),
storeInSessionStorage: uiSettings.get('state:storeInSessionStorage'),
history, history,
toasts: services.core.notifications.toasts, savedSearch,
uiSettings, services,
}), }),
[uiSettings, data, history, savedSearch, services.core.notifications.toasts, storage] [history, savedSearch, services]
); );
const { appStateContainer } = stateContainer; const { appStateContainer } = stateContainer;
@ -231,10 +223,8 @@ export function useDiscoverState({
const newDataView = newSavedSearch.searchSource.getField('index') || dataView; const newDataView = newSavedSearch.searchSource.getField('index') || dataView;
newSavedSearch.searchSource.setField('index', newDataView); newSavedSearch.searchSource.setField('index', newDataView);
const newAppState = getStateDefaults({ const newAppState = getStateDefaults({
config: uiSettings,
data,
savedSearch: newSavedSearch, savedSearch: newSavedSearch,
storage, services,
}); });
restoreStateFromSavedSearch({ restoreStateFromSavedSearch({
@ -245,7 +235,7 @@ export function useDiscoverState({
await stateContainer.replaceUrlAppState(newAppState); await stateContainer.replaceUrlAppState(newAppState);
setState(newAppState); setState(newAppState);
}, },
[services, dataView, uiSettings, data, storage, stateContainer] [services, dataView, stateContainer]
); );
/** /**

View file

@ -9,10 +9,9 @@ import { Subject } from 'rxjs';
import { renderHook } from '@testing-library/react-hooks'; import { renderHook } from '@testing-library/react-hooks';
import { createSearchSessionMock } from '../../../__mocks__/search_session'; import { createSearchSessionMock } from '../../../__mocks__/search_session';
import { discoverServiceMock } from '../../../__mocks__/services'; import { discoverServiceMock } from '../../../__mocks__/services';
import { savedSearchMock } from '../../../__mocks__/saved_search'; import { savedSearchMock, savedSearchMockWithSQL } from '../../../__mocks__/saved_search';
import { RecordRawType, useSavedSearch } from './use_saved_search'; import { RecordRawType, useSavedSearch } from './use_saved_search';
import { getState, AppState } from '../services/discover_state'; import { getState } from '../services/discover_state';
import { uiSettingsMock } from '../../../__mocks__/ui_settings';
import { useDiscoverState } from './use_discover_state'; import { useDiscoverState } from './use_discover_state';
import { FetchStatus } from '../../types'; import { FetchStatus } from '../../types';
import { dataViewMock } from '../../../__mocks__/data_view'; import { dataViewMock } from '../../../__mocks__/data_view';
@ -25,9 +24,9 @@ describe('test useSavedSearch', () => {
test('useSavedSearch return is valid', async () => { test('useSavedSearch return is valid', async () => {
const { history, searchSessionManager } = createSearchSessionMock(); const { history, searchSessionManager } = createSearchSessionMock();
const stateContainer = getState({ const stateContainer = getState({
getStateDefaults: () => ({ index: 'the-data-view-id' }), savedSearch: savedSearchMock,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
const { result } = renderHook(() => { const { result } = renderHook(() => {
@ -51,9 +50,9 @@ describe('test useSavedSearch', () => {
test('refetch$ triggers a search', async () => { test('refetch$ triggers a search', async () => {
const { history, searchSessionManager } = createSearchSessionMock(); const { history, searchSessionManager } = createSearchSessionMock();
const stateContainer = getState({ const stateContainer = getState({
getStateDefaults: () => ({ index: 'the-data-view-id' }), savedSearch: savedSearchMock,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
discoverServiceMock.data.query.timefilter.timefilter.getTime = jest.fn(() => { discoverServiceMock.data.query.timefilter.timefilter.getTime = jest.fn(() => {
@ -95,9 +94,9 @@ describe('test useSavedSearch', () => {
test('reset sets back to initial state', async () => { test('reset sets back to initial state', async () => {
const { history, searchSessionManager } = createSearchSessionMock(); const { history, searchSessionManager } = createSearchSessionMock();
const stateContainer = getState({ const stateContainer = getState({
getStateDefaults: () => ({ index: 'the-data-view-id' }), savedSearch: savedSearchMock,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
discoverServiceMock.data.query.timefilter.timefilter.getTime = jest.fn(() => { discoverServiceMock.data.query.timefilter.timefilter.getTime = jest.fn(() => {
@ -139,21 +138,17 @@ describe('test useSavedSearch', () => {
test('useSavedSearch returns plain record raw type', async () => { test('useSavedSearch returns plain record raw type', async () => {
const { history, searchSessionManager } = createSearchSessionMock(); const { history, searchSessionManager } = createSearchSessionMock();
const stateContainer = getState({ const stateContainer = getState({
getStateDefaults: () => savedSearch: savedSearchMockWithSQL,
({ services: discoverServiceMock,
index: 'the-index-pattern-id',
query: { sql: 'SELECT * FROM test' },
} as unknown as AppState),
history, history,
uiSettings: uiSettingsMock,
}); });
const { result } = renderHook(() => { const { result } = renderHook(() => {
return useSavedSearch({ return useSavedSearch({
initialFetchStatus: FetchStatus.LOADING, initialFetchStatus: FetchStatus.LOADING,
savedSearch: savedSearchMock, savedSearch: savedSearchMockWithSQL,
searchSessionManager, searchSessionManager,
searchSource: savedSearchMock.searchSource.createCopy(), searchSource: savedSearchMockWithSQL.searchSource.createCopy(),
services: discoverServiceMock, services: discoverServiceMock,
stateContainer, stateContainer,
useNewFieldsApi: true, useNewFieldsApi: true,

View file

@ -12,15 +12,14 @@ import { createSearchSessionMock } from '../../../__mocks__/search_session';
import { discoverServiceMock } from '../../../__mocks__/services'; import { discoverServiceMock } from '../../../__mocks__/services';
import { savedSearchMock } from '../../../__mocks__/saved_search'; import { savedSearchMock } from '../../../__mocks__/saved_search';
import { getState } from '../services/discover_state'; import { getState } from '../services/discover_state';
import { uiSettingsMock } from '../../../__mocks__/ui_settings';
describe('test useSearchSession', () => { describe('test useSearchSession', () => {
test('getting the next session id', async () => { test('getting the next session id', async () => {
const { history } = createSearchSessionMock(); const { history } = createSearchSessionMock();
const stateContainer = getState({ const stateContainer = getState({
getStateDefaults: () => ({ index: 'test' }), savedSearch: savedSearchMock,
history, history,
uiSettings: uiSettingsMock, services: discoverServiceMock,
}); });
const nextId = 'id'; const nextId = 'id';

View file

@ -6,7 +6,6 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import { IUiSettingsClient } from '@kbn/core/public';
import { import {
getState, getState,
GetStateReturn, GetStateReturn,
@ -14,17 +13,14 @@ import {
} from './discover_state'; } from './discover_state';
import { createBrowserHistory, History } from 'history'; import { createBrowserHistory, History } from 'history';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public';
import { SEARCH_FIELDS_FROM_SOURCE } from '../../../../common'; import { savedSearchMock, savedSearchMockWithTimeField } from '../../../__mocks__/saved_search';
import { discoverServiceMock } from '../../../__mocks__/services';
let history: History; let history: History;
let state: GetStateReturn; let state: GetStateReturn;
const getCurrentUrl = () => history.createHref(history.location); const getCurrentUrl = () => history.createHref(history.location);
const uiSettingsMock = {
get: <T>(key: string) => (key === SEARCH_FIELDS_FROM_SOURCE ? true : ['_source']) as unknown as T,
} as IUiSettingsClient;
describe('Test discover state', () => { describe('Test discover state', () => {
let stopSync = () => {}; let stopSync = () => {};
@ -32,9 +28,9 @@ describe('Test discover state', () => {
history = createBrowserHistory(); history = createBrowserHistory();
history.push('/'); history.push('/');
state = getState({ state = getState({
getStateDefaults: () => ({ index: 'test' }), savedSearch: savedSearchMock,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
await state.replaceUrlAppState({}); await state.replaceUrlAppState({});
stopSync = state.startSync(); stopSync = state.startSync();
@ -46,7 +42,9 @@ describe('Test discover state', () => {
test('setting app state and syncing to URL', async () => { test('setting app state and syncing to URL', async () => {
state.setAppState({ index: 'modified' }); state.setAppState({ index: 'modified' });
state.flushToUrl(); state.flushToUrl();
expect(getCurrentUrl()).toMatchInlineSnapshot(`"/#?_a=(index:modified)"`); expect(getCurrentUrl()).toMatchInlineSnapshot(
`"/#?_a=(columns:!(default_column),index:modified,interval:auto,sort:!())"`
);
}); });
test('changing URL to be propagated to appState', async () => { test('changing URL to be propagated to appState', async () => {
@ -60,11 +58,9 @@ describe('Test discover state', () => {
test('URL navigation to url without _a, state should not change', async () => { test('URL navigation to url without _a, state should not change', async () => {
history.push('/#?_a=(index:modified)'); history.push('/#?_a=(index:modified)');
history.push('/'); history.push('/');
expect(state.appStateContainer.getState()).toMatchInlineSnapshot(` expect(state.appStateContainer.getState()).toEqual({
Object { index: 'modified',
"index": "modified", });
}
`);
}); });
test('isAppStateDirty returns whether the current state has changed', async () => { test('isAppStateDirty returns whether the current state has changed', async () => {
@ -89,46 +85,45 @@ describe('Test discover state', () => {
}); });
}); });
describe('Test discover initial state sort handling', () => { describe('Test discover initial state sort handling', () => {
test('Non-empty sort in URL should not fallback to state defaults', async () => { test('Non-empty sort in URL should not be overwritten by saved search sort', async () => {
history = createBrowserHistory(); history = createBrowserHistory();
history.push('/#?_a=(sort:!(!(order_date,desc)))'); history.push('/#?_a=(sort:!(!(order_date,desc)))');
state = getState({ state = getState({
getStateDefaults: () => ({ sort: [['fallback', 'desc']] }), savedSearch: { ...savedSearchMock, ...{ sort: [['bytes', 'desc']] } },
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
await state.replaceUrlAppState({}); await state.replaceUrlAppState({});
const stopSync = state.startSync(); const stopSync = state.startSync();
expect(state.appStateContainer.getState().sort).toMatchInlineSnapshot(` expect(state.appStateContainer.getState().sort).toEqual([['order_date', 'desc']]);
Array [
Array [
"order_date",
"desc",
],
]
`);
stopSync(); stopSync();
}); });
test('Empty sort in URL should allow fallback state defaults', async () => { test('Empty sort in URL should use saved search sort for state', async () => {
history = createBrowserHistory(); history = createBrowserHistory();
history.push('/#?_a=(sort:!())'); history.push('/#?_a=(sort:!())');
const nextSavedSearch = { ...savedSearchMock, ...{ sort: [['bytes', 'desc']] as SortOrder[] } };
state = getState({ state = getState({
getStateDefaults: () => ({ sort: [['fallback', 'desc']] }), savedSearch: nextSavedSearch,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
await state.replaceUrlAppState({}); await state.replaceUrlAppState({});
const stopSync = state.startSync(); const stopSync = state.startSync();
expect(state.appStateContainer.getState().sort).toMatchInlineSnapshot(` expect(state.appStateContainer.getState().sort).toEqual([['bytes', 'desc']]);
Array [ stopSync();
Array [ });
"fallback", test('Empty sort in URL and saved search should sort by timestamp', async () => {
"desc", history = createBrowserHistory();
], history.push('/#?_a=(sort:!())');
] state = getState({
`); savedSearch: savedSearchMockWithTimeField,
services: discoverServiceMock,
history,
});
await state.replaceUrlAppState({});
const stopSync = state.startSync();
expect(state.appStateContainer.getState().sort).toEqual([['timestamp', 'desc']]);
stopSync(); stopSync();
}); });
}); });
@ -140,20 +135,17 @@ describe('Test discover state with legacy migration', () => {
"/#?_a=(query:(query_string:(analyze_wildcard:!t,query:'type:nice%20name:%22yeah%22')))" "/#?_a=(query:(query_string:(analyze_wildcard:!t,query:'type:nice%20name:%22yeah%22')))"
); );
state = getState({ state = getState({
getStateDefaults: () => ({ index: 'test' }), savedSearch: savedSearchMock,
services: discoverServiceMock,
history, history,
uiSettings: uiSettingsMock,
}); });
expect(state.appStateContainer.getState()).toMatchInlineSnapshot(` expect(state.appStateContainer.getState().query).toMatchInlineSnapshot(`
Object { Object {
"index": "test", "language": "lucene",
"query": Object { "query": Object {
"language": "lucene", "query_string": Object {
"query": Object { "analyze_wildcard": true,
"query_string": Object { "query": "type:nice name:\\"yeah\\"",
"analyze_wildcard": true,
"query": "type:nice name:\\"yeah\\"",
},
}, },
}, },
} }
@ -167,8 +159,9 @@ describe('createSearchSessionRestorationDataProvider', () => {
const searchSessionInfoProvider = createSearchSessionRestorationDataProvider({ const searchSessionInfoProvider = createSearchSessionRestorationDataProvider({
data: mockDataPlugin, data: mockDataPlugin,
appStateContainer: getState({ appStateContainer: getState({
history: createBrowserHistory(), savedSearch: savedSearchMock,
uiSettings: uiSettingsMock, services: discoverServiceMock,
history,
}).appStateContainer, }).appStateContainer,
getSavedSearch: () => mockSavedSearch, getSavedSearch: () => mockSavedSearch,
}); });
@ -217,12 +210,10 @@ describe('createSearchSessionRestorationDataProvider', () => {
test('restoreState has paused autoRefresh', async () => { test('restoreState has paused autoRefresh', async () => {
const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData(); const { initialState, restoreState } = await searchSessionInfoProvider.getLocatorData();
expect(initialState.refreshInterval).toBe(undefined); expect(initialState.refreshInterval).toBe(undefined);
expect(restoreState.refreshInterval).toMatchInlineSnapshot(` expect(restoreState.refreshInterval).toEqual({
Object { pause: true,
"pause": true, value: 0,
"value": 0, });
}
`);
}); });
}); });
}); });

View file

@ -9,7 +9,6 @@
import { cloneDeep, isEqual } from 'lodash'; import { cloneDeep, isEqual } from 'lodash';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { History } from 'history'; import { History } from 'history';
import { NotificationsStart, IUiSettingsClient } from '@kbn/core/public';
import { import {
Filter, Filter,
FilterStateStore, FilterStateStore,
@ -37,6 +36,8 @@ import {
} from '@kbn/data-plugin/public'; } from '@kbn/data-plugin/public';
import { DataView } from '@kbn/data-views-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public';
import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { SavedSearch } from '@kbn/saved-search-plugin/public';
import { getStateDefaults } from '../utils/get_state_defaults';
import { DiscoverServices } from '../../../build_services';
import { DiscoverGridSettings } from '../../../components/discover_grid/types'; import { DiscoverGridSettings } from '../../../components/discover_grid/types';
import { handleSourceColumnState } from '../../../utils/state_helpers'; import { handleSourceColumnState } from '../../../utils/state_helpers';
import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '../../../locator'; import { DISCOVER_APP_LOCATOR, DiscoverAppLocatorParams } from '../../../locator';
@ -107,30 +108,18 @@ export interface AppStateUrl extends Omit<AppState, 'sort'> {
} }
interface GetStateParams { interface GetStateParams {
/**
* Default state used for merging with with URL state to get the initial state
*/
getStateDefaults?: () => AppState;
/**
* Determins the use of long vs. short/hashed urls
*/
storeInSessionStorage?: boolean;
/** /**
* Browser history * Browser history
*/ */
history: History; history: History;
/** /**
* Core's notifications.toasts service * The current savedSearch
* In case it is passed in,
* kbnUrlStateStorage will use it notifying about inner errors
*/ */
toasts?: NotificationsStart['toasts']; savedSearch: SavedSearch;
/** /**
* core ui settings service * core ui settings service
*/ */
uiSettings: IUiSettingsClient; services: DiscoverServices;
} }
export interface GetStateReturn { export interface GetStateReturn {
@ -179,9 +168,9 @@ export interface GetStateReturn {
*/ */
isAppStateDirty: () => boolean; isAppStateDirty: () => boolean;
/** /**
* Reset AppState to default, discarding all changes * Reset AppState by the given savedSearch discarding all changes
*/ */
resetAppState: () => void; resetAppState: (nextSavedSearch: SavedSearch) => void;
/** /**
* Pause the auto refresh interval without pushing an entry to history * Pause the auto refresh interval without pushing an entry to history
*/ */
@ -195,14 +184,13 @@ const GLOBAL_STATE_URL_KEY = '_g';
* Builds and returns appState and globalState containers and helper functions * Builds and returns appState and globalState containers and helper functions
* Used to sync URL with UI state * Used to sync URL with UI state
*/ */
export function getState({ export function getState({ history, savedSearch, services }: GetStateParams): GetStateReturn {
getStateDefaults, const storeInSessionStorage = services.uiSettings.get('state:storeInSessionStorage');
storeInSessionStorage = false, const toasts = services.core.notifications.toasts;
history, const defaultAppState = getStateDefaults({
toasts, savedSearch,
uiSettings, services,
}: GetStateParams): GetStateReturn { });
const defaultAppState = getStateDefaults ? getStateDefaults() : {};
const stateStorage = createKbnUrlStateStorage({ const stateStorage = createKbnUrlStateStorage({
useHash: storeInSessionStorage, useHash: storeInSessionStorage,
history, history,
@ -216,7 +204,7 @@ export function getState({
...defaultAppState, ...defaultAppState,
...appStateFromUrl, ...appStateFromUrl,
}, },
uiSettings services.uiSettings
); );
// todo filter source depending on fields fetching flag (if no columns remain and source fetching is enabled, use default columns) // todo filter source depending on fields fetching flag (if no columns remain and source fetching is enabled, use default columns)
@ -275,10 +263,10 @@ export function getState({
resetInitialAppState: () => { resetInitialAppState: () => {
initialAppState = appStateContainer.getState(); initialAppState = appStateContainer.getState();
}, },
resetAppState: () => { resetAppState: (nextSavedSearch: SavedSearch) => {
const defaultState = handleSourceColumnState( const defaultState = handleSourceColumnState(
getStateDefaults ? getStateDefaults() : {}, getStateDefaults({ savedSearch: nextSavedSearch, services }),
uiSettings services.uiSettings
); );
setState(appStateContainerModified, defaultState); setState(appStateContainerModified, defaultState);
}, },

View file

@ -7,23 +7,18 @@
*/ */
import { getStateDefaults } from './get_state_defaults'; import { getStateDefaults } from './get_state_defaults';
import { createSearchSourceMock, dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks';
import { uiSettingsMock } from '../../../__mocks__/ui_settings';
import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield'; import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield';
import { savedSearchMock } from '../../../__mocks__/saved_search'; import { savedSearchMock } from '../../../__mocks__/saved_search';
import { dataViewMock } from '../../../__mocks__/data_view'; import { dataViewMock } from '../../../__mocks__/data_view';
import { discoverServiceMock } from '../../../__mocks__/services'; import { discoverServiceMock } from '../../../__mocks__/services';
describe('getStateDefaults', () => { describe('getStateDefaults', () => {
const storage = discoverServiceMock.storage;
test('data view with timefield', () => { test('data view with timefield', () => {
savedSearchMock.searchSource = createSearchSourceMock({ index: dataViewWithTimefieldMock }); savedSearchMock.searchSource = createSearchSourceMock({ index: dataViewWithTimefieldMock });
const actual = getStateDefaults({ const actual = getStateDefaults({
config: uiSettingsMock, services: discoverServiceMock,
data: dataPluginMock.createStartContract(),
savedSearch: savedSearchMock, savedSearch: savedSearchMock,
storage,
}); });
expect(actual).toMatchInlineSnapshot(` expect(actual).toMatchInlineSnapshot(`
Object { Object {
@ -55,10 +50,8 @@ describe('getStateDefaults', () => {
savedSearchMock.searchSource = createSearchSourceMock({ index: dataViewMock }); savedSearchMock.searchSource = createSearchSourceMock({ index: dataViewMock });
const actual = getStateDefaults({ const actual = getStateDefaults({
config: uiSettingsMock, services: discoverServiceMock,
data: dataPluginMock.createStartContract(),
savedSearch: savedSearchMock, savedSearch: savedSearchMock,
storage,
}); });
expect(actual).toMatchInlineSnapshot(` expect(actual).toMatchInlineSnapshot(`
Object { Object {

View file

@ -8,9 +8,8 @@
import { cloneDeep, isEqual } from 'lodash'; import { cloneDeep, isEqual } from 'lodash';
import { IUiSettingsClient } from '@kbn/core/public'; import { IUiSettingsClient } from '@kbn/core/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { SavedSearch } from '@kbn/saved-search-plugin/public';
import { DiscoverServices } from '../../../build_services';
import { getDefaultSort, getSortArray } from '../../../utils/sorting'; import { getDefaultSort, getSortArray } from '../../../utils/sorting';
import { import {
DEFAULT_COLUMNS_SETTING, DEFAULT_COLUMNS_SETTING,
@ -22,33 +21,33 @@ import {
import { AppState } from '../services/discover_state'; import { AppState } from '../services/discover_state';
import { CHART_HIDDEN_KEY } from '../components/chart/discover_chart'; import { CHART_HIDDEN_KEY } from '../components/chart/discover_chart';
function getDefaultColumns(savedSearch: SavedSearch, config: IUiSettingsClient) { function getDefaultColumns(savedSearch: SavedSearch, uiSettings: IUiSettingsClient) {
if (savedSearch.columns && savedSearch.columns.length > 0) { if (savedSearch.columns && savedSearch.columns.length > 0) {
return [...savedSearch.columns]; return [...savedSearch.columns];
} }
if (config.get(SEARCH_FIELDS_FROM_SOURCE) && isEqual(config.get(DEFAULT_COLUMNS_SETTING), [])) { if (
uiSettings.get(SEARCH_FIELDS_FROM_SOURCE) &&
isEqual(uiSettings.get(DEFAULT_COLUMNS_SETTING), [])
) {
return ['_source']; return ['_source'];
} }
return [...config.get(DEFAULT_COLUMNS_SETTING)]; return [...uiSettings.get(DEFAULT_COLUMNS_SETTING)];
} }
export function getStateDefaults({ export function getStateDefaults({
config,
data,
savedSearch, savedSearch,
storage, services,
}: { }: {
config: IUiSettingsClient;
data: DataPublicPluginStart;
savedSearch: SavedSearch; savedSearch: SavedSearch;
storage: Storage; services: DiscoverServices;
}) { }) {
const { searchSource } = savedSearch; const { searchSource } = savedSearch;
const { data, uiSettings, storage } = services;
const dataView = searchSource.getField('index'); const dataView = searchSource.getField('index');
const query = searchSource.getField('query') || data.query.queryString.getDefaultQuery(); const query = searchSource.getField('query') || data.query.queryString.getDefaultQuery();
const sort = getSortArray(savedSearch.sort ?? [], dataView!); const sort = getSortArray(savedSearch.sort ?? [], dataView!);
const columns = getDefaultColumns(savedSearch, config); const columns = getDefaultColumns(savedSearch, uiSettings);
const chartHidden = storage.get(CHART_HIDDEN_KEY); const chartHidden = storage.get(CHART_HIDDEN_KEY);
const defaultState: AppState = { const defaultState: AppState = {
@ -56,8 +55,8 @@ export function getStateDefaults({
sort: !sort.length sort: !sort.length
? getDefaultSort( ? getDefaultSort(
dataView, dataView,
config.get(SORT_DEFAULT_ORDER_SETTING, 'desc'), uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'),
config.get(DOC_HIDE_TIME_COLUMN_SETTING, false) uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false)
) )
: sort, : sort,
columns, columns,