diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
index effa9f99d6c4b..5535990f72f4c 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx
@@ -45,6 +45,17 @@ async function mountComponent(fetchStatus: FetchStatus, hits: EsHitRecord[]) {
stateContainer.appState.update({
dataSource: createDataViewDataSource({ dataViewId: dataViewMock.id! }),
});
+ stateContainer.internalState.transitions.setDataRequestParams({
+ timeRangeRelative: {
+ from: '2020-05-14T11:05:13.590',
+ to: '2020-05-14T11:20:13.590',
+ },
+ timeRangeAbsolute: {
+ from: '2020-05-14T11:05:13.590',
+ to: '2020-05-14T11:20:13.590',
+ },
+ });
+
stateContainer.dataState.data$.documents$ = documents$;
const props = {
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
index 18996a7cdf9ca..ee00abbe5659d 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx
@@ -46,7 +46,6 @@ import useObservable from 'react-use/lib/useObservable';
import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types';
import { DiscoverGridSettings } from '@kbn/saved-search-plugin/common';
import { useQuerySubscriber } from '@kbn/unified-field-list';
-import { map } from 'rxjs';
import { DiscoverGrid } from '../../../../components/discover_grid';
import { getDefaultRowsPerPage } from '../../../../../common/constants';
import { useInternalStateSelector } from '../../state_management/discover_internal_state_container';
@@ -112,6 +111,7 @@ function DiscoverDocumentsComponent({
const documents$ = stateContainer.dataState.data$.documents$;
const savedSearch = useSavedSearchInitial();
const { dataViews, capabilities, uiSettings, uiActions, ebtManager, fieldsMetadata } = services;
+ const requestParams = useInternalStateSelector((state) => state.dataRequestParams);
const [
dataSource,
query,
@@ -269,20 +269,14 @@ function DiscoverDocumentsComponent({
: undefined,
[documentState.esqlQueryColumns]
);
-
const { filters } = useQuerySubscriber({ data: services.data });
- const timeRange = useObservable(
- services.timefilter.getTimeUpdate$().pipe(map(() => services.timefilter.getTime())),
- services.timefilter.getTime()
- );
-
const cellActionsMetadata = useAdditionalCellActions({
dataSource,
dataView,
query,
filters,
- timeRange,
+ timeRange: requestParams.timeRangeAbsolute,
});
const renderDocumentView = useCallback(
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx
index 9aec3589c753e..0513a690e8b8a 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.test.tsx
@@ -38,20 +38,30 @@ import { createDataViewDataSource } from '../../../../../common/data_sources';
function getStateContainer(savedSearch?: SavedSearch) {
const stateContainer = getDiscoverStateMock({ isTimeBased: true, savedSearch });
const dataView = savedSearch?.searchSource?.getField('index') as DataView;
-
- stateContainer.appState.update({
+ const appState = {
dataSource: createDataViewDataSource({ dataViewId: dataView?.id! }),
interval: 'auto',
hideChart: false,
- });
+ };
+
+ stateContainer.appState.update(appState);
stateContainer.internalState.transitions.setDataView(dataView);
+ stateContainer.internalState.transitions.setDataRequestParams({
+ timeRangeAbsolute: {
+ from: '2020-05-14T11:05:13.590',
+ to: '2020-05-14T11:20:13.590',
+ },
+ timeRangeRelative: {
+ from: '2020-05-14T11:05:13.590',
+ to: '2020-05-14T11:20:13.590',
+ },
+ });
return stateContainer;
}
const mountComponent = async ({
- isEsqlMode = false,
storage,
savedSearch = savedSearchMockWithTimeField,
searchSessionId = '123',
@@ -65,16 +75,7 @@ const mountComponent = async ({
const dataView = savedSearch?.searchSource?.getField('index') as DataView;
let services = discoverServiceMock;
- services.data.query.timefilter.timefilter.getAbsoluteTime = () => {
- return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' };
- };
- services.data.query.timefilter.timefilter.getTime = () => {
- return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' };
- };
- (services.data.query.queryString.getDefaultQuery as jest.Mock).mockReturnValue({
- language: 'kuery',
- query: '',
- });
+
(searchSourceInstanceMock.fetch$ as jest.Mock).mockImplementation(
jest.fn().mockReturnValue(of({ rawResponse: { hits: { total: 2 } } }))
);
@@ -176,8 +177,6 @@ describe('Discover histogram layout component', () => {
const { component } = await mountComponent();
expect(component.find(PanelsToggle).first().prop('isChartAvailable')).toBe(undefined);
expect(component.find(PanelsToggle).first().prop('renderedFor')).toBe('histogram');
- expect(component.find(PanelsToggle).last().prop('isChartAvailable')).toBe(true);
- expect(component.find(PanelsToggle).last().prop('renderedFor')).toBe('tabs');
});
});
});
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx
index 20afaf22373d5..65838d5fb44d5 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_histogram_layout.tsx
@@ -75,6 +75,18 @@ export const DiscoverHistogramLayout = ({
if (!searchSessionId && !isEsqlMode) {
return null;
}
+ if (hideChart) {
+ return (
+ <>
+
+ >
+ );
+ }
return (
{
it('should include PanelsToggle when chart is available', async () => {
const component = await mountComponent({ isChartAvailable: true });
- expect(component.find(PanelsToggle).prop('isChartAvailable')).toBe(true);
- expect(component.find(PanelsToggle).prop('renderedFor')).toBe('tabs');
+ expect(component.find(PanelsToggle).prop('renderedFor')).toBe('root');
expect(component.find(EuiHorizontalRule).exists()).toBe(true);
});
it('should include PanelsToggle when chart is available and hidden', async () => {
const component = await mountComponent({ isChartAvailable: true, hideChart: true });
- expect(component.find(PanelsToggle).prop('isChartAvailable')).toBe(true);
- expect(component.find(PanelsToggle).prop('renderedFor')).toBe('tabs');
+ expect(component.find(PanelsToggle).prop('renderedFor')).toBe('root');
expect(component.find(EuiHorizontalRule).exists()).toBe(false);
});
it('should include PanelsToggle when chart is not available', async () => {
const component = await mountComponent({ isChartAvailable: false });
- expect(component.find(PanelsToggle).prop('isChartAvailable')).toBe(false);
- expect(component.find(PanelsToggle).prop('renderedFor')).toBe('tabs');
+ expect(component.find(PanelsToggle).prop('renderedFor')).toBe('root');
expect(component.find(EuiHorizontalRule).exists()).toBe(false);
});
});
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx b/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx
index 78801581418a4..f61a3cdffd644 100644
--- a/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/discover_main_content.tsx
@@ -106,23 +106,11 @@ export const DiscoverMainContent = ({
setDiscoverViewMode={setDiscoverViewMode}
patternCount={patternCount}
dataView={dataView}
- prepend={
- React.isValidElement(panelsToggle)
- ? React.cloneElement(panelsToggle, { renderedFor: 'tabs', isChartAvailable })
- : undefined
- }
+ prepend={panelsToggle}
/>
);
},
- [
- viewMode,
- isEsqlMode,
- stateContainer,
- setDiscoverViewMode,
- dataView,
- panelsToggle,
- isChartAvailable,
- ]
+ [viewMode, isEsqlMode, stateContainer, setDiscoverViewMode, dataView, panelsToggle]
);
const viewModeToggle = useMemo(() => renderViewModeToggle(), [renderViewModeToggle]);
diff --git a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx
index c8f829d442444..863a162c63a93 100644
--- a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx
+++ b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx
@@ -379,6 +379,23 @@ describe('useDiscoverHistogram', () => {
});
expect(hook.result.current.isChartLoading).toBe(true);
});
+
+ it('should use timerange + timeRangeRelative + query given by the internalState container', async () => {
+ const fetch$ = new Subject();
+ const stateContainer = getStateContainer();
+ const timeRangeAbs = { from: '2021-05-01T20:00:00Z', to: '2021-05-02T20:00:00Z' };
+ const timeRangeRel = { from: 'now-15m', to: 'now' };
+ stateContainer.internalState.transitions.setDataRequestParams({
+ timeRangeAbsolute: timeRangeAbs,
+ timeRangeRelative: timeRangeRel,
+ });
+ const { hook } = await renderUseDiscoverHistogram({ stateContainer });
+ act(() => {
+ fetch$.next();
+ });
+ expect(hook.result.current.timeRange).toBe(timeRangeAbs);
+ expect(hook.result.current.relativeTimeRange).toBe(timeRangeRel);
+ });
});
describe('refetching', () => {
diff --git a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts
index 3f2acf0ce933b..b66df7edcd904 100644
--- a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts
+++ b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts
@@ -217,14 +217,9 @@ export const useDiscoverHistogram = ({
* Request params
*/
const { query, filters } = useQuerySubscriber({ data: services.data });
+ const requestParams = useInternalStateSelector((state) => state.dataRequestParams);
const customFilters = useInternalStateSelector((state) => state.customFilters);
- const timefilter = services.data.query.timefilter.timefilter;
- const timeRange = timefilter.getAbsoluteTime();
- const relativeTimeRange = useObservable(
- timefilter.getTimeUpdate$().pipe(map(() => timefilter.getTime())),
- timefilter.getTime()
- );
-
+ const { timeRangeRelative: relativeTimeRange, timeRangeAbsolute: timeRange } = requestParams;
// When in ES|QL mode, update the data view, query, and
// columns only when documents are done fetching so the Lens suggestions
// don't frequently change, such as when the user modifies the table
@@ -272,15 +267,15 @@ export const useDiscoverHistogram = ({
* Data fetching
*/
- const skipRefetch = useRef();
+ const skipRefetch = useRef();
// Skip refetching when showing the chart since Lens will
// automatically fetch when the chart is shown
useEffect(() => {
if (skipRefetch.current === undefined) {
- skipRefetch.current = false;
- } else {
- skipRefetch.current = !hideChart;
+ skipRefetch.current = 0;
+ } else if (!hideChart) {
+ skipRefetch.current = 3;
}
}, [hideChart]);
@@ -309,13 +304,14 @@ export const useDiscoverHistogram = ({
}
const subscription = fetchChart$.subscribe((source) => {
- if (!skipRefetch.current) {
+ if (skipRefetch.current === 0) {
if (source === 'discover') addLog('Unified Histogram - Discover refetch');
if (source === 'lens') addLog('Unified Histogram - Lens suggestion refetch');
unifiedHistogram.refetch();
+ } else {
+ addLog('Unified Histogram - Skip refetch');
+ skipRefetch.current = skipRefetch.current! - 1;
}
-
- skipRefetch.current = false;
});
// triggering the initial request for total hits hook
@@ -499,8 +495,25 @@ const createTotalHitsObservable = (state$?: Observable) =
const createCurrentSuggestionObservable = (state$: Observable) => {
return state$.pipe(
- map((state) => state.currentSuggestionContext),
- distinctUntilChanged(isEqual)
+ // Emit the previous and current state as a pair
+ pairwise(),
+ // Filter out the transition where chartHidden changes from false to true
+ filter(([prev, curr]) => {
+ const isTransition = prev.chartHidden && !curr.chartHidden;
+ if (isTransition) {
+ // console.log('Filtered out transition from chartHidden: false to true');
+ return false;
+ }
+ /**
+ const differences = getDifferences(
+ prev.currentSuggestionContext.suggestion,
+ curr.currentSuggestionContext.suggestion
+ );
+ console.log('Differences in currentSuggestionContext:', differences);
+ **/
+
+ return !isEqual(prev.currentSuggestionContext, curr.currentSuggestionContext);
+ })
);
};
diff --git a/src/plugins/discover/public/application/main/data_fetching/fetch_all.test.ts b/src/plugins/discover/public/application/main/data_fetching/fetch_all.test.ts
index ce2edba5d231e..0f620dab03654 100644
--- a/src/plugins/discover/public/application/main/data_fetching/fetch_all.test.ts
+++ b/src/plugins/discover/public/application/main/data_fetching/fetch_all.test.ts
@@ -81,6 +81,7 @@ describe('test fetchAll', () => {
rowHeight: false,
breakdownField: false,
},
+ dataRequestParams: {},
}),
searchSessionId: '123',
initialFetchStatus: FetchStatus.UNINITIALIZED,
@@ -273,6 +274,7 @@ describe('test fetchAll', () => {
rowHeight: false,
breakdownField: false,
},
+ dataRequestParams: {},
}),
};
fetchAll(subjects, false, deps);
@@ -396,6 +398,7 @@ describe('test fetchAll', () => {
rowHeight: false,
breakdownField: false,
},
+ dataRequestParams: {},
}),
};
fetchAll(subjects, false, deps);
diff --git a/src/plugins/discover/public/application/main/data_fetching/fetch_all.ts b/src/plugins/discover/public/application/main/data_fetching/fetch_all.ts
index f8552411c0add..95a02128eba84 100644
--- a/src/plugins/discover/public/application/main/data_fetching/fetch_all.ts
+++ b/src/plugins/discover/public/application/main/data_fetching/fetch_all.ts
@@ -7,20 +7,33 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
-import { Adapters } from '@kbn/inspector-plugin/common';
+import { Adapters, RequestAdapter } from '@kbn/inspector-plugin/common';
import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public';
import {
BehaviorSubject,
+ catchError,
combineLatest,
distinctUntilChanged,
filter,
firstValueFrom,
+ lastValueFrom,
+ map,
+ of,
race,
switchMap,
} from 'rxjs';
import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
import { isEqual } from 'lodash';
-import { isOfAggregateQueryType } from '@kbn/es-query';
+import {
+ type AggregateQuery,
+ type Filter,
+ isOfAggregateQueryType,
+ type Query,
+ type TimeRange,
+} from '@kbn/es-query';
+import { DataView, DataViewType } from '@kbn/data-views-plugin/common';
+import { i18n } from '@kbn/i18n';
+import { isRunningResponse } from '@kbn/data-plugin/common';
import type { DiscoverAppState } from '../state_management/discover_app_state_container';
import { updateVolatileSearchSource } from './update_search_source';
import {
@@ -97,6 +110,7 @@ export function fetchAll(
services,
sort: getAppState().sort as SortOrder[],
customFilters: getInternalState().customFilters,
+ inputTimeRange: getInternalState().dataRequestParams.timeRangeAbsolute,
});
}
@@ -117,8 +131,29 @@ export function fetchAll(
data,
expressions,
profilesManager,
+ inputTimeRange: getInternalState().dataRequestParams.timeRangeAbsolute,
})
: fetchDocuments(searchSource, fetchDeps);
+ const responseTotalHits =
+ getAppState().hideChart && query && !isEsqlQuery
+ ? fetchTotalHitsSearchSource({
+ services,
+ searchSessionId: fetchDeps.searchSessionId,
+ adapter: inspectorAdapters.requests,
+ abortSignal: abortController.signal,
+ dataView,
+ filters: getInternalState().customFilters,
+ query,
+ timeRange: getInternalState().dataRequestParams.timeRangeAbsolute!,
+ })
+ : undefined;
+ responseTotalHits?.then(({ result, resultStatus }) => {
+ dataSubjects.totalHits$.next({
+ fetchStatus: resultStatus,
+ result,
+ });
+ });
+
const fetchType = isEsqlQuery ? 'fetchTextBased' : 'fetchDocuments';
const startTime = window.performance.now();
@@ -281,3 +316,88 @@ const noResultsFound = (subject: DataMain$) => {
)
);
};
+
+const fetchTotalHitsSearchSource = async ({
+ services: { data },
+ abortSignal,
+ adapter,
+ dataView,
+ searchSessionId,
+ filters: originalFilters,
+ query,
+ timeRange,
+}: {
+ services: DiscoverServices;
+ abortSignal: AbortSignal;
+ dataView: DataView;
+ searchSessionId: string | undefined;
+ adapter: RequestAdapter | undefined;
+ filters: Filter[];
+ query: Query | AggregateQuery;
+ timeRange: TimeRange;
+}) => {
+ const searchSource = data.search.searchSource.createEmpty();
+
+ searchSource
+ .setField('index', dataView)
+ .setField('query', query)
+ .setField('size', 0)
+ .setField('trackTotalHits', true);
+
+ let filters = originalFilters;
+
+ if (dataView.type === DataViewType.ROLLUP) {
+ // We treat that data view as "normal" even if it was a rollup data view,
+ // since the rollup endpoint does not support querying individual documents, but we
+ // can get them from the regular _search API that will be used if the data view
+ // not a rollup data view.
+ searchSource.setOverwriteDataViewType(undefined);
+ } else {
+ // Set the date range filter fields from timeFilter using the absolute format.
+ // Search sessions requires that it be converted from a relative range
+ const timeFilter = data.query.timefilter.timefilter.createFilter(dataView, timeRange);
+
+ if (timeFilter) {
+ filters = [...filters, timeFilter];
+ }
+ }
+
+ searchSource.setField('filter', filters);
+
+ // Let the consumer inspect the request if they want to track it
+ const inspector = adapter
+ ? {
+ adapter,
+ title: i18n.translate('discover.inspectorRequestDataTitleTotalHits', {
+ defaultMessage: 'Total hits',
+ }),
+ description: i18n.translate('discove.inspectorRequestDescriptionTotalHits', {
+ defaultMessage: 'This request queries Elasticsearch to fetch the total hits.',
+ }),
+ }
+ : undefined;
+
+ const fetch$ = searchSource
+ .fetch$({
+ inspector,
+ sessionId: searchSessionId,
+ abortSignal,
+ executionContext: {
+ description: 'fetch total hits',
+ },
+ disableWarningToasts: true, // TODO: show warnings as a badge next to total hits number
+ })
+ .pipe(
+ filter((res) => !isRunningResponse(res)),
+ map((res) => res.rawResponse.hits.total as number),
+ catchError((error: Error) => of(error))
+ );
+
+ const result = await lastValueFrom(fetch$);
+
+ const resultStatus = result instanceof Error ? FetchStatus.ERROR : FetchStatus.COMPLETE;
+
+ const nrOfHits = result instanceof Error ? undefined : result;
+
+ return { resultStatus, result: nrOfHits };
+};
diff --git a/src/plugins/discover/public/application/main/data_fetching/fetch_esql.test.ts b/src/plugins/discover/public/application/main/data_fetching/fetch_esql.test.ts
index f4f2d6e4fa4af..4fcac182a7864 100644
--- a/src/plugins/discover/public/application/main/data_fetching/fetch_esql.test.ts
+++ b/src/plugins/discover/public/application/main/data_fetching/fetch_esql.test.ts
@@ -13,13 +13,23 @@ import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { of } from 'rxjs';
import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield';
import { discoverServiceMock } from '../../../__mocks__/services';
-import { fetchEsql } from './fetch_esql';
+import { fetchEsql, getTextBasedQueryStateToAstProps } from './fetch_esql';
+import { TimeRange } from '@kbn/es-query';
describe('fetchEsql', () => {
beforeEach(() => {
jest.clearAllMocks();
});
+ const fetchEsqlMockProps = {
+ query: { esql: 'from *' },
+ dataView: dataViewWithTimefieldMock,
+ inspectorAdapters: { requests: new RequestAdapter() },
+ data: discoverServiceMock.data,
+ expressions: discoverServiceMock.expressions,
+ profilesManager: discoverServiceMock.profilesManager,
+ };
+
it('resolves with returned records', async () => {
const hits = [
{ _id: '1', foo: 'bar' },
@@ -46,16 +56,7 @@ describe('fetchEsql', () => {
discoverServiceMock.profilesManager,
'resolveDocumentProfile'
);
- expect(
- await fetchEsql({
- query: { esql: 'from *' },
- dataView: dataViewWithTimefieldMock,
- inspectorAdapters: { requests: new RequestAdapter() },
- data: discoverServiceMock.data,
- expressions: discoverServiceMock.expressions,
- profilesManager: discoverServiceMock.profilesManager,
- })
- ).toEqual({
+ expect(await fetchEsql(fetchEsqlMockProps)).toEqual({
records,
esqlQueryColumns: ['_id', 'foo'],
esqlHeaderWarning: undefined,
@@ -64,4 +65,24 @@ describe('fetchEsql', () => {
expect(resolveDocumentProfileSpy).toHaveBeenCalledWith({ record: records[0] });
expect(resolveDocumentProfileSpy).toHaveBeenCalledWith({ record: records[1] });
});
+
+ it('should use inputTimeRange if provided', () => {
+ const inputTimeRange: TimeRange = { from: 'now-15m', to: 'now' };
+ const result = getTextBasedQueryStateToAstProps({ ...fetchEsqlMockProps, inputTimeRange });
+ expect(result.time).toEqual(inputTimeRange);
+ });
+
+ it('should use absolute time from data if inputTimeRange is not provided', () => {
+ const absoluteTimeRange: TimeRange = {
+ from: '2021-08-31T22:00:00.000Z',
+ to: '2021-09-01T22:00:00.000Z',
+ };
+ jest
+ .spyOn(discoverServiceMock.data.query.timefilter.timefilter, 'getAbsoluteTime')
+ .mockReturnValue(absoluteTimeRange);
+
+ const result = getTextBasedQueryStateToAstProps(fetchEsqlMockProps);
+
+ expect(result.time).toEqual(absoluteTimeRange);
+ });
});
diff --git a/src/plugins/discover/public/application/main/data_fetching/fetch_esql.ts b/src/plugins/discover/public/application/main/data_fetching/fetch_esql.ts
index d7cad10b177f6..254dc96a31c44 100644
--- a/src/plugins/discover/public/application/main/data_fetching/fetch_esql.ts
+++ b/src/plugins/discover/public/application/main/data_fetching/fetch_esql.ts
@@ -51,20 +51,16 @@ export function fetchEsql({
expressions: ExpressionsStart;
profilesManager: ProfilesManager;
}): Promise {
- const timeRange = inputTimeRange ?? data.query.timefilter.timefilter.getTime();
- return textBasedQueryStateToAstWithValidation({
- filters,
+ const props = getTextBasedQueryStateToAstProps({
query,
- time: timeRange,
- timeFieldName: dataView.timeFieldName,
inputQuery,
- titleForInspector: i18n.translate('discover.inspectorEsqlRequestTitle', {
- defaultMessage: 'Table',
- }),
- descriptionForInspector: i18n.translate('discover.inspectorEsqlRequestDescription', {
- defaultMessage: 'This request queries Elasticsearch to fetch results for the table.',
- }),
- })
+ filters,
+ inputTimeRange,
+ dataView,
+ inspectorAdapters,
+ data,
+ });
+ return textBasedQueryStateToAstWithValidation(props)
.then((ast) => {
if (ast) {
const contract = expressions.execute(ast, null, {
@@ -118,3 +114,34 @@ export function fetchEsql({
throw new Error(err.message);
});
}
+export function getTextBasedQueryStateToAstProps({
+ query,
+ inputQuery,
+ filters,
+ inputTimeRange,
+ dataView,
+ data,
+}: {
+ query: Query | AggregateQuery;
+ inputQuery?: Query;
+ filters?: Filter[];
+ inputTimeRange?: TimeRange;
+ dataView: DataView;
+ inspectorAdapters: Adapters;
+ data: DataPublicPluginStart;
+}) {
+ const timeRange = inputTimeRange ?? data.query.timefilter.timefilter.getAbsoluteTime();
+ return {
+ filters,
+ query,
+ time: timeRange,
+ timeFieldName: dataView.timeFieldName,
+ inputQuery,
+ titleForInspector: i18n.translate('discover.inspectorEsqlRequestTitle', {
+ defaultMessage: 'Table',
+ }),
+ descriptionForInspector: i18n.translate('discover.inspectorEsqlRequestDescription', {
+ defaultMessage: 'This request queries Elasticsearch to fetch results for the table.',
+ }),
+ };
+}
diff --git a/src/plugins/discover/public/application/main/data_fetching/update_search_source.ts b/src/plugins/discover/public/application/main/data_fetching/update_search_source.ts
index ad79e93ec37e4..05ba512d0e716 100644
--- a/src/plugins/discover/public/application/main/data_fetching/update_search_source.ts
+++ b/src/plugins/discover/public/application/main/data_fetching/update_search_source.ts
@@ -7,9 +7,9 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
-import { ISearchSource } from '@kbn/data-plugin/public';
-import { DataViewType, DataView } from '@kbn/data-views-plugin/public';
-import { Filter } from '@kbn/es-query';
+import type { ISearchSource } from '@kbn/data-plugin/public';
+import { DataViewType, type DataView } from '@kbn/data-views-plugin/public';
+import type { Filter, TimeRange } from '@kbn/es-query';
import type { SortOrder } from '@kbn/saved-search-plugin/public';
import { SORT_DEFAULT_ORDER_SETTING } from '@kbn/discover-utils';
import { DiscoverServices } from '../../../build_services';
@@ -25,11 +25,13 @@ export function updateVolatileSearchSource(
services,
sort,
customFilters,
+ inputTimeRange,
}: {
dataView: DataView;
services: DiscoverServices;
sort?: SortOrder[];
customFilters: Filter[];
+ inputTimeRange?: TimeRange;
}
) {
const { uiSettings, data } = services;
@@ -48,7 +50,7 @@ export function updateVolatileSearchSource(
if (dataView.type !== DataViewType.ROLLUP) {
// Set the date range filter fields from timeFilter using the absolute format. Search sessions requires that it be converted from a relative range
- const timeFilter = data.query.timefilter.timefilter.createFilter(dataView);
+ const timeFilter = data.query.timefilter.timefilter.createFilter(dataView, inputTimeRange);
filters = timeFilter ? [...filters, timeFilter] : filters;
}
diff --git a/src/plugins/discover/public/application/main/state_management/discover_data_state_container.ts b/src/plugins/discover/public/application/main/state_management/discover_data_state_container.ts
index 59220d7def3c1..29960268a8144 100644
--- a/src/plugins/discover/public/application/main/state_management/discover_data_state_container.ts
+++ b/src/plugins/discover/public/application/main/state_management/discover_data_state_container.ts
@@ -13,7 +13,6 @@ import type { DatatableColumn } from '@kbn/expressions-plugin/common';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
import { AggregateQuery, isOfAggregateQueryType, Query } from '@kbn/es-query';
-import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types';
import type { DataView } from '@kbn/data-views-plugin/common';
import { reportPerformanceMetricEvent } from '@kbn/ebt-tools';
import type { SearchResponseWarning } from '@kbn/search-response-warnings';
@@ -66,14 +65,6 @@ export interface DataTotalHitsMsg extends DataMsg {
result?: number;
}
-export interface DataChartsMessage extends DataMsg {
- response?: SearchResponse;
-}
-
-export interface DataAvailableFieldsMsg extends DataMsg {
- fields?: string[];
-}
-
export interface DiscoverDataStateContainer {
/**
* Implicitly starting fetching data from ES
@@ -106,7 +97,7 @@ export interface DiscoverDataStateContainer {
/**
* resetting all data observable to initial state
*/
- reset: () => void;
+ reset: (status?: FetchStatus) => void;
/**
* cancels the running queries
@@ -254,6 +245,11 @@ export function getDataStateContainer({
return;
}
+ internalStateContainer.transitions.setDataRequestParams({
+ timeRangeAbsolute: timefilter.getAbsoluteTime(),
+ timeRangeRelative: timefilter.getTime(),
+ });
+
await profilesManager.resolveDataSourceProfile({
dataSource: appStateContainer.getState().dataSource,
dataView: getSavedSearch().searchSource.getField('index'),
@@ -366,8 +362,9 @@ export function getDataStateContainer({
return refetch$;
};
- const reset = () => {
- sendResetMsg(dataSubjects, getInitialFetchStatus());
+ const reset = (status?: FetchStatus) => {
+ const fetchStatus = status || getInitialFetchStatus();
+ sendResetMsg(dataSubjects, fetchStatus);
};
const cancel = () => {
diff --git a/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts b/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts
index 8aad8eb91738b..74815ad816daf 100644
--- a/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts
+++ b/src/plugins/discover/public/application/main/state_management/discover_internal_state_container.ts
@@ -14,10 +14,15 @@ import {
ReduxLikeStateContainer,
} from '@kbn/kibana-utils-plugin/common';
import type { DataView, DataViewListItem } from '@kbn/data-views-plugin/common';
-import type { Filter } from '@kbn/es-query';
+import type { Filter, TimeRange } from '@kbn/es-query';
import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { UnifiedHistogramVisContext } from '@kbn/unified-histogram-plugin/public';
+interface InternalStateDataRequestParams {
+ timeRangeAbsolute?: TimeRange;
+ timeRangeRelative?: TimeRange;
+}
+
export interface InternalState {
dataView: DataView | undefined;
isDataViewLoading: boolean;
@@ -33,6 +38,7 @@ export interface InternalState {
rowHeight: boolean;
breakdownField: boolean;
};
+ dataRequestParams: InternalStateDataRequestParams;
}
export interface InternalStateTransitions {
@@ -65,6 +71,9 @@ export interface InternalStateTransitions {
) => (
resetDefaultProfileState: Omit
) => InternalState;
+ setDataRequestParams: (
+ state: InternalState
+ ) => (params: InternalStateDataRequestParams) => InternalState;
}
export type DiscoverInternalStateContainer = ReduxLikeStateContainer<
@@ -91,6 +100,7 @@ export function getInternalStateContainer() {
rowHeight: false,
breakdownField: false,
},
+ dataRequestParams: {},
},
{
setDataView: (prevState: InternalState) => (nextDataView: DataView) => ({
@@ -162,6 +172,11 @@ export function getInternalStateContainer() {
overriddenVisContextAfterInvalidation: undefined,
expandedDoc: undefined,
}),
+ setDataRequestParams:
+ (prevState: InternalState) => (params: InternalStateDataRequestParams) => ({
+ ...prevState,
+ dataRequestParams: params,
+ }),
setResetDefaultProfileState:
(prevState: InternalState) =>
(resetDefaultProfileState: Omit) => ({
diff --git a/src/plugins/discover/public/application/main/state_management/utils/load_saved_search.ts b/src/plugins/discover/public/application/main/state_management/utils/load_saved_search.ts
index 295bfe01c5d7a..c875533208215 100644
--- a/src/plugins/discover/public/application/main/state_management/utils/load_saved_search.ts
+++ b/src/plugins/discover/public/application/main/state_management/utils/load_saved_search.ts
@@ -10,6 +10,7 @@
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
import { cloneDeep, isEqual } from 'lodash';
import { isOfAggregateQueryType } from '@kbn/es-query';
+import { FetchStatus } from '../../../types';
import { getEsqlDataView } from './get_esql_data_view';
import { loadAndResolveDataView } from './resolve_data_view';
import { DiscoverInternalStateContainer } from '../discover_internal_state_container';
@@ -162,7 +163,7 @@ function updateBySavedSearch(savedSearch: SavedSearch, deps: LoadSavedSearchDeps
}
// Finally notify dataStateContainer, data.query and filterManager about new derived state
- dataStateContainer.reset();
+ dataStateContainer.reset(FetchStatus.SETUP);
// set data service filters
const filters = savedSearch.searchSource.getField('filter');
if (Array.isArray(filters) && filters.length) {
diff --git a/src/plugins/discover/public/application/main/utils/get_result_state.ts b/src/plugins/discover/public/application/main/utils/get_result_state.ts
index 070ba65b0e902..9c16b7155f0e7 100644
--- a/src/plugins/discover/public/application/main/utils/get_result_state.ts
+++ b/src/plugins/discover/public/application/main/utils/get_result_state.ts
@@ -21,7 +21,7 @@ export const resultStatuses = {
* Determines what is displayed in Discover main view (loading view, data view, empty data view, ...)
*/
export function getResultState(fetchStatus: FetchStatus, foundDocuments: boolean = false) {
- if (fetchStatus === FetchStatus.UNINITIALIZED) {
+ if (fetchStatus === FetchStatus.UNINITIALIZED || fetchStatus === FetchStatus.SETUP) {
return resultStatuses.UNINITIALIZED;
}
if (fetchStatus === FetchStatus.ERROR) return resultStatuses.NO_RESULTS;
diff --git a/src/plugins/discover/public/application/types.ts b/src/plugins/discover/public/application/types.ts
index 9d25158750f10..433f775797f5a 100644
--- a/src/plugins/discover/public/application/types.ts
+++ b/src/plugins/discover/public/application/types.ts
@@ -12,6 +12,7 @@ import type { DataTableRecord } from '@kbn/discover-utils/types';
import type { SearchResponseWarning } from '@kbn/search-response-warnings';
export enum FetchStatus {
+ SETUP = 'setup',
UNINITIALIZED = 'uninitialized',
LOADING = 'loading',
LOADING_MORE = 'loading_more',
diff --git a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.ts b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.ts
index 1399074816903..dca6e37dfdd5f 100644
--- a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.ts
+++ b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.ts
@@ -129,7 +129,7 @@ const fetchTotalHits = async ({
onTotalHitsChange?.(response.resultStatus, response.result);
};
-const fetchTotalHitsSearchSource = async ({
+export const fetchTotalHitsSearchSource = async ({
services: { data },
abortController,
dataView,
diff --git a/test/functional/apps/discover/group3/_request_counts.ts b/test/functional/apps/discover/group3/_request_counts.ts
index ecf84ede5a714..267d5f891a740 100644
--- a/test/functional/apps/discover/group3/_request_counts.ts
+++ b/test/functional/apps/discover/group3/_request_counts.ts
@@ -158,7 +158,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
log.debug('Creating saved search');
await expectSearches(
type,
- type === 'esql' ? actualExpectedRequests + 2 : actualExpectedRequests,
+ type === 'esql' ? actualExpectedRequests + 1 : actualExpectedRequests,
async () => {
await discover.saveSearch(savedSearch);
}
@@ -173,7 +173,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
log.debug('Clearing saved search');
await expectSearches(
type,
- type === 'esql' ? actualExpectedRequests + 2 : actualExpectedRequests,
+ type === 'esql' ? actualExpectedRequests + 1 : actualExpectedRequests,
async () => {
await testSubjects.click('discoverNewButton');
await waitForLoadingToFinish();
@@ -182,7 +182,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
log.debug('Loading saved search');
await expectSearches(
type,
- type === 'esql' ? actualExpectedRequests + 2 : actualExpectedRequests,
+ type === 'esql' ? actualExpectedRequests + 1 : actualExpectedRequests,
async () => {
await discover.loadSavedSearch(savedSearch);
}
@@ -285,7 +285,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await expectSearches(type, 1, async () => {
await discover.toggleChartVisibility();
});
- await expectSearches(type, 3, async () => {
+ await expectSearches(type, 2, async () => {
await discover.toggleChartVisibility();
});
});