From 9c6feb8de5fb5adf0304b79b88fc03917ff5b177 Mon Sep 17 00:00:00 2001 From: Andrew Hackmann <5140848+bossinc@users.noreply.github.com> Date: Tue, 30 Dec 2025 09:37:19 -0600 Subject: [PATCH] Elasticsearch: Builder queries no longer execute in code mode (#115456) * The builder query no longer runs if code mode query is empty. Remove checks for query being empty to run raw query. * missed save * prettier? * Update public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.ts Co-authored-by: Andreas Christou --------- Co-authored-by: Andreas Christou --- .../elasticsearch/data_query_processor.go | 2 +- .../elasticsearch/data_query_validator.go | 2 +- .../state/reducer.test.ts | 25 ++++++++++- .../BucketAggregationsEditor/state/reducer.ts | 7 ++- .../state/reducer.test.ts | 24 ++++++++++- .../MetricAggregationsEditor/state/reducer.ts | 7 ++- .../components/QueryEditor/state.test.ts | 43 ++++++++++++++++++- .../components/QueryEditor/state.ts | 4 ++ 8 files changed, 107 insertions(+), 7 deletions(-) diff --git a/pkg/tsdb/elasticsearch/data_query_processor.go b/pkg/tsdb/elasticsearch/data_query_processor.go index 1c4ec7b3cdd..288d6ce30de 100644 --- a/pkg/tsdb/elasticsearch/data_query_processor.go +++ b/pkg/tsdb/elasticsearch/data_query_processor.go @@ -24,7 +24,7 @@ func (e *elasticsearchDataQuery) processQuery(q *Query, ms *es.MultiSearchReques filters.AddDateRangeFilter(defaultTimeField, to, from, es.DateFormatEpochMS) filters.AddQueryStringFilter(q.RawQuery, true) - if q.EditorType != nil && *q.EditorType == "code" && q.RawDSLQuery != "" { + if q.EditorType != nil && *q.EditorType == "code" { cfg := backend.GrafanaConfigFromContext(e.ctx) if !cfg.FeatureToggles().IsEnabled("elasticsearchRawDSLQuery") { return backend.DownstreamError(fmt.Errorf("raw DSL query feature is disabled. Enable the elasticsearchRawDSLQuery feature toggle to use this query type")) diff --git a/pkg/tsdb/elasticsearch/data_query_validator.go b/pkg/tsdb/elasticsearch/data_query_validator.go index 648dbb53109..72bcde016b6 100644 --- a/pkg/tsdb/elasticsearch/data_query_validator.go +++ b/pkg/tsdb/elasticsearch/data_query_validator.go @@ -7,7 +7,7 @@ import ( // isQueryWithError validates the query and returns an error if invalid func isQueryWithError(query *Query) error { // Skip validation for raw DSL queries because no easy way to see it is valid without just running it - if query.EditorType != nil && *query.EditorType == "code" && query.RawDSLQuery != "" { + if query.EditorType != nil && *query.EditorType == "code" { return nil } if len(query.BucketAggs) == 0 { diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.test.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.test.ts index 6a34d5d7d91..f4a5cc02dde 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.test.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.test.ts @@ -7,7 +7,7 @@ import { import { defaultBucketAgg } from '../../../../queryDef'; import { reducerTester } from '../../../reducerTester'; import { changeMetricType } from '../../MetricAggregationsEditor/state/actions'; -import { initQuery } from '../../state'; +import { changeEditorTypeAndResetQuery, initQuery } from '../../state'; import { bucketAggregationConfig } from '../utils'; import { @@ -180,4 +180,27 @@ describe('Bucket Aggregations Reducer', () => { .thenStateShouldEqual([bucketAgg]); }); }); + + describe('When switching editor type', () => { + it('Should reset bucket aggregations to default when switching editor types', () => { + const defaultTimeField = '@timestamp'; + const initialState: BucketAggregation[] = [ + { + id: '1', + type: 'date_histogram', + field: '@timestamp', + }, + { + id: '2', + type: 'terms', + field: 'status', + }, + ]; + + reducerTester() + .givenReducer(createReducer(defaultTimeField), initialState) + .whenActionIsDispatched(changeEditorTypeAndResetQuery('code')) + .thenStateShouldEqual([{ ...defaultBucketAgg('2'), field: defaultTimeField }]); + }); + }); }); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.ts index b3638e1f1d1..5ba29e656d8 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/state/reducer.ts @@ -6,7 +6,7 @@ import { defaultBucketAgg } from '../../../../queryDef'; import { removeEmpty } from '../../../../utils'; import { changeMetricType } from '../../MetricAggregationsEditor/state/actions'; import { metricAggregationConfig } from '../../MetricAggregationsEditor/utils'; -import { initQuery } from '../../state'; +import { changeEditorTypeAndResetQuery, initQuery } from '../../state'; import { bucketAggregationConfig } from '../utils'; import { @@ -87,6 +87,11 @@ export const createReducer = return state; } + if (changeEditorTypeAndResetQuery.match(action)) { + // Returns the default bucket agg. We will always want to set the default when switching types + return [{ ...defaultBucketAgg('2'), field: defaultTimeField }]; + } + if (changeBucketAggregationSetting.match(action)) { return state!.map((bucketAgg) => { if (bucketAgg.id !== action.payload.bucketAgg.id) { diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.test.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.test.ts index 5662ad399ea..9dcbaa9f974 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.test.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.test.ts @@ -7,7 +7,7 @@ import { import { defaultMetricAgg } from '../../../../queryDef'; import { reducerTester } from '../../../reducerTester'; -import { initQuery } from '../../state'; +import { changeEditorTypeAndResetQuery, initQuery } from '../../state'; import { metricAggregationConfig } from '../utils'; import { @@ -248,4 +248,26 @@ describe('Metric Aggregations Reducer', () => { .whenActionIsDispatched(initQuery()) .thenStateShouldEqual([defaultMetricAgg('1')]); }); + + describe('When switching editor type', () => { + it('Should reset to single default metric when switching to code editor', () => { + const initialState: MetricAggregation[] = [ + { + id: '1', + type: 'avg', + field: 'value', + }, + { + id: '2', + type: 'max', + field: 'value', + }, + ]; + + reducerTester() + .givenReducer(reducer, initialState) + .whenActionIsDispatched(changeEditorTypeAndResetQuery('code')) + .thenStateShouldEqual([defaultMetricAgg('1')]); + }); + }); }); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.ts index 966bd71d6c8..c0dab7bd4b1 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/state/reducer.ts @@ -4,7 +4,7 @@ import { ElasticsearchDataQuery, MetricAggregation } from 'app/plugins/datasourc import { defaultMetricAgg, queryTypeToMetricType } from '../../../../queryDef'; import { removeEmpty } from '../../../../utils'; -import { initQuery } from '../../state'; +import { changeEditorTypeAndResetQuery, initQuery } from '../../state'; import { isMetricAggregationWithMeta, isMetricAggregationWithSettings, isPipelineAggregation } from '../aggregations'; import { getChildren, metricAggregationConfig } from '../utils'; @@ -65,6 +65,11 @@ export const reducer = ( }); } + if (changeEditorTypeAndResetQuery.match(action)) { + // Reset to default metric when switching to editor types + return [defaultMetricAgg('1')]; + } + if (changeMetricField.match(action)) { return state!.map((metric) => { if (metric.id !== action.payload.id) { diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.test.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.test.ts index cad89cd32a7..111b284eb79 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.test.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.test.ts @@ -1,7 +1,15 @@ import { ElasticsearchDataQuery } from '../../dataquery.gen'; import { reducerTester } from '../reducerTester'; -import { aliasPatternReducer, changeAliasPattern, changeQuery, initQuery, queryReducer } from './state'; +import { + aliasPatternReducer, + changeAliasPattern, + changeEditorTypeAndResetQuery, + changeQuery, + initQuery, + queryReducer, + rawDSLQueryReducer, +} from './state'; describe('Query Reducer', () => { describe('On Init', () => { @@ -42,6 +50,17 @@ describe('Query Reducer', () => { .whenActionIsDispatched({ type: 'THIS ACTION SHOULD NOT HAVE ANY EFFECT IN THIS REDUCER' }) .thenStateShouldEqual(initialState); }); + + describe('When switching editor type', () => { + it('Should clear query when switching editor types', () => { + const initialQuery: ElasticsearchDataQuery['query'] = 'Some lucene query'; + + reducerTester() + .givenReducer(queryReducer, initialQuery) + .whenActionIsDispatched(changeEditorTypeAndResetQuery('code')) + .thenStateShouldEqual(''); + }); + }); }); describe('Alias Pattern Reducer', () => { @@ -62,4 +81,26 @@ describe('Alias Pattern Reducer', () => { .whenActionIsDispatched({ type: 'THIS ACTION SHOULD NOT HAVE ANY EFFECT IN THIS REDUCER' }) .thenStateShouldEqual(initialState); }); + + describe('When switching editor type', () => { + it('Should clear alias when switching editor types', () => { + const initialAlias: ElasticsearchDataQuery['alias'] = 'Some alias pattern'; + + reducerTester() + .givenReducer(aliasPatternReducer, initialAlias) + .whenActionIsDispatched(changeEditorTypeAndResetQuery('code')) + .thenStateShouldEqual(''); + }); + }); +}); + +describe('Raw DSL Query Reducer', () => { + it('Should clear raw DSL query when switching editor types', () => { + const initialRawQuery: ElasticsearchDataQuery['rawDSLQuery'] = '{"query": {"match_all": {}}}'; + + reducerTester() + .givenReducer(rawDSLQueryReducer, initialRawQuery) + .whenActionIsDispatched(changeEditorTypeAndResetQuery('builder')) + .thenStateShouldEqual(''); + }); }); diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts index a9ed51b39ff..5a1be7be31c 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/state.ts @@ -58,6 +58,10 @@ export const aliasPatternReducer = (prevAliasPattern: ElasticsearchDataQuery['al return action.payload; } + if (changeEditorTypeAndResetQuery.match(action)) { + return ''; + } + if (initQuery.match(action)) { return prevAliasPattern || ''; }