mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Discover] Refactor default appState generation (#140572)
This commit is contained in:
parent
2c4e1fb547
commit
d0a43c9688
12 changed files with 117 additions and 154 deletions
|
@ -46,6 +46,7 @@ const fields = [
|
||||||
scripted: false,
|
scripted: false,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
aggregatable: true,
|
aggregatable: true,
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'scripted',
|
name: 'scripted',
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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,
|
});
|
||||||
}
|
|
||||||
`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue