diff --git a/public/app/plugins/datasource/elasticsearch/QueryBuilder.ts b/public/app/plugins/datasource/elasticsearch/QueryBuilder.ts
index 59a7158c0cf..f398b87fa39 100644
--- a/public/app/plugins/datasource/elasticsearch/QueryBuilder.ts
+++ b/public/app/plugins/datasource/elasticsearch/QueryBuilder.ts
@@ -26,6 +26,9 @@ import {
} from './types';
import { convertOrderByToMetricId, getScriptValue } from './utils';
+// Omitting 1m, 1h, 1d for now, as these cover the main use cases for calendar_interval
+export const calendarIntervals: string[] = ['1w', '1M', '1q', '1y'];
+
export class ElasticQueryBuilder {
timeField: string;
@@ -100,7 +103,6 @@ export class ElasticQueryBuilder {
getDateHistogramAgg(aggDef: DateHistogram) {
const esAgg: any = {};
const settings = aggDef.settings || {};
- const calendarIntervals: string[] = ['1w', '1M', '1q', '1y'];
esAgg.field = aggDef.field || this.timeField;
esAgg.min_doc_count = settings.min_doc_count || 0;
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx
new file mode 100644
index 00000000000..9389f779bf7
--- /dev/null
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx
@@ -0,0 +1,87 @@
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
+
+import { DateHistogram } from 'app/plugins/datasource/elasticsearch/types';
+
+import { useDispatch } from '../../../../hooks/useStatelessReducer';
+
+import { DateHistogramSettingsEditor } from './DateHistogramSettingsEditor';
+
+jest.mock('../../../../hooks/useStatelessReducer');
+
+describe('DateHistogramSettingsEditor', () => {
+ test('Renders the date histogram selector', async () => {
+ const bucketAgg: DateHistogram = {
+ field: '@timestamp',
+ id: '2',
+ settings: { interval: 'auto' },
+ type: 'date_histogram',
+ };
+ render();
+ expect(await screen.findByText('Fixed interval')).toBeInTheDocument();
+ expect(await screen.findByText('auto')).toBeInTheDocument();
+ });
+ test('Renders the date histogram selector with a fixed interval', async () => {
+ const bucketAgg: DateHistogram = {
+ field: '@timestamp',
+ id: '2',
+ settings: { interval: '10s' },
+ type: 'date_histogram',
+ };
+ render();
+ expect(await screen.findByText('Fixed interval')).toBeInTheDocument();
+ expect(await screen.findByText('10s')).toBeInTheDocument();
+ });
+ test('Renders the date histogram selector with a calendar interval', async () => {
+ const bucketAgg: DateHistogram = {
+ field: '@timestamp',
+ id: '2',
+ settings: { interval: '1w' },
+ type: 'date_histogram',
+ };
+ render();
+ expect(await screen.findByText('Calendar interval')).toBeInTheDocument();
+ expect(await screen.findByText('1w')).toBeInTheDocument();
+ });
+
+ describe('Handling change', () => {
+ let dispatch = jest.fn();
+ beforeEach(() => {
+ dispatch.mockClear();
+ jest.mocked(useDispatch).mockReturnValue(dispatch);
+ });
+ test('Handles changing from calendar to fixed interval type', async () => {
+ const bucketAgg: DateHistogram = {
+ field: '@timestamp',
+ id: '2',
+ settings: { interval: '1w' },
+ type: 'date_histogram',
+ };
+ render();
+
+ expect(await screen.findByText('Calendar interval')).toBeInTheDocument();
+ expect(await screen.findByText('1w')).toBeInTheDocument();
+
+ await selectOptionInTest(screen.getByLabelText('Calendar interval'), '10s');
+
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ });
+ test('Renders the date histogram selector with a calendar interval', async () => {
+ const bucketAgg: DateHistogram = {
+ field: '@timestamp',
+ id: '2',
+ settings: { interval: '1m' },
+ type: 'date_histogram',
+ };
+ render();
+
+ expect(await screen.findByText('Fixed interval')).toBeInTheDocument();
+ expect(await screen.findByText('1m')).toBeInTheDocument();
+
+ await selectOptionInTest(screen.getByLabelText('Fixed interval'), '1q');
+
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ });
+ });
+});
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
index 5b5f1c5f03d..7fd36121783 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
@@ -1,9 +1,10 @@
import { uniqueId } from 'lodash';
-import React, { useRef } from 'react';
+import React, { useCallback, useRef } from 'react';
import { GroupBase, OptionsOrGroups } from 'react-select';
import { InternalTimeZones, SelectableValue } from '@grafana/data';
import { InlineField, Input, Select, TimeZonePicker } from '@grafana/ui';
+import { calendarIntervals } from 'app/plugins/datasource/elasticsearch/QueryBuilder';
import { useDispatch } from '../../../../hooks/useStatelessReducer';
import { DateHistogram } from '../../../../types';
@@ -22,6 +23,10 @@ const defaultIntervalOptions: Array> = [
{ label: '20m', value: '20m' },
{ label: '1h', value: '1h' },
{ label: '1d', value: '1d' },
+ { label: '1w', value: '1w' },
+ { label: '1M', value: '1M' },
+ { label: '1q', value: '1q' },
+ { label: '1y', value: '1y' },
];
const hasValue =
@@ -48,16 +53,35 @@ interface Props {
bucketAgg: DateHistogram;
}
+const getIntervalType = (interval: string | undefined): 'calendar' | 'fixed' => {
+ return interval && calendarIntervals.includes(interval) ? 'calendar' : 'fixed';
+};
+
export const DateHistogramSettingsEditor = ({ bucketAgg }: Props) => {
const dispatch = useDispatch();
const { current: baseId } = useRef(uniqueId('es-date_histogram-'));
- const handleIntervalChange = ({ value }: SelectableValue) =>
- dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'interval', newValue: value }));
+ const handleIntervalChange = useCallback(
+ ({ value }: SelectableValue) =>
+ dispatch(changeBucketAggregationSetting({ bucketAgg, settingName: 'interval', newValue: value })),
+ [bucketAgg, dispatch]
+ );
+
+ const intervalType = getIntervalType(
+ bucketAgg.settings?.interval || bucketAggregationConfig.date_histogram.defaultSettings?.interval
+ );
return (
<>
-
+
-
> = {
- labelWidth: 16,
+ labelWidth: 18,
};
interface Props {