diff --git a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts index ccc8158ecace..07130c84b6fd 100644 --- a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts +++ b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts @@ -39,6 +39,18 @@ export const METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP = Object.freeze>({ + 'Data Retained in Storage': 'storage_retained', + 'Data Ingested': 'ingest_rate', + 'Search VCU': 'search_vcu', + 'Ingest VCU': 'ingest_vcu', + 'ML VCU': 'ml_vcu', + 'Index Latency': 'index_latency', + 'Index Rate': 'index_rate', + 'Search Latency': 'search_latency', + 'Search Rate': 'search_rate', +}); + // type guard for MetricTypes export const isMetricType = (type: string): type is MetricTypes => METRIC_TYPE_VALUES.includes(type as MetricTypes); diff --git a/x-pack/plugins/data_usage/common/test_utils/index.ts b/x-pack/plugins/data_usage/common/test_utils/index.ts index c3c8e75b2945..4e13a4048ee2 100644 --- a/x-pack/plugins/data_usage/common/test_utils/index.ts +++ b/x-pack/plugins/data_usage/common/test_utils/index.ts @@ -7,4 +7,3 @@ export { TestProvider } from './test_provider'; export { dataUsageTestQueryClientOptions } from './test_query_client_options'; -export { timeXMinutesAgo } from './time_ago'; diff --git a/x-pack/plugins/data_usage/common/test_utils/time_ago.ts b/x-pack/plugins/data_usage/common/test_utils/time_ago.ts deleted file mode 100644 index 7fe74e232bda..000000000000 --- a/x-pack/plugins/data_usage/common/test_utils/time_ago.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const timeXMinutesAgo = (x: number) => - new Date(new Date().getTime() - x * 60 * 1000).toISOString(); diff --git a/x-pack/plugins/data_usage/common/utils.test.ts b/x-pack/plugins/data_usage/common/utils.test.ts new file mode 100644 index 000000000000..fc6b158c1caa --- /dev/null +++ b/x-pack/plugins/data_usage/common/utils.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isDateRangeValid } from './utils'; + +describe('isDateRangeValid', () => { + describe('Valid ranges', () => { + it.each([ + ['both start and end date is `now`', { start: 'now', end: 'now' }], + ['start date is `now-10s` and end date is `now`', { start: 'now-10s', end: 'now' }], + ['bounded within the min and max date range', { start: 'now-8d', end: 'now-4s' }], + ])('should return true if %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(true); + }); + }); + + describe('Invalid ranges', () => { + it.each([ + ['starts before the min date', { start: 'now-11d', end: 'now-5s' }], + ['ends after the max date', { start: 'now-9d', end: 'now+2s' }], + [ + 'end date is before the start date even when both are within min and max date range', + { start: 'now-3s', end: 'now-10s' }, + ], + ])('should return false if the date range %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/data_usage/common/utils.ts b/x-pack/plugins/data_usage/common/utils.ts index ddd707b1134f..3fd7240153d4 100644 --- a/x-pack/plugins/data_usage/common/utils.ts +++ b/x-pack/plugins/data_usage/common/utils.ts @@ -6,5 +6,50 @@ */ import dateMath from '@kbn/datemath'; -export const dateParser = (date: string) => dateMath.parse(date)?.toISOString(); + +export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ + autoRefreshOptions: { + enabled: false, + duration: 10000, + }, + startDate: 'now-24h/h', + endDate: 'now', + maxDate: 'now+1s', + minDate: 'now-9d', + recentlyUsedDateRanges: [], +}); + export const momentDateParser = (date: string) => dateMath.parse(date); +export const transformToUTCtime = ({ + start, + end, + isISOString = false, +}: { + start: string; + end: string; + isISOString?: boolean; +}) => { + const utcOffset = momentDateParser(start)?.utcOffset() ?? 0; + const utcStart = momentDateParser(start)?.utc().add(utcOffset, 'm'); + const utcEnd = momentDateParser(end)?.utc().add(utcOffset, 'm'); + return { + start: isISOString ? utcStart?.toISOString() : momentDateParser(start), + end: isISOString ? utcEnd?.toISOString() : momentDateParser(end), + }; +}; + +export const isDateRangeValid = ({ start, end }: { start: string; end: string }): boolean => { + const startDate = momentDateParser(start); + const endDate = momentDateParser(end); + + if (!startDate || !endDate) { + return false; + } + const minDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.minDate); + const maxDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.maxDate); + return ( + startDate.isSameOrAfter(minDate, 's') && + endDate.isSameOrBefore(maxDate, 's') && + startDate <= endDate + ); +}; diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx index 91e2fd5ddafa..befae95393e1 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx @@ -344,18 +344,27 @@ describe('DataUsageMetrics', () => { }); it('should refetch usage metrics with `Refresh` button click', async () => { - const refetch = jest.fn(); - mockUseGetDataUsageMetrics.mockReturnValue({ - ...getBaseMockedDataUsageMetrics, - data: ['.ds-1', '.ds-2'], - isFetched: true, + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: generateDataStreams(3), + isFetching: false, }); + const refetch = jest.fn(); mockUseGetDataUsageMetrics.mockReturnValue({ ...getBaseMockedDataUsageMetrics, - isFetched: true, + data: {}, + isFetched: false, refetch, }); - const { getByTestId } = renderComponent(); + const { getByTestId, getAllByTestId } = renderComponent(); + + const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); + + expect(toggleFilterButton).toHaveTextContent('Data streams3'); + await user.click(toggleFilterButton); + const allFilterOptions = getAllByTestId('dataStreams-filter-option'); + await user.click(allFilterOptions[2]); + const refreshButton = getByTestId(`${testIdFilter}-super-refresh-button`); // click refresh 5 times for (let i = 0; i < 5; i++) { @@ -364,7 +373,7 @@ describe('DataUsageMetrics', () => { expect(mockUseGetDataUsageMetrics).toHaveBeenLastCalledWith( expect.any(Object), - expect.objectContaining({ enabled: false }) + expect.objectContaining({ enabled: true }) ); expect(refetch).toHaveBeenCalledTimes(5); }); diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx index d7d6417cf144..efaa779dfe3c 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx @@ -17,7 +17,12 @@ import { PLUGIN_NAME } from '../../translations'; import { useGetDataUsageMetrics } from '../../hooks/use_get_usage_metrics'; import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams'; import { useDataUsageMetricsUrlParams } from '../hooks/use_charts_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS, useDateRangePicker } from '../hooks/use_date_picker'; +import { + DEFAULT_DATE_RANGE_OPTIONS, + transformToUTCtime, + isDateRangeValid, +} from '../../../common/utils'; +import { useDateRangePicker } from '../hooks/use_date_picker'; import { ChartFilters, ChartFiltersProps } from './filters/charts_filters'; import { ChartsLoading } from './charts_loading'; import { NoDataCallout } from './no_data_callout'; @@ -104,11 +109,39 @@ export const DataUsageMetrics = memo( ...prevState, metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes, dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams, + from: startDateFromUrl ?? prevState.from, + to: endDateFromUrl ?? prevState.to, })); - }, [metricTypesFromUrl, dataStreamsFromUrl]); + }, [metricTypesFromUrl, dataStreamsFromUrl, startDateFromUrl, endDateFromUrl]); const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); + const isValidDateRange = useMemo( + () => + isDateRangeValid({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + }), + [dateRangePickerState.endDate, dateRangePickerState.startDate] + ); + + const enableFetchUsageMetricsData = useMemo( + () => + isValidDateRange && + metricsFilters.dataStreams.length > 0 && + metricsFilters.metricTypes.length > 0, + [isValidDateRange, metricsFilters.dataStreams, metricsFilters.metricTypes] + ); + + const utcTimeRange = useMemo( + () => + transformToUTCtime({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + isISOString: true, + }), + [dateRangePickerState] + ); const { error: errorFetchingDataUsageMetrics, data: usageMetricsData, @@ -118,12 +151,12 @@ export const DataUsageMetrics = memo( } = useGetDataUsageMetrics( { ...metricsFilters, - from: dateRangePickerState.startDate, - to: dateRangePickerState.endDate, + from: utcTimeRange.start as string, + to: utcTimeRange.end as string, }, { retry: false, - enabled: !!(metricsFilters.dataStreams.length && metricsFilters.metricTypes.length), + enabled: enableFetchUsageMetricsData, } ); @@ -134,8 +167,11 @@ export const DataUsageMetrics = memo( }, [isFetching, hasFetchedDataUsageMetricsData]); const onRefresh = useCallback(() => { + if (!enableFetchUsageMetricsData) { + return; + } refetchDataUsageMetrics(); - }, [refetchDataUsageMetrics]); + }, [enableFetchUsageMetricsData, refetchDataUsageMetrics]); const onChangeDataStreamsFilter = useCallback( (selectedDataStreams: string[]) => { @@ -206,6 +242,7 @@ export const DataUsageMetrics = memo( ( if (isMetricsFilter) { setUrlMetricTypesFilter( optionsToSelect - .map((option) => findKey(METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP, option)) + .map((option) => METRIC_TYPE_UI_OPTIONS_VALUES_TO_API_MAP[option]) .join(',') ); } diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx index 3b2142e0e336..52561aa9f26f 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx @@ -20,6 +20,7 @@ import { FilterName } from '../../hooks'; export interface ChartFiltersProps { dateRangePickerState: DateRangePickerValues; isDataLoading: boolean; + isUpdateDisabled: boolean; filterOptions: Record; onRefresh: () => void; onRefreshChange: (evt: OnRefreshChangeProps) => void; @@ -33,6 +34,7 @@ export const ChartFilters = memo( ({ dateRangePickerState, isDataLoading, + isUpdateDisabled, filterOptions, onClick, onRefresh, @@ -59,7 +61,8 @@ export const ChartFilters = memo( const onClickRefreshButton = useCallback(() => onClick(), [onClick]); return ( - + + {filters} @@ -78,6 +81,7 @@ export const ChartFilters = memo( data-test-subj={getTestId('super-refresh-button')} fill={false} isLoading={isDataLoading} + isDisabled={isUpdateDisabled} onClick={onClickRefreshButton} /> diff --git a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx index 81ab435670f8..1b04587b4245 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx @@ -15,9 +15,8 @@ import type { OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; -import { momentDateParser } from '../../../../common/utils'; +import { momentDateParser, DEFAULT_DATE_RANGE_OPTIONS } from '../../../../common/utils'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; -import { DEFAULT_DATE_RANGE_OPTIONS } from '../../hooks/use_date_picker'; export interface DateRangePickerValues { autoRefreshOptions: { diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx index 3a1ba7dc1de6..37e1fdc5d1ab 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx @@ -8,7 +8,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { type MetricTypes, isMetricType } from '../../../common/rest_types'; import { useUrlParams } from '../../hooks/use_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS } from './use_date_picker'; +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; interface UrlParamsDataUsageMetricsFilters { metricTypes: string; diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx index f4d198461f73..6b7e6f792b69 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx @@ -12,18 +12,7 @@ import type { } from '@elastic/eui/src/components/date_picker/types'; import { useDataUsageMetricsUrlParams } from './use_charts_url_params'; import { DateRangePickerValues } from '../components/filters/date_picker'; - -export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ - autoRefreshOptions: { - enabled: false, - duration: 10000, - }, - startDate: 'now-24h/h', - endDate: 'now', - maxDate: 'now+1s', - minDate: 'now-9d', - recentlyUsedDateRanges: [], -}); +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; export const useDateRangePicker = () => { const { diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx index 1ddb84d89ffc..4532126bc1a5 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx @@ -11,7 +11,8 @@ import { renderHook } from '@testing-library/react-hooks'; import { useGetDataUsageMetrics } from './use_get_usage_metrics'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; import { coreMock as mockCore } from '@kbn/core/public/mocks'; -import { dataUsageTestQueryClientOptions, timeXMinutesAgo } from '../../common/test_utils'; +import { dataUsageTestQueryClientOptions } from '../../common/test_utils'; +import { transformToUTCtime } from '../../common/utils'; const useQueryMock = _useQuery as jest.Mock; @@ -40,16 +41,31 @@ jest.mock('../utils/use_kibana', () => { }; }); -const defaultUsageMetricsRequestBody = { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), - metricTypes: ['ingest_rate'], - dataStreams: ['ds-1'], -}; - describe('useGetDataUsageMetrics', () => { + const timeRange = { + start: 'now-15m', + end: 'now', + }; + const getUtcTimeRange = (range: { start: string; end: string }) => + transformToUTCtime({ + ...range, + isISOString: true, + }); + let defaultUsageMetricsRequestBody = { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: ['ds-1'], + }; + beforeEach(() => { jest.clearAllMocks(); + + defaultUsageMetricsRequestBody = { + ...defaultUsageMetricsRequestBody, + from: getUtcTimeRange(timeRange).start as string, + to: getUtcTimeRange(timeRange).end as string, + }; }); it('should call the correct API', async () => { @@ -67,6 +83,19 @@ describe('useGetDataUsageMetrics', () => { }); }); + it('should not call the API if invalid date range', async () => { + const requestBody = { + ...defaultUsageMetricsRequestBody, + from: 'invalid-date', + to: 'invalid-date', + }; + await renderHook(() => useGetDataUsageMetrics(requestBody, { enabled: true }), { + wrapper: createWrapper(), + }); + + expect(mockServices.http.post).not.toHaveBeenCalled(); + }); + it('should not call the API if disabled', async () => { await renderHook( () => useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { enabled: false }), diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts index da5f3004d002..649bcb45ee37 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts @@ -8,7 +8,7 @@ import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { dateParser } from '../../common/utils'; +import { momentDateParser } from '../../common/utils'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; import type { UsageMetricsRequestBody, @@ -27,9 +27,15 @@ export const useGetDataUsageMetrics = ( ): UseQueryResult> => { const { http } = useKibanaContextForPlugin().services; + // parse values anyway to ensure they are valid + // and to avoid sending invalid values to the server + const from = momentDateParser(body.from)?.toISOString(); + const to = momentDateParser(body.to)?.toISOString(); + return useQuery>({ queryKey: ['get-data-usage-metrics', body], ...options, + enabled: !!(from && to) && options.enabled, keepPreviousData: true, queryFn: async ({ signal }) => { return http @@ -37,8 +43,8 @@ export const useGetDataUsageMetrics = ( signal, version: '1', body: JSON.stringify({ - from: dateParser(body.from), - to: dateParser(body.to), + from, + to, metricTypes: body.metricTypes, dataStreams: body.dataStreams, }), diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts index c0eb0e5e8ef2..f2bccd6d9c6b 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts @@ -19,7 +19,16 @@ import { DATA_USAGE_METRICS_API_ROUTE } from '../../../common'; import { createMockedDataUsageContext } from '../../mocks'; import { CustomHttpRequestError } from '../../utils'; import { AutoOpsError } from '../../services/errors'; -import { timeXMinutesAgo } from '../../../common/test_utils'; +import { transformToUTCtime } from '../../../common/utils'; + +const timeRange = { + start: 'now-15m', + end: 'now', +}; +const utcTimeRange = transformToUTCtime({ + ...timeRange, + isISOString: true, +}); describe('registerUsageMetricsRoute', () => { let mockCore: MockedKeys>; @@ -56,8 +65,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: [], }, @@ -123,8 +132,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate', 'storage_retained'], dataStreams: ['.ds-1', '.ds-2'], }, @@ -191,8 +200,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: timeXMinutesAgo(15), - to: timeXMinutesAgo(0), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: ['.ds-1', '.ds-2'], }, diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts index c2dee4ca2ce5..eb27c2a9b7ed 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts @@ -7,6 +7,7 @@ import { chunk } from 'lodash/fp'; import { RequestHandler } from '@kbn/core/server'; +import { momentDateParser } from '../../../common/utils'; import type { MetricTypes, UsageMetricsAutoOpsResponseSchemaBody, @@ -37,6 +38,17 @@ export const getUsageMetricsHandler = ( logger.debug(`Retrieving usage metrics`); const { from, to, metricTypes, dataStreams: requestDsNames } = request.body; + // parse date strings to validate + const parsedFrom = momentDateParser(from)?.toISOString(); + const parsedTo = momentDateParser(to)?.toISOString(); + + if (!parsedFrom || !parsedTo) { + const customErrorMessage = `[request body.${ + !parsedTo ? 'to' : 'from' + }] Invalid date range ${!parsedTo ? to : from} is out of range`; + return errorHandler(logger, response, new CustomHttpRequestError(customErrorMessage, 400)); + } + // redundant check as we don't allow making requests via UI without data streams, // but it's here to make sure the request body is validated before requesting metrics from auto-ops if (!requestDsNames?.length) { @@ -74,8 +86,8 @@ export const getUsageMetricsHandler = ( const dataUsageService = new DataUsageService(logger); const metrics = await dataUsageService.getMetrics({ - from, - to, + from: parsedFrom, + to: parsedTo, metricTypes: formatStringParams(metricTypes) as MetricTypes[], dataStreams: formatStringParams(dataStreamsResponse.map((ds) => ds.name)), }); diff --git a/x-pack/plugins/data_usage/server/services/autoops_api.ts b/x-pack/plugins/data_usage/server/services/autoops_api.ts index 2ff824e04f6d..ac9265d081d3 100644 --- a/x-pack/plugins/data_usage/server/services/autoops_api.ts +++ b/x-pack/plugins/data_usage/server/services/autoops_api.ts @@ -14,12 +14,12 @@ import { Logger } from '@kbn/logging'; import type { AxiosError, AxiosRequestConfig } from 'axios'; import axios from 'axios'; import { LogMeta } from '@kbn/core/server'; +import { momentDateParser } from '../../common/utils'; import { UsageMetricsAutoOpsResponseSchema, type UsageMetricsAutoOpsResponseSchemaBody, type UsageMetricsRequestBody, } from '../../common/rest_types'; -import { dateParser } from '../../common/utils'; import { AutoOpsConfig } from '../types'; import { AutoOpsError } from './errors'; import { appContextService } from './app_context'; @@ -76,8 +76,8 @@ export class AutoOpsAPIService { const requestConfig: AxiosRequestConfig = { url: getAutoOpsAPIRequestUrl(autoopsConfig.api?.url, cloudSetup?.serverless.projectId), data: { - from: dateParser(requestBody.from), - to: dateParser(requestBody.to), + from: momentDateParser(requestBody.from)?.toISOString(), + to: momentDateParser(requestBody.to)?.toISOString(), size: requestBody.dataStreams.length, level: 'datastream', metric_types: requestBody.metricTypes,