Skip to content

Commit 41adf31

Browse files
authored
[Discover] Skip fetch for non-document view modes (elastic#245663)
1 parent 06aacc6 commit 41adf31

5 files changed

Lines changed: 148 additions & 28 deletions

File tree

src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,17 @@ describe('saved search embeddable', () => {
144144
});
145145
});
146146

147-
it('should render field stats table in AGGREGATED_LEVEL view mode', async () => {
148-
const { search, resolveSearch } = createSearchFnMock(0);
147+
it('should render field stats table in AGGREGATED_LEVEL view mode and not fetch documents', async () => {
148+
const { search } = createSearchFnMock(0);
149149
runtimeState = getInitialRuntimeState({
150150
searchMock: search,
151151
partialState: { viewMode: VIEW_MODE.AGGREGATED_LEVEL },
152152
});
153+
154+
discoverServiceMock.uiSettings.get = jest.fn().mockImplementation((key: string) => {
155+
if (key === SHOW_FIELD_STATISTICS) return true;
156+
});
157+
153158
const { Component, api } = await factory.buildEmbeddable({
154159
initialState: { rawState: { savedObjectId: 'id' } }, // runtimeState passed via mocked deserializeState
155160
finalizeApi: finalizeApiMock,
@@ -158,15 +163,10 @@ describe('saved search embeddable', () => {
158163
});
159164
await waitOneTick(); // wait for build to complete
160165

161-
discoverServiceMock.uiSettings.get = jest.fn().mockImplementationOnce((key: string) => {
162-
if (key === SHOW_FIELD_STATISTICS) return true;
163-
});
164166
const discoverComponent = render(<Component />);
165167

166-
// wait for data fetching
167-
expect(api.dataLoading$.getValue()).toBe(true);
168-
resolveSearch();
169-
await waitOneTick();
168+
// Field statistics mode should not trigger document fetching
169+
expect(search).not.toHaveBeenCalled();
170170
expect(api.dataLoading$.getValue()).toBe(false);
171171

172172
expect(discoverComponent.queryByTestId('dscFieldStatsEmbeddedContent')).toBeInTheDocument();
@@ -178,7 +178,7 @@ describe('saved search embeddable', () => {
178178
const { search, resolveSearch } = createSearchFnMock(1);
179179
runtimeState = getInitialRuntimeState({
180180
searchMock: search,
181-
partialState: { viewMode: VIEW_MODE.AGGREGATED_LEVEL },
181+
partialState: { viewMode: VIEW_MODE.DOCUMENT_LEVEL },
182182
});
183183
const { api } = await factory.buildEmbeddable({
184184
initialState: { rawState: { savedObjectId: 'id' } }, // runtimeState passed via mocked deserializeState

src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { BehaviorSubject, firstValueFrom, merge } from 'rxjs';
1212

1313
import { CellActionsProvider } from '@kbn/cell-actions';
1414
import { APPLY_FILTER_TRIGGER, generateFilters } from '@kbn/data-plugin/public';
15-
import { SEARCH_EMBEDDABLE_TYPE, SHOW_FIELD_STATISTICS } from '@kbn/discover-utils';
15+
import { SEARCH_EMBEDDABLE_TYPE } from '@kbn/discover-utils';
1616
import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public';
1717
import { FilterStateStore } from '@kbn/es-query';
1818
import { i18n } from '@kbn/i18n';
@@ -26,12 +26,10 @@ import {
2626
useBatchedPublishingSubjects,
2727
} from '@kbn/presentation-publishing';
2828
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
29-
import { VIEW_MODE } from '@kbn/saved-search-plugin/common';
3029
import type { SearchResponseIncompleteWarning } from '@kbn/search-response-warnings/src/types';
3130

3231
import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
3332
import { initializeUnsavedChanges } from '@kbn/presentation-containers';
34-
import { getValidViewMode } from '../application/main/utils/get_valid_view_mode';
3533
import type { DiscoverServices } from '../build_services';
3634
import { SearchEmbeddablFieldStatsTableComponent } from './components/search_embeddable_field_stats_table_component';
3735
import { SearchEmbeddableGridComponent } from './components/search_embeddable_grid_component';
@@ -43,6 +41,7 @@ import type { SearchEmbeddableApi } from './types';
4341
import { deserializeState, serializeState } from './utils/serialization_utils';
4442
import { BaseAppWrapper } from '../context_awareness';
4543
import { ScopedServicesProvider } from '../components/scoped_services_provider';
44+
import { isFieldStatsMode } from './utils/is_field_stats_mode';
4645

4746
export const getSearchEmbeddableFactory = ({
4847
startServices,
@@ -259,14 +258,6 @@ export const getSearchEmbeddableFactory = ({
259258
};
260259
}, []);
261260

262-
const viewMode = useMemo(() => {
263-
if (!savedSearch.searchSource) return;
264-
return getValidViewMode({
265-
viewMode: savedSearch.viewMode,
266-
isEsqlMode: isEsqlMode(savedSearch),
267-
});
268-
}, [savedSearch]);
269-
270261
const dataView = useMemo(() => {
271262
const hasDataView = (dataViews ?? []).length > 0;
272263
if (!hasDataView) {
@@ -313,12 +304,8 @@ export const getSearchEmbeddableFactory = ({
313304
);
314305

315306
const renderAsFieldStatsTable = useMemo(
316-
() =>
317-
Boolean(discoverServices.uiSettings.get(SHOW_FIELD_STATISTICS)) &&
318-
viewMode === VIEW_MODE.AGGREGATED_LEVEL &&
319-
Boolean(dataView) &&
320-
Array.isArray(savedSearch.columns),
321-
[savedSearch, dataView, viewMode]
307+
() => isFieldStatsMode(savedSearch, dataView, discoverServices.uiSettings),
308+
[savedSearch, dataView]
322309
);
323310

324311
return (

src/platform/plugins/shared/discover/public/embeddable/initialize_fetch.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import type { PublishesSavedSearch, SearchEmbeddableStateManager } from './types
4545
import { getTimeRangeFromFetchContext, updateSearchSource } from './utils/update_search_source';
4646
import { createDataSource } from '../../common/data_sources';
4747
import type { ScopedProfilesManager } from '../context_awareness';
48+
import { isFieldStatsMode } from './utils/is_field_stats_mode';
4849

4950
type SavedSearchPartialFetchApi = PublishesSavedSearch &
5051
PublishesSavedObjectId &
@@ -179,8 +180,13 @@ export function initializeFetch({
179180
}),
180181
switchMap(async ([fetchContext, savedSearch, dataViews, esqlVariables]) => {
181182
const dataView = dataViews?.length ? dataViews[0] : undefined;
183+
182184
setBlockingError(undefined);
183-
if (!dataView || !savedSearch.searchSource) {
185+
if (
186+
!dataView ||
187+
!savedSearch.searchSource ||
188+
isFieldStatsMode(savedSearch, dataView, discoverServices.uiSettings)
189+
) {
184190
return;
185191
}
186192

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import { VIEW_MODE } from '@kbn/saved-search-plugin/common';
11+
import { SHOW_FIELD_STATISTICS } from '@kbn/discover-utils';
12+
import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__';
13+
import { isFieldStatsMode } from './is_field_stats_mode';
14+
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
15+
import type { SavedSearch } from '@kbn/saved-search-plugin/common';
16+
17+
const dataViewMock = buildDataViewMock({ name: 'test-data-view' });
18+
19+
const createMockUiSettings = (showFieldStats: boolean): IUiSettingsClient => {
20+
return {
21+
get: jest.fn((key: string) => {
22+
if (key === SHOW_FIELD_STATISTICS) {
23+
return showFieldStats;
24+
}
25+
return undefined;
26+
}),
27+
} as unknown as IUiSettingsClient;
28+
};
29+
30+
const createMockSavedSearch = (viewMode: VIEW_MODE, columns: string[] | undefined): SavedSearch => {
31+
return {
32+
viewMode,
33+
columns,
34+
searchSource: {
35+
getField: jest.fn((field: string) => {
36+
if (field === 'query') {
37+
return { language: 'kuery' }; // Default to non-ES|QL query
38+
}
39+
return undefined;
40+
}),
41+
},
42+
} as unknown as SavedSearch;
43+
};
44+
45+
const columns = ['field1', 'field2'];
46+
47+
describe('isFieldStatsMode', () => {
48+
describe('DOCUMENT_LEVEL mode', () => {
49+
it('should return false when in DOCUMENT_LEVEL view mode', () => {
50+
const savedSearch = createMockSavedSearch(VIEW_MODE.DOCUMENT_LEVEL, columns);
51+
const uiSettings = createMockUiSettings(false);
52+
53+
expect(isFieldStatsMode(savedSearch, dataViewMock, uiSettings)).toBe(false);
54+
});
55+
});
56+
57+
describe('AGGREGATED_LEVEL mode (Field Statistics)', () => {
58+
it('should return true when all Field Statistics conditions are met', () => {
59+
const savedSearch = createMockSavedSearch(VIEW_MODE.AGGREGATED_LEVEL, columns);
60+
const uiSettings = createMockUiSettings(true);
61+
62+
expect(isFieldStatsMode(savedSearch, dataViewMock, uiSettings)).toBe(true);
63+
});
64+
65+
it('should return false when SHOW_FIELD_STATISTICS setting is false', () => {
66+
const savedSearch = createMockSavedSearch(VIEW_MODE.AGGREGATED_LEVEL, columns);
67+
const uiSettings = createMockUiSettings(false);
68+
69+
expect(isFieldStatsMode(savedSearch, dataViewMock, uiSettings)).toBe(false);
70+
});
71+
72+
it('should return false when dataView is undefined', () => {
73+
const savedSearch = createMockSavedSearch(VIEW_MODE.AGGREGATED_LEVEL, columns);
74+
const uiSettings = createMockUiSettings(true);
75+
76+
expect(isFieldStatsMode(savedSearch, undefined, uiSettings)).toBe(false);
77+
});
78+
79+
it('should return false when columns is not an array', () => {
80+
const savedSearch = createMockSavedSearch(VIEW_MODE.AGGREGATED_LEVEL, undefined);
81+
const uiSettings = createMockUiSettings(true);
82+
83+
expect(isFieldStatsMode(savedSearch, dataViewMock, uiSettings)).toBe(false);
84+
});
85+
86+
it('should return true when columns is an empty array', () => {
87+
const savedSearch = createMockSavedSearch(VIEW_MODE.AGGREGATED_LEVEL, []);
88+
const uiSettings = createMockUiSettings(true);
89+
90+
expect(isFieldStatsMode(savedSearch, dataViewMock, uiSettings)).toBe(true);
91+
});
92+
});
93+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
import { SHOW_FIELD_STATISTICS } from '@kbn/discover-utils';
11+
import { VIEW_MODE } from '@kbn/saved-search-plugin/common';
12+
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
13+
import type { SavedSearch } from '@kbn/saved-search-plugin/common';
14+
import type { DataView } from '@kbn/data-views-plugin/common';
15+
import { getValidViewMode } from '../../application/main/utils/get_valid_view_mode';
16+
import { isEsqlMode } from '../initialize_fetch';
17+
18+
export function isFieldStatsMode(
19+
savedSearch: SavedSearch,
20+
dataView: DataView | undefined,
21+
uiSettings: IUiSettingsClient
22+
): boolean {
23+
const validatedViewMode = getValidViewMode({
24+
viewMode: savedSearch.viewMode,
25+
isEsqlMode: isEsqlMode(savedSearch),
26+
});
27+
28+
return (
29+
Boolean(uiSettings.get(SHOW_FIELD_STATISTICS)) &&
30+
validatedViewMode === VIEW_MODE.AGGREGATED_LEVEL &&
31+
Boolean(dataView) &&
32+
Array.isArray(savedSearch.columns)
33+
);
34+
}

0 commit comments

Comments
 (0)